Example #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);
        }
Example #2
0
 public void Emit()
 {
     if (Trace.Flavor == TraceFlavor.Remainder)
     {
         foreach (var kv in Trace.AssemblyMap)
         {
             var compiler = new AssemblyCompiler(this, kv.Value);
             compiler.Emit(null);
         }
     }
     else
     {
         var rootEnv = Env.Global.Environment();
         var body = new Seq<JST.Statement>();
         body.Add(JST.Statement.Var(RootId, new JST.Identifier(Env.Root).ToE()));
         foreach (var nm in rootEnv.AllLoadedAssembliesInLoadOrder().Where(Trace.AssemblyMap.ContainsKey))
         {
             var compiler = new AssemblyCompiler(this, Trace.AssemblyMap[nm]);
             compiler.Emit(body);
         }
         var program = new JST.Program
             (new JST.Statements
                  (new JST.ExpressionStatement
                       (new JST.StatementsPseudoExpression(new JST.Statements(body), null))));
         var fileName = Path.Combine(Env.OutputDirectory, Trace.Name + ".js");
         program.ToFile(fileName, Env.PrettyPrint);
         Env.Log(new GeneratedJavaScriptFile("trace '" + Trace.Name + "'", fileName));
     }
 }
Example #3
0
 public CallContext(IImSeq<Identifier> parameters, IImSeq<Expression> arguments, Func<Expression, bool> isValue)
 {
     var paramMap = new Map<Identifier, int>();
     for (var i = 0; i < parameters.Count; i++)
         paramMap.Add(parameters[i], i);
     Parameters = paramMap;
     var argumentEffects = new Seq<Effects>(parameters.Count);
     SeenParameters = new Seq<bool>(parameters.Count);
     var allReadOnly = true;
     AllArgumentEffects = Effects.Bottom;
     foreach (var e in arguments)
     {
         var fxCtxt = new EffectsContext(isValue);
         e.AccumEffects(fxCtxt, null, null);
         argumentEffects.Add(fxCtxt.AccumEffects);
         AllArgumentEffects = AllArgumentEffects.Lub(fxCtxt.AccumEffects);
         if (!fxCtxt.AccumEffects.IsReadOnly)
             allReadOnly = false;
         SeenParameters.Add(false);
     }
     ArgumentEffects = argumentEffects;
     AllReadOnly = allReadOnly;
     IsOk = true;
 }
Example #4
0
 public CallContext(CompilationEnvironment outerCompEnv, CompilationEnvironment inlinedCompEnv, IImSeq<Expression> arguments)
 {
     var paramMap = new Map<JST.Identifier, int>();
     for (var i = 0; i < inlinedCompEnv.Method.Arity; i++)
         paramMap.Add(inlinedCompEnv.ValueParameterIds[i], i);
     Parameters = paramMap;
     var argumentEffects = new Seq<JST.Effects>(inlinedCompEnv.Method.Arity);
     SeenParameters = new Seq<bool?>(inlinedCompEnv.Method.Arity);
     AllArgumentEffects = JST.Effects.Bottom;
     var allReadOnly = true;
     foreach (var e in arguments)
     {
         var fxCtxt = new JST.EffectsContext(null);
         e.AccumEffects(fxCtxt, null, null);
         argumentEffects.Add(fxCtxt.AccumEffects);
         AllArgumentEffects = AllArgumentEffects.Lub(fxCtxt.AccumEffects);
         if (!fxCtxt.AccumEffects.IsReadOnly)
             allReadOnly = false;
         SeenParameters.Add(e.IsValue(outerCompEnv) ? default(bool?) : false);
     }
     ArgumentEffects = argumentEffects;
     AllReadOnly = allReadOnly;
     IsOk = true;
 }
        // ----------------------------------------------------------------------
        // Entry point from AssemblyCompiler
        // ----------------------------------------------------------------------

        public void Emit(Seq<JST.Statement> body)
        {
            if (Env.BreakOnBreak &&
                Env.AttributeHelper.TypeHasAttribute(TyconEnv.Assembly, TyconEnv.Type, Env.AttributeHelper.BreakAttributeRef, false, false))
                System.Diagnostics.Debugger.Break();

            CollectMembers();

            var typeName = CST.CSTWriter.WithAppend
                (Env.Global, CST.WriterStyle.Uniform, TyconEnv.Type.EffectiveName(Env.Global).Append);
            var slotName = Env.GlobalMapping.ResolveTypeDefToSlot(TyconEnv.Assembly, TyconEnv.Type);

            if (TypeTrace != null && TypeTrace.IncludeType && TypeTrace.Parent.Parent.Flavor == TraceFlavor.Remainder)
            {
                // Self-loader fragment
                var assmName = CST.CSTWriter.WithAppend
                    (Env.Global, CST.WriterStyle.Uniform, TyconEnv.Assembly.Name.Append);
                var funcBody = new Seq<JST.Statement>();
                BuildTypeStructure(funcBody);
                var func = new JST.FunctionExpression
                    (new Seq<JST.Identifier> { RootId, AssemblyId, TypeDefinitionId }, new JST.Statements(funcBody));
                var loaderBody = new Seq<JST.Statement>();
                if (Env.DebugMode)
                    loaderBody.Add(new JST.CommentStatement(TyconEnv.ToString()));
                loaderBody.Add
                    (JST.Statement.DotCall
                         (new JST.Identifier(Env.Root).ToE(),
                          Constants.RootBindType,
                          new JST.StringLiteral(assmName),
                          new JST.StringLiteral(slotName),
                          new JST.StringLiteral(typeName),
                          func));
                var program = new JST.Program(new JST.Statements(loaderBody));
                var typePath = Path.Combine
                    (Path.Combine(Env.OutputDirectory, JST.Lexemes.StringToFileName(assmName)), slotName);
                var fileName = Path.Combine(typePath, Constants.TypeFileName);
                program.ToFile(fileName, Env.PrettyPrint);
                Env.Log(new GeneratedJavaScriptFile("type '" + TyconEnv.TypeConstructorRef + "'", fileName));

                CompileMethods(null, NameSupply);
            }
            else if (TypeTrace != null && !TypeTrace.IncludeType && TypeTrace.Parent.Parent.Flavor == TraceFlavor.Remainder)
            {
                // Just passisng through
                CompileMethods(body, NameSupply);
            }
            else if (TypeTrace != null && !TypeTrace.IncludeType)
            {
                // Type defined elsewhere, include some/all methods only
                body.Add
                    (JST.Statement.Var
                         (TypeDefinitionId,
                          JST.Expression.DotCall
                              (AssemblyId.ToE(),
                               new JST.Identifier(Constants.AssemblyTypeBuilderSlot(slotName)),
                               Env.JSTHelpers.PhaseExpression(TypePhase.Slots))));
                CompileMethods(body, NameSupply);
            }
            else
            {
                // Inline type definition and some/all methods
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement(TyconEnv.ToString()));
                // We must construct the type explicity to phase 1 rather than using type compiler environment
                // since it thinks the type is already at phase 2.
                body.Add
                    (JST.Statement.Var
                         (TypeDefinitionId,
                          JST.Expression.DotCall
                              (AssemblyId.ToE(),
                               new JST.Identifier(Constants.AssemblyTypeBuilderSlot(slotName)),
                               Env.JSTHelpers.PhaseExpression(TypePhase.Id))));
                BuildTypeStructure(body);
                CompileMethods(body, NameSupply);
            }
        }
        // ----------------------------------------------------------------------
        // Building type structures
        // ----------------------------------------------------------------------

        private void BuildTypeStructure(Seq<JST.Statement> body)
        {
            // Already bound: T, Id, Assembly, Name, Slot

            var compiler = new TypeCompiler(this);
            compiler.Emit(body);

            if (TyconEnv.Type.Arity > 0)
            {
                // Methods live on type definition itself if type is higher-kinded
                if (Env.DebugMode)
                    body.Add(new JST.CommentStatement("Method definitions (accepting type-bound type arguments)"));
                EmitMethods(body, TypeDefinitionId.ToE(), NameSupply, TypeDefinitionId.ToE(), false);
                EmitMethods(body, TypeDefinitionId.ToE(), NameSupply, TypeDefinitionId.ToE(), true);
            }

            // Shared strings
            if (Env.DebugMode)
                body.Add(new JST.CommentStatement("Shared strings"));
            foreach (var kv in Env.GlobalMapping.AllStringSlots(TyconEnv.Assembly, TyconEnv.Type))
            {
                body.Add
                    (JST.Statement.DotAssignment
                         (TypeDefinitionId.ToE(),
                          new JST.Identifier(Constants.TypeStringSlot(kv.Value)),
                          new JST.StringLiteral(kv.Key)));
            }
        }
Example #7
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);
        }
Example #8
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()))));
            }
        }
Example #9
0
        internal void UsedByMembersClosure(Global global, AssemblyDef assemblyDef, TypeDef typeDef, Set<QualifiedMemberName> visitedMemberDefs, Seq<QualifiedMemberName> scc)
        {
            if (usedByMembers == null)
                return;

            var self = QualifiedMemberName(global, assemblyDef, typeDef);
            if (!visitedMemberDefs.Contains(self))
            {
                visitedMemberDefs.Add(self);
                scc.Add(self);
                foreach (var r in usedByMembers)
                {
                    var usedByAssemblyDef = default(AssemblyDef);
                    var usedByTypeDef = default(TypeDef);
                    var usedByMemberDef = default(MemberDef);
                    if (r.PrimTryResolve(global, out usedByAssemblyDef, out usedByTypeDef, out usedByMemberDef))
                        usedByMemberDef.UsedByMembersClosure
                            (global, usedByAssemblyDef, usedByTypeDef, visitedMemberDefs, scc);
                }
            }
        }
Example #10
0
 private LoopClause LoopClause()
 {
     var loc = Only("loop clause", "'('", InputElementTag.LParen);
     if (Current.Tag == InputElementTag.Semicolon)
     {
         Consume();
         var condition = default(Expression);
         if (Current.Tag != InputElementTag.Semicolon)
             condition = Expression(false);
         Only("loop clause", "';'", InputElementTag.Semicolon);
         if (condition != null)
             condition = ConsumeCommentExpression(condition);
         var increment = default(Expression);
         if (Current.Tag != InputElementTag.RParen)
             increment = Expression(false);
         loc = loc.Union(Only("loop clause", "')'", InputElementTag.RParen));
         if (increment != null)
             increment = ConsumeCommentExpression(increment);
         return new ForLoopClause(loc, null, condition, increment);
     }
     else if (Current.Tag == InputElementTag.Var)
     {
         Consume();
         var vd = VariableDeclaration(true);
         if (Current.Tag == InputElementTag.In)
         {
             Consume();
             var collection = Expression(false);
             loc = loc.Union(Only("loop clause", "')'", InputElementTag.RParen));
             collection = ConsumeCommentExpression(collection);
             return new ForEachVarLoopClause(loc, vd, collection);
         }
         else
         {
             var iterationVariables = new Seq<VariableDeclaration>();
             iterationVariables.Add(vd);
             while (Current.Tag == InputElementTag.Comma)
             {
                 Consume();
                 iterationVariables.Add(VariableDeclaration(true));
             }
             Only("loop clause", "';'", InputElementTag.Semicolon);
             var condition = default(Expression);
             if (Current.Tag != InputElementTag.Semicolon)
                 condition = Expression(false);
             Only("loop clause", "';'", InputElementTag.Semicolon);
             if (condition != null)
                 condition = ConsumeCommentExpression(condition);
             var increment = default(Expression);
             if (Current.Tag != InputElementTag.RParen)
                 increment = Expression(false);
             loc = loc.Union(Only("loop clause", "')'", InputElementTag.RParen));
             if (increment != null)
                 increment = ConsumeCommentExpression(increment);
             return new ForVarLoopClause(loc, iterationVariables, condition, increment);
         }
     }
     else
     {
         var isLHS = true;
         var i = Expression(true, ref isLHS);
         if (Current.Tag == InputElementTag.Semicolon)
         {
             var initializer = i;
             Consume();
             initializer = ConsumeCommentExpression(initializer);
             var condition = default(Expression);
             if (Current.Tag != InputElementTag.Semicolon)
                 condition = Expression(false);
             Only("loop clause", "';'", InputElementTag.Semicolon);
             if (condition != null)
                 condition = ConsumeCommentExpression(condition);
             var increment = default(Expression);
             if (Current.Tag != InputElementTag.RParen)
                 increment = Expression(false);
             loc = loc.Union(Only("loop clause", "')'", InputElementTag.RParen));
             if (increment != null)
                 increment = ConsumeCommentExpression(increment);
             return new ForLoopClause(loc, initializer, condition, increment);
         }
         else if (isLHS)
         {
             Only("loop clause", "'in'", InputElementTag.In);
             var iterationVariable = i;
             iterationVariable = ConsumeCommentExpression(iterationVariable);
             var collection = Expression(false);
             loc = loc.Union(Only("loop clause", "')'", InputElementTag.RParen));
             collection = ConsumeCommentExpression(collection);
             return new ForEachLoopClause(loc, iterationVariable, collection);
         }
         else
             throw MsgError("loop clause", "syntax error");
     }
 }
