コード例 #1
0
        protected override void VisitForSyntax(ForSyntax pNode)
        {
            _locals.AddScope();
            if (pNode.Iterator != null)
            {
                Visit(pNode.Iterator);
            }
            else
            {
                foreach (var d in pNode.Initializer)
                {
                    Visit(d);
                }
                Visit(pNode.Condition);

                foreach (var f in pNode.Finalizer)
                {
                    Visit(f);
                }
            }

            using (var iw = Store.AddValue("CanBreak", true))
            {
                _breakCount++;
                Visit(pNode.Body);
                _breakCount--;
            }
            _locals.RemoveScope();
        }
コード例 #2
0
        protected virtual SyntaxNode VisitForSyntax(ForSyntax pNode)
        {
            if (pNode.Iterator != null)
            {
                return(SyntaxFactory.For(Visit(pNode.Iterator), pNode.Reverse, (BlockSyntax)Visit(pNode.Body)));
            }

            List <DeclarationSyntax> initializer = new List <DeclarationSyntax>(pNode.Initializer.Count);

            foreach (var d in pNode.Initializer)
            {
                initializer.Add((DeclarationSyntax)Visit(d));
            }
            var cond = Visit(pNode.Condition);

            List <SyntaxNode> finalizer = new List <SyntaxNode>(pNode.Finalizer.Count);

            foreach (var f in pNode.Finalizer)
            {
                finalizer.Add(Visit(f));
            }
            Visit(pNode.Body);

            return(SyntaxFactory.For(initializer, cond, finalizer, (BlockSyntax)Visit(pNode.Body)));
        }
コード例 #3
0
 public override SyntaxNode Visit(ForSyntax pNode)
 {
     using (new MetadataCache.LocalScope())
     {
         return(base.Visit(pNode));
     }
 }
コード例 #4
0
        public override void VisitForSyntax(ForSyntax syntax)
        {
            // save previous property loop count on the call stack
            var previousPropertyLoopCount = this.propertyLoopCount;

            switch (this.IsLoopAllowedHere(syntax))
            {
            case false:
                // this loop was used incorrectly
                this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).ForExpressionsNotSupportedHere());
                break;

            case null:
                // this is a property loop
                this.propertyLoopCount += 1;

                if (this.propertyLoopCount > MaximumNestedPropertyLoopCount)
                {
                    // too many property loops
                    this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).TooManyPropertyForExpressions());
                }

                break;
            }

            // visit children
            base.VisitForSyntax(syntax);

            // restore previous property loop count
            this.propertyLoopCount = previousPropertyLoopCount;
        }
コード例 #5
0
        public override void VisitForSyntax(ForSyntax syntax)
        {
            // we must have a scope in the map for the loop body - otherwise binding won't work
            Debug.Assert(this.allLocalScopes.ContainsKey(syntax.Body), "this.allLocalScopes.ContainsKey(syntax.Body)");

            // visit all the children
            base.VisitForSyntax(syntax);
        }
コード例 #6
0
        public void EmitCopyObject(string?name, ForSyntax syntax, SyntaxBase?input, string?copyIndexOverride = null)
        {
            writer.WriteStartObject();

            if (name is not null)
            {
                this.EmitProperty("name", name);
            }

            // construct the length ARM expression from the Bicep array expression
            // type check has already ensured that the array expression is an array
            this.EmitPropertyWithTransform(
                "count",
                syntax.Expression,
                arrayExpression => new FunctionExpression("length", new[] { arrayExpression }, Array.Empty <LanguageExpression>()));

            if (input != null)
            {
                if (copyIndexOverride == null)
                {
                    this.EmitProperty("input", input);
                }
                else
                {
                    this.EmitPropertyWithTransform("input", input, expression =>
                    {
                        // the named copy index in the serialized expression is incorrect
                        // because the object syntax here does not match the JSON equivalent due to the presence of { "value": ... } wrappers
                        // for now, we will manually replace the copy index in the converted expression
                        // this approach will not work for nested property loops
                        var visitor = new LanguageExpressionVisitor
                        {
                            OnFunctionExpression = function =>
                            {
                                if (string.Equals(function.Function, "copyIndex") &&
                                    function.Parameters.Length == 1 &&
                                    function.Parameters[0] is JTokenExpression)
                                {
                                    // it's an invocation of the copyIndex function with 1 argument with a literal value
                                    // replace the argument with the correct value
                                    function.Parameters = new LanguageExpression[] { new JTokenExpression("value") };
                                }
                            }
                        };

                        // mutate the expression
                        expression.Accept(visitor);

                        return(expression);
                    });
                }
            }

            writer.WriteEndObject();
        }
