public JsExpression ReferenceEquals(JsExpression a, JsExpression b, IRuntimeContext context)
 {
     if (a.NodeType == ExpressionNodeType.Null)
     {
         return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "isNullOrUndefined"), b));
     }
     else if (b.NodeType == ExpressionNodeType.Null)
     {
         return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "isNullOrUndefined"), a));
     }
     else if (a.NodeType == ExpressionNodeType.String || b.NodeType == ExpressionNodeType.String)
     {
         return(JsExpression.Same(a, b));
     }
     else
     {
         return(JsExpression.Invocation(JsExpression.Member(CreateTypeReferenceExpression(_systemScript), "referenceEquals"), a, b));
     }
 }
Example #2
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));
     }
 }
 public JsExpression ReferenceEquals(JsExpression a, JsExpression b)
 {
     if (a.NodeType == ExpressionNodeType.Null)
     {
         return(JsExpression.Invocation(JsExpression.Member(_createTypeReferenceExpression(ReflectionHelper.ParseReflectionName("System.Script")), "isNullOrUndefined"), b));
     }
     else if (b.NodeType == ExpressionNodeType.Null)
     {
         return(JsExpression.Invocation(JsExpression.Member(_createTypeReferenceExpression(ReflectionHelper.ParseReflectionName("System.Script")), "isNullOrUndefined"), a));
     }
     else if (a.NodeType == ExpressionNodeType.String || b.NodeType == ExpressionNodeType.String)
     {
         return(JsExpression.Same(a, b));
     }
     else
     {
         return(JsExpression.Invocation(JsExpression.Member(_createTypeReferenceExpression(ReflectionHelper.ParseReflectionName("System.Script")), "referenceEquals"), a, b));
     }
 }
        private JsExpression GenerateFieldCompare(IField field, JsExpression o)
        {
            var impl = _metadataImporter.GetFieldSemantics(field);

            if (impl.Type != FieldScriptSemantics.ImplType.Field)
            {
                return(null);
            }

            bool simpleCompare = false;

            if (field.Type.Kind == TypeKind.Enum && !MetadataUtils.IsNamedValues(field.Type.GetDefinition(), _attributeStore))
            {
                simpleCompare = true;
            }
            if (field.Type is ITypeDefinition)
            {
                switch (((ITypeDefinition)field.Type).KnownTypeCode)
                {
                case KnownTypeCode.Boolean:
                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:
                    simpleCompare = true;
                    break;
                }
            }

            var m1 = JsExpression.Member(JsExpression.This, impl.Name);
            var m2 = JsExpression.Member(o, impl.Name);

            return(simpleCompare ? (JsExpression)JsExpression.Same(m1, m2) : JsExpression.Invocation(JsExpression.Member(_systemScript, "equals"), m1, m2));
        }
        private bool HandleSwitchStatement(JsSwitchStatement 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);
            JsExpression expression = stmt.Expression;

            if (_isExpressionComplexEnoughForATemporaryVariable(expression))
            {
                string newName = _allocateTempVariable();
                currentBlock.Add(JsStatement.Var(newName, expression));
                expression = JsExpression.Identifier(newName);
            }

            var         clauses                 = new List <Tuple <JsExpression, JsBlockStatement> >();
            JsStatement defaultClause           = null;
            State?      currentFallthroughState = null;

            for (int i = 0; i < stmt.Sections.Count; i++)
            {
                var clause = stmt.Sections[i];

                var origBody = new List <JsStatement>();
                origBody.AddRange(clause.Body.Statements);

                State?nextFallthroughState;

                if (i < stmt.Sections.Count - 1 && (origBody.Count == 0 || IsNextStatementReachable(origBody[origBody.Count - 1])))
                {
                    // Fallthrough
                    var nextBody = stmt.Sections[i + 1].Body.Statements;
                    if (nextBody.Count > 0 && nextBody[0] is JsLabelledStatement)
                    {
                        nextFallthroughState = GetOrCreateStateForLabel(((JsLabelledStatement)nextBody[0]).Label, currentState.FinallyStack);
                    }
                    else
                    {
                        nextFallthroughState = CreateNewStateValue(currentState.FinallyStack);
                    }
                }
                else
                {
                    nextFallthroughState = null;
                }

                breakStack = breakStack.Push(Tuple.Create(GetLabelForState(currentState), stateAfter.Item1));

                IList <JsStatement> body;
                if (currentFallthroughState != null)
                {
                    body = new List <JsStatement>();
                    body.Add(new JsGotoStateStatement(currentFallthroughState.Value, currentState));
                    Enqueue(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(JsStatement.Block(origBody), 0)), breakStack, continueStack, currentFallthroughState.Value, stateAfter.Item1);
                }
                else
                {
                    body = Handle(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(JsStatement.Block(origBody), 0)), breakStack, continueStack, currentState, nextFallthroughState ?? stateAfter.Item1, false, false);
                }

                if (clause.Values.Any(v => v == null))
                {
                    defaultClause = JsStatement.Block(body);
                }
                else
                {
                    JsExpression test = clause.Values.Select(v => JsExpression.Same(expression, v)).Aggregate((o, e) => o != null ? JsExpression.LogicalOr(o, e) : e);
                    clauses.Add(Tuple.Create(test, JsStatement.Block(body)));
                }

                currentFallthroughState = nextFallthroughState;
            }
            clauses.Reverse();

            currentBlock.Add(clauses.Where(c => c.Item1 != null).Aggregate(defaultClause, (o, n) => JsStatement.If(n.Item1, n.Item2, o)));
            currentBlock.Add(new JsGotoStateStatement(stateAfter.Item1, currentState));

            if (stateAfter.Item2)
            {
                Enqueue(PushFollowing(stack, location), breakStack, continueStack, stateAfter.Item1, returnState);
                return(false);
            }

            return(true);
        }
        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, bool isFirstStatement)
        {
            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 = JsStatement.Block(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, new State(currentState.LoopLabelName, currentState.StateValue, innerState.FinallyStack), stateBeforeFinally, false, false));

                Enqueue(ImmutableStack <StackEntry> .Empty.Push(new StackEntry(JsStatement.Block(JsStatement.BlockMerged(new JsStatement[0])), 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(JsStatement.Try(JsStatement.Try(stmt.GuardedStatement, stmt.Catch, null), null, stmt.Finally), location, stack, breakStack, continueStack, currentState, returnState, currentBlock, isFirstStatement));
            }
            else
            {
                var rewriter = new NestedStatementFixer(breakStack, continueStack, currentState, _exitState.Value, _makeSetResult);
                JsBlockStatement guarded;
                var guardedConstructs = FindInterestingConstructsVisitor.Analyze(stmt.GuardedStatement);
                if ((guardedConstructs & (InterestingConstruct.Label | InterestingConstruct.Await)) != InterestingConstruct.None)
                {
                    if (!isFirstStatement)
                    {
                        var sv = CreateNewStateValue(currentState.FinallyStack);
                        Enqueue(stack.Push(location), breakStack, continueStack, sv, returnState);
                        currentBlock.Add(new JsGotoStateStatement(sv, currentState));
                        return(false);
                    }

                    var inner = ProcessInner(stmt.GuardedStatement, breakStack, continueStack, currentState.FinallyStack, currentState.StateValue);
                    guarded = JsStatement.Block(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 = JsStatement.Catch(stmt.Catch.Identifier, JsStatement.Block(new[] { new JsSetNextStateStatement(inner.Item2) }.Concat(inner.Item1)));
                    }
                    else
                    {
                        var body = rewriter.Process(stmt.Catch.Body);
                        @catch = ReferenceEquals(body, stmt.Catch.Body) ? stmt.Catch : JsStatement.Catch(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 = JsStatement.Block(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 = JsStatement.Block(JsStatement.If(JsExpression.Identifier(_doFinallyBlocksVariableName), @finally, null));
                    }
                }
                else
                {
                    @finally = null;
                }

                if (currentBlock.Count > 0 && _childStates.ContainsKey(currentState.StateValue))
                {
                    var newBlock = JsStatement.If(JsExpression.Same(JsExpression.Identifier(_stateVariableName), JsExpression.Number(currentState.StateValue)), JsStatement.Block(currentBlock), null);
                    currentBlock.Clear();
                    currentBlock.Add(newBlock);
                }

                currentBlock.Add(JsStatement.Try(guarded, @catch, @finally));
                return(true);
            }
        }