Example #11
0
        // Take acccount of
        //   - PassRootAsArgument
        //   - PassInstanceAsArgument
        //   - InlineParamsArray
        private ImportMethodInfo FinalImportScript(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn, JST.Expression script, bool isNew)
        {
            if (script == null)
                throw new InvalidOperationException("expecting default script value");

            var lastArgIsParamsArray = LastArgIsParamsArray(ctxt, methodDefn) && interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheInlineParamsArrayProperty);
            var methodArity = Arity(methodDefn);
            var isInstanceMethod = !(methodDefn.IsStatic || methodDefn is CCI.InstanceInitializer);
            var scriptExpectsRoot = interopTypes.GetValue
                (ctxt, methodDefn, env.ImportAttributeType, interopTypes.ThePassRootAsArgumentProperty);
            var instanceIsThis = isInstanceMethod &&
                                 !interopTypes.GetValue
                                      (ctxt,
                                       methodDefn,
                                       env.ImportAttributeType,
                                       interopTypes.ThePassInstanceAsArgumentProperty);
            var expectedScriptArity = methodArity - (lastArgIsParamsArray ? 1 : 0) + (scriptExpectsRoot ? 1 : 0) -
                                      (instanceIsThis ? 1 : 0);
            CheckScriptArity(ctxt, methodDefn, script, expectedScriptArity);

            var function = default(JST.FunctionExpression);
            if (gensym != null)
            {
                var parameters = new Seq<JST.Identifier>();
                var body = new Seq<JST.Statement>();

                var callArgs = new Seq<JST.Expression>();

                if (lastArgIsParamsArray)
                {
                    var argsId = gensym();
                    body.Add(JST.Statement.Var(argsId, new JST.ArrayLiteral()));

                    if (scriptExpectsRoot)
                        body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, rootId.ToE()));

                    if (!isInstanceMethod)
                        callArgs.Add(new JST.NullExpression());

                    for (var i = 0; i < methodArity; i++)
                    {
                        var id = gensym();
                        parameters.Add(id);
                        if (isInstanceMethod && i == 0)
                        {
                            if (instanceIsThis)
                                callArgs.Add(id.ToE());
                            else
                            {
                                callArgs.Add(new JST.NullExpression());
                                body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, id.ToE()));
                            }
                        }
                        else if (i == methodArity - 1)
                        {
                            var iId = gensym();
                            body.Add
                                (new JST.IfStatement
                                     (JST.Expression.IsNotNull(id.ToE()),
                                      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(id.ToE(), Constants.length)),
                                                     new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)),
                                                new JST.Statements
                                                    (JST.Statement.DotCall
                                                         (argsId.ToE(),
                                                          Constants.push,
                                                          new JST.IndexExpression(id.ToE(), iId.ToE())))))));
                        }
                        else
                            body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, id.ToE()));
                    }
                    if (script is JST.FunctionExpression)
                    {
                        var funcId = gensym();
                        body.Add(JST.Statement.Var(funcId, script));
                        script = JST.Expression.Dot(funcId.ToE(), Constants.apply);
                    }
                    else
                        script = JST.Expression.Dot(script, Constants.apply);
                    callArgs.Add(argsId.ToE());
                }
                else
                {
                    if (scriptExpectsRoot)
                        callArgs.Add(rootId.ToE());

                    for (var i = 0; i < methodArity; i++)
                    {
                        var id = gensym();
                        parameters.Add(id);
                        if (i == 0 && instanceIsThis)
                        {
                            if (script is JST.FunctionExpression)
                            {
                                callArgs.Insert(0, id.ToE());
                                var funcId = gensym();
                                body.Add(JST.Statement.Var(funcId, script));
                                script = JST.Expression.Dot(funcId.ToE(), Constants.call);
                            }
                            else
                                script = JST.Expression.Dot(id.ToE(), JST.Expression.ExplodePath(script));
                        }
                        else
                            callArgs.Add(id.ToE());
                    }
                }

                var exp = (JST.Expression)new JST.CallExpression(script, callArgs);
                if (isNew)
                    exp = new JST.NewExpression(exp);

                if (ReturnType(methodDefn) == null)
                    body.Add(new JST.ExpressionStatement(exp));
                else
                    body.Add(new JST.ReturnStatement(exp));

                function = new JST.FunctionExpression(parameters, new JST.Statements(body));
            }
            return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
        }
Example #12
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(MessageContext ctxt, CCI.Member member, JST.Expression script, bool isExport)
        {
            if (script != null && script is JST.FunctionExpression)
                return script;

            var isNonInstance = member.IsStatic || member is CCI.InstanceInitializer;
            var qual = interopTypes.GetValue
                (ctxt, member, env.NamingAttributeType, interopTypes.TheQualificationProperty);
            var isProto = isExport &&
                          interopTypes.GetValue
                              (ctxt,
                               member,
                               env.ExportAttributeType,
                               interopTypes.TheBindToPrototypeProperty);
            var path = new Seq<JST.PropertyName>();

            if (script == null && member is CCI.InstanceInitializer && 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 = interopTypes.GetValue
                    (ctxt, member, env.NamingAttributeType, interopTypes.TheGlobalObjectProperty);
                if (global != null)
                {
                    if (global is JST.FunctionExpression)
                    {
                        env.Log(new InvalidInteropMessage
                            (RewriterMsgContext.Member(ctxt, member), "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 nsCasing = interopTypes.GetValue
                    (ctxt, member, env.NamingAttributeType, interopTypes.TheNamespaceCasingProperty);
                foreach (var name in member.DeclaringType.Namespace.Name.Split('.'))
                {
                    if (string.IsNullOrEmpty(name))
                    {
                        env.Log(new InvalidInteropMessage
                            (RewriterMsgContext.Member(ctxt, member),
                             "member's namespace cannot be represented in JavaScript"));
                        throw new DefinitionException();
                    }
                    path.Add(new JST.PropertyName(Recase(name, nsCasing)));
                }
            }

            if (qual == Qualification.Full || qual == Qualification.Type)
            {
                var type = member.DeclaringType;
                var i = path.Count;
                do
                {
                    var tnCasing = interopTypes.GetValue
                        (ctxt, type, env.NamingAttributeType, interopTypes.TheTypeNameCasingProperty);
                    path.Insert(i, new JST.PropertyName(Recase(type.Name.Name, tnCasing)));
                    type = type.DeclaringType;
                }
                while (type != null);
            }

            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);
        }
Example #13
0
        public void Emit()
        {
            var assm = typeof (RuntimeCompiler).Assembly;
            var res = "Microsoft.LiveLabs.JavaScript.IL2JS." + Constants.RuntimeFileName;
            var runtime = default(JST.Program);
            using (var runtimeStream = assm.GetManifestResourceStream(res))
            {
                if (runtimeStream == null)
                    throw new InvalidOperationException("unable to find runtime resource");
                runtime = JST.Program.FromStream(Constants.RuntimeFileName, runtimeStream, true);
            }

            var mode = default(string);
            switch (env.CompilationMode)
            {
            case CompilationMode.Plain:
                mode = "plain";
                break;
            case CompilationMode.Collecting:
                mode = "collecting";
                break;
            case CompilationMode.Traced:
                mode = "traced";
                break;
            default:
                throw new ArgumentOutOfRangeException();
            }

            var body = default(ISeq<JST.Statement>);
            if (env.DebugMode)
            {
                body = new Seq<JST.Statement>();
                body.Add
                    (JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel)));
                body.Add(JST.Statement.Var(Constants.DebugId, new JST.BooleanLiteral(true)));
                body.Add(JST.Statement.Var(Constants.ModeId, new JST.StringLiteral(mode)));
                body.Add(JST.Statement.Var(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop)));
                foreach (var s in runtime.Body.Body)
                    body.Add(s);
            }
            else
            {
                // Simplify
                var simpCtxt =
                    new JST.SimplifierContext(true, env.DebugMode, new JST.NameSupply(Constants.Globals), null).
                        InFreshStatements();
                simpCtxt.Bind(Constants.DebugId, new JST.BooleanLiteral(false));
                simpCtxt.Bind(Constants.ModeId, new JST.StringLiteral(mode));
                simpCtxt.Bind(Constants.SafeId, new JST.BooleanLiteral(env.SafeInterop));
                simpCtxt.Add(JST.Statement.Var(Constants.DebugLevel, new JST.NumericLiteral(env.DebugLevel)));
                runtime.Body.Simplify(simpCtxt, EvalTimes.Bottom, false);
                body = simpCtxt.Statements;
            }

            var opts = new OrdMap<JST.Identifier, JST.Expression>();
            var mscorlibName = new JST.StringLiteral
                (CST.CSTWriter.WithAppend(env.Global, CST.WriterStyle.Uniform, env.Global.MsCorLibName.Append));
            opts.Add(Constants.SetupMscorlib, mscorlibName);
            var target = default(string);
            switch (env.Target)
            {
            case Target.Browser:
                target = "browser";
                break;
            case Target.CScript:
                target = "cscript";
                break;
            default:
                throw new ArgumentOutOfRangeException();
            }
            opts.Add(Constants.SetupTarget, new JST.StringLiteral(target));
            var loadPaths = env.LoadPaths.Select<string, JST.Expression>(FixupPath).ToSeq();
            if (loadPaths.Count == 0)
                loadPaths.Add(new JST.StringLiteral(""));
            opts.Add(Constants.SetupSearchPaths, new JST.ArrayLiteral(loadPaths));

            if (env.DebugMode)
                body.Add(new JST.CommentStatement("Setup runtime"));
            var rootId = new JST.Identifier(env.Root);
            body.Add(JST.Statement.Var(rootId, new JST.ObjectLiteral()));
            body.Add(JST.Statement.Call(Constants.NewRuntime.ToE(), rootId.ToE(), new JST.ObjectLiteral(opts)));

            var program = new JST.Program(new JST.Statements(body));
            var runtimeFileName = Path.Combine(env.OutputDirectory, Constants.RuntimeFileName);
            program.ToFile(runtimeFileName, env.PrettyPrint);
            env.Log(new GeneratedJavaScriptFile("runtime", runtimeFileName));
        }
        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;
        }
Example #15
0
 public static ISeq<BBLoop> Loops(BasicBlock root)
 {
     var res = new Seq<BBLoop>();
     var backEdges = BackEdges(root);
     foreach (var backEdge in backEdges)
     {
         var body = new Set<BasicBlock> { backEdge.Target };
         ReachableFrom(backEdge.Source, body);
         res.Add(new BBLoop(backEdge.Target, backEdge.Source, body, null));
     }
     return res;
 }
Example #16
0
 private void PushOpenPunctuator(InputElement openElem)
 {
     openPunctuators.Add(openElem);
 }