コード例 #7
0
 public override void Visit(ForSyntax pNode)
 {
     if (pNode.Condition.Type == SmallType.Undefined)
     {
         Compiler.ReportError(CompilerErrorType.UndefinedType, pNode);
     }
     else
     {
         if (!SmallType.Boolean.IsAssignableFrom(pNode.Condition.Type))
         {
             Compiler.ReportError(CompilerErrorType.TypeMismatch, pNode, SmallType.Boolean.ToString(), pNode.Condition.Type.ToString());
         }
     }
     base.Visit(pNode);
 }
コード例 #8
0
        public override void VisitForSyntax(ForSyntax syntax) =>
        this.Build(() => base.VisitForSyntax(syntax), children =>
        {
            Debug.Assert(children.Length == 8);

            ILinkedDocument openBracket     = children[0];
            ILinkedDocument forKeyword      = children[1];
            ILinkedDocument variableBlock   = children[2];
            ILinkedDocument inKeyword       = children[3];
            ILinkedDocument arrayExpression = children[4];
            ILinkedDocument colon           = children[5];
            ILinkedDocument loopBody        = children[6];
            ILinkedDocument closeBracket    = children[7];

            return(Concat(openBracket, Spread(forKeyword, variableBlock, inKeyword, arrayExpression), Spread(colon, loopBody), closeBracket));
        });
コード例 #9
0
        public override void VisitForSyntax(ForSyntax syntax)
        {
            this.Visit(syntax.OpenSquare);
            this.Visit(syntax.ForKeyword);
            this.Visit(syntax.VariableSection);
            this.Visit(syntax.InKeyword);
            this.deployTimeConstantScopeSyntax = syntax;
            this.Visit(syntax.Expression);

            if (this.errorSyntax != null)
            {
                this.AppendError();
            }

            this.deployTimeConstantScopeSyntax = null;
            this.Visit(syntax.Colon);
            this.Visit(syntax.Body);
            this.Visit(syntax.CloseSquare);
        }
コード例 #10
0
        protected override void VisitForSyntax(ForSyntax pNode)
        {
            if (pNode.Iterator != null)
            {
                if (SmallTypeCache.TryGetEnumerable(_unit, out SmallType enumerable))
                {
                    if (!pNode.Iterator.Type.IsArray && !CanCast(pNode.Iterator.Type, enumerable))
                    {
                        CompilerErrors.IteratorError(pNode.Iterator.Type, pNode.Iterator.Span);
                    }
                }
            }
            else if (!CanCast(pNode.Condition.Type, SmallTypeCache.Boolean))
            {
                CompilerErrors.TypeCastError(pNode.Condition.Type, SmallTypeCache.Boolean, pNode.Condition.Span);
            }

            base.VisitForSyntax(pNode);
        }
