Beispiel #1
0
        // Complete a first-kinded type structure. If type definition is higher kinded, this will
        // complete an instance of the type at the type arguments. Otherwise, this will complete
        // the type definition itself.
        private void BuildTypeExpression(Seq<JST.Statement> body, JST.Expression lhs)
        {
            TypeCompEnv.BindUsage(body, CollectPhase1Usage(), TypePhase.Id);

            // TODO: Replace with prototype
            body.Add(JST.Statement.DotCall(RootId.ToE(), Constants.RootSetupTypeDefaults, TypeId.ToE()));

            EmitBaseAndSupertypes(body, lhs);
            EmitDefaultConstructor(body, lhs);
            EmitMemberwiseClone(body, lhs);
            EmitClone(body, lhs);
            EmitDefaultValue(body, lhs);
            EmitStaticMethods(body, lhs);
            EmitConstructObjectAndInstanceMethods(body, lhs);
            EmitVirtualAndInterfaceMethodRedirectors(body, lhs);
            EmitSetupType(body, lhs);
            EmitUnbox(body, lhs);
            EmitBox(body, lhs);
            EmitUnboxAny(body, lhs);
            EmitConditionalDeref(body, lhs);
            EmitIsValue(body, lhs);
            EmitEquals(body, lhs);
            EmitHash(body, lhs);
            EmitInterop(body, lhs);
        }
 private TypeCompilerEnvironment
     (CST.Global global,
      IImSeq<CST.SkolemDef> skolemDefs,
      CST.AssemblyDef assembly,
      CST.TypeDef type,
      IImSeq<CST.TypeRef> typeBoundArguments,
      CompilerEnvironment env,
      JST.NameSupply nameSupply,
      JST.Identifier rootId,
      JST.Identifier assemblyId,
      JST.Identifier typeId,
      IImSeq<JST.Identifier> typeBoundTypeParameterIds,
      TypeTrace typeTrace)
     : base(
         global,
         skolemDefs,
         assembly,
         type,
         typeBoundArguments)
 {
     this.env = env;
     NameSupply = nameSupply;
     this.rootId = rootId;
     this.assemblyId = assemblyId;
     this.typeId = typeId;
     TypeBoundTypeParameterIds = typeBoundTypeParameterIds;
     boundAssemblies = new Map<CST.AssemblyName, JST.Expression>();
     boundTypes = new Map<CST.TypeRef, ExpressionAndPhase>();
     this.typeTrace = typeTrace;
 }
Beispiel #3
0
 public TypeRepresentation(InstanceState state, int numExportsBoundToInstance, int numStepsToRootType, JST.Expression keyField, JST.Expression typeClassifier, bool undefininedIsNotNull)
 {
     State = state;
     NumExportsBoundToInstance = numExportsBoundToInstance;
     NumStepsToRootType = numStepsToRootType;
     KeyField = keyField;
     TypeClassifier = typeClassifier;
     UndefininedIsNotNull = undefininedIsNotNull;
 }
Beispiel #4
0
 private void EmitDefaultConstructor(Seq<JST.Statement> body, JST.Expression lhs)
 {
     if (Parent.DefaultConstructor != null)
     {
         var innerNameSupply = NameSupply.Fork();
         var innerBody = new Seq<JST.Statement>();
         var ctor = Env.JSTHelpers.ConstructorExpression
             (TypeCompEnv, innerNameSupply, innerBody, null, Parent.DefaultConstructor, JST.Constants.EmptyExpressions);
         innerBody.Add(new JST.ReturnStatement(ctor));
         body.Add
             (JST.Statement.DotAssignment
                  (lhs, Constants.TypeDefaultConstructor, new JST.FunctionExpression(null, new JST.Statements(innerBody))));
     }
     // else: leave undefined
 }
        // ----------------------------------------------------------------------
        // Methods
        // ----------------------------------------------------------------------

        // Emit bindings for static or instance methods, but not for virtuals or interface methods
        //  - Invoked from TypeDefinitionCompiler for higher-kinded type definitions
        //  - Invoked from TypeCompiler for first-kinded type definitions
        public void EmitMethods(Seq<JST.Statement> body, JST.Expression lhs, JST.NameSupply outerNameSupply, JST.Expression target, bool isStatic)
        {
            switch (Env.CompilationMode)
            {
                case CompilationMode.Plain:
                {
                    // Method definitions are bound directly into target
                    foreach (var methodDef in Methods.Where(m => m.Invalid == null))
                    {
                        if (Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef) == isStatic)
                        {
                            var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                            compiler.Emit(body, target);
                        }
                    }
                    break;
                }
            case CompilationMode.Collecting:
                {
                    // Method definitions are bound into MethodCache, redirectors are bound into target
                    foreach (var methodDef in Methods.Where(m => m.Invalid == null))
                    {
                        if (Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef) == isStatic)
                        {
                            var slot = Env.GlobalMapping.ResolveMethodDefToSlot(TyconEnv.Assembly, TyconEnv.Type, methodDef);
                            var methodName = CST.CSTWriter.WithAppend
                                (Env.Global, CST.WriterStyle.Uniform, methodDef.MethodSignature.Append);
                            body.Add
                                (JST.Statement.DotCall
                                     (RootId.ToE(),
                                      Constants.RootCollectingBindMethodBuilder,
                                      lhs,
                                      new JST.BooleanLiteral(isStatic),
                                      new JST.StringLiteral(slot),
                                      new JST.StringLiteral(methodName)));
                            var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                            compiler.Emit(body, JST.Expression.Dot(target, Constants.TypeMethodCache));
                        }
                    }
                    break;
                }
            case CompilationMode.Traced:
                {
                    // Methods in the initial trace or this trace will be bound directly.
                    // Methods in a trace other than above are bound via builder which is given trace name.
                    // Remaining methods are built via builder with null trace name.
                    var traceToArgs = new Map<string, Seq<JST.Expression>>();
                    var remainingArgs = new Seq<JST.Expression>();
                    remainingArgs.Add(TypeDefinitionId.ToE());
                    remainingArgs.Add(new JST.BooleanLiteral(isStatic));
                    remainingArgs.Add(new JST.NullExpression());
                    foreach (var methodDef in Methods.Where(m => m.Invalid == null))
                    {
                        if (Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef) == isStatic)
                        {
                            var slot = Env.GlobalMapping.ResolveMethodDefToSlot(TyconEnv.Assembly, TyconEnv.Type, methodDef);
                            var defTrace = Env.Traces.MethodToTrace[methodDef.QualifiedMemberName(Env.Global, TyconEnv.Assembly, TyconEnv.Type)];
                            if (defTrace.Flavor == TraceFlavor.OnDemand && defTrace != TypeTrace.Parent.Parent)
                            {
                                // Method definition in in another trace, bind redirector for it.
                                var args = default(Seq<JST.Expression>);
                                if (!traceToArgs.TryGetValue(defTrace.Name, out args))
                                {
                                    args = new Seq<JST.Expression>();
                                    args.Add(lhs);
                                    args.Add(new JST.BooleanLiteral(isStatic));
                                    args.Add(new JST.StringLiteral(defTrace.Name));
                                    traceToArgs.Add(defTrace.Name, args);
                                }
                                args.Add(new JST.StringLiteral(slot));
                            }
                            else if (defTrace.Flavor == TraceFlavor.Remainder)
                                // Method definition is in a stand-alone loader, bind redirector for it.
                                remainingArgs.Add(new JST.StringLiteral(slot));
                            else
                            {
                                // Method definition is bound directly
                                var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                                compiler.Emit(body, target);
                            }
                        }
                    }
                    foreach (var kv in traceToArgs)
                        body.Add(JST.Statement.DotCall(RootId.ToE(), Constants.RootBindMethodBuilders, kv.Value));
                    if (remainingArgs.Count > 3)
                        body.Add(JST.Statement.DotCall(RootId.ToE(), Constants.RootBindMethodBuilders, remainingArgs));
                    break;
                }
            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Beispiel #6