Example #17
0
 private Location VariableDeclarations(Seq<VariableDeclaration> variables)
 {
     // Current is 'var'
     var loc = Current.Loc;
     Consume();
     while (true)
     {
         var vd = VariableDeclaration(false);
         variables.Add(vd);
         loc = loc.Union(vd.Loc);
         if (Current.Tag == InputElementTag.Comma)
             Consume();
         else
             break;
     }
     OptSemicolon("variable declarations");
     return loc;
 }
Example #18
0
        public ImportMethodInfo ImportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn)
        {
            if (!IsImported(ctxt, methodDefn))
                return null;

            if (gensym != null)
                CheckParameterAndReturnTypesAreImportableExportable(ctxt, methodDefn);

            var methodArity = Arity(methodDefn);
            var script = interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheScriptProperty);

            if (methodDefn is CCI.InstanceInitializer)
            {
                // XREF1171
                // Constructor
                if (script == null)
                {
                    switch (
                        interopTypes.GetValue
                            (ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheCreationProperty))
                    {
                        case Creation.Constructor:
                            script = PrefixName(ctxt, methodDefn, null, false);
                            break;
                        case Creation.Object:
                            if (methodArity > 0)
                            {
                                env.Log(new InvalidInteropMessage
                                    (RewriterMsgContext.Method(ctxt, methodDefn),
                                     "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();
                    }
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, true);
                }
                else if (script is JST.FunctionExpression)
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                else
                {
                    script = PrefixName(ctxt, methodDefn, script, false);
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, true);
                }
            }
            else
            {
                if (methodDefn.DeclaringMember != null)
                {
                    var isOnMethod = interopTypes.HasAttribute(methodDefn, env.ImportAttributeType, false);
                    var localScript = isOnMethod ? interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheScriptProperty, false) : default(JST.Expression);

                    var prop = methodDefn.DeclaringMember as CCI.Property;
                    if (prop != null)
                    {
                        // XREF1187
                        if (methodDefn == prop.Getter)
                        {
                            // Getter
                            if (isOnMethod)
                            {
                                script = PrefixName
                                    (ctxt,
                                     methodDefn,
                                     GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "get", localScript), false);
                                return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                            }
                            else if (script != null && script is JST.FunctionExpression)
                            {
                                env.Log(new InvalidInteropMessage
                                    (RewriterMsgContext.Method(ctxt, methodDefn),
                                     "property import script cannot be a function"));
                                throw new DefinitionException();
                            }
                            else
                            {
                                var function = default(JST.FunctionExpression);
                                if (gensym != null)
                                {
                                    var parameters = new Seq<JST.Identifier>();
                                    var body = new Seq<JST.Statement>();

                                    for (var i = 0; i < methodArity; i++)
                                        parameters.Add(gensym());
                                    if (script == null && methodArity == 2 && !methodDefn.IsStatic)
                                        body.Add
                                            (new JST.ReturnStatement
                                                 (new JST.IndexExpression
                                                      (parameters[0].ToE(), parameters[1].ToE())));
                                    else
                                    {
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic && methodArity == 0)
                                            body.Add(new JST.ReturnStatement(script));
                                        else if (!methodDefn.IsStatic && methodArity == 1)
                                            body.Add
                                                (new JST.ReturnStatement
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script))));
                                        else
                                        {
                                            env.Log(new InvalidInteropMessage
                                                (RewriterMsgContext.Method(ctxt, methodDefn),
                                                 "additional getter parameters not supported for default getters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                    function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                }
                                return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                            }
                        }
                        else if (methodDefn == prop.Setter)
                        {
                            // Setter
                            if (isOnMethod)
                            {
                                script = PrefixName
                                    (ctxt,
                                     methodDefn,
                                     GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "set", localScript), false);
                                return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                            }
                            else if (script != null && script is JST.FunctionExpression)
                            {
                                env.Log(new InvalidInteropMessage
                                    (RewriterMsgContext.Method(ctxt, methodDefn),
                                     "property import script cannot be a function"));
                                throw new DefinitionException();
                            }
                            else
                            {
                                var function = default(JST.FunctionExpression);
                                if (gensym != null)
                                {
                                    var parameters = new Seq<JST.Identifier>();
                                    var body = new Seq<JST.Statement>();

                                    for (var i = 0; i < methodArity; i++)
                                        parameters.Add(gensym());
                                    if (script == null && methodArity == 3 && !methodDefn.IsStatic)
                                        body.Add
                                            (JST.Statement.IndexAssignment
                                                 (parameters[0].ToE(),
                                                  parameters[1].ToE(),
                                                  parameters[2].ToE()));
                                    else
                                    {
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic && methodArity == 1)
                                            body.Add
                                                (JST.Statement.Assignment(script, parameters[0].ToE()));
                                        else if (!methodDefn.IsStatic && methodArity == 2)
                                            body.Add
                                                (JST.Statement.Assignment
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script)),
                                                      parameters[1].ToE()));
                                        else
                                        {
                                            env.Log(new InvalidInteropMessage
                                                (RewriterMsgContext.Method(ctxt, methodDefn),
                                                 "additional setter parameters not supported for default setters"));
                                            throw new DefinitionException();
                                        }
                                    }
                                    function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                }
                                return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                            }
                        }
                        else
                            throw new InvalidOperationException();
                    }
                    else
                    {
                        var evnt = methodDefn.DeclaringMember as CCI.Event;
                        if (evnt != null)
                        {
                            // XREF1201
                            if (methodDefn == evnt.HandlerAdder)
                            {
                                // Adder
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (ctxt,
                                         methodDefn,
                                         GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "add", localScript), false);
                                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log(new InvalidInteropMessage
                                        (RewriterMsgContext.Method(ctxt, methodDefn),
                                         "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    var function = default(JST.FunctionExpression);
                                    if (gensym != null)
                                    {
                                        var parameters = new Seq<JST.Identifier>();
                                        var body = new Seq<JST.Statement>();

                                        for (var i = 0; i < methodArity; i++)
                                            parameters.Add(gensym());
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic)
                                            body.Add
                                                (JST.Statement.Assignment(script, parameters[0].ToE()));
                                        else
                                            body.Add
                                                (JST.Statement.Assignment
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script)),
                                                      parameters[1].ToE()));
                                        function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                    }
                                    return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                                }
                            }
                            else if (methodDefn == evnt.HandlerRemover)
                            {
                                // Remover
                                if (isOnMethod)
                                {
                                    script = PrefixName
                                        (ctxt,
                                         methodDefn,
                                         GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "remove", localScript), false);
                                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                                }
                                else if (script != null && script is JST.FunctionExpression)
                                {
                                    env.Log(new InvalidInteropMessage
                                        (RewriterMsgContext.Method(ctxt, methodDefn),
                                         "event import script cannot be a function"));
                                    throw new DefinitionException();
                                }
                                else
                                {
                                    var function = default(JST.FunctionExpression);
                                    if (gensym != null)
                                    {
                                        var parameters = new Seq<JST.Identifier>();
                                        var body = new Seq<JST.Statement>();

                                        for (var i = 0; i < methodArity; i++)
                                            parameters.Add(gensym());
                                        script = PrefixName
                                            (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false);
                                        if (methodDefn.IsStatic)
                                            body.Add
                                                (JST.Statement.Assignment(script, parameters[0].ToE()));
                                        else
                                            body.Add
                                                (JST.Statement.Assignment
                                                     (JST.Expression.Dot
                                                          (parameters[0].ToE(),
                                                           JST.Expression.ExplodePath(script)),
                                                      parameters[1].ToE()));

                                        function = new JST.FunctionExpression(parameters, new JST.Statements(body));
                                    }
                                    return new ImportMethodInfo { MethodDefn = methodDefn, Script = function };
                                }
                            }
                            else
                                throw new InvalidOperationException();
                        }
                        else
                            throw new InvalidOperationException();
                    }
                }
                else
                {
                    // XREF1153
                    // Normal method
                    script = PrefixName(ctxt, methodDefn, RecaseMember(ctxt, methodDefn, script), false);
                    return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false);
                }
            }
        }
Example #19
0
        internal void TopologicalAllDeps(Global global, AssemblyDef assemblyDef, TypeDef typeDef, Set<QualifiedMemberName> visitedMemberDefs, Seq<QualifiedMemberName> sortedMemberDefs)
        {
            var self = QualifiedMemberName(global, assemblyDef, typeDef);
            if (visitedMemberDefs.Contains(self))
                return;
            visitedMemberDefs.Add(self);

            if (usedTypes == null)
                return;

            foreach (var r in usedTypes)
            {
                var usedAssemblyDef = default(AssemblyDef);
                var usedTypeDef = default(TypeDef);
                if (r.PrimTryResolve(global, out usedAssemblyDef, out usedTypeDef))
                    usedTypeDef.UsedBy(self);
            }

            foreach (var r in usedMembers)
            {
                var usedAssemblyDef = default(AssemblyDef);
                var usedTypeDef = default(TypeDef);
                var usedMemberDef = default(MemberDef);
                if (r.PrimTryResolve(global, out usedAssemblyDef, out usedTypeDef, out usedMemberDef))
                {
                    usedMemberDef.UsedBy(self);
                    usedMemberDef.TopologicalAllDeps
                        (global, usedAssemblyDef, usedTypeDef, visitedMemberDefs, sortedMemberDefs);
                }
            }

            sortedMemberDefs.Add(self);
        }
Example #20
0
        // Take account of:
        //  - BindToPrototype
        //  - PassRootAsArgument
        //  - PassInstanceAsArgument
        //  - InlineParamsArray
        private ExportMethodInfo FinalExportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn, JST.Expression script)
        {
            if (script == null)
                throw new InvalidOperationException("expecting default script value");

            var isInstance = !methodDefn.IsStatic && !(methodDefn is CCI.InstanceInitializer);
            if (isInstance)
            {
                var declType = methodDefn.DeclaringType;
                if (declType.IsValueType)
                {
                    env.Log(new InvalidInteropMessage
                        (RewriterMsgContext.Method(ctxt, methodDefn), "cannot export instance methods from value types"));
                    throw new DefinitionException();
                }
            }

            var lastArgIsParamsArray = LastArgIsParamsArray(ctxt, methodDefn) &&
                                       interopTypes.GetValue
                                           (ctxt,
                                            methodDefn,
                                            env.ExportAttributeType,
                                            interopTypes.TheInlineParamsArrayProperty);
            var isPassRoot = interopTypes.GetValue
                (ctxt, methodDefn, env.ExportAttributeType, interopTypes.ThePassRootAsArgumentProperty);
            var isProto = interopTypes.GetValue
                (ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheBindToPrototypeProperty);
            var isPassInstance = interopTypes.GetValue
                (ctxt, methodDefn, env.ExportAttributeType, interopTypes.ThePassInstanceAsArgumentProperty);
            var bindToInstance = isInstance && !isProto;
            var captureThis = isInstance && !isPassInstance;

            var expectedScriptArity = (isPassRoot ? 1 : 0) + (bindToInstance ? 1 : 0) + 1;
            CheckScriptArity(ctxt, methodDefn, script, expectedScriptArity);

            var function = default(JST.FunctionExpression);

            if (gensym != null)
            {
                var parameters = new Seq<JST.Identifier>();
                var body = new Seq<JST.Statement>();

                var callArgs = new Seq<JST.Expression>();
                if (isPassRoot)
                    callArgs.Add(rootId.ToE());
                var instArgId = default(JST.Identifier);
                if (bindToInstance)
                {
                    instArgId = gensym();
                    parameters.Add(instArgId);
                    callArgs.Add(instArgId.ToE());
                }
                var funcArgId = gensym();
                parameters.Add(funcArgId);

                if (captureThis || lastArgIsParamsArray)
                {
                    var innerParameters = new Seq<JST.Identifier>();
                    var innerBody = new Seq<JST.Statement>();
                    var innerArgs = new Seq<JST.Expression>();
                    var methodArity = Arity(methodDefn);
                    for (var i = 0; i < methodArity; i++)
                    {
                        if (i == 0 && captureThis)
                            innerArgs.Add(new JST.ThisExpression());
                        else if (i == methodArity - 1 && lastArgIsParamsArray)
                        {
                            var iId = gensym();
                            var arrId = gensym();
                            innerBody.Add(JST.Statement.Var(arrId, new JST.ArrayLiteral()));
                            innerBody.Add
                                (new JST.ForStatement
                                     (new JST.ForVarLoopClause
                                          (iId,
                                           new JST.NumericLiteral(methodArity - 1),
                                           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())))));
                            innerArgs.Add(arrId.ToE());
                        }
                        else
                        {
                            var innerArgId = gensym();
                            innerParameters.Add(innerArgId);
                            innerArgs.Add(innerArgId.ToE());
                        }
                    }
                    if (ReturnType(methodDefn) == null)
                    {
                        innerBody.Add(JST.Statement.Call(funcArgId.ToE(), innerArgs));
                        innerBody.Add(new JST.ReturnStatement());
                    }
                    else
                        innerBody.Add(new JST.ReturnStatement(new JST.CallExpression(funcArgId.ToE(), innerArgs)));
                    var innerFunction = new JST.FunctionExpression(innerParameters, new JST.Statements(innerBody));
                    callArgs.Add(innerFunction);
                }
                else
                    callArgs.Add(funcArgId.ToE());

                if (script is JST.FunctionExpression)
                    body.Add(new JST.ExpressionStatement(new JST.CallExpression(script, callArgs)));
                else
                {
                    var i = 0;
                    if (bindToInstance)
                        script = JST.Expression.Dot(callArgs[i++], JST.Expression.ExplodePath(script));
                    EnsurePathExists(body, script, !bindToInstance);
                    body.Add(JST.Statement.Assignment(script, callArgs[i]));
                }

                function = new JST.FunctionExpression(parameters, new JST.Statements(body));
            }

            return new ExportMethodInfo { MethodDefn = methodDefn, Script = function, BindToInstance = bindToInstance };
        }
