public override JsNode _VisitDelegate(ITypeDefinition ce) { var CurrentType = new JsClrType { Kind = JsClrTypeKind.Delegate }; CurrentType.fullname = GetJsTypeName(ce); //Generate constructor var genericParams = new List <ITypeParameter>(ce.GetGenericArguments()); var func = new JsFunction(); func.Parameters = genericParams.Select(t => t.Name).ToList(); func.Parameters.Add("obj"); func.Parameters.Add("func"); func.Block = Js.Block(); foreach (var ga in genericParams) { func.Block.Add(Js.This().Member(ga.Name).Assign(Js.Member(ga.Name)).Statement()); } func.Block.Add(Js.Members("System.MulticastDelegate.ctor.call").Invoke(Js.This(), Js.Member("obj"), Js.Member("func")).Statement()); CurrentType.GetDefinition(false)["ctor"] = func; return(OnAfterExportType(ce, CurrentType)); //return func; //FullName',{ ShortName:function(T1,T2,T3,...,obj,func){this.T1=T1;....;this.construct(obj,func);}, })"); }
public JsNode VisitUsingStatement(UsingStatement node) { var st3 = Visit(node.ResourceAcquisition); JsVariableDeclarationStatement stVar; if (st3 is JsExpression) { stVar = Js.Var("$r" + VariableResourceCounter++, (JsExpression)st3).Statement(); } else { stVar = (JsVariableDeclarationStatement)st3; } var trySt = VisitStatement(node.EmbeddedStatement); var st2 = new JsTryStatement { TryBlock = trySt.ToBlock(), FinallyBlock = Js.Block() }; //var resource = node.ResourceAcquisition; //var decl = resource as VariableDeclarationStatement; //if (decl == null || decl.Variables.Count == 0) // throw new Exception("using statement is supported only with the var keyword in javascript. Example: using(var g = new MyDisposable()){}"); foreach (var dr in stVar.Declaration.Declarators) { st2.FinallyBlock.Add(Js.Member(dr.Name).Member("Dispose").Invoke().Statement()); } return(Js.Block().Add(stVar).Add(st2)); //TODO: get rid of block }
public JsBlockStatement GotoStateBlock(State newState) { return(Js.Block( ChangeState(newState), GotoTop() )); }
protected override Expression VisitBlock(BlockExpression node) { var list = new List <Js>(); foreach (var e in node.Expressions) { Visit(e); list.Add(constructed); } constructed = Js.Block(list.ToArray()); return(node); }
public void Process() { AfterFunction = BeforeFunction; SetParents(BeforeFunction.Block); foreach (var me in BeforeFunction.Block.Descendants <JsMemberExpression>().ToList()) { if (me.PreviousMember == null && me.NodeType == JsNodeType.MemberExpression) { me.PreviousMember = Js.This(); } } BeginNewStep(); ProcessStatement(BeforeFunction.Block); BeforeFunction.Block.Statements.Clear(); var func = new JsFunction { Block = new JsBlock { Statements = new List <JsStatement>() } }; var i = 0; func.Block.Statements.Add(Js.Var("result").Statement()); var stSwitch = Js.Switch(_state()); var lastStep = Js.Block().Add(_state().Assign(Js.Value(Steps.Count)).Statement()).Add(new JsBreakStatement()); Steps.Add(new YieldStep { Statements = { lastStep } }); foreach (var step in Steps) { stSwitch.Case(Js.Value(i), step.Statements); i++; } func.Block.Statements.Add(stSwitch); func.Block.Statements.Add(Js.Member("result").Assign(Js.Value(false)).Statement()); func.Block.Statements.Add(Js.Return(Js.Member("result"))); BeforeFunction.Block.Statements.Add(Js.Return(Js.New(Js.Member("CustomEnumerable"), func))); return; }
public override JsNode VisitAwaitExpression(AwaitExpressionSyntax node) { var operand = (JsExpression)node.Expression.Accept(this); /* * var expressionInfo = stateGenerator.Transformer.model.GetAwaitExpressionInfo(node); * if (expressionInfo.GetResultMethod == null) * { * var classText = node.FirstAncestorOrSelf<ClassDeclarationSyntax>().NormalizeWhitespace().ToString(); * var diagnostics = model.GetDiagnostics().Select(x => x.ToString()).ToArray(); * } * * var returnsVoid = expressionInfo.GetResultMethod.ReturnsVoid; */ var expressionInfo = stateGenerator.Transformer.model.GetTypeInfo(node).ConvertedType; var returnsVoid = expressionInfo.SpecialType == SpecialType.System_Void; var operandType = model.GetTypeInfo(node.Expression).ConvertedType; var awaiterMethodName = ((INamedTypeSymbol)operandType).GetMethodByName("GetAwaiter").GetMemberName(); // Store the awaiter in a field var awaiterIdentifier = stateGenerator.HoistVariable(new LiftedVariableKey("$awaiter")); var awaiter = awaiterIdentifier.GetReference(); stateGenerator.CurrentState.Add(awaiter.Assign(operand.Member(awaiterMethodName).Invoke()).Express()); var nextState = stateGenerator.InsertState(); JsExpression result = null; if (!returnsVoid) { // If the await returns a value, store it in a field var resultIdentifier = stateGenerator.HoistVariable(new LiftedVariableKey("$result")); result = resultIdentifier.GetReference(); // Make sure the field gets set from the awaiter at the beginning of the next state. nextState.Add(result.Assign(awaiter.Member("GetResult").Invoke()).Express()); } else { // We still need to call GetResult even if void in order to propagate exceptions nextState.Add(awaiter.Member("GetResult").Invoke().Express()); } // Set the state to the next state stateGenerator.CurrentState.Add(stateGenerator.ChangeState(nextState)); stateGenerator.CurrentState.Add(Js.If( awaiter.Member("get_IsCompleted").Invoke(), // If the awaiter is already completed, go to the next state stateGenerator.GotoTop(), // Otherwise await for completion Js.Block( // Start the async process Js.Reference(builder) .Member("TrueAwaitOnCompleted") .Invoke(awaiterIdentifier.GetReference(), Js.Reference(stateMachine)) .Express(), Js.Return() ) )); stateGenerator.CurrentState = nextState; return(result ?? Js.Null()); }
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); } }
public JsNode VisitForeachStatement(ForeachStatement node) { if (node.InExpression != null) { var expRes = node.InExpression.Resolve(); var et = expRes.Type.GetDefinitionOrArrayType(); //var et = node.expression.entity_typeref.GetEntityType(); if (et != null) { var jta = Sk.GetJsTypeAttribute(et); if (jta != null && jta.NativeEnumerator) { var node2 = new JsForInStatement { Initializer = Js.Var(node.VariableName), Member = VisitExpression(node.InExpression), Statement = VisitStatement(node.EmbeddedStatement) }; return(node2); } else if (jta != null && jta.NativeArrayEnumerator) { VariableIteratorCounter++; var iteratorName = "$i" + VariableIteratorCounter; var lengthCacheName = "$l" + VariableIteratorCounter; var exp2 = VisitExpression(node.InExpression); var target = exp2; var targetCacheName = "$t" + VariableIteratorCounter; if (exp2.NodeType != JsNodeType.MemberExpression || ((JsMemberExpression)exp2).PreviousMember != null) //is not simple name { target = Js.Member(targetCacheName); } var itemAccess = target.IndexerAccess(Js.Member(iteratorName)); var node2 = new JsForStatement(); node2.Condition = Js.Member(iteratorName).LessThan(Js.Member(lengthCacheName)); node2.Iterators = new List <JsStatement> { Js.Member(iteratorName).PlusPlus().Statement(), Js.Member(node.VariableName).Assign(itemAccess).Statement() }; if (target != exp2) //use target caching { node2.Initializers = new List <JsStatement> { Js.Var(iteratorName, Js.Value(0)).AndVar(targetCacheName, exp2.Clone()).AndVar(lengthCacheName, target.Clone().Member("length")).AndVar(node.VariableName, itemAccess.Clone()).Statement() }; } else { node2.Initializers = new List <JsStatement> { Js.Var(iteratorName, Js.Value(0)).AndVar(lengthCacheName, exp2.Clone().Member("length")).AndVar(node.VariableName, itemAccess.Clone()).Statement() }; } node2.Statement = VisitStatement(node.EmbeddedStatement); return(node2); } } } var iteratorName2 = "$it" + VariableIteratorCounter; VariableIteratorCounter++; var node3 = Js.Var(iteratorName2, VisitExpression(node.InExpression).Member("GetEnumerator").Invoke()).Statement(); var whileNode = Js.While(Js.Member(iteratorName2).Member("MoveNext").Invoke()); var getCurrentStatement = Js.Var(node.VariableName, Js.Member(iteratorName2).Member("get_Current").Invoke()).Statement(); var jsStatement = VisitStatement(node.EmbeddedStatement); JsBlock block; if (jsStatement is JsBlock) { block = (JsBlock)jsStatement; } else { block = Js.Block().Add(jsStatement); } block.Statements.Insert(0, getCurrentStatement); whileNode.Statement = block; var block2 = Js.Block().Add(node3).Add(whileNode); return(block2); }
protected JsBlock ExportMethodBody(IMethod me) { if (CompilerConfiguration.Current.EnableLogging) { Log.Debug("JsTypeImporter: Visit Method: " + me.ToString()); } var nativeCode = Sk.GetNativeCode(me); if (nativeCode != null) { var block = Js.Block().Add(Js.CodeStatement(nativeCode)); //TODO: double semicolon? return(block); } var def = me.GetDefinition(); if (def == null || def.IsNull) { if (me.IsAutomaticEventAccessor()) { if (me.IsEventAddAccessor()) { var node = GenerateAutomaticEventAccessor((IEvent)me.GetOwner(), false); return(node.Block); } else if (me.IsEventRemoveAccessor()) { var node = GenerateAutomaticEventAccessor((IEvent)me.GetOwner(), true); return(node.Block); } } else if (me.IsAutomaticPropertyAccessor()) { var bf = Js.Member(AutoPropertyPrefix + SkJs.GetEntityJsName(me.AccessorOwner)); if (!me.IsStatic) { bf.PreviousMember = Js.This(); } else if (!Sk.IsGlobalMethod(me)) { bf.PreviousMember = SkJs.EntityToMember(me.DeclaringTypeDefinition); } if (me.IsGetter()) { return(Js.Block().Add(Js.Return(bf))); } else { return(Js.Block().Add(bf.Assign(Js.Member("value")).Statement())); } } return(null); } var block2 = (JsBlock)AstNodeConverter.Visit(def); block2.ContainsYield = false; if (def.Descendants.OfType <YieldReturnStatement>().FirstOrDefault() != null) { block2.ContainsYield = true; if (!AstNodeConverter.SupportClrYield) { if (block2.Statements == null) { block2.Statements = new List <JsStatement>(); } //block2.Statements.Insert(0, Js.Var("$yield", Js.NewJsonArray()).Statement()); //block2.Statements.Add(AstNodeConverter.GenerateYieldReturnStatement(me)); } } return(block2); }
public override void VisitUsingStatement(UsingStatementSyntax node) { var afterTry = GetNextState(); var newTryStatement = Js.Try(); // Keep track of exception, if any, so we can rethrow var exceptionIdentifier = HoistVariable(new LiftedVariableKey("$usingex")); // Identifier for caught exception var caughtExceptionIdentifier = UniqueName("$caughtex"); // Hoist the variable into a field var disposables = new List <JsExpression>(); if (node.Declaration != null) { foreach (var variable in node.Declaration.Variables) { var symbol = (ILocalSymbol)Transformer.Model.GetDeclaredSymbol(variable); var identifier = HoistVariable(new LiftedVariableKey(variable.Identifier, symbol)); var name = identifier.GetReference(); disposables.Add(name); CurrentState.Add(name.Assign((JsExpression)variable.Initializer.Value.Accept(Transformer)).Express()); } } if (node.Expression != null) { var identifier = Js.Reference(UniqueName("$using")); disposables.Add(identifier); CurrentState.Add(identifier.Assign((JsExpression)node.Expression.Accept(Transformer)).Express()); } var tryState = NewSubstate(); GotoState(tryState); var finallyState = GetNextState(); CurrentState = finallyState; foreach (var disposable in disposables) { CurrentState.Add(disposable.Member("Dispose").Invoke().Express()); } CurrentState.Add(Js.If(exceptionIdentifier.GetReference().NotEqualTo(Js.Null()), Js.Throw(exceptionIdentifier.GetReference()))); GotoState(afterTry); newTryStatement.Catch = Js.Catch(Js.Variable(caughtExceptionIdentifier)); newTryStatement.Catch.Body = Js.Block( new[] { exceptionIdentifier.GetReference().Assign(Js.Reference(caughtExceptionIdentifier)).Express() } .Concat(GotoStateStatements(finallyState)) .ToArray() ); tryState.Wrap = switchStatement => { newTryStatement.Body = Js.Block(switchStatement); return(newTryStatement); }; StartSubstate(tryState); AcceptStatement(node.Statement); GotoState(finallyState); EndSubstate(); CurrentState = afterTry; }
public override void VisitTryStatement(TryStatementSyntax node) { var afterTry = GetNextState(); var newTryStatement = Js.Try(); var tryState = NewSubstate(); GotoState(tryState); // Keep track of exception, if any, so we can rethrow var exceptionIdentifier = HoistVariable(new LiftedVariableKey("$ex")); var exceptionVariable = UniqueName("$caughtex"); State finallyState = node.Finally == null ? null : GetNextState(); // Declare a block to store all the catch statements the try statement's only catch clause. (No // type-specific catch clauses in Javascript var catchBlock = Js.Block(); // Make sure that the exception is stored in a variable accessible to the entire state machine. catchBlock.Express(exceptionIdentifier.GetReference().Assign(Js.Reference(exceptionVariable))); foreach (var catchClause in node.Catches) { // Get the symbol that represents the exception declaration (identifier and type) var symbol = Transformer.Model.GetDeclaredSymbol(catchClause.Declaration); var exceptionType = symbol == null ? null : symbol.Type; if (exceptionType == null && catchClause.Declaration != null && catchClause.Declaration.Type != null) { exceptionType = (ITypeSymbol)Transformer.Model.GetSymbolInfo(catchClause.Declaration.Type).Symbol; } // True if it is actually declaring the variable (as opposed to a catch clause that specifies // merely an exception type var hasDeclaration = catchClause.Declaration.Identifier.Kind() != SyntaxKind.None; // A variable to store the new unique identifier to store the exception IJsDeclaration newIdentifier; // Hoist the variable into a field if (hasDeclaration) { newIdentifier = HoistVariable(new LiftedVariableKey(catchClause.Declaration.Identifier, symbol)); } else { newIdentifier = HoistVariable(new LiftedVariableKey(SyntaxFactory.Identifier("ex"))); } // Collect all the catch statements into the catchState by making that state current var catchState = GetNextState(); CurrentState = catchState; AcceptStatement(catchClause.Block); // Add onto the catch state some commands to go to the next state. if (finallyState != null) { GotoState(finallyState); } else { GotoState(afterTry); } // Create the statements that will live in the actual catch handler, which directs the logic // to the actual catch state and also stores the exception in the correct identifier. var thisCatchStatements = Js.Block(); thisCatchStatements.Express(newIdentifier.SetReference().Assign(exceptionIdentifier.GetReference())); // Apply filter if present if (catchClause.Filter != null) { var filter = (JsExpression)catchClause.Filter.FilterExpression.Accept(Transformer); thisCatchStatements.Add(Js.If(filter, Js.Block(GotoStateStatements(catchState)))); } else { thisCatchStatements.AddRange(GotoStateStatements(catchState)); } // Only do the above if the current exception is of the type expected by the catch handler. var condition = Idioms.Is(exceptionIdentifier.GetReference(), exceptionType); catchBlock.Add(Js.If(condition, thisCatchStatements)); } if (node.Finally != null) { // Collect the statements of the finally block into the finally state CurrentState = finallyState; AcceptStatement(node.Finally.Block); // If the exception object is not null, then rethrow it. In other words, if this is a finally // clause that has responded to an exception, we need to propagate the exception rather than // continue after the try statement. Otherwise, go to the code after the try block. CurrentState.Add(Js.If(exceptionIdentifier.GetReference().NotEqualTo(Js.Null()), Js.Throw(exceptionIdentifier.GetReference()), Js.Block(GotoStateStatements(afterTry)))); // Finally, at the very end of the catch clause (and we can only get here if the logic didn't break // out as it would with the logic in the catch handlers) go to the finally state. catchBlock.AddRange(GotoStateStatements(finallyState).ToArray()); } catchBlock.Add(Js.Throw(exceptionIdentifier.GetReference())); newTryStatement.Catch = Js.Catch(Js.Variable(exceptionVariable)); newTryStatement.Catch.Body = catchBlock; tryState.Wrap = switchStatement => { newTryStatement.Body = Js.Block(switchStatement); return(newTryStatement); }; StartSubstate(tryState); AcceptStatement(node.Block); if (node.Finally != null) { GotoState(finallyState); } else { GotoState(afterTry); } EndSubstate(); CurrentState = afterTry; }