Skip to content

Commit

Permalink
Removing $super and replacing with BaseType.prototype.Method.call(thi…
Browse files Browse the repository at this point in the history
…s). Adding support for hosted mode GetTypeName().
  • Loading branch information
Frank Laub committed Jun 28, 2010
1 parent 490a322 commit 392addd
Show file tree
Hide file tree
Showing 57 changed files with 1,103 additions and 1,032 deletions.
File renamed without changes.
File renamed without changes.
38 changes: 18 additions & 20 deletions src/DotWeb.Hosting.Bridge/JsBridge.cs
Expand Up @@ -434,9 +434,27 @@ public class JsBridge : IDotWebHost
return function;
}

private bool IsObjectExtensions(Type type) {
return type.FullName == "System.ObjectExtensions";
}

private object InvokeOnObjectExtensions(object scope, MethodInfo method, object[] args) {
var obj = args.First();
if (method.Name == "GetTypeName") {
var type = obj.GetType();
return type.FullName;
}

throw new NotSupportedException();
}

public object Invoke(object scope, object objMethod, object[] args) {
try {
MethodBase method = (MethodBase)objMethod;
if (IsObjectExtensions(method.DeclaringType)) {
return InvokeOnObjectExtensions(scope, (MethodInfo)method, args);
}

if (IsJsDynamic(method.DeclaringType)) {
return InvokeOnDynamic(scope, (MethodInfo)method, args);
}
Expand Down Expand Up @@ -511,26 +529,6 @@ public class JsBridge : IDotWebHost
throw new InvalidOperationException();
}

//public object InvokeRemoteMethod(object scope, int stackDepth, params object[] args) {
// if (this.isUnwrapping) {
// return null;
// }

// StackFrame frame = new StackFrame(stackDepth + 1);
// var method = frame.GetMethod();

// if (method.IsConstructor) {
// StackFrame previous = new StackFrame(stackDepth + 2);
// // this prevents ctors from being called twice
// // we only want the derived class's ctor to execute, not any bases
// //if (previous.GetMethod().DeclaringType.IsSubclassOf(typeof(JsNativeBase))) {
// // return null;
// //}
// }

// return InvokeRemoteMethod(method, scope, args);
//}

public T Cast<T>(object obj) {
int handle = GetRemoteReference(obj);
var brother = CreateInstance(typeof(T));
Expand Down
51 changes: 21 additions & 30 deletions src/DotWeb.Hosting.Weaver/SimpleWeaver.cs
Expand Up @@ -162,7 +162,7 @@ class ConstantNames

private Dictionary<string, MethodReference> PrepareTemplates(ModuleDefinition module) {
var templates = new Dictionary<string, MethodReference>();
foreach (var ctor in PredefinedTypes.JsAttributes) {
foreach (var ctor in PredefinedTypes.JsAttributeCtors) {
var methodRef = module.Import(ctor);
templates.Add(methodRef.ToString(), methodRef);
}
Expand Down Expand Up @@ -304,19 +304,22 @@ static class PredefinedTypes
public static readonly SR.MethodInfo MethodBase_GetCurrentMethod;
public static readonly SR.ConstructorInfo Object_ctor;

public static readonly Type JsCode = typeof(JsCodeAttribute);
public static readonly Type JsMacro = typeof(JsMacroAttribute);
public static readonly Type JsAugment = typeof(JsAugmentAttribute);
public static readonly Type JsCamelCase = typeof(JsCamelCaseAttribute);
public static readonly Type JsName = typeof(JsNameAttribute);
public static readonly Type JsNamespace = typeof(JsNamespaceAttribute);
public static readonly Type JsAnonymous = typeof(JsAnonymousAttribute);
public static readonly Type JsIntrinsic = typeof(JsIntrinsicAttribute);
public static readonly Type JsObject = typeof(JsObjectAttribute);
public static readonly Type JsDynamic = typeof(JsDynamicAttribute);
public static readonly Type Extension = typeof(ExtensionAttribute);

public static readonly List<SR.ConstructorInfo> JsAttributes = new List<SR.ConstructorInfo>();
private static Type[] JsAttributeTypes =
{
typeof(JsCodeAttribute),
typeof(JsMacroAttribute),
typeof(JsAugmentAttribute),
typeof(JsCamelCaseAttribute),
typeof(JsNameAttribute),
typeof(JsNamespaceAttribute),
typeof(JsAnonymousAttribute),
typeof(JsIntrinsicAttribute),
typeof(JsObjectAttribute),
typeof(JsDynamicAttribute),
typeof(ExtensionAttribute),
};

public static readonly List<SR.ConstructorInfo> JsAttributeCtors = new List<SR.ConstructorInfo>();

static PredefinedTypes() {
HostedMode_get_Host = HostedMode.GetMethod("get_Host");
Expand All @@ -325,22 +328,10 @@ static class PredefinedTypes
MethodBase_GetCurrentMethod = MethodBase.GetMethod("GetCurrentMethod");
Object_ctor = Object.GetConstructor(Type.EmptyTypes);

PrepareJsAttribute(JsCode);
PrepareJsAttribute(JsMacro);
PrepareJsAttribute(JsAugment);
PrepareJsAttribute(JsCamelCase);
PrepareJsAttribute(JsName);
PrepareJsAttribute(JsNamespace);
PrepareJsAttribute(JsAnonymous);
PrepareJsAttribute(JsIntrinsic);
PrepareJsAttribute(JsObject);
PrepareJsAttribute(JsDynamic);
PrepareJsAttribute(Extension);
}

private static void PrepareJsAttribute(Type type) {
foreach (var ctor in type.GetConstructors()) {
JsAttributes.Add(ctor);
foreach (var attrType in JsAttributeTypes) {
foreach (var ctor in attrType.GetConstructors()) {
JsAttributeCtors.Add(ctor);
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/DotWeb.System/DotWeb/JsArray.cs
Expand Up @@ -555,5 +555,7 @@ public class JsArray
/// <param name="initialValue"></param>
/// <returns></returns>
public extern object ReduceRight(ArrayReduceFn callback, object initialValue);

public extern override string ToString();
}
}
29 changes: 27 additions & 2 deletions src/DotWeb.Translator/Generator/JavaScript/JsPrinter.cs
Expand Up @@ -380,6 +380,10 @@ class JsPrinter : ICodeExpressionVisitor<string>
// return string.Format("{0}.{1}", Print(exp.TargetObject), EncodeName(exp.Property.Name));
//}
Debug.Assert(exp.ReferenceType == CodePropertyReference.RefType.Get);
if (exp.Method.TargetObject is CodeBaseReference) {
return PrintCallBaseMethod(exp.Method, null);
}

return VisitReturn(exp.Method) + "()";
}

Expand Down Expand Up @@ -425,7 +429,7 @@ class JsPrinter : ICodeExpressionVisitor<string>
}

public string VisitReturn(CodeBaseReference exp) {
return "this.$super";
throw new NotSupportedException();
}

public string VisitReturn(CodeCastExpression exp) {
Expand Down Expand Up @@ -461,7 +465,28 @@ class JsPrinter : ICodeExpressionVisitor<string>
}
}

return string.Format("{0}({1})", Print(exp.Method), Print(exp.Parameters));
var strArgs = Print(exp.Parameters);

if (exp.Method.TargetObject is CodeBaseReference) {
return PrintCallBaseMethod(exp.Method, strArgs);
}
else {
var strMethod = Print(exp.Method);
return string.Format("{0}({1})", strMethod, strArgs);
}
}

private string PrintCallBaseMethod(CodeMethodReference method, string strArgs) {
var strMethod = GetMethodName(method.Reference);
var strBase = Print(CurrentMethod.DeclaringType.BaseType);
if (string.IsNullOrEmpty(strArgs)) {
var ret = string.Format("{0}.prototype.{1}.call(this)", strBase, strMethod);
return ret;
}
else {
var ret = string.Format("{0}.prototype.{1}.call(this, {2})", strBase, strMethod, strArgs);
return ret;
}
}

public string VisitReturn(CodePrimitiveExpression exp) {
Expand Down
1 change: 0 additions & 1 deletion src/DotWeb.Translator/Generator/JavaScript/Runtime.js
Expand Up @@ -38,7 +38,6 @@ $Class = function(parent, ns, name, dict) {
tmp.prototype = parent.prototype;
cls.prototype = new tmp();
cls.prototype.constructor = cls;
cls.prototype.$super = tmp.prototype;
}

var typename = name;
Expand Down
49 changes: 38 additions & 11 deletions src/DotWeb.Translator/TranslationContext.cs
Expand Up @@ -46,28 +46,23 @@ public class TranslationContext
bool followDependencies,
List<AssemblyDefinition> asmDependencies) {
if (followDependencies) {
var typesCache = new List<TypeDefinition>();
var typesCache = new TypesCache(asmDependencies);
var methodsCache = new List<MethodDefinition>();
GenerateMethod(method, typesCache, methodsCache);

foreach (var type in typesCache) {
var asm = type.Module.Assembly;
asmDependencies.AddUnique(asm);
}
}
else {
var parsedMethod = Parse(method);
this.generator.Write(parsedMethod);
}
}

private void GenerateMethod(MethodDefinition method, List<TypeDefinition> typesCache, List<MethodDefinition> methodsCache) {
private void GenerateMethod(MethodDefinition method, TypesCache typesCache, List<MethodDefinition> methodsCache) {
// we still need to process virtual methods even if they aren't emittable
if (method.IsVirtual) {
var overrides = this.typeSystem.GetOverridesForVirtualMethod(method);
foreach (var overridenMethod in overrides) {
var overridenType = overridenMethod.DeclaringType;
if (typesCache.Contains(overridenType)) {
if (typesCache.HasVisited(overridenType)) {
GenerateMethod(overridenMethod, typesCache, methodsCache);
}
}
Expand All @@ -78,6 +73,7 @@ public class TranslationContext

// to deal with recursive methods, add to the cache before processing
methodsCache.Add(method);
typesCache.AddVisited(method.DeclaringType);

if (IsEmittable(method)) {
var parsedMethod = Parse(method);
Expand All @@ -93,8 +89,8 @@ public class TranslationContext
}
}

private void GenerateTypeDecl(TypeDefinition type, List<TypeDefinition> typesCache) {
if (!typesCache.Contains(type)) {
private void GenerateTypeDecl(TypeDefinition type, TypesCache typesCache) {
if (!typesCache.HasEmitted(type)) {
var baseType = type.BaseType.Resolve();
if (IsEmittable(baseType)) {
GenerateTypeDecl(baseType, typesCache);
Expand All @@ -108,7 +104,35 @@ public class TranslationContext
this.generator.WriteStaticConstructor(staticCtorMethod);
}
}
typesCache.Add(type);
typesCache.AddEmitted(type);
}
}

class TypesCache
{
private List<AssemblyDefinition> asmDependencies;
private List<TypeDefinition> visited = new List<TypeDefinition>();
private List<TypeDefinition> emitted = new List<TypeDefinition>();

public TypesCache(List<AssemblyDefinition> asmDependencies) {
this.asmDependencies = asmDependencies;
}

public bool HasVisited(TypeDefinition type) {
return this.visited.Contains(type);
}

public bool HasEmitted(TypeDefinition type) {
return this.emitted.Contains(type);
}

public void AddVisited(TypeDefinition type) {
this.visited.AddUnique(type);
}

public void AddEmitted(TypeDefinition type) {
this.emitted.Add(type);
this.asmDependencies.AddUnique(type.Module.Assembly);
}
}

Expand Down Expand Up @@ -181,6 +205,9 @@ public class TranslationContext
}

private bool IsEmittable(MethodDefinition method) {
if (method.IsAbstract)
return false;

if (AttributeHelper.GetJsMacro(method) != null) {
return false;
}
Expand Down
22 changes: 3 additions & 19 deletions test/DotWeb.Functional.Test/Client/ArrayTest.cs
Expand Up @@ -4,28 +4,12 @@

namespace DotWeb.Functional.Test.Client
{
class ArrayTest : JsScript
class ArrayTest : TestBase
{
private TestResultView view;

public ArrayTest() {
var sandbox = Document.getElementById("sandbox");
this.view = new TestResultView(sandbox);

Log.Write("ArrayTest starting...");

try {
RunTest();
}
catch (Exception ex) {
Log.Write(ex.Message);
}
}

private void RunTest() {
protected override void RunTest() {
var array = new int[] { 1, 2, 3 };

this.view.AreEqual("identity", array, () => array);
AreEqual("identity", array, () => array);
}
}
}
30 changes: 7 additions & 23 deletions test/DotWeb.Functional.Test/Client/DictionaryTest.cs
Expand Up @@ -4,39 +4,23 @@

namespace DotWeb.Functional.Test.Client
{
class DictionaryTest : JsScript
class DictionaryTest : TestBase
{
private TestResultView view;

public DictionaryTest() {
var sandbox = Document.getElementById("sandbox");
this.view = new TestResultView(sandbox);

Log.Write("DictionaryTest starting...");

try {
RunTest();
}
catch (Exception ex) {
Log.Write(ex.Message);
}
}

private void RunTest() {
protected override void RunTest() {
var dict = new Dictionary<string, string>();

this.view.AreStringsEqual("empty", "{}", () => dict);
this.view.AreEqual("dict.Count == 0", 0, () => dict.Count);
this.view.AreStringsEqual("dict.Add(\"key\", \"value\")", "{key: value}", () => {
AreStringsEqual("empty", "{}", () => dict);
AreEqual("dict.Count == 0", 0, () => dict.Count);
AreStringsEqual("dict.Add(\"key\", \"value\")", "{key: value}", () => {
dict.Add("key", "value");
return dict;
});
this.view.AreStringsEqual("dict.Add(\"other\", \"other\")", "{key: value, other: other}", () => {
AreStringsEqual("dict.Add(\"other\", \"other\")", "{key: value, other: other}", () => {
dict.Add("other", "other");
return dict;
});

this.view.AreStringsEqual("dict.Clear()", "{}", () => {
AreStringsEqual("dict.Clear()", "{}", () => {
dict.Clear();
return dict;
});
Expand Down
Expand Up @@ -40,6 +40,7 @@
<Compile Include="StringBuilderTest.cs" />
<Compile Include="StringTest.cs" />
<Compile Include="Lambda.cs" />
<Compile Include="TestBase.cs" />
<Compile Include="TestResultView.cs" />
<Compile Include="ListTest.cs" />
<Compile Include="Log.cs" />
Expand Down

0 comments on commit 392addd

Please sign in to comment.