public override void Visit(ChainExpr expr) { if (ReferencesRootVariableVisitor.ReferencesRootVariable(expr)) { _needsAsync = true; return; } // Some things can't be simplified by themselves, but they can be in the // context of a chain. If this chain doesn't need to be asynchronous, then // the next key or index won't need it either. if (NeedsAsyncByItselfVisitor.NeedsAsyncByItself(expr.Next)) { _needsAsync = true; return; } }
private Expr ParseChainRemainder(Expr prev) { var token = GetToken(); Expr first = null; if (token.Kind == ".") { Match("."); first = ParseKeyExpr(prev); } else if (token.Kind == "[?") { first = ParseFilterExpr(prev); } else if (token.Kind == "[") { first = ParseIndexExpr(prev); } else if (token.Kind == "(") { // Super gross; in retrospect, all expressions should just be self-contained, or this // should at least work the same as the other chain expressions. first = ParseIndexedLookup(prev); } else if (token.Kind == "{") { var map = ParseMapProjectionExpr(null); first = new ChainExpr(prev, map, ChainBehavior.ToMultipleIfArray); } var nextToken = GetToken(); if (nextToken.Kind == "." || nextToken.Kind == "[" || nextToken.Kind == "(" || nextToken.Kind == "{" || nextToken.Kind == "[?") { return(ParseChainRemainder(first)); } else { return(first); } }
public virtual void Visit(ChainExpr expr) { }
private Expr ParseMapProjectionExpr(Expr prev) { var bracket = Match("{"); var projections = new List <Expr>(); while (true) { var token = GetToken(); if (token.Kind == "}") { Match("}"); break; } string id = null; Expr projection; if (token.Kind == "}") { Match("}"); break; } if (token.Kind == "...") { var ellipsis = Match("..."); var next = GetToken(); projection = new SpreadExpr(GetLocation(ellipsis), ParseExpr()); } else if (token.Kind == "$") { var dollar = Match("$"); var dollarLocation = GetLocation(dollar); id = Match("ID").Text; projection = new KeyValuePairExpr(dollarLocation, id, new VariableExpr(dollarLocation, id)); } else { var idToken = MatchAny(new [] { "STRING", "ID" }); var idLocation = GetLocation(idToken); id = idToken.Text; var curr = GetToken(); if (curr.Kind == ":") { Match(":"); projection = new KeyValuePairExpr(idLocation, id, ParseExpr()); } else if (curr.Kind == "{") { // These are all equivalent: // foo: foo | { a, b, c } // foo | { a, b, c } // foo { a, b, c } MatchOptional("|"); var rhs = new ChainExpr( new KeyExpr(idLocation, prev, id), ParseExpr(), ChainBehavior.ToMultipleIfArray); projection = new KeyValuePairExpr(idLocation, id, rhs); } else if (curr.Kind == "(") { // key(a: 123) => key: key(a:123) var keyExpr = new KeyExpr(idLocation, prev, id); var rhs = ParseChainRemainder(keyExpr); projection = new KeyValuePairExpr(idLocation, id, rhs); } else if (curr.Kind == "[?") { // x[? filter] => x: x[? filter] var keyExpr = new KeyExpr(idLocation, prev, id); var rhs = ParseChainRemainder(keyExpr); projection = new KeyValuePairExpr(idLocation, id, rhs); } else if (curr.Kind == "[") { // x[5] => x: x[5] var keyExpr = new KeyExpr(idLocation, prev, id); var rhs = ParseChainRemainder(keyExpr); projection = new KeyValuePairExpr(idLocation, id, rhs); } else if (curr.Kind == "|") { // These are all equivalent: // foo: foo | { a, b, c } // foo | { a, b, c } // foo { a, b, c } MatchOptional("|"); var rhs = new ChainExpr( new KeyExpr(idLocation, prev, id), ParseExpr(), ChainBehavior.OneToOne); projection = new KeyValuePairExpr(idLocation, id, rhs); } else if (curr.Kind == "|<") { // This is another shorthand for filtring an array of objects. These are equivalent: /// foo: foo |< { a, b, c } /// foo |< { a, b, c} Match("|<"); var rhs = new ChainExpr( new KeyExpr(idLocation, prev, id), ParseExpr(), ChainBehavior.ToMultiple); projection = new KeyValuePairExpr(idLocation, id, rhs); } else { projection = new KeyValuePairExpr(idLocation, id, new KeyExpr(idLocation, null, id)); } } projections.Add(projection); var tok = MatchAny(new [] { ",", "}" }); if (tok.Kind == "}") { break; } } return(new MapProjectionExpr(GetLocation(bracket), prev, projections)); }