internal JsBlockStatement Process(JsBlockStatement statement) { _allocateFinallyHandler = null; _makeSetCurrent = null; var result = Process(statement, false, false); var hoistResult = VariableHoistingVisitor.Process(result); return(new JsBlockStatement(new[] { new JsVariableDeclarationStatement(new[] { new JsVariableDeclaration(_stateVariableName, JsExpression.Number(0)) }.Concat(hoistResult.Item2.Select(v => new JsVariableDeclaration(v, null)))) }.Concat(hoistResult.Item1.Statements))); }
public void NewArgumentListContainsNoSpaces() { AssertCorrect(JsExpression.New(JsExpression.Identifier("x"), null), "new x"); AssertCorrect(JsExpression.New(JsExpression.Identifier("x")), "new x()"); AssertCorrect(JsExpression.New(JsExpression.Identifier("x"), JsExpression.Number(1), JsExpression.Number(2), JsExpression.Number(3)), "new x(1,2,3)"); }
public void ObjectLiteralsContainNoEmbeddedSpaces() { AssertCorrect(JsExpression.ObjectLiteral(), "{}"); AssertCorrect(JsExpression.ObjectLiteral(new JsObjectLiteralProperty("x", JsExpression.Number(1))), "{x:1}"); AssertCorrect(JsExpression.ObjectLiteral(new JsObjectLiteralProperty("x", JsExpression.Number(1)), new JsObjectLiteralProperty("y", JsExpression.Number(2)), new JsObjectLiteralProperty("z", JsExpression.Number(3))), "{x:1,y:2,z:3}"); }
public void IfStatementIsCorrectlyOutput() { AssertCorrect(new JsIfStatement(JsExpression.True, new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), null), "if(true){i=0;}"); AssertCorrect(new JsIfStatement(JsExpression.True, new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(1)))), "if(true){i=0;}else{i=1;}"); }
public void WhileStatementIsCorrectlyOutput() { AssertCorrect(new JsWhileStatement(JsExpression.True, new JsBlockStatement(new JsVariableDeclarationStatement(new JsVariableDeclaration("x", JsExpression.Number(0))))), "while(true){var x=0;}"); }
private static JsExpression ConstructConstructorInfo(IMethod constructor, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, Func <IType, JsExpression> instantiateType, bool includeDeclaringType) { var properties = GetCommonMemberInfoProperties(constructor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType); var sem = metadataImporter.GetConstructorSemantics(constructor); if (sem.Type == ConstructorScriptSemantics.ImplType.NotUsableFromScript) { errorReporter.Message(Messages._7200, constructor.FullName); return(JsExpression.Null); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Constructor))); properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(constructor.Parameters.Select(p => instantiateType(p.Type))))); if (sem.Type == ConstructorScriptSemantics.ImplType.NamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name))); } if (sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod) { properties.Add(new JsObjectLiteralProperty("sm", JsExpression.True)); } if ((sem.Type == ConstructorScriptSemantics.ImplType.UnnamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.NamedConstructor || sem.Type == ConstructorScriptSemantics.ImplType.StaticMethod) && sem.ExpandParams) { properties.Add(new JsObjectLiteralProperty("exp", JsExpression.True)); } if (sem.Type == ConstructorScriptSemantics.ImplType.Json || sem.Type == ConstructorScriptSemantics.ImplType.InlineCode) { var usedNames = new HashSet <string>(); var parameters = new List <IVariable>(); var variables = new Dictionary <IVariable, VariableData>(); IList <ResolveResult> constructorParameters = null; IList <ResolveResult> initializerStatements = null; if (sem.Type == ConstructorScriptSemantics.ImplType.Json && constructor.DeclaringType.Kind == TypeKind.Anonymous) { initializerStatements = new List <ResolveResult>(); foreach (var p in constructor.DeclaringType.GetProperties()) { string paramName = MakeCamelCase(p.Name); string name = namer.GetVariableName(paramName, usedNames); usedNames.Add(name); var variable = new SimpleVariable(p.ReturnType, paramName, DomRegion.Empty); parameters.Add(variable); variables.Add(variable, new VariableData(name, null, false)); initializerStatements.Add(new OperatorResolveResult(p.ReturnType, ExpressionType.Assign, new MemberResolveResult(new InitializedObjectResolveResult(constructor.DeclaringType), p), new LocalResolveResult(variable))); } } else { constructorParameters = new List <ResolveResult>(); foreach (var p in constructor.Parameters) { string name = namer.GetVariableName(p.Name, usedNames); usedNames.Add(name); var variable = new SimpleVariable(p.Type, p.Name, DomRegion.Empty); parameters.Add(variable); variables.Add(variable, new VariableData(name, null, false)); constructorParameters.Add(new LocalResolveResult(variable)); } } var compileResult = CompileConstructorInvocation(constructor, initializerStatements, constructor.DeclaringTypeDefinition, constructor, constructorParameters, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, variables, usedNames); var definition = JsExpression.FunctionDefinition(parameters.Select(p => variables[p].Name), new JsBlockStatement(compileResult.AdditionalStatements.Concat(new[] { new JsReturnStatement(compileResult.Expression) }))); properties.Add(new JsObjectLiteralProperty("def", definition)); } return(JsExpression.ObjectLiteral(properties)); }
public void VariableDeclarationStatementsAreCorrectlyOutput() { AssertCorrect(new JsVariableDeclarationStatement(new[] { new JsVariableDeclaration("i", null) }), "var i;"); AssertCorrect(new JsVariableDeclarationStatement(new[] { new JsVariableDeclaration("i", null), new JsVariableDeclaration("j", null) }), "var i,j;"); AssertCorrect(new JsVariableDeclarationStatement(new[] { new JsVariableDeclaration("i", JsExpression.Number(0)) }), "var i=0;"); AssertCorrect(new JsVariableDeclarationStatement(new[] { new JsVariableDeclaration("i", JsExpression.Number(0)), new JsVariableDeclaration("j", JsExpression.Number(1)) }), "var i=0,j=1;"); AssertCorrect(new JsVariableDeclarationStatement(new[] { new JsVariableDeclaration("i", JsExpression.Number(0)), new JsVariableDeclaration("j", null) }), "var i=0,j;"); }
private void AddClassMembers(JsClass c, JsExpression typeRef, ICompilation compilation, List <JsStatement> stmts) { ICollection <JsMethod> instanceMethods; if (_metadataImporter.IsTestFixture(c.CSharpTypeDefinition)) { var tests = new List <Tuple <string, string, bool, int?, JsFunctionDefinitionExpression> >(); var instanceMethodList = new List <JsMethod>(); foreach (var m in c.InstanceMethods) { var td = (m.CSharpMember is IMethod ? _metadataImporter.GetTestData((IMethod)m.CSharpMember) : null); if (td != null) { tests.Add(Tuple.Create(td.Description, td.Category, td.IsAsync, td.ExpectedAssertionCount, m.Definition)); } else { instanceMethodList.Add(m); } } var testInvocations = new List <JsExpression>(); foreach (var category in tests.GroupBy(t => t.Item2).Select(g => new { Category = g.Key, Tests = g.Select(x => new { Description = x.Item1, IsAsync = x.Item3, ExpectedAssertionCount = x.Item4, Function = x.Item5 }) }).OrderBy(x => x.Category)) { if (category.Category != null) { testInvocations.Add(JsExpression.Invocation(JsExpression.Identifier("module"), JsExpression.String(category.Category))); } testInvocations.AddRange(category.Tests.Select(t => JsExpression.Invocation(JsExpression.Identifier(t.IsAsync ? "asyncTest" : "test"), t.ExpectedAssertionCount != null ? new JsExpression[] { JsExpression.String(t.Description), JsExpression.Number(t.ExpectedAssertionCount.Value), _runtimeLibrary.Bind(t.Function, JsExpression.This) } : new JsExpression[] { JsExpression.String(t.Description), _runtimeLibrary.Bind(t.Function, JsExpression.This) }))); } instanceMethodList.Add(new JsMethod(null, "runTests", null, JsExpression.FunctionDefinition(new string[0], new JsBlockStatement(testInvocations.Select(t => new JsExpressionStatement(t)))))); instanceMethods = instanceMethodList; } else { instanceMethods = c.InstanceMethods; } if (instanceMethods.Count > 0) { stmts.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, Prototype), JsExpression.ObjectLiteral(instanceMethods.Select(m => new JsObjectLiteralProperty(m.Name, m.Definition != null ? RewriteMethod(m) : JsExpression.Null)))))); } if (c.NamedConstructors.Count > 0) { stmts.AddRange(c.NamedConstructors.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, m.Name), m.Definition)))); stmts.Add(new JsExpressionStatement(c.NamedConstructors.Reverse().Aggregate((JsExpression)JsExpression.MemberAccess(typeRef, Prototype), (right, ctor) => JsExpression.Assign(JsExpression.MemberAccess(JsExpression.MemberAccess(typeRef, ctor.Name), Prototype), right)))); // This generates a statement like {C}.ctor1.prototype = {C}.ctor2.prototype = {C}.prototoype } var defaultConstructor = c.CSharpTypeDefinition.GetConstructors().SingleOrDefault(x => x.Parameters.Count == 0 && x.IsPublic); if (defaultConstructor != null) { JsExpression createInstance = CreateDefaultConstructorInvocation(defaultConstructor, typeRef); if (createInstance != null) { stmts.Add(new JsExpressionStatement( JsExpression.Assign( JsExpression.MemberAccess(typeRef, "createInstance"), JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(createInstance))))); } } stmts.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, m.Name), RewriteMethod(m))))); if (c.TypeArgumentNames.Count > 0) { if (c.ClassType == JsClass.ClassTypeEnum.Interface) { stmts.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterGenericInterfaceInstance), typeRef, new JsTypeReferenceExpression(compilation.MainAssembly, c.Name), JsExpression.ArrayLiteral(c.TypeArgumentNames.Select(JsExpression.Identifier)), JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(JsExpression.ArrayLiteral(c.ImplementedInterfaces)))))); } else { stmts.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterGenericClassInstance), typeRef, new JsTypeReferenceExpression(compilation.MainAssembly, c.Name), JsExpression.ArrayLiteral(c.TypeArgumentNames.Select(JsExpression.Identifier)), JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(c.BaseClass)), JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(JsExpression.ArrayLiteral(c.ImplementedInterfaces)))))); } } }
public IList <JsStatement> Rewrite(IEnumerable <JsType> types, ICompilation compilation) { var netSystemType = compilation.FindType(KnownTypeCode.Type).GetDefinition(); var systemType = new JsTypeReferenceExpression(netSystemType.ParentAssembly, _metadataImporter.GetTypeSemantics(netSystemType).Name); var result = new List <JsStatement>(); var orderedTypes = OrderByNamespace(types, t => t.Name).ToList(); string currentNs = ""; foreach (var t in orderedTypes) { try { var globalMethodsPrefix = _metadataImporter.GetGlobalMethodsPrefix(t.CSharpTypeDefinition); string ns = GetNamespace(t.Name); if (ns != currentNs && globalMethodsPrefix == null) { result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(systemType, RegisterNamespace), JsExpression.String(ns)))); currentNs = ns; } result.Add(new JsComment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + t.CSharpTypeDefinition.FullName)); var typeRef = new JsTypeReferenceExpression(compilation.MainAssembly, t.Name); if (t is JsClass) { var c = (JsClass)t; if (globalMethodsPrefix != null) { if (globalMethodsPrefix == "") { result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.MemberAccess(JsExpression.Identifier("window"), m.Name), m.Definition)))); } else { result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(MakeNestedMemberAccess(globalMethodsPrefix + "." + m.Name), m.Definition)))); } } else if (_metadataImporter.IsResources(t.CSharpTypeDefinition)) { result.Add(GenerateResourcesClass(c)); } else { var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement); if (c.TypeArgumentNames.Count == 0) { result.Add(new JsExpressionStatement(JsExpression.Assign(typeRef, unnamedCtor))); AddClassMembers(c, typeRef, compilation, result); } else { var stmts = new List <JsStatement> { new JsVariableDeclarationStatement(InstantiatedGenericTypeVariableName, unnamedCtor) }; AddClassMembers(c, JsExpression.Identifier(InstantiatedGenericTypeVariableName), compilation, stmts); stmts.AddRange(c.StaticInitStatements); stmts.Add(new JsReturnStatement(JsExpression.Identifier(InstantiatedGenericTypeVariableName))); result.Add(new JsExpressionStatement(JsExpression.Assign(typeRef, JsExpression.FunctionDefinition(c.TypeArgumentNames, new JsBlockStatement(stmts))))); result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, c.ClassType == JsClass.ClassTypeEnum.Interface ? RegisterGenericInterface : RegisterGenericClass), JsExpression.String(c.Name), JsExpression.Number(c.TypeArgumentNames.Count)))); } } } else if (t is JsEnum) { var e = (JsEnum)t; bool flags = GetAttributePositionalArgs(t.CSharpTypeDefinition, FlagsAttribute, "System") != null; result.Add(new JsExpressionStatement(JsExpression.Assign(typeRef, JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement)))); result.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.MemberAccess(typeRef, Prototype), JsExpression.ObjectLiteral(e.Values.Select(v => new JsObjectLiteralProperty(v.Name, (_metadataImporter.IsNamedValues(t.CSharpTypeDefinition) ? JsExpression.String(v.Name) : JsExpression.Number(v.Value)))))))); result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterEnum), JsExpression.String(t.Name), JsExpression.Boolean(flags)))); } } catch (Exception ex) { _errorReporter.Region = t.CSharpTypeDefinition.Region; _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName); } } var typesToRegister = orderedTypes.OfType <JsClass>() .Where(c => c.TypeArgumentNames.Count == 0 && _metadataImporter.GetGlobalMethodsPrefix(c.CSharpTypeDefinition) == null && !_metadataImporter.IsResources(c.CSharpTypeDefinition)) .ToList(); result.AddRange(TopologicalSortTypesByInheritance(typesToRegister) .Select(c => { try { var typeRef = new JsTypeReferenceExpression(compilation.MainAssembly, c.Name); if (c.ClassType == JsClass.ClassTypeEnum.Interface) { return(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterInterface), JsExpression.String(c.Name), JsExpression.ArrayLiteral(c.ImplementedInterfaces))); } else { return(CreateRegisterClassCall(JsExpression.String(c.Name), c.BaseClass, c.ImplementedInterfaces, typeRef)); } } catch (Exception ex) { _errorReporter.Region = c.CSharpTypeDefinition.Region; _errorReporter.InternalError(ex, "Error formatting type " + c.CSharpTypeDefinition.FullName); return(JsExpression.Number(0)); } }) .Select(expr => new JsExpressionStatement(expr))); result.AddRange(orderedTypes.OfType <JsClass>().Where(c => c.TypeArgumentNames.Count == 0 && !_metadataImporter.IsResources(c.CSharpTypeDefinition)).SelectMany(t => t.StaticInitStatements)); return(result); }
private bool HandleTryStatement(JsTryStatement stmt, StackEntry location, ImmutableStack <StackEntry> stack, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, State currentState, State returnState, IList <JsStatement> currentBlock) { if (_isIteratorBlock && (FindInterestingConstructsVisitor.Analyze(stmt.GuardedStatement, InterestingConstruct.YieldReturn) || (stmt.Finally != null && stmt.Catch == null && !currentState.FinallyStack.IsEmpty))) { if (stmt.Catch != null) { throw new InvalidOperationException("Cannot yield return from try with catch"); } string handlerName = _allocateFinallyHandler(); JsBlockStatement handler; if (FindInterestingConstructsVisitor.Analyze(stmt.Finally, InterestingConstruct.Label)) { var inner = ProcessInner(stmt.Finally, breakStack, continueStack, currentState.FinallyStack, currentState.StateValue); handler = new JsBlockStatement(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1)); handler = new FinalizerRewriter(_stateVariableName, _labelStates).Process(handler); } else { handler = stmt.Finally; } _finallyHandlers.Add(Tuple.Create(handlerName, handler)); var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState); var innerState = CreateNewStateValue(currentState.FinallyStack, handlerName); var stateBeforeFinally = CreateNewStateValue(innerState.FinallyStack); currentBlock.Add(new JsSetNextStateStatement(innerState.StateValue)); currentBlock.AddRange(Handle(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(stmt.GuardedStatement, 0)), breakStack, continueStack, innerState, stateBeforeFinally)); Enqueue(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(new JsBlockStatement(new JsBlockStatement(new JsStatement[0], true)), 0)), breakStack, continueStack, stateBeforeFinally, stateAfter.Item1); if (!stack.IsEmpty || location.Index < location.Block.Statements.Count - 1) { Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState); } return(false); } else if (_isIteratorBlock && stmt.Finally != null && !currentState.FinallyStack.IsEmpty) { // This is necessary to special-case in order to ensure that the inner finally block is executed before all outer ones. return(HandleTryStatement(new JsTryStatement(new JsTryStatement(stmt.GuardedStatement, stmt.Catch, null), null, stmt.Finally), location, stack, breakStack, continueStack, currentState, returnState, currentBlock)); } else { var rewriter = new NestedJumpStatementRewriter(breakStack, continueStack, currentState, _exitState.Value); JsBlockStatement guarded; var guardedConstructs = FindInterestingConstructsVisitor.Analyze(stmt.GuardedStatement); if ((guardedConstructs & (InterestingConstruct.Label | InterestingConstruct.Await)) != InterestingConstruct.None) { var inner = ProcessInner(stmt.GuardedStatement, breakStack, continueStack, currentState.FinallyStack, currentState.StateValue); guarded = new JsBlockStatement(inner.Item1); currentBlock.Add(new JsSetNextStateStatement(inner.Item2)); } else { guarded = rewriter.Process(stmt.GuardedStatement); } JsCatchClause @catch; if (stmt.Catch != null) { if (FindInterestingConstructsVisitor.Analyze(stmt.Catch.Body, InterestingConstruct.Label)) { var inner = ProcessInner(stmt.Catch.Body, breakStack, continueStack, currentState.FinallyStack, null); @catch = new JsCatchClause(stmt.Catch.Identifier, new JsBlockStatement(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1))); } else { var body = rewriter.Process(stmt.Catch.Body); @catch = ReferenceEquals(body, stmt.Catch.Body) ? stmt.Catch : new JsCatchClause(stmt.Catch.Identifier, body); } } else { @catch = null; } JsBlockStatement @finally; if (stmt.Finally != null) { if (FindInterestingConstructsVisitor.Analyze(stmt.Finally, InterestingConstruct.Label)) { var inner = ProcessInner(stmt.Finally, breakStack, continueStack, currentState.FinallyStack, null); @finally = new JsBlockStatement(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1)); } else { @finally = rewriter.Process(stmt.Finally); } if ((guardedConstructs & InterestingConstruct.Await) != InterestingConstruct.None) { // Wrap the finally block inside an 'if (doFinallyBlocks) {}' @finally = new JsBlockStatement(new JsIfStatement(JsExpression.Identifier(_doFinallyBlocksVariableName), @finally, null)); } } else { @finally = null; } if (currentBlock.Count > 0 && _childStates.ContainsKey(currentState.StateValue)) { var newBlock = new JsIfStatement(JsExpression.Same(JsExpression.Identifier(_stateVariableName), JsExpression.Number(currentState.StateValue)), new JsBlockStatement(currentBlock), null); currentBlock.Clear(); currentBlock.Add(newBlock); } currentBlock.Add(new JsTryStatement(guarded, @catch, @finally)); return(true); } }
public JsExpression Default(IType type, IRuntimeContext context) { if (type.IsReferenceType == true || type.Kind == TypeKind.Dynamic || type.IsKnownType(KnownTypeCode.NullableOfT)) { return(JsExpression.Null); } else if (type.Kind == TypeKind.Enum) { return(MetadataUtils.IsNamedValues(type.GetDefinition(), _attributeStore) ? JsExpression.Null : JsExpression.Number(0)); } else if (type is ITypeDefinition) { switch (((ITypeDefinition)type).KnownTypeCode) { case KnownTypeCode.Boolean: return(JsExpression.False); case KnownTypeCode.NullableOfT: return(JsExpression.Null); case KnownTypeCode.DateTime: return(JsExpression.New(CreateTypeReferenceExpression(KnownTypeReference.DateTime), JsExpression.Number(0))); case KnownTypeCode.Byte: case KnownTypeCode.SByte: case KnownTypeCode.Char: case KnownTypeCode.Int16: case KnownTypeCode.UInt16: case KnownTypeCode.Int32: case KnownTypeCode.UInt32: case KnownTypeCode.Int64: case KnownTypeCode.UInt64: case KnownTypeCode.Decimal: case KnownTypeCode.Single: case KnownTypeCode.Double: return(JsExpression.Number(0)); } } return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "getDefaultValue"), GetScriptType(type, TypeContext.GetScriptType, context))); }
private Tuple <List <JsStatement>, int> ProcessInner(JsBlockStatement statement, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, ImmutableStack <Tuple <int, string> > finallyStack, int?parentState) { var oldLoopLabel = _currentLoopLabel; var oldRemainingBlocks = _remainingBlocks; try { _currentLoopLabel = _allocateLoopLabel(); _remainingBlocks = new Queue <RemainingBlock>(); _remainingBlocks.Enqueue(new RemainingBlock(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(statement, 0)), breakStack, continueStack, CreateNewStateValue(finallyStack), new State(_currentLoopLabel, -1, finallyStack))); if (_exitState == null) { _exitState = new State(_currentLoopLabel, -1, ImmutableStack <Tuple <int, string> > .Empty); } var sections = new List <Section>(); int iterationCount = 0; while (_remainingBlocks.Count > 0) { var current = _remainingBlocks.Dequeue(); var list = Handle(current.Stack, current.BreakStack, current.ContinueStack, current.StateValue, current.ReturnState, _isIteratorBlock || _isAsync); // Merge all top-level blocks that should be merged with their parents. list = list.SelectMany(stmt => (stmt is JsBlockStatement && ((JsBlockStatement)stmt).MergeWithParent) ? ((JsBlockStatement)stmt).Statements : (IList <JsStatement>) new[] { stmt }).ToList(); sections.Add(new Section(current.StateValue, list)); if (iterationCount++ > 100000) { throw new Exception("Infinite loop when rewriting method to a state machine"); } } if (parentState != null && _isAsync) { List <int> childStates; if (!_childStates.TryGetValue(parentState.Value, out childStates)) { _childStates[parentState.Value] = childStates = new List <int>(); } childStates.AddRange(sections.Select(s => s.State.StateValue)); } var body = new List <JsStatement> { new JsLabelledStatement(_currentLoopLabel, new JsForStatement(new JsEmptyStatement(), null, null, new JsSwitchStatement(JsExpression.Identifier(_stateVariableName), sections.Select(b => new JsSwitchSection( GetAllContainedStateValues(b.State.StateValue).OrderBy(v => v).Select(v => JsExpression.Number(v)), new JsBlockStatement(b.Statements))) .Concat(new[] { new JsSwitchSection(new JsExpression[] { null }, new JsBreakStatement(_currentLoopLabel)) })))) }; return(Tuple.Create(body, sections[0].State.StateValue)); } finally { _currentLoopLabel = oldLoopLabel; _remainingBlocks = oldRemainingBlocks; } }
private JsBlockStatement ProcessAsyncMethod(JsBlockStatement statement, string stateMachineMethodName, string doFinallyBlocksVariableName, JsVariableDeclaration taskCompletionSource, Func <JsExpression, JsExpression> makeSetResult, Func <JsExpression, JsExpression> makeSetException, Func <JsExpression> getTask) { _stateMachineMethodName = stateMachineMethodName; _doFinallyBlocksVariableName = doFinallyBlocksVariableName; _makeSetResult = taskCompletionSource != null ? makeSetResult : null; _needDoFinallyBlocksVariable = new HasAwaitInsideTryWithFinallyVisitor().Analyze(statement); var result = Process(statement, isIteratorBlock: false, isAsync: true); var hoistResult = VariableHoistingVisitor.Process(result); string catchVariable = _allocateTempVariable(); JsBlockStatement tryBody; if (taskCompletionSource != null && (statement.Statements.Count == 0 || IsNextStatementReachable(statement.Statements[statement.Statements.Count - 1]))) // If we return the task, and if we risk falling out of the original method, we need to add a setResult call. { tryBody = new JsBlockStatement(hoistResult.Item1.Statements.Concat(new[] { new JsExpressionStatement(makeSetResult(null)) })); } else { tryBody = hoistResult.Item1; } JsStatement body = new JsTryStatement(tryBody, new JsCatchClause(catchVariable, taskCompletionSource != null ? new JsBlockStatement(new JsExpressionStatement(makeSetException(JsExpression.Identifier(catchVariable)))) : JsBlockStatement.EmptyStatement), null); IEnumerable <JsVariableDeclaration> declarations = new[] { new JsVariableDeclaration(_stateVariableName, JsExpression.Number(0)) }; if (taskCompletionSource != null) { declarations = declarations.Concat(new[] { taskCompletionSource }); } declarations = declarations.Concat(hoistResult.Item2.Select(v => new JsVariableDeclaration(v, null))); if (_needDoFinallyBlocksVariable) { body = new JsBlockStatement(new JsVariableDeclarationStatement(_doFinallyBlocksVariableName, JsExpression.True), body); } IEnumerable <JsStatement> stmts = new JsStatement[] { new JsVariableDeclarationStatement(declarations), new JsVariableDeclarationStatement(stateMachineMethodName, JsExpression.FunctionDefinition(new string[0], body)), new JsExpressionStatement(JsExpression.Invocation(JsExpression.Identifier(stateMachineMethodName))) }; if (taskCompletionSource != null) { stmts = stmts.Concat(new[] { new JsReturnStatement(getTask()) }); } return(new JsBlockStatement(stmts)); }
private IteratorStateMachine ProcessIteratorBlock(JsBlockStatement statement, Func <string> allocateFinallyHandler, Func <JsExpression, JsExpression> makeSetCurrent) { _allocateFinallyHandler = allocateFinallyHandler; _makeSetCurrent = makeSetCurrent; var result = Process(statement, isIteratorBlock: true, isAsync: false); var stateFinallyHandlers = _allStates.Where(s => !s.FinallyStack.IsEmpty).Select(s => Tuple.Create(s.StateValue, s.FinallyStack.Select(x => x.Item2).Reverse().ToList())).ToList(); var hoistResult = VariableHoistingVisitor.Process(result); return(new IteratorStateMachine(hoistResult.Item1, new[] { new JsVariableDeclaration(_stateVariableName, JsExpression.Number(0)) }.Concat(hoistResult.Item2.Select(v => new JsVariableDeclaration(v, null))), _finallyHandlers.Select(h => Tuple.Create(h.Item1, JsExpression.FunctionDefinition(new string[0], h.Item2))), stateFinallyHandlers.Count > 0 ? DisposeGenerator.GenerateDisposer(_stateVariableName, stateFinallyHandlers) : null)); }
private static JsStatement GenerateBody(string stateVariableName, List <Node> nodes) { if (nodes.Count == 0) { return(JsBlockStatement.EmptyStatement); } return(new JsSwitchStatement(JsExpression.Identifier(stateVariableName), nodes.Select(n => new JsSwitchSection(n.StateValues.Select(v => JsExpression.Number(v)), new JsTryStatement( GenerateBody(stateVariableName, n.Children), null, new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier(n.HandlerName), "call"), JsExpression.This))))))); }
public void CommaExpressionIsParenthesizedInsideObjectLiteral() { AssertCorrect(JsExpression.ObjectLiteral(new JsObjectLiteralProperty("x", JsExpression.Comma(JsExpression.Number(1), JsExpression.Number(2))), new JsObjectLiteralProperty("y", JsExpression.Number(3))), "{ x: (1, 2), y: 3 }"); }
public static JsBlockStatement GenerateDisposer(string stateVariableName, List <Tuple <int, List <string> > > stateFinallyHandlers) { if (stateFinallyHandlers.Count == 0) { return(null); } return(new JsBlockStatement( new JsTryStatement( GenerateBody(stateVariableName, GenerateHandlerTree(stateFinallyHandlers)), null, new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(stateVariableName), JsExpression.Number(-1))) ) )); }
public void NumberIsParenthesizedWhenUsedAsMemberAccessTarget() { AssertCorrect(JsExpression.Member(JsExpression.Number(1), "X"), "(1).X"); }
public static JsExpression ConstructMemberInfo(IMember m, ICompilation compilation, IMetadataImporter metadataImporter, INamer namer, IRuntimeLibrary runtimeLibrary, IErrorReporter errorReporter, Func <IType, JsExpression> instantiateType, bool includeDeclaringType) { if (m is IMethod && ((IMethod)m).IsConstructor) { return(ConstructConstructorInfo((IMethod)m, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType)); } var properties = GetCommonMemberInfoProperties(m, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType); if (m.IsStatic) { properties.Add(new JsObjectLiteralProperty("isStatic", JsExpression.True)); } if (m is IMethod) { var method = (IMethod)m; var sem = metadataImporter.GetMethodSemantics(method); if (sem.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7201, m.FullName, "method"); return(JsExpression.Null); } if ((sem.Type == MethodScriptSemantics.ImplType.NormalMethod || sem.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) && sem.ExpandParams) { properties.Add(new JsObjectLiteralProperty("exp", JsExpression.True)); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method))); if (sem.Type == MethodScriptSemantics.ImplType.InlineCode) { var usedNames = new HashSet <string>(); var parameters = new List <IVariable>(); var variables = new Dictionary <IVariable, VariableData>(); var arguments = new List <ResolveResult>(); foreach (var p in method.Parameters) { string name = namer.GetVariableName(p.Name, usedNames); usedNames.Add(name); var variable = new SimpleVariable(p.Type, p.Name, DomRegion.Empty); parameters.Add(variable); variables.Add(variable, new VariableData(name, null, false)); arguments.Add(new LocalResolveResult(variable)); } var tokens = InlineCodeMethodCompiler.Tokenize(method, sem.LiteralCode, _ => {}); var compileResult = Compile(new CSharpInvocationResolveResult(new ThisResolveResult(method.DeclaringType), method, arguments), method.DeclaringTypeDefinition, method, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, true, variables, usedNames); var definition = JsExpression.FunctionDefinition(parameters.Select(p => variables[p].Name), new JsBlockStatement(compileResult.AdditionalStatements.Concat(new[] { new JsReturnStatement(compileResult.Expression) }))); if (tokens.Any(t => t.Type == InlineCodeToken.TokenType.TypeParameter && t.OwnerType == EntityType.Method)) { definition = JsExpression.FunctionDefinition(method.TypeParameters.Select(namer.GetTypeParameterName), new JsReturnStatement(definition)); properties.Add(new JsObjectLiteralProperty("tpcount", JsExpression.Number(method.TypeParameters.Count))); } properties.Add(new JsObjectLiteralProperty("def", definition)); } else { if (IsJsGeneric(method, metadataImporter)) { properties.Add(new JsObjectLiteralProperty("tpcount", JsExpression.Number(method.TypeParameters.Count))); } if (sem.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) { properties.Add(new JsObjectLiteralProperty("sm", JsExpression.True)); } properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name))); } properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(method.ReturnType))); properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(method.Parameters.Select(p => instantiateType(p.Type))))); } else if (m is IField) { var field = (IField)m; var sem = metadataImporter.GetFieldSemantics(field); if (sem.Type != FieldScriptSemantics.ImplType.Field) { errorReporter.Message(Messages._7201, m.FullName, "field"); return(JsExpression.Null); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Field))); properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(field.ReturnType))); properties.Add(new JsObjectLiteralProperty("sname", JsExpression.String(sem.Name))); } else if (m is IProperty) { var prop = (IProperty)m; var sem = metadataImporter.GetPropertySemantics(prop); properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Property))); properties.Add(new JsObjectLiteralProperty("returnType", instantiateType(prop.ReturnType))); if (prop.Parameters.Count > 0) { properties.Add(new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(prop.Parameters.Select(p => instantiateType(p.Type))))); } switch (sem.Type) { case PropertyScriptSemantics.ImplType.GetAndSetMethods: if (sem.GetMethod != null && sem.GetMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.GetMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.GetMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "property", "getter"); return(JsExpression.Null); } if (sem.SetMethod != null && sem.SetMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.SetMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.SetMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "property", "setter"); return(JsExpression.Null); } if (sem.GetMethod != null) { properties.Add(new JsObjectLiteralProperty("getter", ConstructMemberInfo(prop.Getter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType))); } if (sem.SetMethod != null) { properties.Add(new JsObjectLiteralProperty("setter", ConstructMemberInfo(prop.Setter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType))); } break; case PropertyScriptSemantics.ImplType.Field: if (prop.CanGet) { properties.Add(new JsObjectLiteralProperty("getter", ConstructFieldPropertyAccessor(prop.Getter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, sem.FieldName, instantiateType, isGetter: true, includeDeclaringType: includeDeclaringType))); } if (prop.CanSet) { properties.Add(new JsObjectLiteralProperty("setter", ConstructFieldPropertyAccessor(prop.Setter, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, sem.FieldName, instantiateType, isGetter: false, includeDeclaringType: includeDeclaringType))); } properties.Add(new JsObjectLiteralProperty("fname", JsExpression.String(sem.FieldName))); break; default: errorReporter.Message(Messages._7201, m.FullName, "property"); return(JsExpression.Null); } } else if (m is IEvent) { var evt = (IEvent)m; var sem = metadataImporter.GetEventSemantics(evt); if (sem.Type != EventScriptSemantics.ImplType.AddAndRemoveMethods) { errorReporter.Message(Messages._7201, m.FullName, "event"); return(JsExpression.Null); } if (sem.AddMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.AddMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.AddMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "event", "add accessor"); return(JsExpression.Null); } if (sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.NormalMethod && sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument && sem.RemoveMethod.Type != MethodScriptSemantics.ImplType.InlineCode) { errorReporter.Message(Messages._7202, m.FullName, "event", "remove accessor"); return(JsExpression.Null); } properties.Add(new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Event))); properties.Add(new JsObjectLiteralProperty("adder", ConstructMemberInfo(evt.AddAccessor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType))); properties.Add(new JsObjectLiteralProperty("remover", ConstructMemberInfo(evt.RemoveAccessor, compilation, metadataImporter, namer, runtimeLibrary, errorReporter, instantiateType, includeDeclaringType))); } else { throw new ArgumentException("Invalid member " + m); } return(JsExpression.ObjectLiteral(properties)); }
public IList <JsStatement> Process(IEnumerable <JsType> types, IMethod entryPoint) { var result = new List <JsStatement>(); var orderedTypes = OrderByNamespace(types, t => _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name).ToList(); foreach (var t in orderedTypes) { try { string name = _metadataImporter.GetTypeSemantics(t.CSharpTypeDefinition).Name; bool isGlobal = string.IsNullOrEmpty(name); bool isMixin = MetadataUtils.IsMixin(t.CSharpTypeDefinition); result.Add(new JsComment("//////////////////////////////////////////////////////////////////////////////" + Environment.NewLine + " " + t.CSharpTypeDefinition.FullName)); var typeRef = JsExpression.Identifier(_namer.GetTypeVariableName(name)); if (t is JsClass) { var c = (JsClass)t; if (isGlobal) { result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Binary(ExpressionNodeType.Assign, JsExpression.Member(GetRoot(t.CSharpTypeDefinition, exportNonPublic: true), m.Name), m.Definition)))); } else if (isMixin) { result.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(MakeNestedMemberAccess(name + "." + m.Name), m.Definition)))); } else if (MetadataUtils.IsResources(c.CSharpTypeDefinition)) { result.Add(GenerateResourcesClass(c)); } else { var unnamedCtor = c.UnnamedConstructor ?? JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement); if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) { var typeParameterNames = c.CSharpTypeDefinition.TypeParameters.Select(tp => _namer.GetTypeParameterName(tp)).ToList(); var stmts = new List <JsStatement> { new JsVariableDeclarationStatement(InstantiatedGenericTypeVariableName, unnamedCtor) }; AddClassMembers(c, JsExpression.Identifier(InstantiatedGenericTypeVariableName), stmts); stmts.AddRange(c.StaticInitStatements); stmts.Add(new JsReturnStatement(JsExpression.Identifier(InstantiatedGenericTypeVariableName))); var replacer = new GenericSimplifier(c.CSharpTypeDefinition, typeParameterNames, JsExpression.Identifier(InstantiatedGenericTypeVariableName)); for (int i = 0; i < stmts.Count; i++) { stmts[i] = replacer.Process(stmts[i]); } result.Add(new JsVariableDeclarationStatement(typeRef.Name, JsExpression.FunctionDefinition(typeParameterNames, new JsBlockStatement(stmts)))); var args = new List <JsExpression> { GetRoot(t.CSharpTypeDefinition), JsExpression.String(name), typeRef, JsExpression.Number(c.CSharpTypeDefinition.TypeParameterCount) }; var metadata = GetMetadataDescriptor(t.CSharpTypeDefinition, false); if (metadata != null) { args.Add(metadata); } result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Interface ? RegisterGenericInterface : RegisterGenericClass), args))); } else { result.Add(new JsVariableDeclarationStatement(typeRef.Name, unnamedCtor)); AddClassMembers(c, typeRef, result); } } } else if (t is JsEnum) { var e = (JsEnum)t; result.Add(new JsVariableDeclarationStatement(typeRef.Name, JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement))); var values = new List <JsObjectLiteralProperty>(); foreach (var v in e.CSharpTypeDefinition.Fields) { if (v.ConstantValue != null) { var sem = _metadataImporter.GetFieldSemantics(v); if (sem.Type == FieldScriptSemantics.ImplType.Field) { values.Add(new JsObjectLiteralProperty(sem.Name, JsExpression.Number(Convert.ToDouble(v.ConstantValue)))); } else if (sem.Type == FieldScriptSemantics.ImplType.Constant && sem.Name != null) { values.Add(new JsObjectLiteralProperty(sem.Name, sem.Value is string?JsExpression.String((string)sem.Value) : JsExpression.Number(Convert.ToDouble(sem.Value)))); } } else { _errorReporter.Region = v.Region; _errorReporter.InternalError("Enum field " + v.FullName + " is not constant."); } } result.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, Prototype), JsExpression.ObjectLiteral(values)))); } } catch (Exception ex) { _errorReporter.Region = t.CSharpTypeDefinition.Region; _errorReporter.InternalError(ex, "Error formatting type " + t.CSharpTypeDefinition.FullName); } } var typesToRegister = orderedTypes .Where(c => !(c is JsClass && MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter)) && !string.IsNullOrEmpty(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name) && (!MetadataUtils.IsResources(c.CSharpTypeDefinition) || c.CSharpTypeDefinition.IsExternallyVisible()) && // Resources classes are only exported if they are public. !MetadataUtils.IsMixin(c.CSharpTypeDefinition)) .ToList(); result.AddRange(TopologicalSortTypesByInheritance(typesToRegister) .Select(c => { try { string name = _metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name; if (c.CSharpTypeDefinition.Kind == TypeKind.Enum) { return(CreateRegisterEnumCall(c.CSharpTypeDefinition, name, JsExpression.Identifier(_namer.GetTypeVariableName(name)))); } if (MetadataUtils.IsResources(c.CSharpTypeDefinition)) { return(JsExpression.Invocation(JsExpression.Member(_systemScript, RegisterType), GetRoot(c.CSharpTypeDefinition), JsExpression.String(name), JsExpression.Identifier(_namer.GetTypeVariableName(name)))); } if (c.CSharpTypeDefinition.Kind == TypeKind.Interface) { return(CreateRegisterInterfaceCall(c.CSharpTypeDefinition, name, JsExpression.Identifier(_namer.GetTypeVariableName(name)), GetImplementedInterfaces(c.CSharpTypeDefinition.GetDefinition()).ToList())); } else { return(CreateRegisterClassCall(c.CSharpTypeDefinition, name, JsExpression.Identifier(_namer.GetTypeVariableName(name)), GetBaseClass(c.CSharpTypeDefinition), GetImplementedInterfaces(c.CSharpTypeDefinition).ToList())); } } catch (Exception ex) { _errorReporter.Region = c.CSharpTypeDefinition.Region; _errorReporter.InternalError(ex, "Error formatting type " + c.CSharpTypeDefinition.FullName); return(JsExpression.Number(0)); } }) .Select(expr => new JsExpressionStatement(expr))); result.AddRange(GetStaticInitializationOrder(orderedTypes.OfType <JsClass>(), 1) .Where(c => !MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter) && !MetadataUtils.IsResources(c.CSharpTypeDefinition)) .SelectMany(c => c.StaticInitStatements)); if (entryPoint != null) { if (entryPoint.Parameters.Count > 0) { _errorReporter.Region = entryPoint.Region; _errorReporter.Message(Messages._7800, entryPoint.FullName); } else { var sem = _metadataImporter.GetMethodSemantics(entryPoint); if (sem.Type != MethodScriptSemantics.ImplType.NormalMethod) { _errorReporter.Region = entryPoint.Region; _errorReporter.Message(Messages._7801, entryPoint.FullName); } else { result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(new JsTypeReferenceExpression(entryPoint.DeclaringTypeDefinition), sem.Name)))); } } } return(result); }
public void ForStatementsAreCorrectlyOutput() { AssertCorrect(new JsForStatement(new JsVariableDeclarationStatement(new JsVariableDeclaration("i", JsExpression.Number(0))), JsExpression.Lesser(JsExpression.Identifier("i"), JsExpression.Number(10)), JsExpression.PostfixPlusPlus(JsExpression.Identifier("i")), JsBlockStatement.EmptyStatement), "for(var i=0;i<10;i++){}"); AssertCorrect(new JsForStatement(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), JsExpression.Lesser(JsExpression.Identifier("i"), JsExpression.Number(10)), JsExpression.PostfixPlusPlus(JsExpression.Identifier("i")), JsBlockStatement.EmptyStatement), "for(i=0;i<10;i++){}"); AssertCorrect(new JsForStatement(new JsVariableDeclarationStatement(new JsVariableDeclaration("i", JsExpression.Number(0)), new JsVariableDeclaration("j", JsExpression.Number(1))), JsExpression.Lesser(JsExpression.Identifier("i"), JsExpression.Number(10)), JsExpression.Comma(JsExpression.PostfixPlusPlus(JsExpression.Identifier("i")), JsExpression.PostfixPlusPlus(JsExpression.Identifier("j"))), JsBlockStatement.EmptyStatement), "for(var i=0,j=1;i<10;i++,j++){}"); AssertCorrect(new JsForStatement(new JsEmptyStatement(), null, null, JsBlockStatement.EmptyStatement), "for(;;){}"); }
private static JsStatement GenerateBody(string stateVariableName, List <Node> nodes) { return(JsStatement.Switch(JsExpression.Identifier(stateVariableName), nodes.Select(n => JsStatement.SwitchSection(n.StateValues.Select(v => JsExpression.Number(v)), JsStatement.Try( n.Children.Count > 0 ? (JsStatement)JsStatement.Block(GenerateBody(stateVariableName, n.Children), JsStatement.Break()) : JsStatement.Break(), null, JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier(n.HandlerName), "call"), JsExpression.This)))))); }
public void IfAndElseIfStatementsAreChained() { AssertCorrect(new JsIfStatement(JsExpression.True, new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), null), "if(true){i=0;}"); AssertCorrect(new JsIfStatement(JsExpression.Identifier("a"), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(0))), new JsIfStatement(JsExpression.Identifier("b"), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(1))), new JsIfStatement(JsExpression.Identifier("c"), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(2))), new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier("i"), JsExpression.Number(3)))))), "if(a){i=0;}else if(b){i=1;}else if(c){i=2;}else{i=3;}"); }
private JsType ConvertType(JsClass type) { if (type.InstanceMethods.Any(m => m.Name == "runTests")) { _errorReporter.Region = type.CSharpTypeDefinition.Region; _errorReporter.Message(MessageSeverity.Error, 7019, string.Format("The type {0} cannot define a method named 'runTests' because it has a [TestFixtureAttribute].", type.CSharpTypeDefinition.FullName)); return(type); } var instanceMethods = new List <JsMethod>(); var tests = new List <Tuple <string, string, bool, int?, JsFunctionDefinitionExpression> >(); foreach (var method in type.InstanceMethods) { var testAttr = _attributeStore.AttributesFor(method.CSharpMember).GetAttribute <TestAttribute>(); if (testAttr != null) { if (!method.CSharpMember.IsPublic || !method.CSharpMember.ReturnType.IsKnownType(KnownTypeCode.Void) || ((IMethod)method.CSharpMember).Parameters.Count > 0 || ((IMethod)method.CSharpMember).TypeParameters.Count > 0) { _errorReporter.Region = method.CSharpMember.Region; _errorReporter.Message(MessageSeverity.Error, 7020, string.Format("Method {0}: Methods decorated with a [TestAttribute] must be public, non-generic, parameterless instance methods that return void.", method.CSharpMember.FullName)); } tests.Add(Tuple.Create(testAttr.Description ?? method.CSharpMember.Name, testAttr.Category, testAttr.IsAsync, testAttr.ExpectedAssertionCount >= 0 ? (int?)testAttr.ExpectedAssertionCount : null, method.Definition)); } else { instanceMethods.Add(method); } } var testInvocations = new List <JsExpression>(); foreach (var category in tests.GroupBy(t => t.Item2).Select(g => new { Category = g.Key, Tests = g.Select(x => new { Description = x.Item1, IsAsync = x.Item3, ExpectedAssertionCount = x.Item4, Function = x.Item5 }) }).OrderBy(x => x.Category)) { if (category.Category != null) { testInvocations.Add(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("QUnit"), "module"), JsExpression.String(category.Category))); } testInvocations.AddRange(category.Tests.Select(t => JsExpression.Invocation(JsExpression.Identifier(t.IsAsync ? "asyncTest" : "test"), t.ExpectedAssertionCount != null ? new JsExpression[] { JsExpression.String(t.Description), JsExpression.Number(t.ExpectedAssertionCount.Value), _runtimeLibrary.Bind(t.Function, JsExpression.This, this) } : new JsExpression[] { JsExpression.String(t.Description), _runtimeLibrary.Bind(t.Function, JsExpression.This, this) }))); } instanceMethods.Add(new JsMethod(null, "runTests", null, JsExpression.FunctionDefinition(new string[0], JsStatement.Block(testInvocations.Select(t => (JsStatement)t))))); var result = type.Clone(); result.InstanceMethods.Clear(); foreach (var m in instanceMethods) { result.InstanceMethods.Add(m); } return(result); }
public void SwitchStatementWorks() { AssertCorrect(new JsSwitchStatement(JsExpression.Identifier("x"), new JsSwitchSection(new[] { JsExpression.Number(0) }, new JsExpressionStatement(JsExpression.Identifier("a"))), new JsSwitchSection(new[] { JsExpression.Number(1), JsExpression.Number(2) }, new JsExpressionStatement(JsExpression.Identifier("b"))), new JsSwitchSection(new[] { null, JsExpression.Number(3) }, new JsExpressionStatement(JsExpression.Identifier("c"))) ), "switch(x){case 0:{a;}case 1:case 2:{b;}default:case 3:{c;}}"); }
public JsExpression Default(IType type, IRuntimeContext context) { if (type.IsReferenceType == true || type.Kind == TypeKind.Dynamic) { return(JsExpression.Null); } else if (type is ITypeParameter) { return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "getDefaultValue"), GetScriptType(type, TypeContext.GetScriptType, context))); } else if (type.Kind == TypeKind.Enum) { return(JsExpression.Number(0)); } else { switch (type.GetDefinition().KnownTypeCode) { case KnownTypeCode.Boolean: return(JsExpression.False); case KnownTypeCode.NullableOfT: return(JsExpression.Null); case KnownTypeCode.DateTime: return(JsExpression.New(CreateTypeReferenceExpression(KnownTypeReference.DateTime), JsExpression.Number(0))); case KnownTypeCode.Byte: case KnownTypeCode.SByte: case KnownTypeCode.Char: case KnownTypeCode.Int16: case KnownTypeCode.UInt16: case KnownTypeCode.Int32: case KnownTypeCode.UInt32: case KnownTypeCode.Int64: case KnownTypeCode.UInt64: case KnownTypeCode.Decimal: case KnownTypeCode.Single: case KnownTypeCode.Double: return(JsExpression.Number(0)); default: return(JsExpression.Invocation(JsExpression.Member(InstantiateType(type, context), "getDefaultValue"))); } } }
public void InvocationArgumentListContainsNoSpaces() { AssertCorrect(JsExpression.Invocation(JsExpression.Identifier("x"), JsExpression.Number(1), JsExpression.Number(2), JsExpression.Number(3)), "x(1,2,3)"); }
public JsExpression GetExpressionForLocal(string name, JsExpression accessor, IType type, IRuntimeContext context) { var scriptType = TypeOf(type, context); JsExpression getterDefinition = JsExpression.FunctionDefinition(new string[0], JsStatement.Return(accessor)); JsExpression setterDefinition = JsExpression.FunctionDefinition(new[] { "$" }, JsExpression.Assign(accessor, JsExpression.Identifier("$"))); if (UsesThisVisitor.Analyze(accessor)) { getterDefinition = JsExpression.Invocation(JsExpression.Member(getterDefinition, "bind"), JsExpression.This); setterDefinition = JsExpression.Invocation(JsExpression.Member(setterDefinition, "bind"), JsExpression.This); } return(JsExpression.ObjectLiteral( new JsObjectLiteralProperty("ntype", JsExpression.Number((int)ExpressionType.MemberAccess)), new JsObjectLiteralProperty("type", scriptType), new JsObjectLiteralProperty("expression", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("ntype", JsExpression.Number((int)ExpressionType.Constant)), new JsObjectLiteralProperty("type", scriptType), new JsObjectLiteralProperty("value", JsExpression.ObjectLiteral()) )), new JsObjectLiteralProperty("member", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())), new JsObjectLiteralProperty("name", JsExpression.String(name)), new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Property)), new JsObjectLiteralProperty("returnType", scriptType), new JsObjectLiteralProperty("getter", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())), new JsObjectLiteralProperty("name", JsExpression.String("get_" + name)), new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)), new JsObjectLiteralProperty("returnType", scriptType), new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral()), new JsObjectLiteralProperty("def", getterDefinition) )), new JsObjectLiteralProperty("setter", JsExpression.ObjectLiteral( new JsObjectLiteralProperty("typeDef", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Object).GetDefinition())), new JsObjectLiteralProperty("name", JsExpression.String("set_" + name)), new JsObjectLiteralProperty("type", JsExpression.Number((int)MemberTypes.Method)), new JsObjectLiteralProperty("returnType", new JsTypeReferenceExpression(_compilation.FindType(KnownTypeCode.Void).GetDefinition())), new JsObjectLiteralProperty("params", JsExpression.ArrayLiteral(scriptType)), new JsObjectLiteralProperty("def", setterDefinition) )) )) )); }
public void ObjectLiteralWithFunctionValuesAreNotOutputOnMultipleLines() { AssertCorrect(JsExpression.ObjectLiteral(new JsObjectLiteralProperty("x", JsExpression.Number(1)), new JsObjectLiteralProperty("y", JsExpression.FunctionDefinition(new string[0], new JsReturnStatement())), new JsObjectLiteralProperty("z", JsExpression.Number(3))), "{x:1,y:function(){return;},z:3}"); }
public void StatementsForEachPhaseAreSortedIndividuallyFirstByDependencyThenByTypeName() { var asm = Common.CreateMockAssembly(); var a = Common.CreateMockTypeDefinition("A", asm); var b = Common.CreateMockTypeDefinition("B", asm); var c = Common.CreateMockTypeDefinition("C", asm); var d = Common.CreateMockTypeDefinition("D", asm); var phase1Deps = new Dictionary <ITypeDefinition, IEnumerable <ITypeDefinition> > { { a, new[] { b, c } }, { b, new[] { d } }, { c, new[] { d } }, { d, new ITypeDefinition[0] }, }; var phase2Deps = new Dictionary <ITypeDefinition, IEnumerable <ITypeDefinition> > { { a, new[] { b, d } }, { b, new[] { c } }, { c, new ITypeDefinition[0] }, { d, new[] { c } }, }; var phase3Deps = new Dictionary <ITypeDefinition, IEnumerable <ITypeDefinition> > { { a, new ITypeDefinition[0] }, { b, new ITypeDefinition[0] }, { c, new ITypeDefinition[0] }, { d, new ITypeDefinition[0] }, }; AssertCorrect(new[] { new JsClass(a), new JsClass(b), new JsClass(c), new JsClass(d) }, @"D(1); B(1); C(1); A(1); C(2); B(2); D(2); A(2); A(3); B(3); C(3); D(3); ", new MockOOPEmulator { EmulateType = t => new TypeOOPEmulation(new[] { new TypeOOPEmulationPhase(phase1Deps[t.CSharpTypeDefinition], new[] { (JsStatement)JsExpression.Invocation(JsExpression.Identifier(t.CSharpTypeDefinition.Name), JsExpression.Number(1)) }), new TypeOOPEmulationPhase(phase2Deps[t.CSharpTypeDefinition], new[] { (JsStatement)JsExpression.Invocation(JsExpression.Identifier(t.CSharpTypeDefinition.Name), JsExpression.Number(2)) }), new TypeOOPEmulationPhase(phase3Deps[t.CSharpTypeDefinition], new[] { (JsStatement)JsExpression.Invocation(JsExpression.Identifier(t.CSharpTypeDefinition.Name), JsExpression.Number(3)) }), }) }, null); }