Пример #1
0
        private static IEnumerable <KeyValuePair <string, object> > Describe(IType type)
        {
            var hierarchy = new JsObject(type.GetFullTypeHierarchy().Select(x => new KeyValuePair <object, object>(x.FullName, 1)));

            var newFunc = new JsFunction();

            newFunc.Body.Add(type.New().Return());

            var list = new PropertyList
            {
                { "ns", type.Namespace ?? "" },
                { "name", type.Name },
                { "kind", type.GetCorlibKind() },
                { "$typecode", type.JsTypeCode() },
                { "$hierarchy", hierarchy },
                { "$new", newFunc },
            };

            if (type.ElementType != null)
            {
                list.Add("$elemType", type.ElementType.FullName);
            }

            if (type.ValueType != null)
            {
                list.Add("$valueType", type.ValueType.FullName);
            }

            return(list);
        }
Пример #2
0
        private JsNode OpNewarr(MethodContext context, IType elemType)
        {
            var key = new InstructionKey(InstructionCode.Newarr, elemType);
            var var = context.Vars[key];

            if (var != null)
            {
                return(var.Id());
            }

            var type = RegisterArrayType(elemType);

            var elemInit = new JsFunction(null);

            elemInit.Body.Add(elemType.InitialValue().Return());

            var info = new JsObject
            {
                { "init", elemInit },
                { "type", type.FullName },
                { "box", new BoxingImpl(this).Box(context, elemType) },
                { "unbox", new BoxingImpl(this).Unbox(context, elemType) },
                { "etc", elemType.JsTypeCode() },
            };

            var = context.Vars.Add(key, info);

            CompileClass(SystemTypes.Array);
            CompileType(elemType);

            return(var.Id());
        }
Пример #3
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");
        }
Пример #4
0
        private void AddImpl(IMethod method, JsFunction func)
        {
            var type  = _host.SystemTypes.Array;
            var klass = _host.CompileClass(type);

            klass.Add(new JsGeneratedMethod(method.JsFullName(type), func));
        }
Пример #5
0
        private void Build(JsClass klass)
        {
            var type = klass.Type;

            // ignore Avm.String we use System.String
            if (type.IsAvmString())
            {
                return;
            }

            Register(type);

            var func = new JsFunction(null);

            if (type.Is(SystemTypeCode.Array))
            {
                func.Body.Add("$types".Id().Get("this".Id().Get("m_type")).Call().Return());
            }
            else
            {
                func.Body.Add("$types".Id().Get(type.FullName).Call().Return());
            }

            klass.ExtendPrototype(func, "GetType");
        }
Пример #6
0
        private void Register(IType type)
        {
            var init = new JsFunction();

            var prop = string.Format("$types['{0}']", "$$" + type.FullName.JsEscape());

            init.Body.Add(new JsText(string.Format("var t = {0};", prop)));
            init.Body.Add(new JsText(string.Format("if (t != undefined) return t;")));

            var t        = "t".Id();
            var typeType = _host.SystemTypes.Type;

            init.Body.Add(t.Set(typeType.New()));
            init.Body.Add(new JsText(string.Format("{0} = t;", prop)));

            var description = Describe(type);

            foreach (var property in description)
            {
                init.Body.Add(t.Set(property.Key, property.Value));
            }

            init.Body.Add(t.Return());

            _program.Add("$types".Id().Set(type.FullName, init));
        }
Пример #7
0
        private void CompileOp(IType type, BinaryOperator op)
        {
            // exclude natively supported types
            if (!HasOperators(type))
            {
                return;
            }

            var method = _operators.Find(op, type, type);

            if (method == null)
            {
                return;
            }

            if (method.Data != null)
            {
                return;
            }

            var jsMethod = CompileMethod(method);

            var val  = "v".Id();
            var func = new JsFunction(null, val.Value);

            func.Body.Add(jsMethod.FullName.Id().Call("this".Id(), val).Return());

            ExtendPrototype(type, func, op.JsName());
        }
Пример #8
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);
        }
Пример #9
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));
            }
        }
Пример #10
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");
        }
