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(); }
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))); }
public override SyntaxNode Visit(ForSyntax pNode) { using (new MetadataCache.LocalScope()) { return(base.Visit(pNode)); } }
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; }
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); }
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(); }
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); }
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)); });
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); }
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); }
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; }
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(); }
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)"); }
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); }
private string?ErrorSyntaxInForBodyOfVariable(ForSyntax forSyntax, SyntaxBase errorSyntax) => this.SemanticModel.Binder.GetParent(forSyntax) is VariableDeclarationSyntax variableDeclarationSyntax &&
public void EmitCopyObject(string?name, ForSyntax syntax, SyntaxBase?input, string?copyIndexOverride = null, long?batchSize = null) {
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)); }
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)); }
public override void VisitForSyntax(ForSyntax syntax) { this.AppendError(syntax); }
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}'."), });