0
        // Take acccount of:
        //   - PassRootAsArgument
        //   - PassInstanceAsArgument
        //   - InlineParamsArray
        private JST.Expression AppendFinalImport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script, ISeq<JST.Statement> body, IImSeq<JST.Expression> arguments)
        {
            var isInstanceMethod = !(methodDef.IsStatic || methodDef.IsConstructor);
            var scriptExpectsRoot = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ImportAttributeRef,
                 attributeHelper.ThePassRootAsArgumentProperty,
                 true,
                 false,
                 ref scriptExpectsRoot);
            var passInstAsArg = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ImportAttributeRef,
                 attributeHelper.ThePassInstanceAsArgumentProperty,
                 true,
                 false,
                 ref passInstAsArg);
            var instanceIsThis = isInstanceMethod && !passInstAsArg;
            var inlineParams = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ImportAttributeRef,
                 attributeHelper.TheInlineParamsArrayProperty,
                 true,
                 false,
                 ref inlineParams);
            var lastArgIsParamsArray = methodDef.HasParamsArray(rootEnv) && inlineParams;

            var funcScript = script as JST.FunctionExpression;

            var nextArg = 0;
            var instArg = default(JST.Expression);
            if (instanceIsThis)
            {
                // Instance argument will be the first arg to 'call' or 'apply', or the target of a '.' call.
                instArg = arguments[nextArg++];
                if (lastArgIsParamsArray && !instArg.IsDuplicatable)
                {
                    // Make sure instance argument is evaluated before the remaining arguments
                    var instId = nameSupply.GenSym();
                    body.Add(JST.Statement.Var(instId, instArg));
                    instArg = instId.ToE();
                }
            }
            else
            {
                if (lastArgIsParamsArray)
                    instArg = new JST.NullExpression();
            }

            var knownArgs = 0;
            var call = default(JST.Expression);

            if (lastArgIsParamsArray)
            {
                // We mush build script args at runtime
                var argsId = nameSupply.GenSym();
                body.Add(JST.Statement.Var(argsId, new JST.ArrayLiteral()));
                if (scriptExpectsRoot)
                {
                    body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, rootId.ToE()));
                    knownArgs++;
                }
                while (nextArg < arguments.Count - 1)
                {
                    body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, arguments[nextArg++]));
                    knownArgs++;
                }
                var arrArg = arguments[nextArg];
                if (!arrArg.IsDuplicatable)
                {
                    var arrId = nameSupply.GenSym();
                    body.Add(JST.Statement.Var(arrId, arrArg));
                    arrArg = arrId.ToE();
                }
                var iId = nameSupply.GenSym();
                body.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNotNull(arrArg),
                          new JST.Statements
                              (new JST.ForStatement
                                   (new JST.ForVarLoopClause
                                        (iId,
                                         new JST.NumericLiteral(0),
                                         new JST.BinaryExpression
                                             (iId.ToE(),
                                              JST.BinaryOp.LessThan,
                                              JST.Expression.Dot(arrArg, Constants.length)),
                                         new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)),
                                    new JST.Statements
                                        (JST.Statement.DotCall
                                             (argsId.ToE(), Constants.push, new JST.IndexExpression(arrArg, iId.ToE())))))));

                if (funcScript != null)
                {
                    // var args = ...; var x = script; x.apply(this/null, args)
                    var scriptId = nameSupply.GenSym();
                    body.Add(JST.Statement.Var(scriptId, funcScript));
                    call = JST.Expression.DotCall(scriptId.ToE(), Constants.apply, instArg, argsId.ToE());
                }
                else
                {
                    if (instanceIsThis)
                    {
                        // var args = ...; (this.script).apply(this, args);
                        call = JST.Expression.DotCall
                            (JST.Expression.Dot(instArg, JST.Expression.ExplodePath(script)),
                             Constants.apply,
                             instArg,
                             argsId.ToE());
                    }
                    else
                    {
                        // var args = ...; script.apply(null, args)
                        call = JST.Expression.DotCall(script, Constants.apply, instArg, argsId.ToE());
                    }
                }
            }
            else
            {
                var callArgs = new Seq<JST.Expression>();
                if (instanceIsThis && funcScript != null)
                    callArgs.Add(instArg);
                if (scriptExpectsRoot)
                {
                    callArgs.Add(rootId.ToE());
                    knownArgs++;
                }
                while (nextArg < arguments.Count)
                {
                    callArgs.Add(arguments[nextArg++]);
                    knownArgs++;
                }
                if (instanceIsThis)
                {
                    if (funcScript != null)
                    {
                        // var x = script; x.call(this, arg1, ..., argn)
                        var scriptId = nameSupply.GenSym();
                        body.Add(JST.Statement.Var(scriptId, funcScript));
                        call = JST.Expression.DotCall(scriptId.ToE(), Constants.call, callArgs);
                    }
                    else
                        // this.script(arg1, ..., angn)
                        call = new JST.CallExpression
                            (JST.Expression.Dot(instArg, JST.Expression.ExplodePath(script)), callArgs);
                }
                else
                    // script(arg1, ..., argn)
                    call = new JST.CallExpression(script, callArgs);
            }

            if (funcScript != null)
            {
                if (funcScript.Parameters.Count < knownArgs)
                {
                    var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);
                    env.Log(new InvalidInteropMessage(ctxt, "script accepts too few arguments"));
                    throw new DefinitionException();
                }
            }

            return call;
        }
Beispiel #7
0
        public void AppendExport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression instance, Seq<JST.Statement> body, AppendCallExported appendCallExported)
        {
            var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);
            if (methodDef.TypeArity > 0)
            {
                env.Log(new InvalidInteropMessage(ctxt, "polymorphic methods cannot be exported"));
                throw new DefinitionException();
            }
            if (typeDef.Arity > 0 && (methodDef.IsConstructor || methodDef.IsStatic))
            {
                env.Log
                    (new InvalidInteropMessage
                         (ctxt, "higher-kinded types cannot export static methods or instance constructors"));
                throw new DefinitionException();
            }

            CheckParameterAndReturnTypesAreImportableExportable(assemblyDef, typeDef, methodDef);

            var script = default(JST.Expression);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.TheScriptProperty,
                 true,
                 false,
                 ref script);
            var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);

            if (!methodDef.IsStatic && methodDef.IsConstructor)
            {
                // Constructors
                if (methodDef.TypeArity > 0)
                    throw new InvalidOperationException("invalid constructor");
            }
            else if (outer != null)
            {
                var localScript = default(JST.Expression);
                var hasLocalScript = attributeHelper.GetValueFromMethod
                    (assemblyDef,
                     typeDef,
                     methodDef,
                     attributeHelper.ExportAttributeRef,
                     attributeHelper.TheScriptProperty,
                     false,
                     false,
                     ref localScript);
                switch (outer.Flavor)
                {
                case CST.MemberDefFlavor.Event:
                    {
                        var eventDef = (CST.EventDef)outer;
                        if (eventDef.Add != null && methodDef.Signature.Equals(eventDef.Add))
                            // Adder
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "add", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "add", script);
                        else if (eventDef.Remove != null && methodDef.Signature.Equals(eventDef.Remove))
                            // Remover
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "remove", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "remove", script);
                        else
                            throw new InvalidOperationException();
                        break;
                    }
                case CST.MemberDefFlavor.Property:
                    {
                        var propDef = (CST.PropertyDef)outer;
                        if (propDef.Get != null && methodDef.Signature.Equals(propDef.Get))
                            // Getter
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "get", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "get", script);
                        else if (propDef.Set != null && methodDef.Signature.Equals(propDef.Set))
                            // Setter
                            script = hasLocalScript
                                         ? GetterSetterAdderRemoverNameFromMethod
                                               (assemblyDef, typeDef, methodDef, "set", localScript)
                                         : GetterSetterAdderRemoverNameFromPropertyEvent
                                               (assemblyDef, typeDef, methodDef, "set", script);
                        else
                            throw new InvalidOperationException();
                        break;
                    }
                case CST.MemberDefFlavor.Field:
                case CST.MemberDefFlavor.Method:
                    throw new InvalidOperationException("not a property or event");
                default:
                    throw new ArgumentOutOfRangeException();
                }
            }
            else
            {
                // Normal methods
                script = RecaseMethod(assemblyDef, typeDef, methodDef, script);
            }

            script = PrefixName(assemblyDef, typeDef, methodDef, script, true);
            AppendFinalExport
                (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, instance, body, appendCallExported);
        }
