Ejemplo n.º 1
0
        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));
            }
        }
Ejemplo n.º 5
0
        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));
        }
Ejemplo n.º 6
0
        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");
 }
Ejemplo n.º 12
0
        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));
        }
Ejemplo n.º 13
0
        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));
        }
Ejemplo n.º 14
0
 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.
     }
 }
Ejemplo n.º 15
0
        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)));
            }
        }
Ejemplo n.º 16
0
        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")));
        }
Ejemplo n.º 19
0
        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");
 }
Ejemplo n.º 21
0
        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;
})();
");
        }
Ejemplo n.º 22
0
        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");
 }
Ejemplo n.º 25
0
 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));
     }
 }
Ejemplo n.º 26
0
        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));
        }
Ejemplo n.º 27
0
 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)");
        }