Example #21
0
 public MethodRef SelfMethodReference(TypeConstructorEnvironment tyconEnv)
 {
     var typeRef = tyconEnv.Type.SelfReference(tyconEnv);
     var methodBoundArguments = default(Seq<TypeRef>);
     if (TypeArity > 0)
     {
         methodBoundArguments = new Seq<TypeRef>(Arity);
         for (var i = 0; i < Arity; i++)
             methodBoundArguments.Add(new ParameterTypeRef(ParameterFlavor.Method, i));
     }
     return PrimMethodReference(tyconEnv.Global, tyconEnv.Assembly, tyconEnv.Type, typeRef.Arguments, methodBoundArguments);
 }
Example #22
0
        public void Load(IImSeq<string> fileNames, out CCI.AssemblyNode mscorlib, out CCI.AssemblyNode jsTypes)
        {
            foreach (var fileName in fileNames)
            {
                var canonicalFileName = CanonicalFileName(fileName);
                if (fileNameToAssembly.ContainsKey(canonicalFileName))
                {
                    env.Log(new DuplicateAssemblyFileNameMessage(fileName, canonicalFileName));
                    throw new ExitException();
                }
                else
                    fileNameToAssembly.Add(canonicalFileName, null);
            }

            // ----------------------------------------
            // Which assembly should we use for mscorlib and JSTypes?
            // ----------------------------------------
            var mscorlibCanonicalName = default(string);
            var jsTypesCanonicalName = default(string);
            foreach (var kv in fileNameToAssembly)
            {
                var baseName = Path.GetFileNameWithoutExtension(kv.Key);
                if (baseName.ToLower().Contains(Constants.MsCorLibSimpleName.ToLower()))
                {
                    if (mscorlibCanonicalName != null)
                    {
                        env.Log(new DuplicateSpecialAssemblyMessage(Constants.MsCorLibSimpleName, mscorlibCanonicalName, kv.Key));
                        throw new ExitException();
                    }
                    mscorlibCanonicalName = kv.Key;
                }
                else if (baseName.ToLower().Contains(Constants.JSTypesSimpleName.ToLower()))
                {
                    if (jsTypesCanonicalName != null)
                    {
                        env.Log(new DuplicateSpecialAssemblyMessage(Constants.JSTypesSimpleName, jsTypesCanonicalName, kv.Key));
                        throw new ExitException();
                    }
                    jsTypesCanonicalName = kv.Key;
                }
            }
            if (mscorlibCanonicalName == null)
            {
                env.Log(new MissingSpecialAssemblyMessage(Constants.MsCorLibSimpleName));
                throw new ExitException();
            }
            if (jsTypesCanonicalName == null)
            {
                env.Log(new MissingSpecialAssemblyMessage(Constants.JSTypesSimpleName));
                throw new ExitException();
            }

            // ----------------------------------------
            // Initialize CCI, which will implicitly load mscorlib
            // ----------------------------------------
            var frameworkDir = Path.GetDirectoryName(mscorlibCanonicalName);
            if (!Directory.Exists(frameworkDir))
            {
                env.Log(new UnloadableAssemblyMessage(frameworkDir, "directory does not exist"));
                throw new ExitException();
            }

            // These special CCI assemblies, and mscorlib, will be picked up from the framework directory
            CCI.SystemDataAssemblyLocation.Location = null;
            CCI.SystemXmlAssemblyLocation.Location = null;

            CCI.TargetPlatform.SetToV2(frameworkDir);

            // At this point we could "fixup" CCI's hard-wired system assembly references:
            //
            //     foreach (var asmRefs in CCI.TargetPlatform.AssemblyReferenceFor.GetEnumerator())
            //     {
            //         var asmRef = (CCI.AssemblyReference)asmRefs.Value;
            //         asmRef.Location = <the right place>;
            //     }
            //     SystemAssemblyLocation.Location = <the right place>;
            //     SystemXmlAssemblyLocation.Location = <the right place>;
            // 
            // But so far that doesn't seem necessary

            CCI.SystemTypes.Initialize(false, true, ResolveReference);

            // ----------------------------------------
            // Account for mscorlib being loaded
            // ----------------------------------------
            mscorlib = CCI.SystemTypes.SystemAssembly;
            if (mscorlib == null || mscorlib.Directory == null)
            {
                env.Log(new UnloadableAssemblyMessage(frameworkDir, "cannot load mscorlib"));
                throw new ExitException();
            }

            env.Log(new FoundSpecialAssemblyMessage(Constants.MsCorLibSimpleName, mscorlib.StrongName));

            fileNameToAssembly[mscorlibCanonicalName] = mscorlib;
            strongNameToInfo.Add
                (mscorlib.StrongName, new Info { Assembly = mscorlib, FileName = mscorlibCanonicalName });

            // ----------------------------------------
            // Load the remaining registered assemblies
            // ----------------------------------------
            var pending = new Seq<string>();
            foreach (var kv in fileNameToAssembly)
            {
                if (kv.Value == null)
                    pending.Add(kv.Key);
                // else: must have been mscorlib, which we loaded above
            }
            jsTypes = null;
            foreach (var canonicalFileName in pending)
            {
                var assembly = CCI.AssemblyNode.GetAssembly(canonicalFileName, null, false, true, true);
                if (assembly == null)
                {
                    env.Log(new UnloadableAssemblyMessage(canonicalFileName, "CCI cannot load assembly"));
                    throw new ExitException();
                }
                var info = default(Info);
                if (strongNameToInfo.TryGetValue(assembly.StrongName, out info))
                {
                    env.Log(new DuplicateAssemblyStrongNameMessage(canonicalFileName, assembly.StrongName, info.FileName));
                    throw new ExitException();
                }
                fileNameToAssembly[canonicalFileName] = assembly;
                strongNameToInfo.Add(assembly.StrongName, new Info { Assembly = assembly, FileName = canonicalFileName });
                assembly.AssemblyReferenceResolution += ResolveReference;

                if (canonicalFileName.Equals(jsTypesCanonicalName))
                {
                    jsTypes = assembly;
                    env.Log(new FoundSpecialAssemblyMessage(Constants.JSTypesSimpleName, jsTypes.StrongName));
                }
            }

#if false
            // ----------------------------------------
            // Check all references resolve to known definitions
            // ----------------------------------------
            foreach (var kv in strongNameToInfo)
            {
                new CCI.StandardVisitor().Visit(kv.Value.Assembly);
                foreach (var reference in kv.Value.Assembly.AssemblyReferences)
                {
                    if (reference.Assembly == null ||
                        !reference.Assembly.StrongName.Equals(reference.StrongName, StringComparison.OrdinalIgnoreCase) ||
                        reference.Assembly.Location.Equals("unknown:location", StringComparison.OrdinalIgnoreCase))
                    {
                        env.Log(new UnresolvableReferenceMessage(kv.Key, kv.Value.FileName, reference.StrongName));
                        throw new ExitException();
                    }
                }
                foreach (var typeDefn in kv.Value.Assembly.Types)
                    CheckTypeDefn(kv.Value.Assembly, typeDefn);

                env.Log(new LoadedAssemblyMessage(kv.Key, kv.Value.FileName));
            }
#endif

            if (loadFailed)
                throw new ExitException();
        }
Example #23
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));
            }
        }
Example #24
0
 // Return all the exception clauses which:
 //  - Start at given instruction index
 //  - Are not in the current context
 //  - Finish at the same instruction index
 // However:
 //  - Only attempt to group catch clauses
 // Return null if no new exception clauses start at given instruction
 public ISeq<PE.ExceptionHandlingClause> OutermostTryBlocks(int i)
 {
     var offset = Instructions[i].Offset;
     if (TryOffsets.Contains(offset))
     {
         // Clauses are in inner-to-outer order, look for the outermost
         var last = -1;
         for (var j = Handlers.Count - 1; j >= 0; j--)
         {
             var ehc = Handlers[j];
             if (offset == ehc.TryOffset && !Within(ehc))
             {
                 last = j;
                 break;
             }
         }
         if (last >= 0)
         {
             var res = new Seq<PE.ExceptionHandlingClause>();
             var first = last - 1;
             while (first >= 0 && Handlers[first].TryOffset == Handlers[last].TryOffset &&
                    Handlers[first].TryLength == Handlers[last].TryLength &&
                    Handlers[first].Flags == PE.CorILExceptionClause.Exception &&
                    Handlers[last].Flags == PE.CorILExceptionClause.Exception)
                 first--;
             first++;
             for (var j = first; j <= last; j++)
                 res.Add(Handlers[j]);
             return res;
         }
         else
             return null;
     }
     else
         return null;
 }
Example #25
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;
        }
