private bool HandleAwaitStatement(JsAwaitStatement stmt, StackEntry location, ImmutableStack <StackEntry> stack, ImmutableStack <Tuple <string, State> > breakStack, ImmutableStack <Tuple <string, State> > continueStack, State currentState, State returnState, IList <JsStatement> currentBlock) { var stateAfter = GetStateAfterStatement(location, stack, currentState.FinallyStack, returnState).Item1; bool createDummyState = false; if (stateAfter.StateValue == returnState.StateValue) { stateAfter = CreateNewStateValue(currentState.FinallyStack); createDummyState = true; // We must never return to our parent state after an await because } currentBlock.Add(new JsSetNextStateStatement(stateAfter.StateValue)); currentBlock.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(stmt.Awaiter, stmt.OnCompletedMethodName), JsExpression.Identifier(_stateMachineMethodName)))); if (_needDoFinallyBlocksVariable) { currentBlock.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(_doFinallyBlocksVariableName), JsExpression.False))); } currentBlock.Add(new JsReturnStatement()); if (!stack.IsEmpty || location.Index < location.Block.Statements.Count - 1) { Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter, returnState); } if (createDummyState) { Enqueue(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(new JsBlockStatement(new JsBlockStatement(new JsStatement[0], mergeWithParent: true)), 0)), breakStack, continueStack, stateAfter, returnState); } return(false); }
public JsStatement VisitGotoStateStatement(JsGotoStateStatement statement, object data) { var result = new List <JsStatement>(); State targetState; if (statement.TargetState == null) { if (!_labelStates.TryGetValue(statement.TargetLabel, out targetState)) { throw new InvalidOperationException("The label " + statement.TargetLabel + " does not exist."); } } else { targetState = statement.TargetState.Value; } var remaining = statement.CurrentState.FinallyStack; for (int i = 0, n = remaining.Count() - targetState.FinallyStack.Count(); i < n; i++) { var current = remaining.Peek(); remaining = remaining.Pop(); result.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Identifier(_stateVariableName), JsExpression.Number(remaining.IsEmpty ? -1 : remaining.Peek().Item1)))); result.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier(current.Item2), "call"), JsExpression.This))); } result.Add(MakeSetNextStateStatement(targetState.StateValue)); result.Add(targetState.StateValue == -1 ? (JsStatement) new JsBreakStatement(targetState.LoopLabelName) : new JsContinueStatement(targetState.LoopLabelName)); return(new JsBlockStatement(result, mergeWithParent: true)); }
public JsFunctionDefinitionExpression CompileAutoEventAdder(IEvent @event, EventScriptSemantics impl, string backingFieldName) { try { string valueName = _namer.GetVariableName(@event.AddAccessor.Parameters[0].Name, new HashSet <string>(@event.DeclaringTypeDefinition.TypeParameters.Select(p => _namer.GetTypeParameterName(p)))); CreateCompilationContext(null, null, null); JsExpression target; string[] args; if (@event.IsStatic) { target = _runtimeLibrary.GetScriptType(@event.DeclaringType, TypeContext.UseStaticMember); args = new[] { valueName }; } else if (impl.AddMethod.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) { target = JsExpression.Identifier(_namer.ThisAlias); args = new[] { _namer.ThisAlias, valueName }; } else { target = JsExpression.This; args = new[] { valueName }; } var bfAccessor = JsExpression.MemberAccess(target, backingFieldName); var combineCall = _statementCompiler.CompileDelegateCombineCall(@event.AddAccessor.Region, bfAccessor, JsExpression.Identifier(valueName)); return(JsExpression.FunctionDefinition(args, new JsBlockStatement(new JsExpressionStatement(JsExpression.Assign(bfAccessor, combineCall))))); } catch (Exception ex) { _errorReporter.Region = @event.Region; _errorReporter.InternalError(ex); return(JsExpression.FunctionDefinition(new string[0], JsBlockStatement.EmptyStatement)); } }
public JsExpression GetMember(IMember member, IRuntimeContext context) { var owner = member is IMethod && ((IMethod)member).IsAccessor ? ((IMethod)member).AccessorOwner : null; int index = FindIndexInReflectableMembers(owner ?? member); if (index >= 0) { JsExpression result = JsExpression.Index( JsExpression.Member( JsExpression.Member( TypeOf(member.DeclaringType, context), "__metadata"), "members"), JsExpression.Number(index)); if (owner != null) { if (owner is IProperty) { if (ReferenceEquals(member, ((IProperty)owner).Getter)) { result = JsExpression.MemberAccess(result, "getter"); } else if (ReferenceEquals(member, ((IProperty)owner).Setter)) { result = JsExpression.MemberAccess(result, "setter"); } else { throw new ArgumentException("Invalid member " + member); } } else if (owner is IEvent) { if (ReferenceEquals(member, ((IEvent)owner).AddAccessor)) { result = JsExpression.MemberAccess(result, "adder"); } else if (ReferenceEquals(member, ((IEvent)owner).RemoveAccessor)) { result = JsExpression.MemberAccess(result, "remover"); } else { throw new ArgumentException("Invalid member " + member); } } else { throw new ArgumentException("Invalid owner " + owner); } } return(result); } else { return(MetadataUtils.ConstructMemberInfo(member, _compilation, _metadataImporter, _namer, this, _errorReporter, t => TypeOf(t, context), includeDeclaringType: true)); } }
public JsExpression TryDowncast(JsExpression expression, IType sourceType, IType targetType) { var jsTarget = GetCastTarget(sourceType, targetType); if (jsTarget == null || IsSystemObjectReference(jsTarget)) { return(expression); } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Type), "safeCast"), expression, jsTarget)); }
public JsExpression TypeIs(JsExpression expression, IType sourceType, IType targetType) { var jsTarget = GetCastTarget(sourceType, targetType); if (jsTarget == null || IsSystemObjectReference(jsTarget)) { return(ReferenceNotEquals(expression, JsExpression.Null)); } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Type), "isInstanceOfType"), expression, jsTarget)); }
private JsExpression MakeNestedMemberAccess(string full) { var parts = full.Split('.'); JsExpression result = JsExpression.Identifier(parts[0]); for (int i = 1; i < parts.Length; i++) { result = JsExpression.MemberAccess(result, parts[i]); } return(result); }
public void MemberAccessIsNotParenthesizedWhenUsedAsInvocationTarget() { AssertCorrect(JsExpression.Invocation( JsExpression.MemberAccess( JsExpression.Identifier("x"), "Member" ), new JsExpression[0] ), "x.Member()"); }
public void NewExpressionIsParenthesizedWhenItIsTheTargetOfAMemberAccess() { AssertCorrect(JsExpression.MemberAccess( JsExpression.New( JsExpression.Number(1), new[] { JsExpression.Number(2) } ), "Member" ), "(new 1(2)).Member"); }
public override JsExpression VisitTypeReferenceExpression(JsTypeReferenceExpression expression, object data) { var parts = expression.TypeName.Split('.'); JsExpression result = JsExpression.Identifier(parts[0]); for (int i = 1; i < parts.Length; i++) { result = JsExpression.MemberAccess(result, parts[i]); } return(result); }
public void InvocationIsNotParenthesizedWhenUsedAsMemberAccessTarget() { AssertCorrect(JsExpression.MemberAccess( JsExpression.Invocation( JsExpression.Number(1), new[] { JsExpression.Number(2) } ), "Member" ), "1(2).Member"); }
public JsExpression CallBase(IType baseType, string methodName, IList <IType> typeArguments, IEnumerable <JsExpression> thisAndArguments) { JsExpression method = JsExpression.MemberAccess(JsExpression.MemberAccess(GetScriptType(baseType, TypeContext.BindBaseCall), "prototype"), methodName); if (typeArguments != null && typeArguments.Count > 0) { method = InstantiateGenericMethod(method, typeArguments); } return(JsExpression.Invocation(JsExpression.MemberAccess(method, "call"), thisAndArguments)); }
public JsExpression BindBaseCall(IType baseType, string methodName, IList <IType> typeArguments, JsExpression @this) { JsExpression method = JsExpression.MemberAccess(JsExpression.MemberAccess(GetScriptType(baseType, TypeContext.BindBaseCall), "prototype"), methodName); if (typeArguments != null && typeArguments.Count > 0) { method = InstantiateGenericMethod(method, typeArguments); } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Delegate), "mkdel"), @this, method)); }
public JsExpression CloneDelegate(JsExpression source, IType sourceType, IType targetType) { if (Equals(sourceType, targetType)) { // The user does something like "D d1 = F(); var d2 = new D(d1)". Assume he does this for a reason and create a clone of the delegate. return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Delegate), "clone"), source)); } else { return(source); // The clone is just to convert the delegate to a different type. The risk of anyone comparing the references is small, so just return the original as delegates are immutable anyway. } }
public JsExpression CreateArray(IType elementType, IEnumerable <JsExpression> size) { var sizeList = (size is IList <JsExpression>) ? (IList <JsExpression>)size : size.ToList(); if (sizeList.Count == 1) { return(JsExpression.New(_createTypeReferenceExpression(KnownTypeReference.Array), sizeList)); } else { return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Array), "multidim"), new[] { Default(elementType) }.Concat(sizeList))); } }
public JsExpression FromNullable(JsExpression expression) { if (_metadataImporter.OmitNullableChecks) { return(expression); } if (expression.NodeType == ExpressionNodeType.LogicalNot) { return(expression); // This is a little hacky. The problem we want to solve is that 'bool b = myDynamic' should compile to !!myDynamic, but the actual call is unbox(convert(myDynamic, bool)), where convert() will return the !!. Anyway, in JS, the !expression will never be null anyway. } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.NullableOfT), "unbox"), expression)); }
public void CreatingObjectOfNestedTypeDoesNotCauseUnnecessaryParentheses() { // Just to get rid of ambiguities AssertCorrect(JsExpression.New( JsExpression.MemberAccess( JsExpression.MemberAccess( JsExpression.Identifier("X"), "Y" ), "Z" ) ), "new X.Y.Z()"); }
public void Works() { var asm = new Mock <IAssembly>(MockBehavior.Strict); var actual = Process(new JsStatement[] { new JsExpressionStatement(new JsTypeReferenceExpression(asm.Object, "GlobalType")), new JsReturnStatement(JsExpression.Binary(ExpressionNodeType.Add, JsExpression.MemberAccess(new JsTypeReferenceExpression(asm.Object, "Global.NestedNamespace.InnerNamespace.Type"), "x"), JsExpression.Number(1))) }); Assert.That(actual.Replace("\r\n", "\n"), Is.EqualTo( @"GlobalType; return Global.NestedNamespace.InnerNamespace.Type.x + 1; ".Replace("\r\n", "\n"))); }
public void AccessingMemberOnTypeWithEmptyScriptNameResultsInGlobalAccess() { var actual = Process(new JsStatement[] { new JsExpressionStatement(JsExpression.MemberAccess(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition("GlobalType", Common.CreateMockAssembly())), "x")), }, Common.CreateMockAssembly(), new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType("") }); AssertCorrect(actual, @"(function() { x; })(); "); }
public void NestedMemberExpressionsAreNotParenthesized() { AssertCorrect(JsExpression.MemberAccess( JsExpression.MemberAccess( JsExpression.MemberAccess( JsExpression.Identifier("x"), "Member1" ), "Member2" ), "Member3" ), "x.Member1.Member2.Member3"); }
public void AccessingMemberOnTypeWithEmptyScriptNameInOwnAssemblyWithModuleNameUsesExports() { var asm = Common.CreateMockAssembly(new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("main-module") }); var actual = Process(new JsStatement[] { new JsExpressionStatement(JsExpression.MemberAccess(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition("GlobalType", asm)), "x")), }, asm, metadata: new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType("") }); AssertCorrect(actual, @"(function() { exports.x; })(); "); }
public void AccessingMemberOnTypeWithEmptyScriptNameInOwnAssemblyButWithDifferentModuleNameResultsInARequire() { var asm = Common.CreateMockAssembly(new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("main-module") }); var actual = Process(new JsStatement[] { new JsExpressionStatement(JsExpression.MemberAccess(new JsTypeReferenceExpression(Common.CreateMockTypeDefinition("GlobalType", asm, attributes: new Expression <Func <Attribute> >[] { () => new ModuleNameAttribute("my-module") })), "x")), }, asm, metadata: new MockMetadataImporter { GetTypeSemantics = t => TypeScriptSemantics.NormalType("") }); AssertCorrect(actual, @"require('mscorlib'); var $mymodule = require('my-module'); $mymodule.x; "); }
public void ChainedFunctionCallsAndMemberAccessesAreNotParenthtesized() { AssertCorrect(JsExpression.Invocation( JsExpression.MemberAccess( JsExpression.Invocation( JsExpression.MemberAccess( JsExpression.Invocation( JsExpression.MemberAccess(JsExpression.This, "x"), new[] { JsExpression.Number(1) } ), "y"), new[] { JsExpression.Number(2) } ), "z"), new[] { JsExpression.Number(3) } ), "this.x(1).y(2).z(3)"); }
public void IndexingDoesNotCauseUnnecessaryParentheses() { AssertCorrect(JsExpression.MemberAccess( JsExpression.Index( JsExpression.MemberAccess( JsExpression.Index( JsExpression.Identifier("a"), JsExpression.Identifier("b") ), "c" ), JsExpression.Identifier("d") ), "e" ), "a[b].c[d].e"); }
public JsExpression ReferenceEquals(JsExpression a, JsExpression b) { if (a.NodeType == ExpressionNodeType.Null) { return(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier("ss"), "isNullOrUndefined"), b)); } else if (b.NodeType == ExpressionNodeType.Null) { return(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier("ss"), "isNullOrUndefined"), a)); } else if (a.NodeType == ExpressionNodeType.String || b.NodeType == ExpressionNodeType.String) { return(JsExpression.Same(a, b)); } else { return(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier("ss"), "referenceEquals"), a, b)); } }
public JsExpression Downcast(JsExpression expression, IType sourceType, IType targetType) { if (_metadataImporter.OmitDowncasts) { return(expression); } if (sourceType.Kind == TypeKind.Dynamic && targetType.IsKnownType(KnownTypeCode.Boolean)) { return(JsExpression.LogicalNot(JsExpression.LogicalNot(expression))); } var jsTarget = GetCastTarget(sourceType, targetType); if (jsTarget == null || IsSystemObjectReference(jsTarget)) { return(expression); } return(JsExpression.Invocation(JsExpression.MemberAccess(_createTypeReferenceExpression(KnownTypeReference.Type), "cast"), expression, jsTarget)); }
public JsExpression ReferenceNotEquals(JsExpression a, JsExpression b) { if (a.NodeType == ExpressionNodeType.Null) { return(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier("ss"), "isValue"), b)); } else if (b.NodeType == ExpressionNodeType.Null) { return(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier("ss"), "isValue"), a)); } else if (a.NodeType == ExpressionNodeType.String || b.NodeType == ExpressionNodeType.String) { return(JsExpression.NotSame(a, b)); } else { return(JsExpression.LogicalNot(JsExpression.Invocation(JsExpression.MemberAccess(JsExpression.Identifier("ss"), "referenceEquals"), a, b))); } }
private JsExpression CreateRegisterClassCall(JsExpression name, JsExpression baseClass, IList <JsExpression> interfaces, JsExpression typeRef) { var args = new List <JsExpression> { name }; if (baseClass != null) { args.Add(baseClass); } else if (interfaces.Count > 0) { args.Add(JsExpression.Null); } if (interfaces.Count > 0) { args.AddRange(interfaces); } return(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, RegisterClass), args)); }
private JsExpression CreateDefaultConstructorInvocation(IMethod defaultConstructor, JsExpression typeRef) { var sem = _metadataImporter.GetConstructorSemantics(defaultConstructor); switch (sem.Type) { case ConstructorScriptSemantics.ImplType.UnnamedConstructor: // default behavior is good enough. case ConstructorScriptSemantics.ImplType.NotUsableFromScript: // Can't be invoked so we don't need to create it. return(null); case ConstructorScriptSemantics.ImplType.NamedConstructor: return(JsExpression.New(JsExpression.MemberAccess(typeRef, sem.Name))); case ConstructorScriptSemantics.ImplType.StaticMethod: if (sem.IsGlobal) { return(JsExpression.Invocation(JsExpression.Identifier(sem.Name))); } else { return(JsExpression.Invocation(JsExpression.MemberAccess(typeRef, sem.Name))); } case ConstructorScriptSemantics.ImplType.InlineCode: var prevRegion = _errorReporter.Region; try { _errorReporter.Region = defaultConstructor.Region; return(InlineCodeMethodCompiler.CompileInlineCodeMethodInvocation(defaultConstructor, sem.LiteralCode, null, EmptyList <JsExpression> .Instance, r => r.Resolve(_compilation), _runtimeLibrary.GetScriptType, false, s => _errorReporter.Message(7525, s))); } finally { _errorReporter.Region = prevRegion; } case ConstructorScriptSemantics.ImplType.Json: return(JsExpression.ObjectLiteral()); default: throw new Exception("Invalid constructor implementation type: " + sem.Type); } }
public void ConstructorIsParenthesizedWhenItContainsAnInvocation() { AssertCorrect(JsExpression.New( JsExpression.Invocation( JsExpression.Identifier("X"), new JsExpression[0] ), new[] { JsExpression.Number(1) } ), "new (X())(1)"); AssertCorrect(JsExpression.New( JsExpression.MemberAccess( JsExpression.Invocation( JsExpression.Identifier("X"), new JsExpression[0] ), "a" ), new[] { JsExpression.Number(1) } ), "new (X().a)(1)"); AssertCorrect(JsExpression.New( JsExpression.MemberAccess( JsExpression.Invocation( JsExpression.MemberAccess( JsExpression.Identifier("a"), "X" ), new JsExpression[0] ), "b" ), new[] { JsExpression.Number(1) } ), "new (a.X().b)(1)"); }