예제 #1
0
        protected override Expression VisitLambda <T>(Expression <T> node)
        {
            Visit(node.Body);

            constructed = Js.Function(node.Name, new[] { Js.Return(constructed) }, node.Parameters.Select(p => p.Name).ToArray());

            return(node);
        }
예제 #2
0
        protected virtual JsFunction GenerateAutomaticEventAccessor(IEvent ee, bool isRemove)
        {
            if (isRemove)
            {
                var remover = Js.Function("value").Add(Js.This().Member(ee.Name).Assign(Js.Member("$RemoveDelegate").Invoke(Js.This().Member(ee.Name), Js.Member("value"))).Statement());
                return(remover);
            }
            var adder = Js.Function("value").Add(Js.This().Member(ee.Name).Assign(Js.Member("$CombineDelegates").Invoke(Js.This().Member(ee.Name), Js.Member("value"))).Statement());

            return(adder);
        }
예제 #3
0
        public void TestMethod2()
        {
            string s;

            var t = Js.Binary((x, y) => x + y);
            var u = Js.AddAssign(
                Js.Variable("t"),
                Js.Function <Func <JsObject, JsObject, JsObject, JsObject> >((a, b, c) => a + b * c)
                );

            s = u.ToString();
        }
예제 #4
0
        public void TestMethod1()
        {
            var x = Js.Variable("x");
            var y = Js.Variable("y");

            var t = Js.Assign(
                Js.Variable("fn"),
                Js.Function(new [] {
                Js.If(
                    Js.Equality(x, y),
                    Js.MultiplyAssign(x, y))
            }, "x", "y")
                );
        }
예제 #5
0
        private JsNode ImportAttributeValue(ResolveResult res)
        {
            var node = AstNodeConverter.Visit(res);

            if (node.NodeType == JsNodeType.InvocationExpression)
            {
                var exp = (JsInvocationExpression)node;
                var me  = exp.Member as JsMemberExpression;
                if (me != null && me.Name == "Typeof")
                {
                    node = Js.Function().AddStatements(Js.Return(exp));
                }
            }
            return(node);
        }
예제 #6
0
        /// <summary>
        /// Wraps a setter invocation with a js function that returns the setter value back, if another assignment operation occurs
        /// var x = contact.Name = "Shooki";
        /// var x = contact.setName("Shooki"); //error
        /// var x = (function(arg){contact.setName(arg);return arg;}).call(this, "Shooki");
        /// </summary>
        /// <param name="res"></param>
        /// <param name="node2"></param>
        /// <returns></returns>
        internal JsNode WrapSetterToReturnValueIfNeeded(OperatorResolveResult res, JsNode node2)
        {
            var node3 = node2 as JsInvocationExpression;

            if (node3 == null)
            {
                return(node2);
            }

            if (RequiresWrapSetterToReturnValue(res))
            {
                var lastArg = node3.Arguments.Last();
                var prmName = "$p" + ParameterNameCounter++;
                node3.Arguments[node3.Arguments.Count - 1] = Js.Member(prmName);

                var func = Js.Function(prmName).Add(((JsExpression)node2).Statement());
                func.Add(Js.Return(Js.Member(prmName)));
                node2 = WrapFunctionAndInvoke(res, func, lastArg);
            }
            return(node2);
        }