Пример #11
0
        public object Compile(MethodContext context, IField field)
        {
            var fieldInfo = context.Vars[field];

            if (fieldInfo != null)
            {
                return(fieldInfo.Id());
            }

            var obj = "o".Id();
            var val = "v".Id();
            var get = new JsFunction(null, obj.Value);
            var set = new JsFunction(null, obj.Value, val.Value);

            var info = new JsObject
            {
                { "get", get },
                { "set", set }
            };

            fieldInfo = context.Vars.Add(field, info);

            if (field.IsStatic)
            {
                _host.InitClass(context, get, field);
                _host.InitClass(context, set, field);

                var name = field.JsFullName();

#if JSC_FIELD_DEBUG
                var value = name.Id().Var("v");
                get.Body.Add(value);
                get.Body.Add(new JsText(string.Format("if (v === undefined) throw new ReferenceError('{0} is undefined');", field.FullName)));
                get.Body.Add(value.Name.Id().Return());
#else
                get.Body.Add(name.Id().Return());
#endif

                set.Body.Add(name.Id().Set(val));
            }
            else
            {
                var name = field.JsName();

#if JSC_FIELD_DEBUG
                var value = obj.Get(name).Var("v");
                get.Body.Add(value);
                get.Body.Add(new JsText(string.Format("if (v === undefined) throw new ReferenceError('{0} is undefined');", field.FullName)));
                get.Body.Add(value.Name.Id().Return());
#else
                get.Body.Add(obj.Get(name).Return());
#endif

                set.Body.Add(obj.Set(name, val));
            }

            return(fieldInfo.Id());
        }
Пример #12
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");
        }
Пример #13
0
        private JsFunction CreateCallFunc(MethodContext context, IMethod method, CallInfo info)
        {
            var obj  = "o".Id();
            var args = "a".Id();
            var func = new JsFunction(null, obj.Value, args.Value);

            InitClass(context, func, method);

            JsNode call = null;

            //TODO: inplace inline calls
            if (method.DeclaringType.Is(SystemTypeCode.Boolean) && method.IsToString())
            {
                call = obj.Ternary("True", "False");
            }

            //to detect stackoverflows
            //func.Body.Add("console.log".Id().Call(method.JsFullName()).AsStatement());

            if (call == null && info != null)
            {
                if (info.ReceiverType != null && (info.Flags & CallFlags.Basecall) != 0)
                {
                    call = method.JsFullName(info.ReceiverType).Id().Apply(obj, args);
                }
                else if (IsSuperCall(context, method, info.Flags))
                {
                    var baseType = context.Method.DeclaringType.BaseType;
                    call = method.JsFullName(baseType).Id().Apply(obj, args);
                    //TODO: remove $base if it is not needed
                    //call = obj.Get("$base").Get(method.JsName()).Apply(obj, args);
                }
            }

            if (call == null)
            {
                if (!method.IsStatic && !method.IsConstructor && method.DeclaringType.IsBoxableType())
                {
                    new BoxingImpl(this).BoxUnboxed(context, method.DeclaringType, func, obj);
                }

                call = method.Apply(obj, args);
            }

            func.Body.Add(method.IsVoid() ? call.AsStatement() : call.Return());

            return(func);
        }
Пример #14
0
        private static JsFunction CompileInlineFunction(IMethod method, InlineMethodInfo info)
        {
            var parameters = method.JsParams();
            var func       = new JsFunction(null, parameters);

            switch (info.Kind)
            {
            case InlineKind.Property:
                //TODO: support static properties
                var propertyName = info.Name;
                if (method.IsSetter())
                {
                    func.Body.Add("this".Id().Set(propertyName, parameters[0].Id()));
                }
                else
                {
                    func.Body.Add("this".Id().Get(propertyName).Return());
                }
                break;

            case InlineKind.Operator:
                var text = "return ";
                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    if (i > 0)
                    {
                        text += info.Name;
                    }
                    text += parameters[i];
                }
                text += ";";
                func.Body.Add(new JsText(text));
                break;

            default:
                var type = method.DeclaringType;
                //TODO: use ABC, pfx meta attributes
                var typeName = type.Namespace == "Avm" ? type.Name : type.JsFullName(method);
                var target   = method.IsStatic ? typeName.Id() : "this".Id();
                func.Body.Add(target.Get(info.Name).Call(parameters.Select(x => x.Id()).ToArray()).Return());
                break;
            }

            return(func);
        }
Пример #15
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);
        }