Example #26
0
        private Instructions InstructionsFromContext(TranslationContext ctxt)
        {
            var instructions = new Seq<Instruction>();
            var i = ctxt.Start;
            while (!ctxt.AtEnd(i))
            {
                var j = i > ctxt.Start ? ctxt.JumpOverHandlers(i) : i;
                if (j > i)
                    i = j;
                else
                {
                    var ehcs = ctxt.OutermostTryBlocks(i);
                    if (ehcs != null)
                    {
                        // A try instruction begins here with given handlers
                        var offset = ctxt.Instructions[i].Offset;
                        var tryCtxt = new TryTranslationContext(ctxt, i, ehcs);
                        var tryBlock = InstructionsFromContext(tryCtxt);

                        var handlers = new Seq<TryInstructionHandler>();
                        foreach (var ehc in ehcs)
                        {
                            var handlerCtxt = new HandlerTranslationContext
                                (tryCtxt, ctxt.OffsetToIndex[ehc.HandlerOffset], ehc);
                            var handlerBlock = InstructionsFromContext(handlerCtxt);
                            switch (ehc.Flags)
                            {
                            case PE.CorILExceptionClause.Exception:
                                handlers.Add(new CatchTryInstructionHandler((TypeRef)ehc.Class, handlerBlock));
                                break;
                            case PE.CorILExceptionClause.Filter:
                                {
                                    var filterCtxt = new FilterTranslationContext
                                        (tryCtxt, ctxt.OffsetToIndex[ehc.FilterOffset], ehc);
                                    var filterBlock = InstructionsFromContext(filterCtxt);
                                    handlers.Add(new FilterTryInstructionHandler(filterBlock, handlerBlock));
                                    break;
                                }
                            case PE.CorILExceptionClause.Finally:
                                handlers.Add(new FinallyTryInstructionHandler(handlerBlock));
                                break;
                            case PE.CorILExceptionClause.Fault:
                                handlers.Add(new FaultTryInstructionHandler(handlerBlock));
                                break;
                            default:
                                throw new ArgumentOutOfRangeException();
                            }
                        }
                        instructions.Add(new TryInstruction(offset, tryBlock, handlers));

                        // Jump over try block
                        var nextOffset = ehcs[0].TryOffset + ehcs[0].TryLength;
                        if (!ctxt.OffsetToIndex.TryGetValue(nextOffset, out i))
                            i = ctxt.Instructions.Length;
                    }
                    else
                    {
                        var instruction = ctxt.Instructions[i++];
                        var offset = instruction.Offset;

                        while (instruction.OpCode == PE.OpCode.Unaligned || instruction.OpCode == PE.OpCode.Volatile ||
                               instruction.OpCode == PE.OpCode.Tailcall)
                        {
                            // Skip over any ignored prefixes, but remember instruction begins at original offset
                            // NOTE: What ever happened to the "no." prefix mentioned in the spec?
                            if (i >= ctxt.Instructions.Length)
                                throw new InvalidOperationException("invalid instructions");
                            instruction = ctxt.Instructions[i++];
                        }
                        switch (instruction.OpCode)
                        {
                        case PE.OpCode.Cpblk:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Cpblk));
                            break;
                        case PE.OpCode.Initblk:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Initblk));
                            break;
                        case PE.OpCode.Arglist:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Arglist));
                            break;
                        case PE.OpCode.Localloc:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Localloc));
                            break;
                        case PE.OpCode.Jmp:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Jmp));
                            break;
                        case PE.OpCode.Calli:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Calli));
                            break;
                        case PE.OpCode.Sizeof:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Sizeof));
                            break;
                        case PE.OpCode.Mkrefany:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Mkrefany));
                            break;
                        case PE.OpCode.Refanytype:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Refanytype));
                            break;
                        case PE.OpCode.Refanyval:
                            instructions.Add(new UnsupportedInstruction(offset, UnsupportedOp.Refanyval));
                            break;
                        case PE.OpCode.Nop:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Nop));
                            break;
                        case PE.OpCode.Break:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Break));
                            break;
                        case PE.OpCode.Dup:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Dup));
                            break;
                        case PE.OpCode.Pop:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Pop));
                            break;
                        case PE.OpCode.Ldnull:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Ldnull));
                            break;
                        case PE.OpCode.Ckfinite:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Ckfinite));
                            break;
                        case PE.OpCode.Throw:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Throw));
                            break;
                        case PE.OpCode.Rethrow:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Rethrow));
                            break;
                        case PE.OpCode.Ldind_ref:
                            instructions.Add(new MiscInstruction(offset, MiscOp.LdindRef));
                            break;
                        case PE.OpCode.Stind_ref:
                            instructions.Add(new MiscInstruction(offset, MiscOp.StindRef));
                            break;
                        case PE.OpCode.Ldelem_ref:
                            instructions.Add(new MiscInstruction(offset, MiscOp.LdelemRef));
                            break;
                        case PE.OpCode.Stelem_ref:
                            instructions.Add(new MiscInstruction(offset, MiscOp.StelemRef));
                            break;
                        case PE.OpCode.Ldlen:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Ldlen));
                            break;
                        case PE.OpCode.Ret:
                            if (ctxt.ResultType == null)
                                instructions.Add(new MiscInstruction(offset, MiscOp.Ret));
                            else
                                instructions.Add(new MiscInstruction(offset, MiscOp.RetVal));
                            break;
                        case PE.OpCode.Endfilter:
                            instructions.Add(new MiscInstruction(offset, MiscOp.Endfilter));
                            break;
                        case PE.OpCode.Endfinally: // aka EndFault
                            instructions.Add(new MiscInstruction(offset, MiscOp.Endfinally));
                            break;
                        case PE.OpCode.Br_s:
                        case PE.OpCode.Br:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.Br, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Brtrue_s: // aka brinst.s
                        case PE.OpCode.Brtrue: // aka brinst
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.Brtrue, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Brfalse_s: // aka brzero.s, brnull.s
                        case PE.OpCode.Brfalse: // aka brzero, brnull
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.Brfalse, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Beq:
                        case PE.OpCode.Beq_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.Breq, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Bne_un:
                        case PE.OpCode.Bne_un_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.Brne, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Leave:
                        case PE.OpCode.Leave_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.Leave, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Blt:
                        case PE.OpCode.Blt_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrLt, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Blt_un:
                        case PE.OpCode.Blt_un_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrLt, true, (int)instruction.Value));
                            break;
                        case PE.OpCode.Ble:
                        case PE.OpCode.Ble_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrLe, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Ble_un:
                        case PE.OpCode.Ble_un_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrLe, true, (int)instruction.Value));
                            break;
                        case PE.OpCode.Bgt:
                        case PE.OpCode.Bgt_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrGt, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Bgt_un:
                        case PE.OpCode.Bgt_un_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrGt, true, (int)instruction.Value));
                            break;
                        case PE.OpCode.Bge:
                        case PE.OpCode.Bge_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrGe, false, (int)instruction.Value));
                            break;
                        case PE.OpCode.Bge_un:
                        case PE.OpCode.Bge_un_s:
                            instructions.Add
                                (new BranchInstruction(offset, BranchOp.BrGe, true, (int)instruction.Value));
                            break;
                        case PE.OpCode.Switch:
                            instructions.Add(new SwitchInstruction(offset, (Seq<int>)instruction.Value));
                            break;
                        case PE.OpCode.Ceq:
                            instructions.Add(new CompareInstruction(offset, CompareOp.Ceq, false));
                            break;
                        case PE.OpCode.Clt:
                            instructions.Add(new CompareInstruction(offset, CompareOp.Clt, false));
                            break;
                        case PE.OpCode.Clt_un:
                            instructions.Add(new CompareInstruction(offset, CompareOp.Clt, true));
                            break;
                        case PE.OpCode.Cgt:
                            instructions.Add(new CompareInstruction(offset, CompareOp.Cgt, false));
                            break;
                        case PE.OpCode.Cgt_un:
                            instructions.Add(new CompareInstruction(offset, CompareOp.Cgt, true));
                            break;
                        case PE.OpCode.Ldarg_0:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 0));
                            break;
                        case PE.OpCode.Ldarg_1:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 1));
                            break;
                        case PE.OpCode.Ldarg_2:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 2));
                            break;
                        case PE.OpCode.Ldarg_3:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, 3));
                            break;
                        case PE.OpCode.Ldarg:
                        case PE.OpCode.Ldarg_s:
                            instructions.Add
                                (new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Arg, (int)instruction.Value));
                            break;
                        case PE.OpCode.Ldarga:
                        case PE.OpCode.Ldarga_s:
                            instructions.Add
                                (new ArgLocalInstruction(offset, ArgLocalOp.Lda, ArgLocal.Arg, (int)instruction.Value));
                            break;
                        case PE.OpCode.Starg:
                        case PE.OpCode.Starg_s:
                            instructions.Add
                                (new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Arg, (int)instruction.Value));
                            break;
                        case PE.OpCode.Ldloc_0:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 0));
                            break;
                        case PE.OpCode.Ldloc_1:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 1));
                            break;
                        case PE.OpCode.Ldloc_2:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 2));
                            break;
                        case PE.OpCode.Ldloc_3:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.Ld, ArgLocal.Local, 3));
                            break;
                        case PE.OpCode.Ldloc:
                        case PE.OpCode.Ldloc_s:
                            instructions.Add
                                (new ArgLocalInstruction
                                     (offset, ArgLocalOp.Ld, ArgLocal.Local, (int)instruction.Value));
                            break;
                        case PE.OpCode.Ldloca:
                        case PE.OpCode.Ldloca_s:
                            instructions.Add
                                (new ArgLocalInstruction
                                     (offset, ArgLocalOp.Lda, ArgLocal.Local, (int)instruction.Value));
                            break;
                        case PE.OpCode.Stloc_0:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 0));
                            break;
                        case PE.OpCode.Stloc_1:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 1));
                            break;
                        case PE.OpCode.Stloc_2:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 2));
                            break;
                        case PE.OpCode.Stloc_3:
                            instructions.Add(new ArgLocalInstruction(offset, ArgLocalOp.St, ArgLocal.Local, 3));
                            break;
                        case PE.OpCode.Stloc:
                        case PE.OpCode.Stloc_s:
                            instructions.Add
                                (new ArgLocalInstruction
                                     (offset, ArgLocalOp.St, ArgLocal.Local, (int)instruction.Value));
                            break;
                        case PE.OpCode.Ldfld:
                            instructions.Add
                                (new FieldInstruction(offset, FieldOp.Ldfld, (FieldRef)instruction.Value, false));
                            break;
                        case PE.OpCode.Ldsfld:
                            instructions.Add
                                (new FieldInstruction(offset, FieldOp.Ldfld, (FieldRef)instruction.Value, true));
                            break;
                        case PE.OpCode.Ldflda:
                            instructions.Add
                                (new FieldInstruction(offset, FieldOp.Ldflda, (FieldRef)instruction.Value, false));
                            break;
                        case PE.OpCode.Ldsflda:
                            instructions.Add
                                (new FieldInstruction(offset, FieldOp.Ldflda, (FieldRef)instruction.Value, true));
                            break;
                        case PE.OpCode.Stfld:
                            instructions.Add
                                (new FieldInstruction(offset, FieldOp.Stfld, (FieldRef)instruction.Value, false));
                            break;
                        case PE.OpCode.Stsfld:
                            instructions.Add
                                (new FieldInstruction(offset, FieldOp.Stfld, (FieldRef)instruction.Value, true));
                            break;
                        case PE.OpCode.Ldtoken:
                            {
                                if (instruction.Value is FieldRef)
                                    instructions.Add
                                        (new FieldInstruction
                                             (offset, FieldOp.Ldtoken, (FieldRef)instruction.Value, default(bool)));
                                else if (instruction.Value is MethodRef)
                                    instructions.Add
                                        (new MethodInstruction
                                             (offset, MethodOp.Ldtoken, null, false, (MethodRef)instruction.Value));
                                else if (instruction.Value is TypeRef)
                                    // NOTE: May be a higher-kinded type
                                    instructions.Add
                                        (new TypeInstruction(offset, TypeOp.Ldtoken, (TypeRef)instruction.Value));
                                else
                                    throw new InvalidOperationException("unexpected ldtoken instruction value");
                                break;
                            }
                        case PE.OpCode.Constrained:
                            {
                                var constrained = (TypeRef)instruction.Value;
                                if (i >= ctxt.Instructions.Length)
                                    throw new InvalidOperationException("invalid instructions");
                                instruction = ctxt.Instructions[i++];
                                if (instruction.OpCode != PE.OpCode.Callvirt)
                                    throw new InvalidOperationException("invalid instruction");
                                instructions.Add
                                    (new MethodInstruction
                                         (offset, MethodOp.Call, constrained, true, (MethodRef)instruction.Value));
                                break;
                            }
                        case PE.OpCode.Call:
                            instructions.Add
                                (new MethodInstruction
                                     (offset, MethodOp.Call, null, false, (MethodRef)instruction.Value));
                            break;
                        case PE.OpCode.Callvirt:
                            instructions.Add
                                (new MethodInstruction
                                     (offset, MethodOp.Call, null, true, (MethodRef)instruction.Value));
                            break;
                        case PE.OpCode.Ldftn:
                            instructions.Add
                                (new MethodInstruction
                                     (offset, MethodOp.Ldftn, null, false, (MethodRef)instruction.Value));
                            break;
                        case PE.OpCode.Ldvirtftn:
                            instructions.Add
                                (new MethodInstruction
                                     (offset, MethodOp.Ldftn, null, true, (MethodRef)instruction.Value));
                            break;
                        case PE.OpCode.Newobj:
                            instructions.Add
                                (new MethodInstruction
                                     (offset, MethodOp.Newobj, null, false, (MethodRef)instruction.Value));
                            break;
                        case PE.OpCode.Ldind_i1:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int8Ref));
                            break;
                        case PE.OpCode.Ldind_u1:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.UInt8Ref));
                            break;
                        case PE.OpCode.Ldind_i2:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int16Ref));
                            break;
                        case PE.OpCode.Ldind_u2:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.UInt16Ref));
                            break;
                        case PE.OpCode.Ldind_i4:
                        case PE.OpCode.Ldind_u4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int32Ref));
                            break;
                        case PE.OpCode.Ldind_i8:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.Int64Ref));
                            break;
                        case PE.OpCode.Ldind_i:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.IntNativeRef));
                            break;
                        case PE.OpCode.Ldind_r4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.SingleRef));
                            break;
                        case PE.OpCode.Ldind_r8:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, global.DoubleRef));
                            break;
                        case PE.OpCode.Ldobj:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldobj, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Stind_i1:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int8Ref));
                            break;
                        case PE.OpCode.Stind_i2:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int16Ref));
                            break;
                        case PE.OpCode.Stind_i4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int32Ref));
                            break;
                        case PE.OpCode.Stind_i8:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.Int64Ref));
                            break;
                        case PE.OpCode.Stind_i:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.IntNativeRef));
                            break;
                        case PE.OpCode.Stind_r4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.SingleRef));
                            break;
                        case PE.OpCode.Stind_r8:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, global.DoubleRef));
                            break;
                        case PE.OpCode.Stobj:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stobj, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Cpobj:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Cpobj, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Newarr:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Newarr, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Initobj:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Initobj, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Castclass:
                            instructions.Add
                                (new TypeInstruction(offset, TypeOp.Castclass, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Isinst:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Isinst, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Box:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Box, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Unbox:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Unbox, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Unbox_any:
                            instructions.Add(new TypeInstruction(offset, TypeOp.UnboxAny, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Ldelem_i1:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int8Ref));
                            break;
                        case PE.OpCode.Ldelem_u1:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.UInt8Ref));
                            break;
                        case PE.OpCode.Ldelem_i2:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int16Ref));
                            break;
                        case PE.OpCode.Ldelem_u2:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.UInt16Ref));
                            break;
                        case PE.OpCode.Ldelem_i4:
                        case PE.OpCode.Ldelem_u4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int32Ref));
                            break;
                        case PE.OpCode.Ldelem_i:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.IntNativeRef));
                            break;
                        case PE.OpCode.Ldelem_i8: // aka ldelem.u8
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.Int64Ref));
                            break;
                        case PE.OpCode.Ldelem_r4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.SingleRef));
                            break;
                        case PE.OpCode.Ldelem_r8:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, global.DoubleRef));
                            break;
                        case PE.OpCode.Ldelem: // aka ldelem.any
                            instructions.Add(new TypeInstruction(offset, TypeOp.Ldelem, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Stelem_i1:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int8Ref));
                            break;
                        case PE.OpCode.Stelem_i2:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int16Ref));
                            break;
                        case PE.OpCode.Stelem_i4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int32Ref));
                            break;
                        case PE.OpCode.Stelem_i8:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.Int64Ref));
                            break;
                        case PE.OpCode.Stelem_i:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.IntNativeRef));
                            break;
                        case PE.OpCode.Stelem_r4:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.SingleRef));
                            break;
                        case PE.OpCode.Stelem_r8:
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, global.DoubleRef));
                            break;
                        case PE.OpCode.Stelem: // aka stelem.any
                            instructions.Add(new TypeInstruction(offset, TypeOp.Stelem, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Readonly:
                            if (i >= ctxt.Instructions.Length)
                                throw new InvalidOperationException("invalid instruction");
                            instruction = ctxt.Instructions[i++];
                            if (instruction.OpCode != PE.OpCode.Ldelema)
                                throw new InvalidOperationException("invalid instruction");
                            instructions.Add(new LdElemAddrInstruction(offset, true, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Ldelema:
                            instructions.Add(new LdElemAddrInstruction(offset, false, (TypeRef)instruction.Value));
                            break;
                        case PE.OpCode.Ldc_i4_0:
                            instructions.Add(new LdInt32Instruction(offset, 0));
                            break;
                        case PE.OpCode.Ldc_i4_1:
                            instructions.Add(new LdInt32Instruction(offset, 1));
                            break;
                        case PE.OpCode.Ldc_i4_2:
                            instructions.Add(new LdInt32Instruction(offset, 2));
                            break;
                        case PE.OpCode.Ldc_i4_3:
                            instructions.Add(new LdInt32Instruction(offset, 3));
                            break;
                        case PE.OpCode.Ldc_i4_4:
                            instructions.Add(new LdInt32Instruction(offset, 4));
                            break;
                        case PE.OpCode.Ldc_i4_5:
                            instructions.Add(new LdInt32Instruction(offset, 5));
                            break;
                        case PE.OpCode.Ldc_i4_6:
                            instructions.Add(new LdInt32Instruction(offset, 6));
                            break;
                        case PE.OpCode.Ldc_i4_7:
                            instructions.Add(new LdInt32Instruction(offset, 7));
                            break;
                        case PE.OpCode.Ldc_i4_8:
                            instructions.Add(new LdInt32Instruction(offset, 8));
                            break;
                        case PE.OpCode.Ldc_i4_m1:
                            instructions.Add(new LdInt32Instruction(offset, -1));
                            break;
                        case PE.OpCode.Ldc_i4:
                        case PE.OpCode.Ldc_i4_s:
                            instructions.Add(new LdInt32Instruction(offset, (int)instruction.Value));
                            break;
                        case PE.OpCode.Ldc_i8:
                            instructions.Add(new LdInt64Instruction(offset, (long)instruction.Value));
                            break;
                        case PE.OpCode.Ldc_r4:
                            instructions.Add(new LdSingleInstruction(offset, (float)instruction.Value));
                            break;
                        case PE.OpCode.Ldc_r8:
                            instructions.Add(new LdDoubleInstruction(offset, (double)instruction.Value));
                            break;
                        case PE.OpCode.Ldstr:
                            instructions.Add(new LdStringInstruction(offset, (string)instruction.Value));
                            break;
                        case PE.OpCode.Add:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Add, false, false));
                            break;
                        case PE.OpCode.Add_ovf:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Add, true, false));
                            break;
                        case PE.OpCode.Add_ovf_un:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Add, true, true));
                            break;
                        case PE.OpCode.Sub:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Sub, false, false));
                            break;
                        case PE.OpCode.Sub_ovf:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Sub, true, false));
                            break;
                        case PE.OpCode.Sub_ovf_un:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Sub, true, true));
                            break;
                        case PE.OpCode.Mul:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Mul, false, false));
                            break;
                        case PE.OpCode.Mul_ovf:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Mul, true, false));
                            break;
                        case PE.OpCode.Mul_ovf_un:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Mul, true, true));
                            break;
                        case PE.OpCode.Div:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Div, false, false));
                            break;
                        case PE.OpCode.Div_un:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Div, false, true));
                            break;
                        case PE.OpCode.Rem:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Rem, false, false));
                            break;
                        case PE.OpCode.Rem_un:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Rem, false, true));
                            break;
                        case PE.OpCode.Neg:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Neg, false, false));
                            break;
                        case PE.OpCode.And:
                            instructions.Add(new ArithInstruction(offset, ArithOp.BitAnd, false, false));
                            break;
                        case PE.OpCode.Or:
                            instructions.Add(new ArithInstruction(offset, ArithOp.BitOr, false, false));
                            break;
                        case PE.OpCode.Xor:
                            instructions.Add(new ArithInstruction(offset, ArithOp.BitXor, false, false));
                            break;
                        case PE.OpCode.Not:
                            instructions.Add(new ArithInstruction(offset, ArithOp.BitNot, false, false));
                            break;
                        case PE.OpCode.Shl:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Shl, false, false));
                            break;
                        case PE.OpCode.Shr:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Shr, false, false));
                            break;
                        case PE.OpCode.Shr_un:
                            instructions.Add(new ArithInstruction(offset, ArithOp.Shr, false, true));
                            break;
                        case PE.OpCode.Conv_i1:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int8, false, false));
                            break;
                        case PE.OpCode.Conv_u1:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt8, false, false));
                            break;
                        case PE.OpCode.Conv_i2:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int16, false, false));
                            break;
                        case PE.OpCode.Conv_u2:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt16, false, false));
                            break;
                        case PE.OpCode.Conv_i4:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int32, false, false));
                            break;
                        case PE.OpCode.Conv_u4:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt32, false, false));
                            break;
                        case PE.OpCode.Conv_i8:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int64, false, false));
                            break;
                        case PE.OpCode.Conv_u8:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt64, false, false));
                            break;
                        case PE.OpCode.Conv_i:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.IntNative, false, false));
                            break;
                        case PE.OpCode.Conv_u:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UIntNative, false, false));
                            break;
                        case PE.OpCode.Conv_r4:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Single, false, false));
                            break;
                        case PE.OpCode.Conv_r8:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Double, false, false));
                            break;
                        case PE.OpCode.Conv_r_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Double, false, true));
                            break;
                        case PE.OpCode.Conv_ovf_i1:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int8, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_u1:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt8, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_i2:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int16, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_u2:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt16, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_i4:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int32, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_u4:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt32, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_i8:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int64, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_u8:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt64, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_i:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.IntNative, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_u:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UIntNative, true, false));
                            break;
                        case PE.OpCode.Conv_ovf_i1_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int8, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_u1_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt8, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_i2_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int16, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_u2_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt16, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_i4_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int32, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_u4_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt32, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_i8_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.Int64, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_u8_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UInt64, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_i_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.IntNative, true, true));
                            break;
                        case PE.OpCode.Conv_ovf_u_un:
                            instructions.Add(new ConvInstruction(offset, NumberFlavor.UIntNative, true, true));
                            break;
                        default:
                            throw new InvalidOperationException("invalid instruction");

                        }
                    }
                }
            }

            // Must always contain at least one instruction, otherwise control would have fallen through
            if (instructions.Count == 0)
                throw new InvalidOperationException("empty instructions");

            return new Instructions(null, instructions);
        }
