public static void CompileCopy(JsClass klass) { var type = klass.Type; var func = new JsFunction(null); var obj = "o".Id(); func.Body.Add(type.New().Var(obj.Value)); foreach (var field in GetInstanceFields(klass)) { var name = field.JsName(); var value = "this".Id().Get(name); if (field.Type.TypeKind == TypeKind.Struct) { value = "$copy".Id().Call(value); } func.Body.Add(obj.Set(name, value)); } func.Body.Add(obj.Return()); klass.ExtendPrototype(func, "$copy"); }
public MethodContext(JsCompiler host, JsClass klass, IMethod method, TryCatchBlock[] blocks) { ProtectedBlocks = blocks; Host = host; Class = klass; Method = method; }
internal JsFunction CompileMethodBody(JsClass klass, IMethod method, IClrMethodBody body) { var blocks = body.GetAllProtectedBlocks().ToArray(); var context = new MethodContext(this, klass, method, blocks); var func = new JsFunction(null, method.JsParams()); //TODO: cache info and code as separate class property var info = new JsObject(true) { { "isVoid", method.IsVoid() }, { "blocks", CompileBlocks(blocks) }, { "blockMap", CompileBlockMap(body, blocks) }, }; var args = CompilerArgs(method); var vars = new JsArray(method.Body.LocalVariables.Select(x => x.Type.InitialValue())); var code = new JsArray(body.Code.Select <Instruction, object>(i => new JsInstruction(i, CompileInstruction(context, i))), "\n"); func.Body.Add(args.Var("args")); func.Body.Add(vars.Var("vars")); func.Body.Add(info.Var("info")); foreach (var var in context.Vars) { func.Body.Add(var); } func.Body.Add(code.Var("code")); func.Body.Add(new JsText("var ctx = new $context(info, args, vars);")); func.Body.Add(new JsText("return ctx.exec(code);")); return(func); }
public static void Compile(JsCompiler compiler, JsClass klass, ObjectMethodId id) { var type = klass.Type; if (!type.IsEnum) { throw new InvalidOperationException("Type is not enum."); } switch (id) { case ObjectMethodId.Equals: //TODO: implement Equals for enums here JsStruct.Compile(compiler, klass, id); break; case ObjectMethodId.GetHashCode: CompileGetHashCode(compiler, klass); break; case ObjectMethodId.ToString: CompileToString(compiler, klass); break; default: throw new ArgumentOutOfRangeException("id"); } }
private static void CompileImplementedMethods(JsClass klass, IMethod method) { if (method.IsExplicitImplementation) { return; } var impls = method.Implements; if (impls == null) { return; } if (impls.Count <= 0) { return; } var type = method.DeclaringType.JsFullName(method); var name = method.JsName(); foreach (var i in impls) { var func = new JsFunction(null, i.JsParams()); var call = "this".Id().Get(name).Call(i.JsArgs()); func.Body.Add(method.IsVoid() ? call.AsStatement() : call.Return()); klass.Add(new JsGeneratedMethod(string.Format("{0}.prototype.{1}", type, i.JsName()), func)); } }
private void CompileOverrides(JsClass klass, IMethod method) { // GetType is implemented by TypeInfoBuilder if (method.IsGetType()) { return; } foreach (var subclass in klass.Subclasses.ToList()) { var o = subclass.Type.FindOverrideMethod(method); if (o != null) { CompileMethod(o); } else { var id = method.GetObjectMethodId(); if (id != ObjectMethodId.Unknown) { CompileMethod(subclass, id); } } CompileOverrides(subclass, method); } }
private static void CompileGetHashCode(JsClass klass) { var func = new JsFunction(null); func.Body.Add("$hash".Id().Call("this".Id()).Return()); klass.ExtendPrototype(func, "GetHashCode"); }
internal JsClass CompileClass(IType type) { if (type == null || type.IsExcluded()) { return(null); } var klass = type.Data as JsClass; if (klass != null) { return(klass); } if (type.IsEnum && type.ValueType.IsInt64()) { CompileClass(type.ValueType); } var baseType = type.BaseType; var baseClass = CompileClass(baseType.Is(SystemTypeCode.ValueType) || type.IsEnum ? SystemTypes.Object : baseType); var ns = string.IsNullOrEmpty(type.Namespace) ? "$global" : type.Namespace; _program.DefineNamespace(ns); klass = new JsClass(type, baseType.Is(SystemTypeCode.ValueType) || type.IsString() ? null : baseClass); type.Data = klass; if (baseClass != null) { baseClass.Subclasses.Add(klass); } foreach (var iface in type.Interfaces) { JsInterface.Make(iface).Implementations.Add(klass); } _program.Add(klass); switch (type.TypeKind) { case TypeKind.Struct: JsStruct.CompileCopy(klass); break; case TypeKind.Delegate: JsDelegate.CreateInstanceImpl(klass); break; } CompileImpls(klass, type); return(klass); }
private static void CompileToString(JsCompiler compiler, JsClass klass) { var type = klass.Type; CompileValues(compiler, klass); var func = new JsFunction(null); var withFlags = type.HasAttribute("System.FlagsAttribute"); func.Body.Add(new JsText(withFlags ? "return $enum.flags(this);" : "return $enum.stringify(this);")); klass.ExtendPrototype(func, "toString"); }
private void CompileMethod(JsClass klass, ObjectMethodId id) { switch (klass.Type.TypeKind) { case TypeKind.Struct: JsStruct.Compile(this, klass, id); break; case TypeKind.Enum: JsEnum.Compile(this, klass, id); break; } }
private void CompileField(JsClass klass, IField field) { if (field.Data != null) { return; } //TODO: do not compile primitive types klass.Add(JsField.Make(field)); if (field.Type.TypeKind == TypeKind.Struct) { CompileType(field.Type); } }
public static void Compile(JsCompiler compiler, JsClass klass, ObjectMethodId id) { switch (id) { case ObjectMethodId.Equals: CompileEquals(compiler, klass); break; case ObjectMethodId.GetHashCode: CompileGetHashCode(klass); break; case ObjectMethodId.ToString: // Object.ToString will be used break; default: throw new ArgumentOutOfRangeException("id"); } }
private static void CompileEquals(JsCompiler compiler, JsClass klass) { var other = "o".Id(); var func = new JsFunction(null, other.Value); func.Body.Add(new JsText("if (o === null || o === undefined) return false;")); //TODO: check object type JsNode result = null; foreach (var field in GetInstanceFields(klass)) { var name = field.JsName(); var left = "this".Id().Get(name); var right = other.Get(name); JsNode e; // primitive and ref types if (field.Type.TypeKind != TypeKind.Struct && !field.Type.IsInt64Based()) { e = left.Op(right, BinaryOperator.Equality); } else // value types, int64 based { var objectType = compiler.SystemTypes.Object; var eq = objectType.Methods.Find("Equals", objectType, objectType); compiler.CompileMethod(eq); e = eq.JsFullName().Id().Call(left, right); } result = result == null ? e : result.And(e); } func.Body.Add(result == null ? "false".Id().Return() : result.Return()); var methodName = ObjectMethods.Find(compiler.SystemTypes.Object, ObjectMethodId.Equals).JsName(); klass.ExtendPrototype(func, methodName); }
private void CompileImpls(JsClass klass, IType type) { var isEnumOrStruct = type.TypeKind == TypeKind.Struct || type.TypeKind == TypeKind.Enum; List <ObjectMethodId> objectMethods = null; if (isEnumOrStruct) { objectMethods = new List <ObjectMethodId> { ObjectMethodId.Equals, ObjectMethodId.GetHashCode, ObjectMethodId.ToString }; } foreach (var method in type.Methods) { if (isEnumOrStruct) { var id = method.GetObjectMethodId(); if (id != ObjectMethodId.Unknown) { objectMethods.Remove(id); } } if (IsCompilableImpl(method)) { CompileMethod(method); } } if (isEnumOrStruct) { foreach (var id in objectMethods.Where(id => ObjectMethods.Find(SystemTypes.Object, id).Data != null)) { CompileMethod(klass, id); } } }
private JsFunction CompileFunction(JsClass klass, IMethod method) { var func = CompileInlineFunction(method); if (func != null) { return(func); } var body = method.Body as IClrMethodBody; if (body == null) { throw new NotSupportedException("The method format is not supported"); } var translator = new Translator(); var codeProvider = new NopCodeProvider(this, klass, method); translator.Translate(method, method.Body, codeProvider); return(codeProvider.Function); }
private static void CompileGetHashCode(JsCompiler compiler, JsClass klass) { var type = klass.Type; var func = new JsFunction(null); var value = "this.$value".Id(); if (type.ValueType.IsInt64()) { //TODO: inline [U]Int64.GetHashCode implementation func.Body.Add(value.Get("GetHashCode").Call().Return()); } else if (!type.ValueType.Is(SystemTypeCode.Int32)) { var int32Type = compiler.SystemTypes.Int32; func.Body.Add("$conv".Id().Call(value, type.ValueType.JsTypeCode(), int32Type.JsTypeCode()).Return()); } else { func.Body.Add(value.Return()); } klass.ExtendPrototype(func, "GetHashCode"); }
private string CompileBox(IType type, JsClass klass) { var name = string.Format("{0}.$box", type.JsFullName()); if (klass.BoxCompiled) { return(name); } klass.BoxCompiled = true; var val = (JsNode)"v".Id(); var func = new JsFunction(null, "v"); if (type.IsNullableInstance()) { func.Body.Add(new JsText(string.Format("if (!v.has_value) return null;"))); func.Body.Add("$copy".Id().Call(val).Return()); type = type.GetTypeArgument(0); CompileClass(type); } else { if (type.Is(SystemTypeCode.Boolean)) { val = val.Op("!!"); } func.Body.Add(type.New(val).Return()); } klass.Add(new JsGeneratedMethod(name, func)); return(name); }
private static void CompileValues(JsCompiler compiler, JsClass klass) { var type = klass.Type; var fields = type.GetEnumFields() .Select(x => { var value = GetValue(compiler, x, type.ValueType); return(new { Name = x.Name, Value = value }); }); var typeName = type.JsFullName(); var valuesField = string.Format("{0}.$$values", typeName); object values; if (type.ValueType.IsInt64()) { values = new JsArray(fields.Select(x => (object)new JsObject { { "name", x.Name }, { "value", x.Value }, })); } else { values = new JsObject(fields.Select(x => new KeyValuePair <object, object>(x.Value, x.Name))); } klass.Add(new JsGeneratedField(valuesField, values)); var func = new JsFunction(null); func.Body.Add(valuesField.Id().Return()); klass.ExtendPrototype(func, "$values"); }
private string CompileUnbox(MethodContext context, IType type, JsClass klass) { var name = string.Format("{0}.$unbox", type.JsFullName()); if (klass.UnboxCompiled) { return(name); } klass.UnboxCompiled = true; var valueType = type.GetTypeArgument(0); var unbox = Unbox(context, valueType); var val = (JsNode)"v".Id(); var func = new JsFunction(null, "v"); func.Body.Add(val.Set(unbox.Call(val))); func.Body.Add(type.New(val).Return()); klass.Add(new JsGeneratedMethod(name, func)); return(name); }
public JsClass(IType type, JsClass baseClass) { Type = type; Base = baseClass; }
public NopCodeProvider(JsCompiler host, JsClass klass, IMethod method) { _host = host; _klass = klass; _method = method; }
private static IEnumerable <IField> GetInstanceFields(JsClass klass) { return(klass.Type.Fields.Where(field => !field.IsStatic && !field.IsConstant)); }