예제 #7
0
        public override void VisitAnonymousObjectCreationExpression(AnonymousObjectCreationExpressionSyntax node)
        {
            var jsBlock = new JsBlockStatement();

            var model     = Context.Instance.Compilation.GetSemanticModel(node.SyntaxTree);
            var classType = (INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(model, node);

            if (processedTypes.Contains(classType))
            {
                return;
            }
            processedTypes.Add(classType);

            JsBlockStatement typeInitializer;
            JsBlockStatement staticInitializer;

            jsBlock.Aggregate(idioms.CreateTypeFunction(classType, out typeInitializer, out staticInitializer));

            // Create default constructor
            var constructorBlock = new JsBlockStatement();

            constructorBlock.Express(idioms.InvokeMethodAsThis(classType.BaseType.InstanceConstructors.Single(x => x.Parameters.Count() == 0)));
            var constructor = classType.InstanceConstructors.Single();

            typeInitializer.Add(idioms.StoreInPrototype(constructor.GetMemberName(), Js.Reference(SpecialNames.DefineConstructor).Invoke(
                                                            Js.Reference(SpecialNames.TypeInitializerTypeFunction),
                                                            Js.Function().Body(constructorBlock))));

            foreach (var property in classType.GetMembers().OfType <IPropertySymbol>())
            {
                typeInitializer.Aggregate(CreateProperty(property));
            }

            Action action = () =>
            {
                body.Aggregate(jsBlock);
            };

            actions.Add(Tuple.Create(classType, action));
        }
예제 #8
0
        public async Task Compile()
        {
            projectName = project.AssemblyName;
            Compilation compilation = await Profiler.Time("Getting initial project compilation", async() => await project.GetCompilationAsync());

            Context.Update(project.Solution, project, compilation, new ReflectionCache(project, compilation));

            // If this is the runtime prjoect, declare the array to hold all the GetAssembly functions (this .js file
            // will be loaded first, and we only want to bother creating the array once.)
            if (projectName == "mscorlib")
            {
                var global = new JsBlockStatement();
                jsCompilationUnit.Global = global;

                var assemblies = Js.Variable(SpecialNames.Assemblies, Js.Array());
                global.Local(assemblies);

                // This ensures that Function.$typeName returns `Function` -- this is important when using
                // a type function as a generic argument, since otherwise when we try to get a
                // unique key for the permuatation of type args including a type function, we would get
                // an empty string for that arg, which would break the cache.
                jsCompilationUnit.Body.Assign(Js.Reference("Function").Member(SpecialNames.TypeName), Js.Primitive("Function"));
            }

            // Declare assembly variable
            var assemblyVariable = Js.Variable("$" + projectName.MaskSpecialCharacters() + "$Assembly", Js.Null());

            jsCompilationUnit.Body.Local(assemblyVariable);

            // Declare array to store all anonymous types
            var anonymousTypes = Js.Variable(compilation.Assembly.GetAssemblyAnonymousTypesArray(), Js.Array());

            jsCompilationUnit.Body.Local(anonymousTypes);

            // Declare array to store all the type functions in the assembly
            var assemblyTypes = Js.Variable(compilation.Assembly.GetAssemblyTypesArray(), Js.Array());

            jsCompilationUnit.Body.Local(assemblyTypes);

            // Build $GetAssemblyMethod, which lazily creates a new Assembly instance
            var globalIdioms = new Idioms(null);
            var getAssembly  = Js.Function();

            getAssembly.Body.If(
                assemblyVariable.GetReference().EqualTo(Js.Null()),
                assemblyVariable.GetReference().Assign(globalIdioms.CreateAssembly(compilation.Assembly, assemblyTypes.GetReference()))
                );
            getAssembly.Body.Return(assemblyVariable.GetReference());
            jsCompilationUnit.Body.Assign(
                Js.Reference(compilation.Assembly.GetAssemblyMethodName()),
                getAssembly);

            // Declare $assembly variable
            jsCompilationUnit.Body.Local(SpecialNames.Assembly, Js.Reference(compilation.Assembly.GetAssemblyMethodName()));
            jsCompilationUnit.Body.Assign(Js.Reference(SpecialNames.Assembly).Member(SpecialNames.AssemblyTypesArray), assemblyTypes.GetReference());

            // Add $GetAssemblyMethod to global assemblies array
            jsCompilationUnit.Body.Express(Js.Reference(SpecialNames.Assemblies).Member("push").Invoke(Js.Reference(SpecialNames.Assembly)));

            // Builds out all the namespace objects.  Types live inside namepsaces, which are represented as
            // nested Javascript objects.  For example, System.Text.StringBuilder is represented (in part) as:
            //
            // System = {};
            // System.Text = {};
            // System.Text.StringBuilder = function() { ... }
            //
            // This allows access to classes using dot notation in the expected way.
            Profiler.Time("Transforming namespaces", () =>
            {
                var namespaceTransformer = new NamespaceTransformer(jsCompilationUnit.Body);
                foreach (var syntaxTree in compilation.SyntaxTrees)
                {
                    var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                    compilationUnit.Accept(namespaceTransformer);
                }
            });

            var actions = new List <Tuple <INamedTypeSymbol, Action> >();

            Profiler.Time("Get diagnostics", () =>
            {
                var diagnostics = compilation.GetDiagnostics();
                foreach (var diagnostic in diagnostics)
                {
                    if (diagnostic.Severity == DiagnosticSeverity.Error)
                    {
                        Console.WriteLine("// " + diagnostic);
                    }
                }
            });

            // Check for partial classes
            Profiler.Time("Reassemble partial classes", () =>
            {
                var partialClassReassembler = new PartialClassReassembler(project, compilation);
                compilation = partialClassReassembler.UnifyPartialTypes();
            });

/*
 *          // Write out all type functions in inheritance order.  This allows for complex references between types and
 *          // nested types.
 *          Profiler.Time("Write out type function declarations", () =>
 *          {
 *              var allTypeDeclarations = new List<INamedTypeSymbol>();
 *              foreach (var syntaxTree in compilation.SyntaxTrees)
 *              {
 *                  var semanticModel = compilation.GetSemanticModel(syntaxTree);
 *                  var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
 *                  var typeDeclarations = GetTypeDeclarations(compilationUnit);
 *                  var types = typeDeclarations.Select(x => semanticModel.GetDeclaredSymbol(x)).ToArray();
 *                  allTypeDeclarations.AddRange(types);
 *              }
 *              SweepSort(allTypeDeclarations, x => x);
 *
 *              jsCompilationUnit.Body.Express(Js.Reference(Context.Instance.SymbolNames[classType.ContainingNamespace, classType.ContainingNamespace.GetFullName()]).Member(classType.GetShortTypeName()),
 *                      Js.Reference(SpecialNames.Define).Invoke(Js.Primitive(displayName), baseType));
 *              jsCompilationUnit.Assign(Js.Reference(Context.Instance.SymbolNames[classType.ContainingNamespace, classType.ContainingNamespace.GetFullName()]).Member(classType.GetShortTypeName()),
 *                      Js.Reference(SpecialNames.Define).Invoke(Js.Primitive(displayName), baseType));
 *          });
 */

            // Scan all syntax trees for anonymous type creation expressions.  We transform them into class
            // declarations with a series of auto implemented properties.
            Profiler.Time("Running AnonymousTypeTransformer", () =>
            {
                var anonymousTypeTransformer = new AnonymousTypeTransformer(jsCompilationUnit.Body, actions);
                foreach (var syntaxTree in compilation.SyntaxTrees)
                {
                    var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                    compilationUnit.Accept(anonymousTypeTransformer);
                }
            });

            // Iterate through all the syntax trees and add entries into `actions` that correspond to type
            // declarations.
            Profiler.Time("Preparing for core transformation process", () =>
            {
                foreach (var syntaxTree in compilation.SyntaxTrees)
                {
                    var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                    var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                    var transformer     = new JsTransformer(syntaxTree, semanticModel, jsCompilationUnit);

                    var typeCollector = new TypeCollector();
                    compilationUnit.Accept(typeCollector);
                    var typeDeclarations     = typeCollector.TypeDeclarations.Where(x => x.GetContainingTypeDeclaration() == null);
                    var delegateDeclarations = typeCollector.DelegateDeclarations.Where(x => x.GetContainingTypeDeclaration() == null);

                    foreach (var type in typeDeclarations)
                    {
                        var _type      = type;
                        var typeSymbol = semanticModel.GetDeclaredSymbol(type);
                        Action action  = () =>
                        {
                            var statements = (JsBlockStatement)_type.Accept(transformer);
                            jsCompilationUnit.Body.Aggregate(statements);
                        };
                        actions.Add(Tuple.Create(typeSymbol, action));
                    }
                    foreach (var type in delegateDeclarations)
                    {
                        var _type     = type;
                        Action action = () =>
                        {
                            var statements = (JsBlockStatement)_type.Accept(transformer);
                            jsCompilationUnit.Body.Aggregate(statements);
                        };
                        actions.Add(Tuple.Create((INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, type), action));
                    }
                }
            });

            // Sort all the type declarations such that base types always come before subtypes.
            Profiler.Time("Sorting transformers", () => SweepSort(actions, x => x.Item1));

            var transformationActions = actions.Select(x => x.Item2).ToArray();

            Profiler.Time("Applying core transformation", () =>
            {
                foreach (var item in transformationActions)
                {
                    item();
                }
            });

            // Create cultures based on installed .NET cultures.  Presumably this is the same regardless
            // of the platform that compiled this assembly.  Only do this for the standard library.
            if (projectName == "mscorlib" && !Context.Instance.Compilation.Assembly.IsCultureInfoExportDisabled())
            {
                foreach (var culture in CultureInfo.GetCultures(CultureTypes.AllCultures))
                {
                    JsExpression target = new JsVariableReferenceExpression(Context.Instance.CultureInfo.GetTypeName()).Invoke().Member("RegisterCulture");
                    jsCompilationUnit.Body.Add(target.Invoke(new[]
                    {
                        Js.Literal(culture.Name),
                        Js.Literal(culture.DateTimeFormat.ShortDatePattern),
                        Js.Literal(culture.DateTimeFormat.LongDatePattern),
                        Js.Literal(culture.DateTimeFormat.ShortTimePattern),
                        Js.Literal(culture.DateTimeFormat.LongTimePattern),
                        Js.Literal(culture.DateTimeFormat.FullDateTimePattern),
                        Js.Literal(culture.DateTimeFormat.YearMonthPattern),
                        Js.Array(culture.DateTimeFormat.MonthNames.Select(x => Js.Literal(x)).ToArray()),
                        Js.Array(culture.DateTimeFormat.AbbreviatedMonthNames.Select(x => Js.Literal(x)).ToArray()),
                        Js.Array(culture.DateTimeFormat.DayNames.Select(x => Js.Literal(x)).ToArray())
                    }).Express());
                }
            }

            // If the project type is a console application, then invoke the Main method at the very
            // end of the file.
            var entryPoint = Context.Instance.Compilation.GetEntryPoint(CancellationToken.None);

            if (entryPoint != null)
            {
                jsCompilationUnit.Body.Express(globalIdioms.InvokeStatic(entryPoint));
            }

            // Test minification
//            var minifier = new JsMinifier();
//            jsCompilationUnit.Accept(minifier);
        }
예제 #9
0
        private JsNode VisitConversion(ResolveResult input, Conversion conversion, IType conversionType)
        {
            ////TODO: HACK: https://github.com/icsharpcode/NRefactory/issues/183
            //var isImplicit = res.Conversion.IsImplicit;
            //if (!isImplicit && res.Conversion.IsExplicit && res.Conversion.Method != null && res.Conversion.Method.Name != null && res.Conversion.Method.Name.Contains("Implicit"))
            //    isImplicit = true;
            if (conversion.IsMethodGroupConversion)
            {
            }
            else if (conversion.IsUserDefined)
            {
                ITypeDefinition typeDef;
                if (conversion.Method != null && conversion.Method.DeclaringType != null)
                {
                    typeDef = conversion.Method.DeclaringType.GetDefinitionOrArrayType();
                }
                else
                {
                    typeDef = conversionType.GetDefinitionOrArrayType();
                }
                var nativeOverloads = Sk.UseNativeOperatorOverloads(typeDef);
                if (nativeOverloads)
                {
                    return(Visit(input));
                }
                ////TODO: Check if OmitCalls is found on conversion method, if so - return Visit(input);
                //if (Sk.IsOmitCalls(conversion.Method))
                //{
                //}
                var fake  = conversion.Method.InvokeMethod(null, input);
                var node2 = Visit(fake);
                return(node2);
            }
            else if (conversion.IsTryCast || conversion.IsExplicit)
            {
                if (ForceIntegers && conversion.IsNumericConversion && IsInteger(conversionType))
                {
                    return(ForceInteger(Visit(input)));
                }

                //Skip enum casts
                if ((conversionType.Kind == TypeKind.Enum && IsInteger(input.Type)) || (input.Type.Kind == TypeKind.Enum && IsInteger(conversionType)))
                {
                    return(Visit(input));
                }

                var omitCasts = Sk.OmitCasts(conversionType);
                if (omitCasts)
                {
                    return(Visit(input));
                }
                if (Sk.NativeCasts(conversionType))
                {
                    var exp2  = VisitExpression(input);
                    var type2 = SkJs.EntityTypeRefToMember(conversionType);
                    if (conversion.IsTryCast)
                    {
                        var node2 = exp2.InstanceOf(type2).Conditional(exp2, Js.Null());
                        return(node2);
                    }
                    else
                    {
                        var node2 = Js.Conditional(exp2.InstanceOf(type2).Or(exp2.Equal(Js.Null())), exp2,
                                                   Js.Parentheses(Js.Function().Add(Js.ThrowNewError("InvalidCastException")).Invoke()));
                        //var node2 = Js.Parentheses(Js.Function().AddStatements(
                        //Js.If(exp2.InstanceOf(type2).Or(exp2.Equal(Js.Null())), Js.Return(exp2)),
                        //Js.ThrowNewError("InvalidCastException"))).Member("call").Invoke(Js.This());
                        return(node2);
                    }
                }
                else
                {
                    var cast  = conversion.IsTryCast ? "As" : "Cast";
                    var node2 = Js.Member(cast).Invoke(VisitExpression(input), SkJs.EntityTypeRefToMember(conversionType));
                    return(node2);
                }
            }
            return(Visit(input));
        }
예제 #10
0
        public JsNode VisitInvocationResolveResultAsCtor(CSharpInvocationResolveResult res)
        {
            if (res.Type.Kind == TypeKind.Delegate)
            {
                return(Visit(res.Arguments.Single()));
            }
            var me    = (IMethod)res.Member;
            var meAtt = Sk.GetJsMethodAttribute(me);
            var ce    = me.GetDeclaringTypeDefinition();
            var att   = ce == null ? null : ce.GetJsTypeAttribute();

            if (att != null && att.Mode == JsMode.Json && (meAtt == null || meAtt.Name == null))
            {
                var jtfn  = ce == null ? null : Sk.GetJsonTypeFieldName(ce);
                var node2 = VisitInvocationResolveResult(res);
                var json  = Importer.InitializersToJson(res.InitializerStatements, res.Type);
                if (jtfn != null)
                {
                    var x = json as JsJsonObjectExpression;
                    if (x != null)
                    {
                        x.Add(jtfn, SkJs.EntityTypeRefToMember(res.Type));
                    }
                }
                return(json);
            }
            else
            {
                var invokeExp = (JsInvocationExpression)VisitInvocationResolveResult(res);
                var newExp    = new JsNewObjectExpression {
                    Invocation = invokeExp
                };
                JsExpression finalExp;
                if (meAtt != null && meAtt.OmitNewOperator)
                {
                    finalExp = invokeExp;
                }
                else
                {
                    finalExp = newExp;
                }

                if (meAtt != null && meAtt.JsonInitializers)
                {
                    var json = Importer.InitializersToJson(res.InitializerStatements, res.Type);
                    invokeExp.Arguments.Add(json);
                }
                else if (res.InitializerStatements.IsNotNullOrEmpty())
                {
                    var func = Js.Function();

                    var inits2 = res.InitializerStatements.Select(t => Visit(t)).ToList();
                    //var init1 = res.InitializerStatements[0];

                    var target  = AstNodeConverter.FindInitializedObjectResolveResult(res);// ((init1 as OperatorResolveResult).Operands[0] as MemberResolveResult).TargetResult as InitializedObjectResolveResult;
                    var varName = Importer.Initializers[target];
                    func.Add(Js.Var(varName, finalExp).Statement());

                    foreach (var init in inits2)
                    {
                        var exp = ((JsExpression)init);
                        func.Add(exp.Statement());
                    }
                    func.Add(Js.Return(Js.Member(varName)));
                    finalExp = Importer.WrapFunctionAndInvoke(res, func);
                }

                return(finalExp);
            }
        }
예제 #11
0
        void TransformIntoBaseMethodCallIfNeeded(CSharpInvocationResolveResult res, JsInvocationExpression node2)
        {
            var target = res.TargetResult as ThisResolveResult;

            if (target != null && target.CausesNonVirtualInvocation) //base.
            {
                //var info = res.GetInfo();
                //var node = info.Nodes.FirstOrDefault();
                var ce = target.Type;// node.FindThisEntity();
                if (ce != null && Sk.IsExtJsType(ce.GetDefinitionOrArrayType()))
                {
                    node2.Member = Js.This().Member("callParent");
                    if (node2.Arguments.IsNotNullOrEmpty())
                    {
                        node2.Arguments = new List <JsExpression> {
                            Js.NewJsonArray(node2.Arguments.ToArray())
                        }
                    }
                    ;
                    //var me2 = (node2.Member as JsMemberExpression);
                    //me2.Name = "callParent";
                    return;
                }
                IMethod me2;
                var     me = res.Member;
                if (me is IProperty)
                {
                    me2 = ((IProperty)me).Getter;
                }
                else if (me is IMethod)
                {
                    me2 = (IMethod)res.Member;
                }
                else
                {
                    throw new Exception("Can't resolve method from member: " + res.Member);
                }
                var member = SkJs.EntityMethodToJsFunctionRef(me2);
                member       = member.Member("call");
                node2.Member = member;
                if (node2.Arguments == null)
                {
                    node2.Arguments = new List <JsExpression>();
                }
                node2.Arguments.Insert(0, Js.This());
            }
        }

        void ProcessByRefs1()
        {
            ByRefs       = new List <ByReferenceResolveResult>();
            ByRefIndexes = new List <int>();
            RefToRefs    = new List <int>();
            var c = 0;

            foreach (var bin in PrmBindings)
            {
                var binding = bin.Binding;
                var byRef   = binding.CallResult as ByReferenceResolveResult;
                if (byRef == null)
                {
                    c++;
                    continue;
                }
                var x = byRef.ElementResult as LocalResolveResult;
                if (x != null && x.Variable != null && x.Variable.Type.Kind == TypeKind.ByReference)
                {
                    if (binding.Parameter.IsRef || binding.Parameter.IsOut)
                    {
                        RefToRefs.Add(c);
                    }
                    c++;
                    continue;
                }
                ByRefs.Add(byRef);
                ByRefIndexes.Add(c);
                c++;
            }
        }

        void ProcessByRefs2()
        {
            var c = 0;

            for (var i = 0; i < Node2.Arguments.Count; i++)
            {
                if (Node2.Arguments[i] is JsMemberExpression)
                {
                    JsMemberExpression jsmex = Node2.Arguments[i] as JsMemberExpression;
                    if (RefToRefs.Contains(i))
                    {
                        Node2.Arguments[i] = jsmex.PreviousMember; //remove the .Value ref wrapper
                    }
                    else if (ByRefIndexes.Contains(i))
                    {
                        Node2.Arguments[i] = Js.Member(RefIndexToName(c));
                        c++;
                    }
                }
                else if (Node2.Arguments[i] is JsIndexerAccessExpression)
                {
                    if (ByRefIndexes.Contains(i))
                    {
                        Node2.Arguments[i] = Js.Member(RefIndexToName(c));
                        c++;
                    }
                }
            }
        }

        void ProcessByRefs3()
        {
            if (ByRefs.IsNotNullOrEmpty())
            {
                var func = Js.Function();

                //It must assigned to a temporary variable, because typed arrays do not acceppt json.
                //调整原来使用临时对象.Value的赋值方式,修改为Object.defineProperty定义get|set方法的实现
                //临时对象统一调用jsclr里的$Ref方法进行创建
                for (var i = 0; i < ByRefs.Count; i++)
                {
                    var byRef = ByRefs[i];
                    var expr  = VisitExpression(byRef);
                    if (expr is JsMemberExpression)
                    {
                        var memberExpr = expr as JsMemberExpression;
                        if (memberExpr.PreviousMember != null)
                        {
                            var refFuncInvoke = new JsInvocationExpression
                            {
                                Member = new JsMemberExpression {
                                    Name = "$Ref"
                                },
                                Arguments = new List <JsExpression> {
                                    memberExpr.PreviousMember, Js.String(memberExpr.Name)
                                }
                            };
                            func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement());
                        }
                        else
                        {
                            //如果是局部变量的话使用旧实现方式
                            var refFuncInvoke = new JsInvocationExpression
                            {
                                Member = new JsMemberExpression {
                                    Name = "$Ref"
                                },
                                Arguments = new List <JsExpression> {
                                    Js.Member("null"), memberExpr
                                }
                            };
                            func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement());
                        }
                    }
                    else if (expr is JsIndexerAccessExpression)
                    {
                        var indexerExpr   = expr as JsIndexerAccessExpression;
                        var indexArg      = indexerExpr.Arguments[0];
                        var refFuncInvoke = new JsInvocationExpression
                        {
                            Member = new JsMemberExpression {
                                Name = "$Ref"
                            },
                            Arguments = new List <JsExpression> {
                                indexerExpr.Member, indexArg
                            }
                        };
                        func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement());
                    }
                }

                func.Add(Js.Var("$res", Node2).Statement());

                for (var i = 0; i < ByRefs.Count; i++)
                {
                    var byRef      = ByRefs[i];
                    var memberExpr = VisitExpression(byRef) as JsMemberExpression;
                    if (memberExpr != null && memberExpr.PreviousMember == null)
                    {
                        func.Add(memberExpr.Assign(Js.Member(RefIndexToName(i)).Member("Value")).Statement());
                    }
                }

                func.Add(Js.Return(Js.Member("$res")));
                Node2 = Importer.WrapFunctionAndInvoke(Res, func);
            }
        }