コード例 #11
0
        public override void VisitForSyntax(ForSyntax syntax)
        {
            // save previous property loop count on the call stack
            var previousPropertyLoopCount = this.propertyLoopCount;

            switch (this.IsLoopAllowedHere(syntax))
            {
            case false:
                // this loop was used incorrectly
                this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).ForExpressionsNotSupportedHere());
                break;

            case true when this.activeLoopCapableTopLevelDeclaration is VariableDeclarationSyntax variable && InlineDependencyVisitor.ShouldInlineVariable(this.semanticModel, variable, out var variableChain):
                // this is a loop variable that has a dependency on functions that are not supported in JSON variables
                // we are initially blocking this because not all cases can be generated in the JSON

                // unable to get a detailed variable dependency chain
                // log a generic error instead and put it on the "for" keyword
                this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).VariableLoopsRuntimeDependencyNotAllowed(variableChain));

                break;

            case null:
                // this is a property loop
                this.propertyLoopCount += 1;

                if (this.propertyLoopCount > MaximumNestedPropertyLoopCount)
                {
                    // too many property loops
                    this.diagnosticWriter.Write(DiagnosticBuilder.ForPosition(syntax.ForKeyword).TooManyPropertyForExpressions());
                }

                break;
            }

            // visit children
            base.VisitForSyntax(syntax);

            // restore previous property loop count
            this.propertyLoopCount = previousPropertyLoopCount;
        }
コード例 #12
0
        protected override void VisitForSyntax(ForSyntax pNode)
        {
            _locals.AddScope();

            if (pNode.Iterator != null)
            {
                Visit(pNode.Iterator);

                //Array vs Enumerable<T>
                if (pNode.Iterator.Type.IsArray)
                {
                    _itType = pNode.Iterator.Type.GetElementType();
                }
                else if (SmallTypeCache.TryGetEnumerable(_unit, out SmallType enumerable) && pNode.Iterator.Type.IsAssignableFrom(enumerable))
                {
                    _itType = pNode.Iterator.Type.GenericArguments[0];
                }
                else
                {
                    _itType = pNode.Iterator.Type;
                }
            }
            else
            {
                foreach (var d in pNode.Initializer)
                {
                    Visit(d);
                }
                Visit(pNode.Condition);

                foreach (var f in pNode.Finalizer)
                {
                    Visit(f);
                }
            }

            Visit(pNode.Body);

            _locals.RemoveScope();
        }
コード例 #13
0
        public override void VisitForSyntax(ForSyntax syntax)
        {
            if (!this.allLocalScopes.TryGetValue(syntax, out var localScope))
            {
                // code defect in the declaration visitor
                throw new InvalidOperationException($"Local scope is missing for {syntax.GetType().Name} at {syntax.Span}");
            }

            // push it to the stack of active scopes
            // as a result this scope will be used to resolve symbols first
            // (then all the previous one and then finally the global scope)
            this.activeScopes.Push(localScope);

            // visit all the children
            base.VisitForSyntax(syntax);

            // we are leaving the loop scope
            // pop the scope - no symbols will be resolved against it ever again
            var lastPopped = this.activeScopes.Pop();

            Debug.Assert(ReferenceEquals(lastPopped, localScope), "ReferenceEquals(lastPopped, localScope)");
        }
コード例 #14
0
        protected virtual void VisitForSyntax(ForSyntax pNode)
        {
            if (pNode.Iterator != null)
            {
                Visit(pNode.Iterator);
            }
            else
            {
                foreach (var d in pNode.Initializer)
                {
                    Visit(d);
                }
                Visit(pNode.Condition);

                foreach (var f in pNode.Finalizer)
                {
                    Visit(f);
                }
            }

            Visit(pNode.Body);
        }
コード例 #15
0
 private string?ErrorSyntaxInForBodyOfVariable(ForSyntax forSyntax, SyntaxBase errorSyntax) =>
 this.SemanticModel.Binder.GetParent(forSyntax) is VariableDeclarationSyntax variableDeclarationSyntax &&