Example #27
0
 private Location Statement(Seq<Statement> statements, bool isTop)
 {
     ConsumeCommentStatement(statements);
     switch (Current.Tag)
     {
     case InputElementTag.LBrace:
         {
             return BlockStatements("block", false, statements);
         }
     case InputElementTag.Var:
         {
             var variableDeclarations = new Seq<VariableDeclaration>();
             var loc = VariableDeclarations(variableDeclarations);
             statements.Add(new VariableStatement(loc, variableDeclarations));
             return loc;
         }
     case InputElementTag.Semicolon:
         {
             var loc = Current.Loc;
             Consume();
             return loc;
         }
     case InputElementTag.If:
         {
             var loc = Current.Loc;
             Consume();
             Only("if statement", "'('", InputElementTag.LParen);
             var condition = Expression(false);
             Only("if statement", "')'", InputElementTag.RParen);
             condition = ConsumeCommentExpression(condition);
             var thenStatements = new Seq<Statement>();
             loc = loc.Union(Statement(thenStatements, false));
             if (Current.Tag == InputElementTag.Else)
             {
                 var elseStatements = new Seq<Statement>();
                 Consume();
                 loc = loc.Union(Statement(elseStatements, false));
                 statements.Add(new IfStatement(loc, condition, new Statements(thenStatements), new Statements(elseStatements)));
             }
             else
                 statements.Add(new IfStatement(loc, condition, new Statements(thenStatements)));
             return loc;
         }
     case InputElementTag.Do:
         {
             var loc = Current.Loc;
             Consume();
             var body = new Seq<Statement>();
             Statement(body, false);
             Only("do statement", "'while'", InputElementTag.While);
             Only("do statement", "'('", InputElementTag.LParen);
             var condition = Expression(false);
             Only("do statement", "')'", InputElementTag.RParen);
             condition = ConsumeCommentExpression(condition);
             OptSemicolon("do statement");
             loc = loc.Union(condition.Loc);
             statements.Add(new DoStatement(loc, new Statements(body), condition));
             return loc;
         }
     case InputElementTag.While:
         {
             var loc = Current.Loc;
             Consume();
             Only("while statement", "'('", InputElementTag.LParen);
             var condition = Expression(false);
             Only("while statement", "')'", InputElementTag.RParen);
             condition = ConsumeCommentExpression(condition);
             var body = new Seq<Statement>();
             loc = loc.Union(Statement(body, false));
             statements.Add(new WhileStatement(loc, condition, new Statements(body)));
             return loc;
         }
     case InputElementTag.For:
         {
             var loc = Current.Loc;
             Consume();
             var loopClause = LoopClause();
             var body = new Seq<Statement>();
             loc = loc.Union(Statement(body, false));
             statements.Add(new ForStatement(loc, loopClause, new Statements(body)));
             return loc;
         }
     case InputElementTag.Continue:
         {
             var loc = Current.Loc;
             Consume();
             // ask for Current to make sure lastLineTerminator is updates
             var isid = Current.Tag == InputElementTag.Identifier;
             var label = default(Identifier);
             if (lastLineTerminator == null)
             {
                 if (isid)
                 {
                     label = new Identifier(Current.Loc, Current.Value);
                     loc = loc.Union(label.Loc);
                     Consume();
                 }
                 OptSemicolon("continue statement");
             }
             statements.Add(new ContinueStatement(loc, label));
             return loc;
         }
     case InputElementTag.Break:
         {
             var loc = Current.Loc;
             Consume();
             // ask for Current to make sure lastLineTerminator is updates
             var isid = Current.Tag == InputElementTag.Identifier;
             var label = default(Identifier);
             if (lastLineTerminator == null)
             {
                 if (isid)
                 {
                     label = new Identifier(Current.Loc, Current.Value);
                     loc = loc.Union(label.Loc);
                     Consume();
                 }
                 OptSemicolon("break statement");
             }
             statements.Add(new BreakStatement(loc, label));
             return loc;
         }
     case InputElementTag.Return:
         {
             var loc = Current.Loc;
             Consume();
             var value = default(Expression);
             // ask for Current to make sure lastLineTerminator is updates
             var isExpr = IsExpression();
             if (lastLineTerminator == null)
             {
                 if (isExpr)
                 {
                     value = Expression(false);
                     loc = loc.Union(value.Loc);
                 }
                 OptSemicolon("return statement");
                 if (value != null)
                     value = ConsumeCommentExpression(value);
             }
             statements.Add(new ReturnStatement(loc, value));
             return loc;
         }
     case InputElementTag.With:
         {
             var loc = Current.Loc;
             Consume();
             Only("with statement", "'('", InputElementTag.LParen);
             var environment = Expression(false);
             Only("with statement", "')'", InputElementTag.RParen);
             environment = ConsumeCommentExpression(environment);
             var body = new Seq<Statement>();
             loc = loc.Union(Statement(body, false));
             statements.Add(new WithStatement(loc, environment, new Statements(body)));
             return loc;
         }
     case InputElementTag.Identifier:
         {
             var loc = Current.Loc;
             var ie = Current;
             Consume();
             if (Current.Tag == InputElementTag.Colon)
             {
                 var label = new Identifier(ie.Loc, ie.Value);
                 Consume();
                 var body = new Seq<Statement>();
                 loc = loc.Union(Statement(body, false));
                 statements.Add(new LabelledStatement(loc, label, new Statements(body)));
             }
             else
             {
                 Regurgitate(ie);
                 var expression = Expression(false);
                 loc = expression.Loc;
                 OptSemicolon("expression statement");
                 expression = ConsumeCommentExpression(expression);
                 statements.Add(new ExpressionStatement(loc, expression));
             }
             return loc;
         }
     case InputElementTag.Switch:
         {
             var loc = Current.Loc;
             Consume();
             Only("switch statement", "'('", InputElementTag.LParen);
             var value = Expression(false);
             Only("switch statement", "')'", InputElementTag.RParen);
             value = ConsumeCommentExpression(value);
             Only("switch statement", "'{'", InputElementTag.LBrace);
             var cases = new Seq<CaseClause>();
             var defaultc = default(DefaultClause);
             while (Current.Tag != InputElementTag.RBrace)
             {
                 if (Current.Tag == InputElementTag.Case)
                 {
                     var caseLoc = Current.Loc;
                     Consume();
                     var caseValue = Expression(false);
                     Only("case clause", "':'", InputElementTag.Colon);
                     var caseBody = new Seq<Statement>();
                     while (Current.Tag != InputElementTag.Case && Current.Tag != InputElementTag.Default &&
                            Current.Tag != InputElementTag.RBrace)
                         caseLoc = caseLoc.Union(Statement(caseBody, false));
                     ConsumeCommentStatement(caseBody);
                     cases.Add(new CaseClause(caseLoc, caseValue, new Statements(caseBody)));
                 }
                 else if (Current.Tag == InputElementTag.Default)
                 {
                     if (defaultc != null)
                         throw MsgError
                             ("case clause",
                              String.Format("default clause already present at {0}", defaultc.Loc));
                     var defaultLoc = Current.Loc;
                     Consume();
                     Only("default clause", "':'", InputElementTag.Colon);
                     var defaultBody = new Seq<Statement>();
                     while (Current.Tag != InputElementTag.Case && Current.Tag != InputElementTag.Default &&
                            Current.Tag != InputElementTag.RBrace)
                         defaultLoc = defaultLoc.Union(Statement(defaultBody, false));
                     ConsumeCommentStatement(defaultBody);
                     defaultc = new DefaultClause(defaultLoc, new Statements(defaultBody), cases.Count);
                 }
                 else
                     throw IEError("switch statement", "'case' or 'default' or '}'");
             }
             loc = loc.Union(Current.Loc);
             Consume();
             statements.Add(new SwitchStatement(loc, value, cases, defaultc));
             return loc;
         }
     case InputElementTag.Throw:
         {
             var loc = Current.Loc;
             Consume();
             // ask for Current to make sure lastLineTerminator is updates
             var dummy = Current;
             var value = default(Expression);
             if (lastLineTerminator == null)
             {
                 value = Expression(false);
                 OptSemicolon("throw statement");
                 value = ConsumeCommentExpression(value);
             }
             else
             {
                 value = Expression(false);
                 value = ConsumeCommentExpression(value);
             }
             loc = loc.Union(value.Loc);
             statements.Add(new ThrowStatement(loc, value));
             return loc;
         }
     case InputElementTag.Try:
         {
             var loc = Current.Loc;
             Consume();
             var tryStatements = new Seq<Statement>();
             BlockStatements("try statement", false, tryStatements);
             var catchc = default(CatchClause);
             var finallyc = default(FinallyClause);
             if (Current.Tag == InputElementTag.Catch)
             {
                 var catchLoc = Current.Loc;
                 Consume();
                 Only("catch clause", "'('", InputElementTag.LParen);
                 if (Current.Tag != InputElementTag.Identifier)
                     throw IEError("catch clasue", "identifier");
                 var name = new Identifier(Current.Loc, Current.Value);
                 Consume();
                 Only("catch clause", "')'", InputElementTag.RParen);
                 var catchBody = new Seq<Statement>();
                 catchLoc = catchLoc.Union(BlockStatements("catch clause", false, catchBody));
                 catchc = new CatchClause(catchLoc, name, new Statements(catchBody));
                 loc = loc.Union(catchLoc);
             }
             if (Current.Tag == InputElementTag.Finally)
             {
                 var finallyLoc = Current.Loc;
                 Consume();
                 var finallyBody = new Seq<Statement>();
                 finallyLoc = finallyLoc.Union(BlockStatements("finally clause", false, finallyBody));
                 finallyc = new FinallyClause(finallyLoc, new Statements(finallyBody));
                 loc = loc.Union(finallyLoc);
             }
             else if (catchc == null)
                 throw IEError("try statement", "'catch' or 'finally'");
             statements.Add(new TryStatement(loc, new Statements(tryStatements), catchc, finallyc));
             return loc;
         }
     case InputElementTag.Function:
         {
             if (lexer.IsStrict && !isTop)
                 throw MsgError("statement", "function declarations not permitted in nested blocks");
             var loc = Current.Loc;
             Consume();
             if (Current.Tag != InputElementTag.Identifier)
                 throw IEError("function declaration", "identifier");
             var name = new Identifier(Current.Loc, Current.Value);
             Consume();
             if (Current.Tag != InputElementTag.LParen)
                 throw IEError("function declaration", "'('");
             var parameters = new Seq<Identifier>();
             DelimitedList
                 ("function declaration parameters",
                  "',' or ')'",
                  InputElementTag.Comma,
                  InputElementTag.RParen,
                  () =>
                      {
                          if (Current.Tag != InputElementTag.Identifier)
                              throw IEError("function declaration parameters", "identifier");
                          parameters.Add(new Identifier(Current.Loc, Current.Value));
                          Consume();
                      });
             var body = new Seq<Statement>();
             loc = loc.Union(BlockStatements("function declaration", true, body));
             statements.Add(new FunctionDeclaration(loc, name, parameters, new Statements(body)));
             return loc;
         }
     default:
         {
             var expression = Expression(false);
             var loc = expression.Loc;
             OptSemicolon("expression statement");
             expression = ConsumeCommentExpression(expression);
             statements.Add(new ExpressionStatement(loc, expression));
             return loc;
         }
     }
 }