Beispiel #8
0
        // Take account of:
        //  - BindToPrototype
        //  - PassRootAsArgument
        //  - PassInstanceAsArgument
        //  - InlineParamsArray
        private void AppendFinalExport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script, JST.Expression instance, ISeq<JST.Statement> body, AppendCallExported appendCallExported)
        {
            if (script == null)
                throw new InvalidOperationException("expecting default script value");

            var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);

            var isInstance = !methodDef.IsStatic && !methodDef.IsConstructor;
            if (isInstance)
            {
                if (typeDef.Style is CST.ValueTypeStyle)
                {
                    env.Log(new InvalidInteropMessage(ctxt, "cannot export instance methods from value types"));
                    throw new DefinitionException();
                }
            }

            var inlineParams = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.TheInlineParamsArrayProperty,
                 true,
                 false,
                 ref inlineParams);
            var lastArgIsParamsArray = methodDef.HasParamsArray(rootEnv) && inlineParams;
            var isPassRoot = default(bool);

            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.ThePassRootAsArgumentProperty,
                 true,
                 false,
                 ref isPassRoot);
            var isProto = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.TheBindToPrototypeProperty,
                 true,
                 false,
                 ref isProto);
            var isPassInstance = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.ThePassInstanceAsArgumentProperty,
                 true,
                 false,
                 ref isPassInstance);
            var bindToInstance = isInstance && !isProto;

            if (bindToInstance != (instance != null))
                throw new InvalidOperationException("expecting instance");

            var captureThis = isInstance && !isPassInstance;

            var funcScript = script as JST.FunctionExpression;

            // Build the function to export

            var funcBody = new Seq<JST.Statement>();
            var funcParameters = new Seq<JST.Identifier>();
            var funcCallArgs = new Seq<JST.Expression>();

            var funcArity = methodDef.Arity;
            if ((methodDef.IsConstructor && !methodDef.IsStatic) || captureThis)
                // unmanaged will not pass the instance
                funcArity--;
            if (lastArgIsParamsArray)
                // managed params args will be extracted from remainder of unmanaged arguments
                funcArity--;

            if (captureThis)
                funcCallArgs.Add(new JST.ThisExpression());

            for (var i = 0; i < funcArity; i++)
            {
                var id = nameSupply.GenSym();
                funcParameters.Add(id);
                funcCallArgs.Add(id.ToE());
            }

            if (lastArgIsParamsArray)
            {
                var iId = nameSupply.GenSym();
                var arrId = nameSupply.GenSym();
                funcBody.Add(JST.Statement.Var(arrId, new JST.ArrayLiteral()));
                funcBody.Add
                    (new JST.ForStatement
                         (new JST.ForVarLoopClause
                              (iId,
                               new JST.NumericLiteral(funcArity),
                               new JST.BinaryExpression
                                   (iId.ToE(),
                                    JST.BinaryOp.LessThan,
                                    JST.Expression.Dot(Constants.arguments.ToE(), Constants.length)),
                               new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)),
                          new JST.Statements
                              (JST.Statement.DotCall
                                   (arrId.ToE(),
                                    Constants.push,
                                    new JST.IndexExpression(Constants.arguments.ToE(), iId.ToE())))));
                funcCallArgs.Add(arrId.ToE());
            }

            appendCallExported(nameSupply, assemblyDef, typeDef, methodDef, funcBody, funcCallArgs);
            var func = new JST.FunctionExpression(funcParameters, new JST.Statements(funcBody));

            // Export the above function

            if (funcScript != null)
            {
                var scriptArgs = new Seq<JST.Expression>();
                if (isPassRoot)
                    scriptArgs.Add(rootId.ToE());
                if (bindToInstance)
                    scriptArgs.Add(instance);
                scriptArgs.Add(func);

                if (funcScript.Parameters.Count != scriptArgs.Count)
                {
                    env.Log(new InvalidInteropMessage(ctxt, "invalid function arity"));
                    throw new DefinitionException();
                }
                body.Add(new JST.ExpressionStatement(new JST.CallExpression(script, scriptArgs)));
            }
            else
            {
                if (bindToInstance)
                    script = JST.Expression.Dot(instance, JST.Expression.ExplodePath(script));
                EnsurePathExists(body, script, !bindToInstance);
                body.Add(JST.Statement.Assignment(script, func));
            }
        }
Beispiel #9
0
        private JST.Expression RecasePropertyEvent(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script)
        {
            var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);
            if (outer == null)
                throw new ArgumentException("not a getter/setter/adder/remover method");

            if (script != null)
                return script;

            var casing = default(Casing);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheMemberNameCasingProperty,
                 true,
                 false,
                 ref casing);
            return new JST.Identifier(JST.Lexemes.StringToIdentifier(Recase(outer.Name, casing))).ToE();
        }