コード例 #16
0
 public void EmitCopyObject(string?name, ForSyntax syntax, SyntaxBase?input, string?copyIndexOverride = null, long?batchSize = null)
 {
コード例 #17
0
        protected override SyntaxNode VisitForSyntax(ForSyntax pNode)
        {
            //Rewrite for statements with iterator arrays to normal for statements
            if (pNode.Iterator != null)
            {
                var i = SyntaxFactory.Identifier("!i");
                i.SetType(SmallTypeCache.Int);

                var postOp = pNode.Reverse ? UnaryExpressionOperator.PostDecrement : UnaryExpressionOperator.PostIncrement;
                UnaryExpressionSyntax finalizer = SyntaxFactory.UnaryExpression(i, postOp);

                SyntaxNode        end  = null;
                DeclarationSyntax decl = null;

                //Save itvar in case we are looping in a case body
                var rw = _rewrite;
                var it = _itVar;

                //Declare our iterator outside the for loop
                //This will help if our iterator is complex like a function call
                var iterVar = SyntaxFactory.Identifier("!iter");
                iterVar.SetType(pNode.Iterator.Type);
                var iterDecl = SyntaxFactory.SingleDeclaration(iterVar, pNode.Iterator);

                if (pNode.Iterator.Type.IsArray)
                {
                    //We are iterating over an array
                    //Reverse loops will start at Array.Length and decrement to 0
                    //Normal loops will start at 0 and increment to Array.Length
                    if (pNode.Reverse)
                    {
                        var length = SyntaxFactory.UnaryExpression(iterVar, UnaryExpressionOperator.Length);
                        length.SetType(SmallTypeCache.Int);
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.BinaryExpression(length, BinaryExpressionOperator.Subtraction, SyntaxFactory.NumericLiteral(1)));
                        end  = SyntaxFactory.NumericLiteral(0);
                    }
                    else
                    {
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.NumericLiteral(0));
                        end  = SyntaxFactory.UnaryExpression(iterVar, UnaryExpressionOperator.Length);
                        ((UnaryExpressionSyntax)end).SetType(SmallTypeCache.Int);
                    }

                    _itVar = SyntaxFactory.ArrayAccess(iterVar, i);
                    ((ArrayAccessSyntax)_itVar).SetType(iterVar.Type);
                }
                else if (pNode.Iterator.Type.IsAssignableFrom(_enumerable))
                {
                    //We are iterating over an enumerable
                    //Reverse loops will start at Count and decrement to 0
                    //Normal loops will start at 0 and increment to Count
                    if (pNode.Reverse)
                    {
                        var count = SyntaxFactory.MemberAccess(iterVar, SyntaxFactory.Identifier("Count"));
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.BinaryExpression(count, BinaryExpressionOperator.Subtraction, SyntaxFactory.NumericLiteral(1)));
                        end  = SyntaxFactory.NumericLiteral(0);
                    }
                    else
                    {
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.NumericLiteral(0));
                        end  = SyntaxFactory.MemberAccess(iterVar, SyntaxFactory.Identifier("Count"));
                    }

                    _itVar = SyntaxFactory.MemberAccess(iterVar, SyntaxFactory.MethodCall("ItemAt", new List <SyntaxNode>()
                    {
                        SyntaxFactory.Identifier("!i")
                    }));
                }
                else
                {
                    //Some bad type. We can't rewrite if it isn't array or enumerable
                    return(base.VisitForSyntax(pNode));
                }

                var op        = pNode.Reverse ? BinaryExpressionOperator.GreaterThanOrEqual : BinaryExpressionOperator.LessThan;
                var condition = SyntaxFactory.BinaryExpression(i, op, end);
                condition.SetType(SmallTypeCache.Boolean);

                var body         = (BlockSyntax)Visit(pNode.Body);
                var forStatement = SyntaxFactory.For(new List <DeclarationSyntax>()
                {
                    decl
                }, condition, new List <SyntaxNode>()
                {
                    finalizer
                }, body);

                //Restore our it for any other nested loops
                _itVar   = it;
                _rewrite = rw;

                //Return our iterator declaration and for rewrite
                return(SyntaxFactory.Block(new List <SyntaxNode>()
                {
                    iterDecl, forStatement
                }));
            }

            return(base.VisitForSyntax(pNode));
        }
