コード例 #1
0
        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");
        }
コード例 #2
0
 public MethodContext(JsCompiler host, JsClass klass, IMethod method, TryCatchBlock[] blocks)
 {
     ProtectedBlocks = blocks;
     Host            = host;
     Class           = klass;
     Method          = method;
 }
コード例 #3
0
        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);
        }
コード例 #4
0
        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");
            }
        }
コード例 #5
0
        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));
            }
        }
コード例 #6
0
        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);
            }
        }
コード例 #7
0
        private static void CompileGetHashCode(JsClass klass)
        {
            var func = new JsFunction(null);

            func.Body.Add("$hash".Id().Call("this".Id()).Return());

            klass.ExtendPrototype(func, "GetHashCode");
        }
コード例 #8
0
        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);
        }
コード例 #9
0
        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");
        }
コード例 #10
0
        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;
            }
        }
コード例 #11
0
        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);
            }
        }
コード例 #12
0
        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");
            }
        }
コード例 #13
0
        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);
        }
コード例 #14
0
        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);
                }
            }
        }
コード例 #15
0
        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);
        }
コード例 #16
0
        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");
        }
コード例 #17
0
        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);
        }
コード例 #18
0
        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");
        }
コード例 #19
0
        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);
        }
コード例 #20
0
 public JsClass(IType type, JsClass baseClass)
 {
     Type = type;
     Base = baseClass;
 }
コード例 #21
0
 public NopCodeProvider(JsCompiler host, JsClass klass, IMethod method)
 {
     _host   = host;
     _klass  = klass;
     _method = method;
 }
コード例 #22
0
 private static IEnumerable <IField> GetInstanceFields(JsClass klass)
 {
     return(klass.Type.Fields.Where(field => !field.IsStatic && !field.IsConstant));
 }