Пример #16
0
        internal void InitClass(MethodContext context, JsFunction func, ITypeMember member)
        {
            var type = member is IType ? (IType)member : member.DeclaringType;

            if (ExcludeInitClass(type))
            {
                return;
            }

            if (member is IType)
            {
                CompileFields(type, true);
                CompileFields(type, false);
            }
            else
            {
                CompileFields(type, member.IsStatic);
            }

            new ClassInitImpl(this).InitClass(context, func, member);
        }
Пример #17
0
        private JsNode OpNewobj(MethodContext context, IMethod method)
        {
            var key  = new InstructionKey(InstructionCode.Newobj, method);
            var data = context.Vars[key];

            if (data != null)
            {
                return(data.Id());
            }

            var args = "a".Id();

            var func = new JsFunction(null, args.Value);

            var info = new JsObject
            {
                { "n", method.Parameters.Count },
                { "f", func },
            };

            data = context.Vars.Add(key, info);

            CompileCallMethod(method);

            InitClass(context, func, method);

            if (method.IsConstructor && method.DeclaringType.IsString())
            {
                func.Body.Add(method.Apply(null, args).Return());
            }
            else
            {
                var obj = "o".Id();
                func.Body.Add(method.DeclaringType.New().Var(obj.Value));
                func.Body.Add(method.Apply(obj, args).AsStatement());
                func.Body.Add(obj.Return());
            }

            return(data.Id());
        }
Пример #18
0
        private JsNode OpInitobj(MethodContext context, IType type)
        {
            var key  = new InstructionKey(InstructionCode.Initobj, type);
            var info = context.Vars[key];

            if (info != null)
            {
                return(info.Id());
            }

            var func = new JsFunction(null);

            info = context.Vars.Add(key, func);

            CompileClass(type);

            InitClass(context, func, type);

            func.Body.Add(type.New().Return());

            return(info.Id());
        }
Пример #19
0
        public JsProgram Compile()
        {
            if (_program != null)
            {
                return(_program);
            }

            _program = new JsProgram();

            _program.Require("core.js");

            var entryPoint = _assembly.EntryPoint;
            var method     = CompileMethod(entryPoint);

            // system exceptions
            CompileClass(CorlibTypes[CorlibTypeId.NullReferenceException]);
            CompileClass(CorlibTypes[CorlibTypeId.InvalidCastException]);
            CompileClass(CorlibTypes[CorlibTypeId.NotImplementedException]);
            CompileClass(CorlibTypes[CorlibTypeId.IndexOutOfRangeException]);

            // build types
            CompileClass(SystemTypes.Type);


            new TypeInfoBuilder(this, _program).Build();

            //TODO: pass args to main from node.js args

            var ctx  = new MethodContext(this, CompileClass(entryPoint.DeclaringType), entryPoint, new TryCatchBlock[0]);
            var main = new JsFunction(null);

            InitClass(ctx, main, entryPoint);
            main.Body.Add(method.FullName.Id().Call().AsStatement());

            _program.Add(main.Call().AsStatement());

            return(_program);
        }
Пример #20
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");
        }
Пример #21
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);
        }
Пример #22
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);
        }
Пример #23
0
        private void GetEnumeratorImpl(IMethod method)
        {
            var type = method.DeclaringType;

            if (type.IsGenericInstance())
            {
                var elemType = type.GetTypeArgument(0);

                var enumerator = CompileArrayEnumerator(elemType);
                var ctor       = enumerator.FindConstructor(1);

                var func = new JsFunction();
                var obj  = "o".Id();
                func.Body.Add(enumerator.New().Var(obj.Value));
                func.Body.Add(obj.Get(ctor.JsName()).Call("this".Id()));
                func.Body.Add(obj.Return());

                AddImpl(method, func);
            }
            else
            {
                throw new NotImplementedException();
            }
        }
Пример #24
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");
        }
Пример #25
0
        internal void ExtendPrototype(IType type, JsFunction func, string name)
        {
            var klass = CompileClass(type);

            klass.ExtendPrototype(func, name);
        }
Пример #26
0
        public void BoxUnboxed(MethodContext context, IType type, JsFunction func, JsNode obj)
        {
            var f = Box(context, type);

            func.Body.Add(obj.Set("$cbox".Id().Call(obj, f)));
        }
Пример #27
0
 public JsGeneratedMethod(string fullName, JsFunction function)
 {
     _fullName = fullName;
     Function  = function;
 }