예제 #12
0
        public async Task <Tuple <string, Project> > Compile(string projectFile)
        {
            var projectFileInfo = new FileInfo(projectFile);
            var projectFolder   = projectFileInfo.Directory.FullName;

            // These two lines are just a weird hack because you get no files back from compilation.SyntaxTrees
            // if the user file isn't modified.  Not sure why that's happening.
            var projectUserFile = projectFolder + "\\" + projectFileInfo.Name + ".user";

            if (File.Exists(projectUserFile))
            {
                File.SetLastWriteTime(projectUserFile, DateTime.Now);
            }

            var project = await MSBuildWorkspace.Create().OpenProjectAsync(projectFile);

            var         projectName = project.AssemblyName;
            Compilation compilation = await project.GetCompilationAsync();

            Context.Update(project.Solution, project, compilation);

            // Check for yield
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var yieldGenerator  = new YieldGenerator(compilation, syntaxTree, semanticModel);
                compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(yieldGenerator);
                compilation     = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath));
            }
            compilation = compilation.Clone();
            Context.Update(project.Solution, project, compilation);

            // After the basic transformation happens, we need to fix up some references afterward
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var yieldFixer      = new YieldGeneratorFixer(compilation, syntaxTree, semanticModel);
                compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(yieldFixer);
                compilation     = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath));
            }
            Context.Update(project.Solution, project, compilation);

            // Check for async
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var asyncGenerator  = new AsyncGenerator(compilation, syntaxTree, semanticModel);
                compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(asyncGenerator);
                compilation     = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath));
            }
            Context.Update(project.Solution, project, compilation);

            var jsCompilationUnit = new JsCompilationUnit {
                UseStrict = true
            };

            // If this is the runtime prjoect, declare the array to hold all the GetAssembly functions (this .js file
            // will be loaded first, and we only want to bother creating the array once.
            if (projectName == "mscorlib")
            {
                var assemblies = Js.Variable(SpecialNames.Assemblies, Js.Array());
                jsCompilationUnit.Body.Local(assemblies);

                // This ensures that Function.$typeName returns `Function` -- this is important when using
                // a type function as a generic argument, since otherwise when we try to assembly a
                // unique key for the permuatation of type args including a type function, we would get
                // an empty string for that arg, which would break the cache.
                jsCompilationUnit.Body.Assign(Js.Reference("Function").Member(SpecialNames.TypeName), Js.Primitive("Function"));
            }

            // Declare assembly variable
            var assemblyVariable = Js.Variable("$" + projectName.MaskSpecialCharacters() + "$Assembly", Js.Null());

            jsCompilationUnit.Body.Local(assemblyVariable);

            // Declare array to store all anonymous types
            var anonymousTypes = Js.Variable(compilation.Assembly.GetAssemblyAnonymousTypesArray(), Js.Array());

            jsCompilationUnit.Body.Local(anonymousTypes);

            // Declare array to store all the type functions in the assembly
            var assemblyTypes = Js.Variable(compilation.Assembly.GetAssemblyTypesArray(), Js.Array());

            jsCompilationUnit.Body.Local(assemblyTypes);

            // Build $GetAssemblyMethod, which lazily creates a new Assembly instance
            var globalIdioms = new Idioms(null);
            var getAssembly  = Js.Function();

            getAssembly.Body.If(
                assemblyVariable.GetReference().EqualTo(Js.Null()),
                assemblyVariable.GetReference().Assign(globalIdioms.CreateAssembly(compilation.Assembly, assemblyTypes.GetReference()))
                );
            getAssembly.Body.Return(assemblyVariable.GetReference());
            jsCompilationUnit.Body.Assign(
                Js.Reference(compilation.Assembly.GetAssemblyMethodName()),
                getAssembly);

            // Add $GetAssemblyMethod to global assemblies array
            jsCompilationUnit.Body.Express(Js.Reference("$assemblies").Member("push").Invoke(Js.Reference(compilation.Assembly.GetAssemblyMethodName())));

            // Builds out all the namespace objects.  Types live inside namepsaces, which are represented as
            // nested Javascript objects.  For example, System.Text.StringBuilder is represented (in part) as:
            //
            // System = {};
            // System.Text = {};
            // System.Text.StringBuilder = function() { ... }
            //
            // This allows access to classes using dot notation in the expected way.
            var namespaceTransformer = new NamespaceTransformer(jsCompilationUnit.Body);

            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                compilationUnit.Accept(namespaceTransformer);
            }

            var actions = new List <Tuple <INamedTypeSymbol, Action> >();

            // Scan all syntax trees for anonymous type creation expressions.  We transform them into class
            // declarations with a series of auto implemented properties.
            var anonymousTypeTransformer = new AnonymousTypeTransformer(jsCompilationUnit.Body, actions);

            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                compilationUnit.Accept(anonymousTypeTransformer);
            }

            var diagnostics = compilation.GetDiagnostics();

            foreach (var diagnostic in diagnostics)
            {
                Console.WriteLine("// " + diagnostic);
            }

            // Iterate through all the syntax trees and add entries into `actions` that correspond to type
            // declarations.
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var transformer     = new JsTransformer(syntaxTree, semanticModel);

                var typeDeclarations = GetTypeDeclarations(compilationUnit);
                foreach (var type in typeDeclarations)
                {
                    Action action = () =>
                    {
                        var statements = (JsBlockStatement)type.Accept(transformer);
                        jsCompilationUnit.Body.Aggregate(statements);
                    };
                    actions.Add(Tuple.Create((INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, type), action));
                }
                var delegateDeclarations = GetDelegates(compilationUnit);
                foreach (var type in delegateDeclarations)
                {
                    Action action = () =>
                    {
                        var statements = (JsBlockStatement)type.Accept(transformer);
                        jsCompilationUnit.Body.Aggregate(statements);
                    };
                    actions.Add(Tuple.Create((INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, type), action));
                }
            }

            // Sort all the type declarations such that base types always come before subtypes.
            SweepSort(actions);
            foreach (var item in actions)
            {
                item.Item2();
            }

            // If the project type is a console application, then invoke the Main method at the very
            // end of the file.
            var entryPoint = compilation.GetEntryPoint(CancellationToken.None);

            if (entryPoint != null)
            {
                jsCompilationUnit.Body.Express(globalIdioms.InvokeStatic(entryPoint));
            }

            // Test minification
//            var minifier = new JsMinifier();
//            jsCompilationUnit.Accept(minifier);

            // Write out the compiled Javascript file to the target location.
            var renderer = new JsRenderer();

            jsCompilationUnit.Accept(renderer);
            return(Tuple.Create(renderer.Output, project));
        }
예제 #13
0
        private JsBlockStatement CreateProperty(IPropertySymbol property)
        {
            var block        = new JsBlockStatement();
            var propertyName = property.GetMemberName();

            var backingField   = property.GetBackingFieldName();
            var valueParameter = Js.Parameter("value");

            block.Add(idioms.StoreInPrototype(backingField, Js.Null()));
            if (property.GetMethod != null)
            {
                block.Add(idioms.StoreInPrototype(property.GetMethod.GetMemberName(), Js.Function().Body(Js.Return(Js.This().Member(backingField)))));
            }
            if (property.SetMethod != null)
            {
                block.Add(idioms.StoreInPrototype(property.SetMethod.GetMemberName() + propertyName, Js.Function(valueParameter).Body(
                                                      Js.Assign(Js.This().Member(backingField), valueParameter.GetReference()))));
            }

            return(block);
        }