Beispiel #10
0
        private void EmitUnboxAny(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;
            if (!(s is CST.HandleTypeStyle || s is CST.ReferenceTypeStyle))
            {
                var innerNameSupply = NameSupply.Fork();
                var parameters = new Seq<JST.Identifier>();
                parameters.Add(innerNameSupply.GenSym());
                var obj = parameters[0].ToE();
                var innerBody = new Seq<JST.Statement>();

                if (s is CST.VoidTypeStyle || s is CST.ManagedPointerTypeStyle)
                    innerBody.Add
                        (new JST.ThrowStatement
                             (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
                else if (s is CST.NullableTypeStyle)
                {
                    innerBody.Add
                        (new JST.IfStatement
                             (JST.Expression.IsNull(obj), new JST.Statements(new JST.ReturnStatement(new JST.NullExpression()))));
                    innerBody.Add
                        (new JST.IfStatement
                             (new JST.BinaryExpression
                                  (JST.Expression.Dot(obj, Constants.ObjectType),
                                   JST.BinaryOp.StrictNotEquals,
                                   TypeCompEnv.ResolveType(TypeCompEnv.TypeBoundArguments[0], TypePhase.Id)),
                              new JST.Statements(new JST.ThrowStatement
                                  (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidCastException)))));
                    innerBody.Add(new JST.ReturnStatement(JST.Expression.DotCall(obj, Constants.PointerRead)));
                }
                else
                {
                    innerBody.Add
                        (new JST.IfStatement
                             (JST.Expression.IsNull(obj),
                              new JST.Statements(new JST.ThrowStatement
                                  (JST.Expression.DotCall(RootId.ToE(), Constants.RootNullReferenceException)))));
                    innerBody.Add
                        (new JST.IfStatement
                             (new JST.BinaryExpression
                                  (JST.Expression.Dot(obj, Constants.ObjectType),
                                   JST.BinaryOp.StrictNotEquals,
                                   lhs),
                              new JST.Statements(new JST.ThrowStatement
                                  (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidCastException)))));
                    innerBody.Add(new JST.ReturnStatement(JST.Expression.DotCall(obj, Constants.PointerRead)));
                }

                body.Add
                    (JST.Statement.DotAssignment
                         (lhs, Constants.TypeUnboxAny, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
            }
            // else: default is ok
        }
Beispiel #11
0
 private void EmitStaticMethods(Seq<JST.Statement> body, JST.Expression lhs)
 {
     if (Env.DebugMode)
         body.Add(new JST.CommentStatement("Static methods"));
     if (TypeCompEnv.Type.Arity > 0)
         EmitFKToHKMethodRedirectors(body, lhs, true);
     else
         Parent.EmitMethods(body, lhs, NameSupply, lhs, true);
 }
Beispiel #12
0
        private void EmitConstructObjectAndInstanceMethods(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;

            var ctor = default(JST.Expression);
            var preserve = false;

            if (s is CST.StringTypeStyle)
            {
                // SPECIAL CASE: System.String is represented as JavaScript String
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement("ConstructObject supplied by JavaScript"));
                ctor = Constants.String.ToE();
                body.Add(JST.Statement.DotAssignment(lhs, Constants.TypeConstructObject, ctor));
                preserve = true;
            }
            else if (TypeCompEnv.TypeRef.Equals(Env.Global.ArrayRef))
            {
                // SPECIAL CASE: System.Array is represented as JavaScript Array
                // (Built-in arrays and multi-dimensional arrays are also JavaScipt array's, but
                //  we explicity overwrite their Type field to capture their exact type.)
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement("ConstructObject supplied by JavaScript"));
                ctor = Constants.Array.ToE();
                body.Add(JST.Statement.DotAssignment(lhs, Constants.TypeConstructObject, ctor));
                preserve = true;
            }
            else if (TypeCompEnv.TypeRef.Equals(Env.Global.MulticastDelegateRef))
            {
                // SPECIAL CASE: System.MulticastDelegate is represented as JavaScript Function
                // (Instance of derived delegate types overwrite their Type field to capture their exact type)
                // We bind into String's prototype
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement("ConstructObject supplied by JavaScript"));
                ctor = Constants.Function.ToE();
                body.Add(JST.Statement.DotAssignment(lhs, Constants.TypeConstructObject, ctor));
                preserve = true;
            }
            else if (s is CST.InterfaceTypeStyle || s is CST.VoidTypeStyle || (TypeCompEnv.Type.IsAbstract && TypeCompEnv.Type.IsSealed))
            {
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement("ConstructObject should never be called"));
                // SPECIAL CASE: Interface types, Void and 'static' types have no instances
                body.Add
                    (JST.Statement.DotAssignment
                         (lhs,
                          Constants.TypeConstructObject,
                          new JST.FunctionExpression
                              (null,
                               new JST.Statements(new JST.ThrowStatement
                                   (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException))))));
                // Shouldn't have any instance fields or methods to bind
                return;
            }
            else
            {
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement("ConstructObject"));
                body.Add(JST.Statement.DotAssignment(lhs, Constants.TypeConstructObject, ConstructObjectFunction()));
                ctor = JST.Expression.Dot(lhs, Constants.TypeConstructObject);
            }

            if (TypeCompEnv.Type.Extends != null)
            {
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement("Inherited prototype"));
                if (preserve)
                {
                    // The constructor's prototype object is fixed, so we must copy all fields of the
                    // base type's prototype object into existing prototype object
                    var baseCtor = JST.Expression.Dot(lhs, Constants.TypeBaseType, Constants.TypeConstructObject);
                    body.Add
                        (JST.Statement.DotCall
                             (RootId.ToE(),
                              Constants.RootInheritPrototypeProperties,
                              JST.Expression.Dot(ctor, Constants.prototype),
                              JST.Expression.Dot(baseCtor, Constants.prototype)));
                }
                else
                {
                    // Use base type's ConstructObject to build our prototype object
                    // (but supress it's field initialization)
                    var newProto = new JST.NewExpression
                        (new JST.CallExpression
                             (JST.Expression.Dot(lhs, Constants.TypeBaseType, Constants.TypeConstructObject),
                              new JST.BooleanLiteral(true)));
                    body.Add(JST.Statement.Assignment(JST.Expression.Dot(ctor, Constants.prototype), newProto));
                }
            }

            // Setup prototype
            var protoId = NameSupply.GenSym();
            body.Add(JST.Statement.Var(protoId, JST.Expression.Dot(ctor, Constants.prototype)));
            var proto = protoId.ToE();

            if (TypeCompEnv.Type.Extends != null && !preserve)
            {
                // Overwrite prototype's constructor
                body.Add(JST.Statement.DotAssignment(proto, Constants.constructor, ctor));
            }
            // else: original constructor is valid

            // Type
            body.Add(JST.Statement.DotAssignment(proto, Constants.ObjectType, lhs));
            // MethodCache
            body.Add(JST.Statement.DotAssignment(proto, Constants.TypeMethodCache, new JST.ObjectLiteral()));

            // Bind normal instance methods
            if (Env.DebugMode)
                body.Add(new JST.CommentStatement("Instance methods"));
            if (TypeCompEnv.Type.Arity > 0)
                EmitFKToHKMethodRedirectors(body, lhs, false);
            else
                Parent.EmitMethods(body, lhs, NameSupply, proto, false);
        }