Example #28
0
 private Expression PrimaryExpression()
 {
     switch (Current.Tag)
     {
     case InputElementTag.This:
         {
             var loc = Current.Loc;
             Consume();
             return new ThisExpression(loc);
         }
     case InputElementTag.Debugger:
         {
             var loc = Current.Loc;
             Consume();
             return new DebuggerExpression(loc);
         }
     case InputElementTag.Identifier:
         {
             var id = new Identifier(Current.Loc, Current.Value);
             Consume();
             return new IdentifierExpression(id.Loc, id);
         }
     case InputElementTag.Number:
         {
             var nl = NumericLiteral.FromJavaScript(Current.Loc, Current.Value);
             Consume();
             return nl;
         }
     case InputElementTag.String:
         {
             var sl = new StringLiteral(Current.Loc, Current.Value);
             // lexer has already converted to underlying value
             Consume();
             return sl;
         }
     case InputElementTag.Null:
         {
             var loc = Current.Loc;
             Consume();
             return new NullExpression(Current.Loc);
         }
     case InputElementTag.True:
     case InputElementTag.False:
         {
             var bl = BooleanLiteral.FromJavaScript(Current.Loc, Current.Value);
             Consume();
             return bl;
         }
     case InputElementTag.Regexp:
         {
             // lexer has NOT already converted to underlying value
             var rl = RegularExpressionLiteral.FromJavaScript(Current.Loc, Current.Value);
             Consume();
             return rl;
         }
     case InputElementTag.LSquare:
         {
             var loc = Current.Loc;
             var elems = new Seq<Expression>();
             Consume();
             while (Current.Tag != InputElementTag.RSquare)
             {
                 if (Current.Tag == InputElementTag.Comma)
                 {
                     var elem = new IdentifierExpression
                         (Current.Loc, new Identifier(Current.Loc, Identifier.Undefined.Value));
                     elems.Add(elem);
                     Consume();
                 }
                 else
                 {
                     var elem = AssignmentExpression(false);
                     elems.Add(elem);
                     if (Current.Tag == InputElementTag.Comma)
                         Consume();
                     else if (Current.Tag != InputElementTag.RSquare)
                         throw IEError("array literal", "',' or ']'");
                 }
             }
             loc = loc.Union(Current.Loc);
             Consume();
             return new ArrayLiteral(loc, elems);
         }
     case InputElementTag.LBrace:
         {
             var bindings = new OrdMap<PropertyName, Expression>();
             var loc = DelimitedList
                 ("object literal",
                  "',' or '}'",
                  InputElementTag.Comma,
                  InputElementTag.RBrace,
                  () =>
                      {
                          var propName = default(PropertyName);
                          switch (Current.Tag)
                          {
                          case InputElementTag.Identifier:
                              propName = new PropertyName(Current.Loc, Current.Value);
                              break;
                          case InputElementTag.String:
                              propName = new PropertyName(Current.Loc, Current.Value);
                              break;
                          case InputElementTag.Number:
                              propName = PropertyName.FromJavaScriptNumber(Current.Loc, Current.Value);
                              break;
                          default:
                              throw IEError("object literal", "identifier, string or number");
                          }
                          Consume();
                          Only("object literal", "':'", InputElementTag.Colon);
                          var value = AssignmentExpression(false);
                          // This will silently ignore repeat bindings
                          bindings.Add(propName, value);
                      });
             LastWasInExpressionContext();
             return new ObjectLiteral(loc, bindings);
         }
     case InputElementTag.LParen:
         {
             Consume();
             var e = Expression(false);
             Only("expression", "')'", InputElementTag.RParen);
             LastWasInExpressionContext();
             return e;
         }
     case InputElementTag.Function:
         {
             var loc = Current.Loc;
             Consume();
             var name = default(Identifier);
             if (Current.Tag == InputElementTag.Identifier)
             {
                 name = new Identifier(Current.Loc, Current.Value);
                 Consume();
             }
             if (Current.Tag != InputElementTag.LParen)
                 throw IEError("function expression", "'('");
             var parameters = new Seq<Identifier>();
             DelimitedList
                 ("function expression parameters",
                  "',' or ')'",
                  InputElementTag.Comma,
                  InputElementTag.RParen,
                  () =>
                      {
                          if (Current.Tag != InputElementTag.Identifier)
                              throw IEError("function expression parameters", "identifier");
                          parameters.Add(new Identifier(Current.Loc, Current.Value));
                          Consume();
                      });
             var body = new Seq<Statement>();
             loc = loc.Union(BlockStatements("function expression", true, body));
             return new FunctionExpression(loc, name, parameters, new Statements(body));
         }
     default:
         throw IEError("expression", "primary expression");
     }
 }
        // ----------------------------------------------------------------------
        // 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();
            }
        }