コード例 #18
0
        protected override SyntaxBase ReplaceForSyntax(ForSyntax syntax)
        {
            syntax = (ForSyntax)base.ReplaceForSyntax(syntax);

            // look for range(0, length(<variable>))
            if (!IsLoopIteratorExpression(semanticModel, syntax.Expression, out var arrayVariable))
            {
                return(syntax);
            }

            if (syntax.VariableSection is not LocalVariableSyntax indexVariable)
            {
                return(syntax);
            }

            var arraySymbol      = semanticModel.GetSymbolInfo(arrayVariable);
            var arrayIndexSymbol = semanticModel.GetSymbolInfo(indexVariable);

            if (arraySymbol is null || arrayIndexSymbol is null)
            {
                return(syntax);
            }

            var arrayAccesses            = new HashSet <ArrayAccessSyntax>();
            var independentIndexAccesses = new HashSet <VariableAccessSyntax>();

            CallbackVisitor.Visit(syntax, child =>
            {
                if (child is ArrayAccessSyntax arrayAccess)
                {
                    if (semanticModel.GetSymbolInfo(arrayAccess.BaseExpression) == arraySymbol &&
                        semanticModel.GetSymbolInfo(arrayAccess.IndexExpression) == arrayIndexSymbol)
                    {
                        arrayAccesses.Add(arrayAccess);

                        // we don't want to count the VariableAccessSyntax under this particular node,
                        // so return false to skip visiting children.
                        return(false);
                    }
                }

                if (child is VariableAccessSyntax variableAccess)
                {
                    var accessSymbol = semanticModel.GetSymbolInfo(variableAccess);
                    if (accessSymbol == arrayIndexSymbol)
                    {
                        independentIndexAccesses.Add(variableAccess);
                    }
                }

                return(true);
            });

            if (!arrayAccesses.Any())
            {
                // nothing to really simplify here
                return(syntax);
            }

            var itemVarName = GetUniqueVariableNameForNewScope(syntax, "item");
            var forBody     = CallbackRewriter.Rewrite(syntax.Body, child =>
            {
                if (arrayAccesses.Contains(child))
                {
                    return(new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(itemVarName)));
                }

                return(child);
            });

            SyntaxBase forVariableBlockSyntax;

            if (independentIndexAccesses.Any())
            {
                forVariableBlockSyntax = new ForVariableBlockSyntax(
                    SyntaxFactory.LeftParenToken,
                    new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(itemVarName)),
                    SyntaxFactory.CommaToken,
                    new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(arrayIndexSymbol.Name)),
                    SyntaxFactory.RightParenToken);
            }
            else
            {
                forVariableBlockSyntax = new LocalVariableSyntax(SyntaxFactory.CreateIdentifier(itemVarName));
            }

            var forExpression = new VariableAccessSyntax(SyntaxFactory.CreateIdentifier(arraySymbol.Name));

            return(new ForSyntax(
                       syntax.OpenSquare,
                       syntax.ForKeyword,
                       forVariableBlockSyntax,
                       syntax.InKeyword,
                       forExpression,
                       syntax.Colon,
                       forBody,
                       syntax.CloseSquare));
        }
コード例 #19
0
 public override void VisitForSyntax(ForSyntax syntax)
 {
     this.AppendError(syntax);
 }
コード例 #20
0
        private LanguageExpression GetLoopVariableExpression(LocalVariableSymbol localVariableSymbol, ForSyntax @for, LanguageExpression indexExpression)
        {
            return(localVariableSymbol.LocalKind switch
            {
                // this is the "item" variable of a for-expression
                // to emit this, we need to index the array expression by the copyIndex() function
                LocalKind.ForExpressionItemVariable => GetLoopItemVariableExpression(@for, indexExpression),

                // this is the "index" variable of a for-expression inside a variable block
                // to emit this, we need to return a copyIndex(...) function
                LocalKind.ForExpressionIndexVariable => indexExpression,

                _ => throw new NotImplementedException($"Unexpected local variable kind '{localVariableSymbol.LocalKind}'."),
            });