Beispiel #13
0
        // For speed we inline rather than chain to base-type default values
        // (Though, actually, that's not necessary since value types are sealed and have not inherited fields...)
        private void EmitDefaultValue(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;
            var innerBody = new Seq<JST.Statement>();

            if (s is CST.VoidTypeStyle || s is CST.ManagedPointerTypeStyle)
                innerBody.Add
                    (new JST.ThrowStatement
                         (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
            else if (s is CST.NumberTypeStyle || s is CST.EnumTypeStyle || TypeCompEnv.TypeRef.Equals(Env.Global.DecimalRef))
                innerBody.Add(new JST.ReturnStatement(new JST.NumericLiteral(0)));
            else if (s is CST.StructTypeStyle)
            {
                var allFieldRefs = new Seq<CST.FieldRef>();
                AccumInstanceFields(TypeCompEnv, allFieldRefs);

                var innerTypeCompEnv = TypeCompEnv.EnterFunction();

                var usage = new CST.Usage();
                foreach (var fieldRef in allFieldRefs)
                {
                    if (Env.JSTHelpers.DefaultFieldValueIsNonNull(innerTypeCompEnv, fieldRef))
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                }
                innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

                var bindings = new OrdMap<JST.Identifier, JST.Expression>();
                foreach (var fieldRef in allFieldRefs)
                    bindings.Add
                        (Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false),
                         Env.JSTHelpers.DefaultFieldValue(innerTypeCompEnv, fieldRef));

                innerBody.Add(new JST.ReturnStatement(new JST.ObjectLiteral(bindings)));
            }
            // else: default default value of null is ok

            if (innerBody.Count > 0)
                body.Add
                    (JST.Statement.DotAssignment
                         (lhs, Constants.TypeDefaultValue, new JST.FunctionExpression(null, new JST.Statements(innerBody))));
        }
Beispiel #14
0
 private void EmitClone(Seq<JST.Statement> body, JST.Expression lhs)
 {
     if (Env.JSTHelpers.CloneIsNonTrivial(TypeCompEnv, TypeCompEnv.TypeRef))
     {
         // Same as MemberwiseClone
         body.Add
             (JST.Statement.DotAssignment
                  (lhs, Constants.TypeClone, JST.Expression.Dot(lhs, Constants.TypeMemberwiseClone)));
     }
     // else: default identify function is ok
 }
Beispiel #15
0
        // For speed we inline rather than chain to base-type clones
        private void EmitMemberwiseClone(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;
            if (s is CST.ClassTypeStyle || s is CST.StructTypeStyle)
            {
                var fields = new Seq<CST.FieldRef>();
                AccumInstanceFields(TypeCompEnv, fields);
                var trivFields = new Seq<CST.FieldRef>();
                var nonTrivFields = new Seq<CST.FieldRef>();
                foreach (var fieldRef in fields)
                {
                    var fieldType = ((CST.FieldSignature)fieldRef.ExternalSignature).FieldType;
                    if (Env.JSTHelpers.CloneIsNonTrivial(TypeCompEnv, fieldType))
                        nonTrivFields.Add(fieldRef);
                    else
                        trivFields.Add(fieldRef);
                }

                if (nonTrivFields.Count > 0)
                {
                    var innerTypeCompEnv = TypeCompEnv.EnterFunction();

                    var parameters = new Seq<JST.Identifier>();
                    parameters.Add(innerTypeCompEnv.NameSupply.GenSym());
                    var oldObj = parameters[0].ToE();
                    var innerBody = new Seq<JST.Statement>();

                    var usage = new CST.Usage();
                    foreach (var fieldRef in nonTrivFields)
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                    innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

                    var newObjId = innerTypeCompEnv.NameSupply.GenSym();
                    if (s is CST.ClassTypeStyle)
                        // Reference type, object Id is allocated lazily
                        innerBody.Add
                            (JST.Statement.Var
                                 (newObjId, JST.Expression.DotCall(TypeId.ToE(), Constants.TypeConstructObject)));
                    else
                        // Value type
                        innerBody.Add(JST.Statement.Var(newObjId, new JST.ObjectLiteral()));
                    var newObj = newObjId.ToE();

                    // Explicity clone non-trivial fields
                    foreach (var fieldRef in nonTrivFields)
                    {
                        var fieldId = Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false);
                        innerBody.Add
                            (JST.Statement.DotAssignment
                                 (newObj,
                                  fieldId,
                                  Env.JSTHelpers.CloneExpressionForType
                                      (innerTypeCompEnv,
                                       fieldRef.ExternalFieldType,
                                       JST.Expression.Dot(oldObj, fieldId))));
                    }
                    if (trivFields.Count < 3)
                    {
                        // Explicity copy the remaining trivial fields
                        foreach (var fieldRef in trivFields)
                        {
                            var fieldId = Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, false);
                            innerBody.Add
                                (JST.Statement.DotAssignment(newObj, fieldId, JST.Expression.Dot(oldObj, fieldId)));
                        }
                    }
                    else
                    {
                        // Generically copy the remaining trivial fields
                        innerBody.Add
                            (JST.Statement.DotCall(RootId.ToE(), Constants.RootInheritProperties, newObj, oldObj));
                    }
                    innerBody.Add(new JST.ReturnStatement(newObj));

                    body.Add
                        (JST.Statement.DotAssignment
                             (lhs, Constants.TypeMemberwiseClone, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
                }
                else
                {
                    // default generic clone with no inner cloning is ok
                    return;
                }
            }
            else
            {
                var innerNameSupply = NameSupply.Fork();
                var parameters = new Seq<JST.Identifier>();
                parameters.Add(innerNameSupply.GenSym());
                var oldObj = parameters[0].ToE();
                var innerBody = new Seq<JST.Statement>();

                if (s is CST.VoidTypeStyle)
                {
                    innerBody.Add
                        (new JST.ThrowStatement
                             (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
                }
                else if (s is CST.ArrayTypeStyle)
                {
                    var newObjId = innerNameSupply.GenSym();
                    innerBody.Add
                        (JST.Statement.Var
                             (newObjId,
                              new JST.NewExpression
                                  (new JST.CallExpression
                                       (Constants.Array.ToE(), JST.Expression.Dot(oldObj, Constants.length)))));
                    innerBody.Add(JST.Statement.DotAssignment(newObjId.ToE(), Constants.ObjectType, TypeId.ToE()));
                    // Object Id is allocated lazily
                    var iId = innerNameSupply.GenSym();
                    var loopClause = new JST.ForVarLoopClause
                        (iId,
                         new JST.BinaryExpression
                             (iId.ToE(), JST.BinaryOp.LessThan, JST.Expression.Dot(oldObj, Constants.length)),
                         new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement));
                    var loopBody = JST.Statement.IndexAssignment
                        (newObjId.ToE(),
                         iId.ToE(),
                         Env.JSTHelpers.CloneExpressionForType
                             (TypeCompEnv,
                              TypeCompEnv.TypeBoundArguments[0],
                              new JST.IndexExpression(oldObj, iId.ToE())));
                    innerBody.Add(new JST.ForStatement(loopClause, new JST.Statements(loopBody)));
                    innerBody.Add(new JST.ReturnStatement(newObjId.ToE()));
                }
                else if (s is CST.NullableTypeStyle)
                {
                    innerBody.Add
                        (new JST.IfStatement
                             (JST.Expression.IsNull(oldObj),
                              new JST.Statements(new JST.ReturnStatement(new JST.NullExpression())),
                              new JST.Statements(new JST.ReturnStatement
                                  (Env.JSTHelpers.CloneExpressionForType
                                       (TypeCompEnv, TypeCompEnv.TypeBoundArguments[0], oldObj)))));
                }
                else
                {
                    innerBody.Add(new JST.ReturnStatement(oldObj));
                }

                body.Add
                    (JST.Statement.DotAssignment
                         (lhs, Constants.TypeMemberwiseClone, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
            }
        }
        public static TypeCompilerEnvironment EnterType
            (CompilerEnvironment env,
             JST.NameSupply nameSupply,
             JST.Identifier rootId,
             JST.Identifier assemblyId,
             JST.Identifier typeId,
             CST.TypeEnvironment typeEnv,
             TypeTrace typeTrace)
        {
            var typeBoundTypeParameterIds = new Seq<JST.Identifier>();
            for (var i = 0; i < typeEnv.Type.Arity; i++)
                typeBoundTypeParameterIds.Add(nameSupply.GenSym());

            var res = new TypeCompilerEnvironment
                (typeEnv.Global,
                 typeEnv.SkolemDefs,
                 typeEnv.Assembly,
                 typeEnv.Type,
                 typeEnv.TypeBoundArguments,
                 env,
                 nameSupply,
                 rootId,
                 assemblyId,
                 typeId,
                 typeBoundTypeParameterIds,
                 typeTrace);

            res.BindSpecial();

            return res;
        }
Beispiel #17
0
        public JST.Expression AppendImport(JST.NameSupply nameSupply, JST.Identifier rootId, CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, ISeq<JST.Statement> body, IImSeq<JST.Expression> arguments)
        {
            var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);
            CheckParameterAndReturnTypesAreImportableExportable(assemblyDef, typeDef, methodDef);

            var script = default(JST.Expression);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ImportAttributeRef,
                 attributeHelper.TheScriptProperty,
                 true,
                 false,
                 ref script);

            if (!methodDef.IsStatic && methodDef.IsConstructor)
            {
                // Constructor
                if (script == null)
                {
                    var creation = default(Creation);
                    attributeHelper.GetValueFromMethod
                        (assemblyDef,
                         typeDef,
                         methodDef,
                         attributeHelper.ImportAttributeRef,
                         attributeHelper.TheCreationProperty,
                         true,
                         false,
                         ref creation);
                    switch (creation)
                    {
                    case Creation.Constructor:
                        script = PrefixName(assemblyDef, typeDef, methodDef, null, false);
                        break;
                    case Creation.Object:
                        if (arguments.Count > 0)
                        {
                            env.Log
                                (new InvalidInteropMessage
                                     (ctxt, "imported constructors for object literals cannot have arguments"));
                            throw new DefinitionException();
                        }
                        script = Constants.Object.ToE();
                        break;
                    case Creation.Array:
                        script = Constants.Array.ToE();
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                    var call = AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                    return new JST.NewExpression(call);
                }
                else if (script is JST.FunctionExpression)
                    return AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                else
                {
                    script = PrefixName(assemblyDef, typeDef, methodDef, script, false);
                    var call = AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                    return new JST.NewExpression(call);
                }
            }
            else
            {
                var outer = typeDef.OuterPropertyOrEvent(methodDef.MethodSignature);
                if (outer != null)
                {
                    var isOnMethod = attributeHelper.MethodHasAttribute
                        (assemblyDef, typeDef, methodDef, attributeHelper.ImportAttributeRef, false, false);
                    var localScript = default(JST.Expression);
                    if (isOnMethod)
                        attributeHelper.GetValueFromMethod
                            (assemblyDef,
                             typeDef,
                             methodDef,
                             attributeHelper.ImportAttributeRef,
                             attributeHelper.TheScriptProperty,
                             false,
                             false,
                             ref localScript);

                    switch (outer.Flavor)
                    {
                    case CST.MemberDefFlavor.Property:
                        {
                            var propDef = (CST.PropertyDef)outer;
                            if (propDef.Get != null && methodDef.Signature.Equals(propDef.Get))
                            {
                                // Getter
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "get", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage
                                             (ctxt, "property import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    if (script == null && arguments.Count == 2 && !methodDef.IsStatic)
                                        return new JST.IndexExpression(arguments[0], arguments[1]);
                                    else
                                    {
                                        script = PrefixName
                                            (assemblyDef,
                                             typeDef,
                                             methodDef,
                                             RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                             false);
                                        if (methodDef.IsStatic && arguments.Count == 0)
                                            return script;
                                        else if (!methodDef.IsStatic && arguments.Count == 1)
                                            return JST.Expression.Dot
                                                (arguments[0], JST.Expression.ExplodePath(script));
                                        else
                                        {
                                            env.Log
                                                (new InvalidInteropMessage
                                                     (ctxt,
                                                      "additional getter parameters not supported for default getters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                }
                            }
                            else if (propDef.Set != null && methodDef.Signature.Equals(propDef.Set))
                            {
                                // Setter
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "set", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage
                                             (ctxt, "property import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    if (script == null && arguments.Count == 3 && !methodDef.IsStatic)
                                        return new JST.BinaryExpression
                                            (new JST.IndexExpression(arguments[0], arguments[1]),
                                             JST.BinaryOp.Assignment,
                                             arguments[2]);
                                    else
                                    {
                                        script = PrefixName
                                            (assemblyDef,
                                             typeDef,
                                             methodDef,
                                             RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                             false);
                                        if (methodDef.IsStatic && arguments.Count == 1)
                                            return new JST.BinaryExpression
                                                (script, JST.BinaryOp.Assignment, arguments[0]);
                                        else if (!methodDef.IsStatic && arguments.Count == 2)
                                            return new JST.BinaryExpression
                                                (JST.Expression.Dot(arguments[0], JST.Expression.ExplodePath(script)),
                                                 JST.BinaryOp.Assignment,
                                                 arguments[1]);
                                        else
                                        {
                                            env.Log
                                                (new InvalidInteropMessage
                                                     (ctxt,
                                                      "additional setter parameters not supported for default setters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                }
                            }
                            else
                                throw new InvalidOperationException();
                        }
                    case CST.MemberDefFlavor.Event:
                        {
                            var eventDef = (CST.EventDef)outer;
                            // XREF1201
                            if (eventDef.Add != null && methodDef.Signature.Equals(eventDef.Add))
                            {
                                // Adder
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "add", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage(ctxt, "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    // The delegate argument has already taken account of the combine, so 
                                    // just a field assignment
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                         false);
                                    if (methodDef.IsStatic && arguments.Count == 1)
                                        return new JST.BinaryExpression(script, JST.BinaryOp.Assignment, arguments[0]);
                                    else if (!methodDef.IsStatic && arguments.Count == 2)
                                        return new JST.BinaryExpression
                                            (JST.Expression.Dot(arguments[0], JST.Expression.ExplodePath(script)),
                                             JST.BinaryOp.Assignment,
                                             arguments[1]);
                                    else
                                        throw new InvalidOperationException("mismatched event adder arity");
                                }
                            }
                            else if (eventDef.Remove != null && methodDef.Signature.Equals(eventDef.Remove))
                            {
                                // Remover
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         GetterSetterAdderRemoverNameFromMethod
                                             (assemblyDef, typeDef, methodDef, "remove", localScript),
                                         false);
                                    return AppendFinalImport
                                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log
                                        (new InvalidInteropMessage(ctxt, "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    // The delegate argument has already taken account of the delete, so 
                                    // just a field assignment
                                    script = PrefixName
                                        (assemblyDef,
                                         typeDef,
                                         methodDef,
                                         RecasePropertyEvent(assemblyDef, typeDef, methodDef, script),
                                         false);
                                    if (methodDef.IsStatic && arguments.Count == 1)
                                        return new JST.BinaryExpression(script, JST.BinaryOp.Assignment, arguments[0]);
                                    else if (!methodDef.IsStatic && arguments.Count == 2)
                                        return new JST.BinaryExpression
                                            (JST.Expression.Dot(arguments[0], JST.Expression.ExplodePath(script)),
                                             JST.BinaryOp.Assignment,
                                             arguments[1]);
                                    else
                                        throw new InvalidOperationException("mismatched event remover arity");
                                }
                            }
                            else
                                throw new InvalidOperationException();
                        }
                    case CST.MemberDefFlavor.Field:
                    case CST.MemberDefFlavor.Method:
                        throw new InvalidOperationException("outer is not property or event");
                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
                else
                {
                    // Normal method
                    script = PrefixName
                        (assemblyDef, typeDef, methodDef, RecaseMethod(assemblyDef, typeDef, methodDef, script), false);
                    return AppendFinalImport
                        (nameSupply, rootId, assemblyDef, typeDef, methodDef, script, body, arguments);
                }
            }
        }
Beispiel #18
0
        private void EmitConditionalDeref(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var s = TypeCompEnv.Type.Style;
            if (!(s is CST.HandleTypeStyle || s is CST.ReferenceTypeStyle))
            {

                var innerNameSupply = NameSupply.Fork();
                var parameters = new Seq<JST.Identifier>();
                parameters.Add(innerNameSupply.GenSym());
                var obj = parameters[0].ToE();
                var innerBody = new Seq<JST.Statement>();

                if (s is CST.VoidTypeStyle)
                    innerBody.Add
                        (new JST.ThrowStatement
                             (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
                else
                    innerBody.Add(new JST.ReturnStatement(obj));

                body.Add
                    (JST.Statement.DotAssignment
                         (lhs, Constants.TypeConditionalDeref, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
            }
            // else: default is ok
        }
Beispiel #19
0
        private void EnsurePathExists(ISeq<JST.Statement> statements, JST.Expression script, bool isStatic)
        {
            var path = JST.Expression.ExplodePath(script);
            for (var i = isStatic ? 0 : 1; i < path.Count - 1; i++)
            {
                var prefixPath = new Seq<JST.PropertyName>();
                for (var j = 0; j <= i; j++)
                    prefixPath.Add(path[j]);
                var prefix = JST.Expression.Path(prefixPath);
                if (i == 0)
                {
                    var exId = new JST.Identifier("e");
#if !JSCRIPT_IS_CORRECT
                    statements.Add(JST.Statement.Var(exId));
#endif
                    statements.Add
                        (new JST.TryStatement
                             (new JST.Statements(new JST.ExpressionStatement(prefix)),
                              new JST.CatchClause
                                  (exId, new JST.Statements(JST.Statement.Assignment(prefix, new JST.ObjectLiteral())))));
                }
                else if (!path[i].Value.Equals(Constants.prototype.Value, StringComparison.Ordinal))
                    statements.Add
                        (new JST.IfStatement
                             (JST.Expression.IsNull(prefix),
                              new JST.Statements(JST.Statement.Assignment(prefix, new JST.ObjectLiteral()))));
            }
        }
Beispiel #20
0
 private void EmitIsValue(Seq<JST.Statement> body, JST.Expression lhs)
 {
     var s = TypeCompEnv.Type.Style;
     if (s is CST.HandleTypeStyle || s is CST.ReferenceTypeStyle || s is CST.ManagedPointerTypeStyle)
         // default is ok
         return;
     else if (s is CST.VoidTypeStyle)
         body.Add(JST.Statement.DotAssignment(lhs, Constants.TypeIsValueType, new JST.NullExpression()));
     else
         body.Add(JST.Statement.DotAssignment(lhs, Constants.TypeIsValueType, new JST.BooleanLiteral(true)));
 }
Beispiel #21
0
        // Return the name for a getter/setter/adder/remover method based on the user-supplied method name or underlying method name
        private JST.Expression GetterSetterAdderRemoverNameFromMethod(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, string prefix, JST.Expression script)
        {
            if (script != null)
                return script;

            var name = methodDef.Name;
            if (name.StartsWith(prefix + "_", StringComparison.OrdinalIgnoreCase))
                name = name.Substring(prefix.Length + 1);

            var removeAccessor = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheRemoveAccessorPrefixProperty,
                 true,
                 false,
                 ref removeAccessor);
            var prefixCasing = default(Casing);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.ThePrefixNameCasingProperty,
                 true,
                 false,
                 ref prefixCasing);
            var removeUnderscore = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheRemoveAccessorUnderscoreProperty,
                 true,
                 false,
                 ref removeUnderscore);
            var memberCasing = default(Casing);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheMemberNameCasingProperty,
                 true,
                 false,
                 ref memberCasing);

            var str = "";
            if (!removeAccessor)
            {
                str += Recase(prefix, prefixCasing);
                if (!removeUnderscore)
                    str += "_";
            }
            str += Recase(name, memberCasing);

            return new JST.Identifier(JST.Lexemes.StringToIdentifier(str)).ToE();
        }
Beispiel #22
0
        private void EmitEquals(Seq<JST.Statement> body, JST.Expression lhs)
        {
            var innerNameSupply = NameSupply.Fork();
            var parameters = new Seq<JST.Identifier>();
            parameters.Add(innerNameSupply.GenSym());
            var left = parameters[0].ToE();
            parameters.Add(innerNameSupply.GenSym());
            var right = parameters[1].ToE();
            var innerBody = new Seq<JST.Statement>();

            var iequatableTypeRef = Env.Global.IEquatableTypeConstructorRef.ApplyTo(TypeCompEnv.TypeRef);
            var hasIEquatable = TypeCompEnv.TypeRef.IsAssignableTo(TypeCompEnv, iequatableTypeRef);

            var s = TypeCompEnv.Type.Style;

            if (s is CST.VoidTypeStyle || s is CST.ManagedPointerTypeStyle)
                innerBody.Add
                    (new JST.ThrowStatement
                         (JST.Expression.DotCall(RootId.ToE(), Constants.RootInvalidOperationException)));
            else if (s is CST.NumberTypeStyle || s is CST.EnumTypeStyle || TypeCompEnv.TypeRef.Equals(Env.Global.DecimalRef))
                innerBody.Add(new JST.ReturnStatement(new JST.BinaryExpression(left, JST.BinaryOp.Equals, right)));
            else if (s is CST.HandleTypeStyle)
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(left), new JST.Statements(new JST.ReturnStatement(JST.Expression.IsNull(right)))));
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(right), new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                innerBody.Add
                    (new JST.ReturnStatement(new JST.BinaryExpression(left, JST.BinaryOp.StrictEquals, right)));
            }
            else if (s is CST.NullableTypeStyle)
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(left), new JST.Statements(new JST.ReturnStatement(JST.Expression.IsNull(right)))));
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(right), new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                innerBody.Add
                    (new JST.ReturnStatement
                         (JST.Expression.DotCall
                              (TypeCompEnv.ResolveType(TypeCompEnv.TypeBoundArguments[0], TypePhase.Slots),
                               Constants.TypeEquals,
                               left,
                               right)));
            }
            else if (s is CST.StructTypeStyle)
            {
                if (hasIEquatable)
                {
                    // Defer to IEquatable<T>::Equals
                    var paramTypeRef = new CST.ParameterTypeRef(CST.ParameterFlavor.Type, 0);
                    var equalsRef = new CST.MethodRef
                        (iequatableTypeRef,
                         "Equals",
                         false,
                         null,
                         new Seq<CST.TypeRef> { paramTypeRef, paramTypeRef },
                         Env.Global.BooleanRef);
                    var leftPtr = JST.Expression.DotCall
                        (RootId.ToE(), Constants.RootNewPointerToValue, left, lhs);
                    var call = Env.JSTHelpers.DefaultVirtualMethodCallExpression
                        (TypeCompEnv,
                         innerNameSupply,
                         innerBody,
                         equalsRef,
                         new Seq<JST.Expression> { leftPtr, right });
                    innerBody.Add(new JST.ReturnStatement(call));
                }
                else
                {
                    foreach (var fieldDef in Parent.Fields.Where(f => !f.IsStatic))
                    {
                        var fieldRef = new CST.FieldRef(TypeCompEnv.TypeRef, fieldDef.FieldSignature);
                        var leftField = Env.JSTHelpers.ResolveInstanceField(TypeCompEnv, left, fieldRef);
                        var rightField = Env.JSTHelpers.ResolveInstanceField(TypeCompEnv, right, fieldRef);
                        innerBody.Add
                            (new JST.IfStatement
                                 (JST.Expression.Not
                                      (JST.Expression.DotCall
                                           (TypeCompEnv.ResolveType(fieldDef.FieldType, TypePhase.Slots),
                                            Constants.TypeEquals,
                                            leftField,
                                            rightField)),
                                  new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                    }
                    innerBody.Add(new JST.ReturnStatement(new JST.BooleanLiteral(true)));
                }
            }
            else if (s is CST.ObjectTypeStyle || (s is CST.ClassTypeStyle & hasIEquatable))
            {
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(left), new JST.Statements(new JST.ReturnStatement(JST.Expression.IsNull(right)))));
                innerBody.Add
                    (new JST.IfStatement
                         (JST.Expression.IsNull(right), new JST.Statements(new JST.ReturnStatement(new JST.BooleanLiteral(false)))));
                var equalsRef = default(CST.MethodRef);
                if (hasIEquatable)
                {
                    // Defer to IEquatable<T>::Equals
                    var paramTypeRef = new CST.ParameterTypeRef(CST.ParameterFlavor.Type, 0);
                    var iequatableSelfTypeRef = Env.Global.IEquatableTypeConstructorRef.ApplyTo(paramTypeRef);
                    equalsRef = new CST.MethodRef
                        (iequatableTypeRef,
                         "Equals",
                         false,
                         null,
                         new Seq<CST.TypeRef> { iequatableSelfTypeRef, paramTypeRef },
                         Env.Global.BooleanRef);
                }
                else
                {
                    // Defer to Object::Equals virtual
                    equalsRef = new CST.MethodRef
                        (Env.Global.ObjectRef,
                         "Equals",
                         false,
                         null,
                         new Seq<CST.TypeRef> { Env.Global.ObjectRef, Env.Global.ObjectRef },
                         Env.Global.BooleanRef);
                }
                var call = Env.JSTHelpers.DefaultVirtualMethodCallExpression
                    (TypeCompEnv, innerNameSupply, innerBody, equalsRef, new Seq<JST.Expression> { left, right });
                innerBody.Add(new JST.ReturnStatement(call));
            }
            else
                // default is ok
                return;

            body.Add
                (JST.Statement.DotAssignment
                     (lhs, Constants.TypeEquals, new JST.FunctionExpression(parameters, new JST.Statements(innerBody))));
        }
Beispiel #23
0
        // Return the exported name for a getter/setter/adder/remover method based on the property/event name
        private JST.Expression GetterSetterAdderRemoverNameFromPropertyEvent(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, string prefix, JST.Expression script)
        {
            if (script != null && script is JST.FunctionExpression)
                throw new InvalidOperationException("not a path expression");

            var names = script == null
                            ? // Take the actual property/event name as a starting point
                        JST.Expression.ExplodePath(RecasePropertyEvent(assemblyDef, typeDef, methodDef, null))
                            : // Take the user supplied property/event name as a starting point
                        JST.Expression.ExplodePath(script);

            var removeAccessor = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheRemoveAccessorPrefixProperty,
                 true,
                 false,
                 ref removeAccessor);
            var prefixCasing = default(Casing);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.ThePrefixNameCasingProperty,
                 true,
                 false,
                 ref prefixCasing);
            var removeUnderscore = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheRemoveAccessorUnderscoreProperty,
                 true,
                 false,
                 ref removeUnderscore);

            // Turn the property/event name into a getter/setter/adder/remover name
            var str = "";
            if (!removeAccessor)
            {
                str += Recase(prefix, prefixCasing);
                if (!removeUnderscore)
                    str += "_";
            }
            str += names[names.Count - 1].Value;
            names[names.Count - 1] = new JST.PropertyName(str);

            return JST.Expression.Path(names);
        }
 private void BindBaseTypes(CST.TypeEnvironment thisTypeEnv, JST.Expression thisType)
 {
     if (thisTypeEnv.Type.Extends != null)
     {
         var baseTypeEnv = thisTypeEnv.Type.Extends.Enter(thisTypeEnv);
         var baseType = JST.Expression.Dot(thisType, Constants.TypeBaseType);
         if (!boundTypes.ContainsKey(baseTypeEnv.TypeRef))
             boundTypes.Add(baseTypeEnv.TypeRef, new ExpressionAndPhase(baseType, TypePhase.Slots));
         if (baseTypeEnv.Type.Arity > 0)
         {
             if (!boundTypes.ContainsKey(baseTypeEnv.TypeConstructorRef))
                 boundTypes.Add(baseTypeEnv.TypeConstructorRef, new ExpressionAndPhase(JST.Expression.Dot(baseType, Constants.TypeApplicand), TypePhase.Slots));
         }
         BindBaseTypes(baseTypeEnv, baseType);
     }
 }
Beispiel #25
0
        // Imports:
        //  - instance methods: no qualification
        //  - static methods & constructors: add qualification
        // Exports:
        //  - instance methods, not prototype bound: no qualification
        //  - instance methods, prototype bound: add qualification and 'prototype'
        //  - static methods & constructors: add qualification
        private JST.Expression PrefixName(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script, bool isExport)
        {
            if (script != null && script is JST.FunctionExpression)
                return script;

            var isNonInstance = methodDef.IsStatic || methodDef.IsConstructor;
            var qual = default(Qualification);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.NamingAttributeRef,
                 attributeHelper.TheQualificationProperty,
                 true,
                 false,
                 ref qual);
            var bindToProto = default(bool);
            attributeHelper.GetValueFromMethod
                (assemblyDef,
                 typeDef,
                 methodDef,
                 attributeHelper.ExportAttributeRef,
                 attributeHelper.TheBindToPrototypeProperty,
                 true,
                 false,
                 ref bindToProto);
            var isProto = isExport && bindToProto;
            var path = new Seq<JST.PropertyName>();

            if (script == null && !methodDef.IsStatic && methodDef.IsConstructor && qual == Qualification.None)
                qual = Qualification.Type;

            if (!isExport && !isNonInstance && qual != Qualification.None)
                qual = Qualification.None;

            if (isExport && !isNonInstance && !isProto && qual != Qualification.None)
                qual = Qualification.None;

            if (isExport && !isNonInstance && isProto && qual == Qualification.None)
                qual = Qualification.Type;

            if (isNonInstance)
            {
                var global = default(JST.Expression);

                attributeHelper.GetValueFromMethod
                    (assemblyDef,
                     typeDef,
                     methodDef,
                     attributeHelper.NamingAttributeRef,
                     attributeHelper.TheGlobalObjectProperty,
                     true,
                     false,
                     ref global);
                if (global != null)
                {
                    if (global is JST.FunctionExpression)
                    {
                        var ctxt = CST.MessageContextBuilders.Member(env.Global, assemblyDef, typeDef, methodDef);
                        env.Log(new InvalidInteropMessage(ctxt, "global object expression cannot be a function"));
                        throw new DefinitionException();
                    }
                    foreach (var p in JST.Expression.ExplodePath(global))
                        path.Add(p);
                }
            }

            if (qual == Qualification.Full)
            {
                var nm = typeDef.EffectiveName(env.Global);
                if (nm.Namespace.Length > 0)
                {
                    var nsCasing = default(Casing);
                    attributeHelper.GetValueFromMethod
                        (assemblyDef,
                         typeDef,
                         methodDef,
                         attributeHelper.NamingAttributeRef,
                         attributeHelper.TheNamespaceCasingProperty,
                         true,
                         false,
                         ref nsCasing);
                    foreach (var n in nm.Namespace.Split('.'))
                        path.Add(new JST.PropertyName(Recase(n, nsCasing)));
                }
            }

            if (qual == Qualification.Full || qual == Qualification.Type)
            {
                var tnCasing = default(Casing);
                attributeHelper.GetValueFromType
                    (assemblyDef,
                     typeDef,
                     attributeHelper.NamingAttributeRef,
                     attributeHelper.TheTypeNameCasingProperty,
                     true,
                     false,
                     ref tnCasing);
                foreach (var n in
                    typeDef.EffectiveName(env.Global).Types.Select
                        (name => new JST.PropertyName(Recase(name, tnCasing))))
                    path.Add(n);
            }

            if (isProto)
                path.Add(new JST.PropertyName(Constants.prototype));

            if (script != null)
            {
                foreach (var p in JST.Expression.ExplodePath(script))
                    path.Add(p);
            }

            return JST.Expression.Path(path);
        }
 public ExpressionAndPhase(JST.Expression expression, TypePhase phase)
 {
     Expression = expression;
     Phase = phase;
 }
Beispiel #27
0
 private JST.Expression RecaseMethod(CST.AssemblyDef assemblyDef, CST.TypeDef typeDef, CST.MethodDef methodDef, JST.Expression script)
 {
     if (script != null)
         return script;
     var casing = default(Casing);
     attributeHelper.GetValueFromMethod
         (assemblyDef,
          typeDef,
          methodDef,
          attributeHelper.NamingAttributeRef,
          attributeHelper.TheMemberNameCasingProperty,
          true,
          false,
          ref casing);
     return new JST.Identifier(JST.Lexemes.StringToIdentifier(Recase(methodDef.Name, casing))).ToE();
 }
        // ----------------------------------------------------------------------
        // Methods
        // ----------------------------------------------------------------------

        public JST.Expression MethodCallExpression(CST.MethodRef methodRef, JST.NameSupply localNameSupply, bool isFactory, IImSeq<JST.Expression> arguments)
        {
            return env.JSTHelpers.DefaultMethodCallExpression(this, localNameSupply, methodRef, isFactory, arguments);
        }
 // Compile all methods not already compiled by above
 private void CompileMethods(Seq<JST.Statement> body, JST.NameSupply outerNameSupply)
 {
     switch (Env.CompilationMode)
     {
     case CompilationMode.Plain:
     case CompilationMode.Collecting:
         // Already compiled above
         return;
     case CompilationMode.Traced:
         foreach (var methodDef in
             Methods.Where(d => TypeTrace.Methods.Contains(d.MethodSignature)))
         {
             if (TypeTrace.Parent.Parent.Flavor == TraceFlavor.Remainder)
             {
                 // Compile method into stand-alone loader
                 var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.SelfContained);
                 compiler.Emit(body, null);
             }
             else
             {
                 // Bind method definition into method cache
                 var target = TypeDefinitionId.ToE();
                 if (TyconEnv.Type.Arity == 0 && !Env.InteropManager.IsStatic(TyconEnv.Assembly, TyconEnv.Type, methodDef))
                     target = JST.Expression.Dot
                         (target, Constants.TypeConstructObject, Constants.prototype);
                 target = JST.Expression.Dot(target, Constants.TypeMethodCache);
                 var compiler = new MethodCompiler(this, outerNameSupply, methodDef, MethodCompilationMode.DirectBind);
                 compiler.Emit(body, target);
             }
         }
         break;
     default:
         throw new ArgumentOutOfRangeException();
     }
 }
Beispiel #30
0
        private void EmitSetupType(Seq<JST.Statement> body, JST.Expression lhs)
        {
            // NOTE: We always emit the SetupType function, even if the body is empty, so that we can
            //       track which types are at phase 3. (We need to initialize base types and type arguments
            //       to phase 3 when type itself is brought up to phase 3.)

            // Collect static fields and their types
            // NOTE: We used to also bind null instance fields into the prototype, but this turns out to
            //       be a significant performance hit
            var staticFields = new Seq<CST.FieldRef>();
            var usage = new CST.Usage();
            foreach (var fieldDef in Parent.Fields.Where(f => f.IsStatic))
            {
                var fieldRef = new CST.FieldRef(TypeCompEnv.TypeRef, fieldDef.FieldSignature);
                if (TypeCompEnv.Type.Style is CST.EnumTypeStyle || fieldDef.Init == null ||
                    fieldDef.Init.Flavor != CST.FieldInitFlavor.Const)
                {
                    staticFields.Add(fieldRef);
                    if (Env.JSTHelpers.DefaultFieldValueIsNonNull(TypeCompEnv, fieldRef))
                        // We'll need type to construct default
                        fieldRef.ExternalFieldType.AccumUsage(usage, true);
                }
                // else: constant static fields, other than enums, don't need any run-time representation
            }

            var innerBody = new Seq<JST.Statement>();
            var innerTypeCompEnv = TypeCompEnv.EnterFunction();

            innerTypeCompEnv.BindUsage(innerBody, usage, TypePhase.Constructed);

            if (staticFields.Count > 0)
            {
                if (Env.DebugMode)
                    innerBody.Add(new JST.CommentStatement("Static fields"));
                foreach (var fieldRef in staticFields)
                {
                    innerBody.Add
                        (JST.Statement.DotAssignment
                             (TypeId.ToE(),
                              Env.JSTHelpers.ResolveFieldToIdentifier(innerTypeCompEnv, fieldRef, true),
                              Env.JSTHelpers.DefaultFieldValue(innerTypeCompEnv, fieldRef)));
                }
            }

            if (Parent.StaticInitializer != null)
            {
                if (Env.DebugMode)
                    innerBody.Add(new JST.CommentStatement("Static constructor"));
                innerBody.Add
                    (new JST.ExpressionStatement
                         (innerTypeCompEnv.MethodCallExpression
                              (Parent.StaticInitializer, innerTypeCompEnv.NameSupply, false, JST.Constants.EmptyExpressions)));
            }

            EmitReflection(innerBody, innerTypeCompEnv, TypeId.ToE());

            body.Add
                (JST.Statement.DotAssignment
                     (lhs, Constants.TypeSetupType, new JST.FunctionExpression(null, new JST.Statements(innerBody))));
        }