Example #30
0
 private Expression LeftHandSideFollow(Seq<InputElement> newStack, Expression lhs)
 {
     switch (Current.Tag)
     {
         case InputElementTag.LParen:
         {
             var applicand = lhs;
             var arguments = new Seq<Expression>();
             var loc = DelimitedList("call expression arguments", "')' or ','", InputElementTag.Comma, InputElementTag.RParen,
                                     () => arguments.Add(AssignmentExpression(false)));
             LastWasInExpressionContext();
             var ce = new CallExpression(lhs.Loc.Union(loc), applicand, arguments);
             if (newStack.Count > 0)
                 return PopNew(newStack, ce);
             else
                 return ce;
         }
         case InputElementTag.LSquare:
         {
             var left = lhs;
             Consume();
             var right = Expression(false);
             var loc = Only("index expression", "']'", InputElementTag.RSquare);
             return new IndexExpression(lhs.Loc.Union(loc), left, right);
         }
         case InputElementTag.Period:
         {
             var left = lhs;
             Consume();
             if (Current.Tag != InputElementTag.Identifier)
                 throw IEError("property access expression", "identifier");
             var right = new StringLiteral(Current.Loc, Current.Value);
             Consume();
             return new IndexExpression(lhs.Loc.Union(right.Loc), left, right);
         }
         default:
             return null;
     }
 }
        // Collect and filter members for subsequent code gen
        private void CollectMembers()
        {
            var fields = new Seq<CST.FieldDef>();
            var events = new Seq<CST.EventDef>();
            var properties = new Seq<CST.PropertyDef>();
            var methods = new Seq<CST.MethodDef>();
            var exportedInstanceMethods = new Seq<CST.MethodDef>();
            StaticInitializer = null;
            DefaultConstructor = null;
            numRelevantMethods = 0;

            foreach (var fieldDef in TyconEnv.Type.Members.OfType<CST.FieldDef>().Where(d => d.Invalid == null))
            {
                if (fieldDef.IsUsed)
                    fields.Add(fieldDef);
                else if (TypeTrace == null || TypeTrace.IncludeType)
                    Env.Log
                        (new UnusedDefinitionMessage
                             (CST.MessageContextBuilders.Member
                                  (Env.Global, TyconEnv.Assembly, TyconEnv.Type, fieldDef)));
            }

            foreach (var eventDef in TyconEnv.Type.Members.OfType<CST.EventDef>().Where(d => d.Invalid == null))
            {
                if (eventDef.IsUsed)
                    events.Add(eventDef);
                else if (TypeTrace == null || TypeTrace.IncludeType)
                    Env.Log
                        (new UnusedDefinitionMessage
                             (CST.MessageContextBuilders.Member
                                  (Env.Global, TyconEnv.Assembly, TyconEnv.Type, eventDef)));
            }

            foreach (var propDef in TyconEnv.Type.Members.OfType<CST.PropertyDef>().Where(d => d.Invalid == null))
            {
                if (propDef.IsUsed)
                    properties.Add(propDef);
                else if (TypeTrace == null || TypeTrace.IncludeType)
                    Env.Log
                        (new UnusedDefinitionMessage
                             (CST.MessageContextBuilders.Member
                                  (Env.Global, TyconEnv.Assembly, TyconEnv.Type, propDef)));
            }

            var state = Env.InteropManager.GetTypeRepresentation(TyconEnv.Assembly, TyconEnv.Type).State;

            var s = TyconEnv.Type.Style;
            if (!(s is CST.InterfaceTypeStyle || s is CST.DelegateTypeStyle))
            {
                foreach (
                    var methodDef in
                        TyconEnv.Type.Members.OfType<CST.MethodDef>().Where(d => d.Invalid == null && !d.IsAbstract))
                {
                    if (!methodDef.IsUsed)
                    {
                        if (TypeTrace == null || TypeTrace.IncludeType)
                            Env.Log
                                (new UnusedDefinitionMessage
                                     (CST.MessageContextBuilders.Member
                                          (Env.Global, TyconEnv.Assembly, TyconEnv.Type, methodDef)));
                    }
                    else if (!Env.Validity.IsMustHaveADefinition(methodDef.QualifiedMemberName(Env.Global, TyconEnv.Assembly, TyconEnv.Type)) &&
                             (Env.InteropManager.IsInlinable(TyconEnv.Assembly, TyconEnv.Type, methodDef, state) ||
                              Env.InlinedMethods.IsInlinable(TyconEnv.Assembly, TyconEnv.Type, methodDef)))
                    {
                        if (TypeTrace == null || TypeTrace.IncludeType)
                            Env.Log
                                (new InlinedDefinitionMessage
                                     (CST.MessageContextBuilders.Member
                                          (Env.Global, TyconEnv.Assembly, TyconEnv.Type, methodDef)));
                    }
                    else if (state != InstanceState.JavaScriptOnly && state != InstanceState.ManagedAndJavaScript &&
                             !methodDef.IsStatic && methodDef.IsConstructor && methodDef.Arity > 1 &&
                             methodDef.ValueParameters[1].Equals(Env.JSContextRef))
                    {
                        // Silently ignore importing constructors unless they are needed.
                        // (Remember, the managed interop rewriter will interpert 'Merged' as
                        // 'JavaScriptOnly', and thus may need importing constructors.)
                    }
                    else
                    {
                        if (methodDef.IsStatic && methodDef.IsConstructor)
                        {
                            if (methodDef.TypeArity > 0)
                                throw new InvalidOperationException
                                    ("static constructors cannot be polymorphic");
                            StaticInitializer = new CST.MethodRef(TyconEnv.AddSelfTypeBoundArguments().TypeRef, methodDef.MethodSignature, null);
                        }
                        else if (!methodDef.IsStatic && methodDef.IsConstructor && methodDef.Arity == 1 &&
                                 !Env.InteropManager.IsFactory(TyconEnv.Assembly, TyconEnv.Type, methodDef))
                        {
                            if (methodDef.TypeArity > 0)
                                throw new InvalidOperationException
                                    ("instance constructors cannot be polymorphic");
                            DefaultConstructor = new CST.MethodRef(TyconEnv.AddSelfTypeBoundArguments().TypeRef, methodDef.MethodSignature, null);
                        }
                        if (Env.InteropManager.IsExported(TyconEnv.Assembly, TyconEnv.Type, methodDef))
                        {
                            if (Env.InteropManager.IsBindToInstance
                                (TyconEnv.Assembly, TyconEnv.Type, methodDef))
                                exportedInstanceMethods.Add(methodDef);
                            // else: will be exported by assembly's Initialize function
                        }

                        methods.Add(methodDef);

                        if (TypeTrace == null || TypeTrace.Methods.Contains(methodDef.MethodSignature))
                            numRelevantMethods++;
                    }
                }
            }
            // else: ignore members of interface and delegate types
            // TODO: Need to emit reflection data for methods of interface types, thus will need
            //       to collect interface methods

            Fields = fields;
            Events = events;
            Properties = properties;
            Methods = methods;
            ExportedInstanceMethods = exportedInstanceMethods;
        }
Example #32
0
        public static MethodCompilerEnvironment EnterMethod
            (CompilerEnvironment env,
            JST.NameSupply outerNameSupply,
            JST.NameSupply nameSupply,
            JST.Identifier rootId,
            JST.Identifier assemblyId,
            JST.Identifier typeDefinitonId,
            CST.CompilationEnvironment compEnv,
            TypeTrace typeTrace)
        {
            // BUG: IE messes up scoping for function identifiers. To compensate we must allocate its
            //      identifier in the outer scope
            var methodId = outerNameSupply.GenSym();

            if (env.DebugMode)
            {
                var sb = new StringBuilder();
                sb.Append(methodId.Value);
                sb.Append('_');
                var namedTypeDef = compEnv.Type as CST.NamedTypeDef;
                if (namedTypeDef != null)
                {
                    if (namedTypeDef.Name.Namespace.Length > 0)
                    {
                        JST.Lexemes.AppendStringToIdentifier(sb, namedTypeDef.Name.Namespace.Replace('.', '_'));
                        sb.Append('_');
                    }
                    foreach (var n in namedTypeDef.Name.Types)
                    {
                        JST.Lexemes.AppendStringToIdentifier(sb, n);
                        sb.Append('_');
                    }
                }
                JST.Lexemes.AppendStringToIdentifier(sb, compEnv.Method.Name);
                methodId = new JST.Identifier(sb.ToString());
            }

            var typeBoundTypeParameterIds = new Seq <JST.Identifier>();

            for (var i = 0; i < compEnv.Type.Arity; i++)
            {
                typeBoundTypeParameterIds.Add(nameSupply.GenSym());
            }

            var methodBoundTypeParameterIds = new Seq <JST.Identifier>();

            for (var i = 0; i < compEnv.Method.TypeArity; i++)
            {
                methodBoundTypeParameterIds.Add(nameSupply.GenSym());
            }

            var res = new MethodCompilerEnvironment
                          (compEnv.Global,
                          compEnv.SkolemDefs,
                          compEnv.Assembly,
                          compEnv.Type,
                          compEnv.TypeBoundArguments,
                          compEnv.Method,
                          compEnv.MethodBoundArguments,
                          compEnv.Variables,
                          compEnv.ValueParameterIds,
                          compEnv.LocalIds,
                          env,
                          nameSupply,
                          rootId,
                          assemblyId,
                          typeDefinitonId,
                          methodId,
                          typeBoundTypeParameterIds,
                          methodBoundTypeParameterIds,
                          typeTrace);

            res.BindSpecial();

            return(res);
        }