private JsExpression VisitLambdaExpression(ExpressionSyntax node, ParameterSyntax[] parameters, CSharpSyntaxNode body) { var expressionType = (INamedTypeSymbol)model.GetTypeInfo(node).ConvertedType; INamedTypeSymbol delegateType; if (Equals(expressionType.OriginalDefinition, Context.Instance.ExpressionGeneric)) { delegateType = (INamedTypeSymbol)expressionType.TypeArguments[0]; } else { delegateType = expressionType; } var lambdaParameters = parameters.ToArray(); var delegateMethod = (IMethodSymbol)delegateType.GetMembers("Invoke")[0]; // Compiler.CsCompilation.FindType() var lambdaMethods = Context.Instance.Expression.GetMembers("Lambda").OfType <IMethodSymbol>().ToArray(); var lambdaMethods2 = lambdaMethods.Where(x => x.TypeParameters.Count() == 1 && x.Parameters.Count() == 2 && Equals(x.Parameters[0].Type, Context.Instance.Expression) && Equals(x.Parameters[1].Type, Context.Instance.ParameterExpressionArray)).ToArray(); var lambdaMethod = lambdaMethods2.Single(); var parameterMethod = Context.Instance.Expression.GetMembers("Parameter").OfType <IMethodSymbol>().Single(x => x.Parameters.Count() == 2 && Equals(x.Parameters[0].Type, Context.Instance.TypeType) && Equals(x.Parameters[1].Type, Context.Instance.String)); lambdaMethod = lambdaMethod.Construct(delegateType); var jsLambda = idioms.InvokeStatic(lambdaMethod); // Convert parameters var workspace = new JsBlockStatement(); var jsParameters = Js.Array(); for (var i = 0; i < delegateMethod.Parameters.Count(); i++) { var delegateParameter = delegateMethod.Parameters[i]; var lambdaParameter = lambdaParameters[i]; var jsParameter = idioms.InvokeStatic(parameterMethod, idioms.TypeOf(delegateParameter.Type), Js.Primitive(lambdaParameter.Identifier.ToString())); var parameterVariableName = "$lambdaparam$" + lambdaParameter.Identifier; parameterVariables[lambdaParameter.Identifier.ToString()] = parameterVariableName; // Declare a variable to hold the parameter object in the parenthetical's scope workspace.Local(parameterVariableName, jsParameter); // Add a reference to this variable (a ParameterExpression) as one of the // parameters to the lambda. jsParameters.Elements.Add(Js.Reference(parameterVariableName)); } var jsBody = body.Accept(this); jsLambda.AddArgument(jsBody); jsLambda.AddArgument(jsParameters); workspace.Return(jsLambda); return(idioms.Wrap(workspace)); }
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); }
private JsStatement TransformBody(JsStatement body) { var block = body is JsBlockStatement ? (JsBlockStatement)body : Js.Block(body); if (!escapeStatements.Any()) { return(Js.Express(idioms.Wrap(block))); } else { if (!(block.Statements.Last() is JsReturnStatement)) { block.Return(Js.Object(Js.Item(EscapeTypeField, Js.Primitive(0))).Compact()); } var wrapped = idioms.Wrap(block); var outerBlock = new JsBlockStatement(); var loopResult = outerBlock.Local("$loopResult", wrapped); if (escapeStatements.Any(x => x.Type == Return)) { outerBlock.If(loopResult.GetReference().Member(EscapeTypeField).EqualTo(Js.Primitive(Return)), Js.Return(loopResult.GetReference().Member(EscapeValueField))); } if (escapeStatements.Any(x => x.Type == Continue)) { var escapes = escapeStatements.Where(x => x.Type == Continue).Distinct(); JsStatement ifTrue; if (!escapes.Any(x => x.Label != null)) { ifTrue = Js.Continue(); } else { ifTrue = Js.Switch( loopResult.GetReference().Member(EscapeLabelField), escapes .Where(x => x.Label == null) .Select(x => Js.Section(Js.Null()).Statement(Js.Continue())) .Concat(escapes .Where(x => x.Label != null && transformer.GetLabelDepth(x.Label) == loopDepth) .Select(x => Js.Section(Js.Primitive(x.Label)).Statement(Js.Continue(x.Label)))) .Concat(new[] { Js.Section(Js.DefaultLabel()).Statements(Js.Return(loopResult.GetReference())) }) .ToArray()); } outerBlock.If(loopResult.GetReference().Member(EscapeTypeField).EqualTo(Js.Primitive(Continue)), ifTrue); } if (escapeStatements.Any(x => x.Type == Break)) { var escapes = escapeStatements.Where(x => x.Type == Break).Distinct(); JsStatement ifTrue; if (!escapes.Any(x => x.Label != null)) { ifTrue = Js.Break(); } else { ifTrue = Js.Switch(loopResult.GetReference().Member(EscapeLabelField), escapes.Select(x => Js.Section(Js.Primitive(x.Label)).Statement(Js.Break(x.Label))).ToArray()); } outerBlock.If(loopResult.GetReference().Member(EscapeTypeField).EqualTo(Js.Primitive(Break)), ifTrue); } return(outerBlock); } }
private JsExpression CreateAttributes(ISymbol symbol) { var result = Js.Array(); foreach (var attribute in symbol.GetAttributes().Where(x => x.AttributeClass.IsExported())) { if (!attribute.AttributeClass.IsExported()) continue; var attributeInstance = CreateObject(attribute.AttributeConstructor, attribute.ConstructorArguments.Select(x => GetConstantValue(x.Type, x.Value)).ToArray()); if (attribute.NamedArguments.Any()) { // Wrap initialization in an anonymous function var initializerBlock = new JsBlockStatement(); var variable = Js.Variable("$obj$", attributeInstance); initializerBlock.Local(variable); // Process named arguments foreach (var argument in attribute.NamedArguments) { initializerBlock.Express(variable.GetReference().Member("set_" + argument.Key).Invoke(Js.Literal(argument.Value))); } // Return obj initializerBlock.Return(Js.Reference("$obj$")); attributeInstance = Wrap(initializerBlock); } result.Elements.Add(attributeInstance); } return MakeArray(result, Context.Instance.Compilation.CreateArrayTypeSymbol(Context.Instance.Attribute)); }
/// <summary> /// This generates the entire state machine as an inline function. State machine fields are represented /// as closed variables of an outer function. The actual "MoveNext" function is an inner function. /// </summary> public JsBlockStatement GenerateYieldMethod(CSharpSyntaxNode node, IMethodSymbol method) { var block = new JsBlockStatement(); var stateMachineBody = Js.Block(); var stateMachineFunc = block.Local("$stateMachineFunc", Js.Function().Body(stateMachineBody)); ITypeSymbol elementType = Context.Instance.ObjectType; if (method.ReturnType is INamedTypeSymbol && ((INamedTypeSymbol)method.ReturnType).IsGenericType) { var genericType = (INamedTypeSymbol)method.ReturnType; genericType = genericType.OriginalDefinition; if (Equals(genericType, Context.Instance.IEnumerableT)) elementType = method.ReturnType.GetGenericArgument(Context.Instance.IEnumerableT, 0); else if (Equals(genericType, Context.Instance.IEnumeratorT)) elementType = method.ReturnType.GetGenericArgument(Context.Instance.IEnumeratorT, 0); } // Declare state machine fields var @this = stateMachineBody.Local(BaseStateGenerator.@this, Js.This()); stateMachineBody.Local(BaseStateGenerator.state, Js.Primitive(0)); var stateMachine = stateMachineBody.Local(BaseStateGenerator.stateMachine, CreateObject(Context.Instance.YieldIterator.Construct(elementType).Constructors.Single())); // var current = stateMachineBody.Local(YieldStateGenerator2.current, DefaultValue(elementType)); // var isStarted = stateMachineBody.Local("$isStarted", Js.Primitive(false)); // Create state generator and generate states var stateGenerator = new YieldStateGenerator(x => transformer, node, stateMachineBody, this, method); stateGenerator.GenerateStates(); var rootState = stateGenerator.TopState; // Called when the initial method needs to return the enumerator, and also when cloning. // Declare the moveNext function var moveNextBody = Js.Block(); var moveNext = stateMachineBody.Local(BaseStateGenerator.moveNext, Js.Function().Body(moveNextBody)); moveNextBody.Add(Js.Label("$top", Js.While(Js.Primitive(true), Js.Block(stateGenerator.GenerateSwitch(rootState), Js.Primitive(false).Return())))); stateMachineBody.Add(MapInterfaceMethod(stateMachine.GetReference(), Context.Instance.YieldIteratorDoMoveNext, Js.Function().Body(moveNext.GetReference().Member("call").Invoke(@this.GetReference()).Return()))); // Declare the clone function var cloneBody = Js.Block((stateMachineFunc.GetReference().Member("call").Invoke(@this.GetReference()).Return())); stateMachineBody.Add(MapInterfaceMethod(stateMachine.GetReference(), Context.Instance.YieldIteratorClone, Js.Function().Body(cloneBody))); // Generate the GetEnumerator method, which looks something like: // if ($isStarted) // return this.Clone().GetEnumerator(); // else // { // $isStarted = true; // return this; // } /* var getEnumeratorBody = Js.Block(); var getEnumerator = stateMachineBody.Local("$getEnumerator", Js.Function().Body(getEnumeratorBody)); getEnumeratorBody.Add(Js.If( isStarted.GetReference(), Invoke(clone.GetReference().Invoke(), Context.Instance.IEnumerableTGetEnumerator).Return(), Js.Block(isStarted.SetReference().Assign(Js.Primitive(true)).Express(), stateMachine.GetReference().Return()) )); */ /* ImplementInterfaceOnAdhocObject(stateMachineBody, stateMachine, Context.Instance.IEnumerable, new Dictionary<IMethodSymbol, JsExpression> { { Context.Instance.IEnumerableGetEnumerator, Js.Function().Body(getEnumerator.GetReference().Member("call").Invoke(@this.GetReference()).Return()) } }); ImplementInterfaceOnAdhocObject(stateMachineBody, stateMachine, Context.Instance.IEnumerableT, new Dictionary<IMethodSymbol, JsExpression> { { Context.Instance.IEnumerableTGetEnumerator, stateMachine.GetReference().Member(Context.Instance.IEnumerableGetEnumerator.GetMemberName()) } }); ImplementInterfaceOnAdhocObject(stateMachineBody, stateMachine, Context.Instance.IEnumerator, new Dictionary<IMethodSymbol, JsExpression> { { Context.Instance.IEnumeratorMoveNext, Js.Function().Body(moveNext.GetReference().Member("call").Invoke(@this.GetReference()).Return()) }, { Context.Instance.IEnumeratorCurrent.GetMethod, Js.Function().Body(current.GetReference().Return()) }, { Context.Instance.IEnumeratorReset, Js.Function() } }); ImplementInterfaceOnAdhocObject(stateMachineBody, stateMachine, Context.Instance.IEnumeratorT, new Dictionary<IMethodSymbol, JsExpression> { { Context.Instance.IEnumeratorTCurrent.GetMethod, Js.Function().Body(current.GetReference().Return()) } }); */ // The state machine function will be invoked by the outer body. It will expect the task // to be returned for non-void async methods. This task will be returned to the original // caller of the async method. stateMachineBody.Return(stateMachine.GetReference()); block.Add(stateMachineFunc.GetReference().Member("call").Invoke(Js.This()).Return()); return block; }
private JsExpression CreateMethodInfo(IMethodSymbol method, bool constructor = false) { JsExpression methodAttributes; switch (method.DeclaredAccessibility) { case Accessibility.Public: methodAttributes = GetEnumValue(Context.Instance.MethodAttributesPublic); break; case Accessibility.Internal: methodAttributes = GetEnumValue(Context.Instance.MethodAttributesAssembly); break; case Accessibility.Private: methodAttributes = GetEnumValue(Context.Instance.MethodAttributesPrivate); break; case Accessibility.Protected: methodAttributes = GetEnumValue(Context.Instance.MethodAttributesFamily); break; case Accessibility.ProtectedOrInternal: methodAttributes = GetEnumValue(Context.Instance.MethodAttributesFamORAssem); break; default: throw new Exception(); } if (method.IsStatic) { methodAttributes = EnumBitwise(SyntaxKind.BitwiseOrExpression, Context.Instance.MethodAttributes, methodAttributes, GetEnumValue(Context.Instance.MethodAttributesStatic)); } var returnType = method.ReturnType; JsExpression info = constructor ? CreateObject(Context.Instance.ConstructorInfoConstructor, Js.Primitive(method.GetMemberName()), GetMethodFunction(method, true), CreateParameterInfos(method.Parameters.ToArray()), methodAttributes, CreateAttributes(method)) : CreateObject(Context.Instance.MethodInfoConstructor, Js.Primitive(method.MetadataName), GetMethodFunction(method, true), CreateParameterInfos(method.Parameters.ToArray()), Type(returnType), methodAttributes, CreateAttributes(method)); if (method.TypeParameters.Any()) { var block = new JsBlockStatement(); foreach (var typeParameter in method.TypeParameters) { block.Local( typeParameter.Name, Js.Reference(SpecialNames.DefineTypeParameter).Invoke( Js.Reference(SpecialNames.Assembly), Js.Primitive(typeParameter.Name), Type(typeParameter.BaseType ?? Context.Instance.ObjectType, true))); } block.Return(info); info = Wrap(block); } return info; }
/// <summary> /// This generates the entire state machine as an inline function. State machine fields are represented /// as closed variables of an outer function. The actual "MoveNext" function is an inner function. /// </summary> public JsBlockStatement GenerateAsyncMethod(CSharpSyntaxNode node, IMethodSymbol method, Action<BaseStateGenerator, JsTransformer> nodeAcceptor = null) { var block = new JsBlockStatement(); var stateMachineBody = Js.Block(); var stateMachine = block.Local(BaseStateGenerator.stateMachine, Js.Function().Body(stateMachineBody)); // Declare state machine fields var @this = stateMachineBody.Local(BaseStateGenerator.@this, Js.This()); var state = stateMachineBody.Local(BaseStateGenerator.state, Js.Primitive(0)); var builder = stateMachineBody.Local(AsyncStateGenerator.builder, InvokeStatic(GetAsyncMethodBuilder(method))); // Start up the async process via a call to the builder's Start method. var moveNextBody = Js.Block(); var moveNext = stateMachineBody.Local(BaseStateGenerator.moveNext, Js.Function().Body(moveNextBody)); // Create state generator and generate states var stateGenerator = new AsyncStateGenerator(this, stateMachineBody, node, method, nodeAcceptor); stateGenerator.GenerateStates(); var rootState = stateGenerator.TopState; // Implement moveNext var moveNextTry = Js.Try(); moveNextBody.Add(moveNextTry); moveNextTry.Body = Js.Block( Js.Label("$top", Js.While(Js.Primitive(true), Js.Block(stateGenerator.GenerateSwitch(rootState), Js.Break()))) ); var moveNextCatchException = Js.Variable("$ex"); moveNextTry.Catch(moveNextCatchException); moveNextTry.Catch.Body = Js.Block( state.SetReference().Assign(Js.Primitive(-1)).Express(), builder.GetReference().Member("SetException").Invoke(moveNextCatchException.GetReference()).Express(), Js.Return() ); // Ensure the stateMachine function implements IAsyncStateMachine ImplementInterfaceOnAdhocObject(stateMachineBody, stateMachine, Context.Instance.IAsyncStateMachine, new Dictionary<IMethodSymbol, JsExpression> { { Context.Instance.IAsyncStateMachineMoveNext, Js.Function().Body(moveNext.GetReference().Member("call").Invoke(@this.GetReference()).Return()) }, { Context.Instance.IAsyncStateMachineSetStateMachine, Js.Null() } }); stateMachineBody.Express(builder.GetReference().Member("TrueStart").Invoke(stateMachine.GetReference())); // The state machine function will be invoked by the outer body. It will expect the task // to be returned for non-void async methods. This task will be returned to the original // caller of the async method. if (!method.ReturnsVoid) stateMachineBody.Return(builder.GetReference().Member("get_Task").Invoke()); var invokeStateMachine = stateMachine.GetReference().Member("call").Invoke(Js.This()); if (!method.ReturnsVoid) block.Add(invokeStateMachine.Return()); else block.Add(invokeStateMachine.Express()); return block; }
public bool TryApplyRefAndOutParametersAfterInvocation(IMethodSymbol method, JsInvocationExpression invocation, out JsExpression result, List<JsStatement> prependers, List<JsStatement> appenders) { // Finishing special handling of ref/out parameters -- doing the actual function wrapping here now that we // have the invocation. if (method.Parameters.Any(x => x.RefKind != RefKind.None)) { // It's a ref or out parameter, we need somewhere to store the value. var invocationStage = new JsBlockStatement(); foreach (var statement in prependers) invocationStage.Add(statement); invocationStage.Local("$result$", invocation); foreach (var statement in appenders) invocationStage.Add(statement); invocationStage.Return(Js.Reference("$result$")); result = Wrap(invocationStage); return true; } result = null; return false; }
public bool TryAsExpression(SyntaxKind type, ISymbol leftSymbol, ISymbol rightSymbol, JsExpression left, JsExpression right, out JsExpression result) { if (type == SyntaxKind.AsExpression) { var operand = (ITypeSymbol)rightSymbol; var asBody = new JsBlockStatement(); var asVariable = Js.Variable("$as$", left); asBody.Local(asVariable); var condition = Type(Context.Instance.TypeType) .Member("prototype") .Member(Context.Instance.TypeIsInstanceOfType.GetMemberName()) .Member("call") .Invoke(Type(operand).Member(SpecialNames.GetTypeFromType).Invoke(), asVariable.GetReference()); asBody.If(Js.Not(condition), asVariable.GetReference().Assign(Js.Null())); asBody.Return(asVariable.GetReference()); result = Wrap(asBody); return true; } result = null; return false; }
public bool TryCharUnaryExpression(SyntaxKind type, TypeInfo operandType, JsExpression operand, out JsExpression result) { if (Equals(operandType.Type, Context.Instance.Char)) { switch (type) { case SyntaxKind.PostDecrementExpression: case SyntaxKind.PostIncrementExpression: { var old = Js.Variable("$old", operand); var op = type == SyntaxKind.PostDecrementExpression ? JsBinaryOperator.Subtract : JsBinaryOperator.Add; result = Js.Binary( op, old.GetReference().Member("charCodeAt").Invoke(Js.Primitive(0)), Js.Primitive(1) ); result = operand.Assign(Js.Reference("String").Member("fromCharCode").Invoke(result)); var block = new JsBlockStatement(); block.Local(old); block.Express(result); block.Return(old.GetReference()); result = Wrap(block); return true; } case SyntaxKind.PreDecrementExpression: case SyntaxKind.PreIncrementExpression: { var op = type == SyntaxKind.PreDecrementExpression ? JsBinaryOperator.Subtract : JsBinaryOperator.Add; result = Js.Binary( op, operand.Member("charCodeAt").Invoke(Js.Primitive(0)), Js.Primitive(1) ); result = operand.Assign(Js.Reference("String").Member("fromCharCode").Invoke(result)); return true; } } } result = null; return false; }
public JsInvocationExpression CreateMulticastDelegate(JsExpression target, JsExpression invocationList) { var delegateBody = new JsBlockStatement(); var list = Js.Variable("$invocationList", invocationList); var i = Js.Variable("$i", Js.Primitive(0)); delegateBody.Add( Js.For( i, i.GetReference().LessThan(list.GetReference().Member("length")), i.GetReference().Increment() ) .Body(list.GetReference().Index(i.GetReference()).Member("apply").Invoke(Js.Null(), Js.Reference("arguments")).Express())); var delegateExpression = Js.Function(); delegateExpression.Body(delegateBody); var delegateVariable = Js.Variable("$delegate$", delegateExpression); var delegateType = invocationList.Index(Js.Primitive(0)).Member(SpecialNames.TypeField); var wrapper = new JsBlockStatement(); wrapper.Local(list); wrapper.Local(delegateVariable); wrapper.Assign(delegateVariable.GetReference().Member("prototype"), Js.New(Type(Context.Instance.MulticastDelegateType))); wrapper.Invoke(Type(Context.Instance.ObjectType).Member(SpecialNames.TypeInitializer), delegateVariable.GetReference(), delegateVariable.GetReference()); wrapper.Invoke(Type(Context.Instance.DelegateType).Member(SpecialNames.TypeInitializer), delegateVariable.GetReference(), delegateVariable.GetReference()); wrapper.Invoke(Type(Context.Instance.MulticastDelegateType).Member(SpecialNames.TypeInitializer), delegateVariable.GetReference(), delegateVariable.GetReference()); wrapper.Invoke(delegateType.Member(SpecialNames.TypeInitializer), delegateVariable.GetReference(), delegateVariable.GetReference()); wrapper.Express(InvokeMethodAs( Context.Instance.MulticastDelegateConstructor, delegateVariable.GetReference(), target, list.GetReference())); wrapper.Assign(delegateVariable.GetReference().Member(SpecialNames.TypeField), delegateType); wrapper.Return(delegateVariable.GetReference()); return Wrap(wrapper); }