github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/gql/parser.go (about) 1 /* 2 * Copyright 2015-2018 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package gql 18 19 import ( 20 "bytes" 21 "fmt" 22 "sort" 23 "strconv" 24 "strings" 25 26 "github.com/dgraph-io/dgraph/lex" 27 "github.com/dgraph-io/dgraph/protos/pb" 28 "github.com/dgraph-io/dgraph/x" 29 "github.com/golang/glog" 30 "github.com/pkg/errors" 31 ) 32 33 const ( 34 uidFunc = "uid" 35 valueFunc = "val" 36 typFunc = "type" 37 lenFunc = "len" 38 countFunc = "count" 39 ) 40 41 // GraphQuery stores the parsed Query in a tree format. This gets converted to 42 // pb.y used query.SubGraph before processing the query. 43 type GraphQuery struct { 44 UID []uint64 45 Attr string 46 Langs []string 47 Alias string 48 IsCount bool 49 IsInternal bool 50 IsGroupby bool 51 Var string 52 NeedsVar []VarContext 53 Func *Function 54 Expand string // Which variable to expand with. 55 56 Args map[string]string 57 // Query can have multiple sort parameters. 58 Order []*pb.Order 59 Children []*GraphQuery 60 Filter *FilterTree 61 MathExp *MathTree 62 Normalize bool 63 Recurse bool 64 RecurseArgs RecurseArgs 65 ShortestPathArgs ShortestPathArgs 66 Cascade bool 67 IgnoreReflex bool 68 Facets *pb.FacetParams 69 FacetsFilter *FilterTree 70 GroupbyAttrs []GroupByAttr 71 FacetVar map[string]string 72 FacetOrder string 73 FacetDesc bool 74 75 // Internal fields below. 76 // If gq.fragment is nonempty, then it is a fragment reference / spread. 77 fragment string 78 79 // Indicates whether count of uids is requested as a child node. If there 80 // is an alias, then UidCountAlias will be set (otherwise it will be the 81 // empty string). 82 UidCount bool 83 UidCountAlias string 84 85 // True for blocks that don't have a starting function and hence no starting nodes. They are 86 // used to aggregate and get variables defined in another block. 87 IsEmpty bool 88 } 89 90 // RecurseArgs stores the arguments needed to process the @recurse directive. 91 type RecurseArgs struct { 92 Depth uint64 93 AllowLoop bool 94 } 95 96 // ShortestPathArgs stores the arguments needed to process the shortest path query. 97 type ShortestPathArgs struct { 98 // From, To can have a uid or a uid function as the argument. 99 // 1. from: 0x01 100 // 2. from: uid(0x01) 101 // 3. from: uid(p) // a variable 102 From *Function 103 To *Function 104 } 105 106 // GroupByAttr stores the arguments needed to process the @groupby directive. 107 type GroupByAttr struct { 108 Attr string 109 Alias string 110 Langs []string 111 } 112 113 // pair denotes the key value pair that is part of the GraphQL query root in parenthesis. 114 type pair struct { 115 Key string 116 Val string 117 } 118 119 // fragmentNode is an internal structure for doing dfs on fragments. 120 type fragmentNode struct { 121 Name string 122 Gq *GraphQuery 123 Entered bool // Entered in dfs. 124 Exited bool // Exited in dfs. 125 } 126 127 // fragmentMap is used to associate fragment names to their corresponding fragmentNode. 128 type fragmentMap map[string]*fragmentNode 129 130 const ( 131 AnyVar = 0 132 UidVar = 1 133 ValueVar = 2 134 ListVar = 3 135 ) 136 137 // VarContext stores information about the vars needed to complete a query. 138 type VarContext struct { 139 Name string 140 Typ int // 1 for UID vars, 2 for value vars 141 } 142 143 // varInfo holds information on GQL variables. 144 type varInfo struct { 145 Value string 146 Type string 147 } 148 149 // varMap is a map with key as GQL variable name. 150 type varMap map[string]varInfo 151 152 // FilterTree is the result of parsing the filter directive. 153 // Either you can have `Op and Children` on non-leaf nodes 154 // Or Func at leaf nodes. 155 type FilterTree struct { 156 Op string 157 Child []*FilterTree 158 Func *Function 159 } 160 161 // Arg stores an argument to a function. 162 type Arg struct { 163 Value string 164 IsValueVar bool // If argument is val(a), e.g. eq(name, val(a)) 165 IsGraphQLVar bool 166 } 167 168 // Function holds the information about gql functions. 169 type Function struct { 170 Attr string 171 Lang string // language of the attribute value 172 Name string // Specifies the name of the function. 173 Args []Arg // Contains the arguments of the function. 174 UID []uint64 175 NeedsVar []VarContext // If the function requires some variable 176 IsCount bool // gt(count(friends),0) 177 IsValueVar bool // eq(val(s), 5) 178 IsLenVar bool // eq(len(s), 5) 179 } 180 181 // filterOpPrecedence is a map from filterOp (a string) to its precedence. 182 var filterOpPrecedence = map[string]int{ 183 "not": 3, 184 "and": 2, 185 "or": 1, 186 } 187 var mathOpPrecedence = map[string]int{ 188 "u-": 500, 189 "floor": 105, 190 "ceil": 104, 191 "since": 103, 192 "exp": 100, 193 "ln": 99, 194 "sqrt": 98, 195 "cond": 90, 196 "pow": 89, 197 "logbase": 88, 198 "max": 85, 199 "min": 84, 200 201 "/": 50, 202 "*": 49, 203 "%": 48, 204 "-": 47, 205 "+": 46, 206 207 "<": 10, 208 ">": 9, 209 "<=": 8, 210 ">=": 7, 211 "==": 6, 212 "!=": 5, 213 } 214 215 // IsAggregator returns true if the function name is an aggregation function. 216 func (f *Function) IsAggregator() bool { 217 return isAggregator(f.Name) 218 } 219 220 // IsPasswordVerifier returns true if the function name is "checkpwd". 221 func (f *Function) IsPasswordVerifier() bool { 222 return f.Name == "checkpwd" 223 } 224 225 // DebugPrint is useful for debugging. 226 func (gq *GraphQuery) DebugPrint(prefix string) { 227 glog.Infof("%s[%x %q %q]\n", prefix, gq.UID, gq.Attr, gq.Alias) 228 for _, c := range gq.Children { 229 c.DebugPrint(prefix + "|->") 230 } 231 } 232 233 func (gq *GraphQuery) isFragment() bool { 234 return gq.fragment != "" 235 } 236 237 func (fn *fragmentNode) expand(fmap fragmentMap) error { 238 if fn.Exited { 239 // This fragment node has already been expanded. 240 return nil 241 } 242 if fn.Entered { 243 return errors.Errorf("Cycle detected: %s", fn.Name) 244 } 245 fn.Entered = true 246 if err := fn.Gq.expandFragments(fmap); err != nil { 247 return err 248 } 249 fn.Exited = true 250 return nil 251 } 252 253 func (gq *GraphQuery) expandFragments(fmap fragmentMap) error { 254 // We have to make a copy of children to preserve order and replace 255 // fragment references with fragment content. The copy is newChildren. 256 var newChildren []*GraphQuery 257 // Expand non-fragments. Do not append to gq.Children. 258 for _, child := range gq.Children { 259 if child.isFragment() { 260 fname := child.fragment // Name of fragment being referenced. 261 fchild := fmap[fname] 262 if fchild == nil { 263 return errors.Errorf("Missing fragment: %s", fname) 264 } 265 if err := fchild.expand(fmap); err != nil { 266 return err 267 } 268 newChildren = append(newChildren, fchild.Gq.Children...) 269 } else { 270 if err := child.expandFragments(fmap); err != nil { 271 return err 272 } 273 newChildren = append(newChildren, child) 274 } 275 } 276 gq.Children = newChildren 277 return nil 278 } 279 280 func convertToVarMap(variables map[string]string) (vm varMap) { 281 vm = make(map[string]varInfo) 282 for k, v := range variables { 283 vm[k] = varInfo{ 284 Value: v, 285 } 286 } 287 return vm 288 } 289 290 // Request stores the query text and the variable mapping. 291 type Request struct { 292 Str string 293 Variables map[string]string 294 } 295 296 func checkValueType(vm varMap) error { 297 for k, v := range vm { 298 typ := v.Type 299 300 if len(typ) == 0 { 301 return errors.Errorf("Type of variable %v not specified", k) 302 } 303 304 // Ensure value is not nil if the variable is required. 305 if typ[len(typ)-1] == '!' { 306 if v.Value == "" { 307 return errors.Errorf("Variable %v should be initialised", k) 308 } 309 typ = typ[:len(typ)-1] 310 } 311 312 // Type check the values. 313 if v.Value != "" { 314 switch typ { 315 case "int": 316 { 317 if _, err := strconv.ParseInt(v.Value, 0, 64); err != nil { 318 return errors.Wrapf(err, "Expected an int but got %v", v.Value) 319 } 320 } 321 case "float": 322 { 323 if _, err := strconv.ParseFloat(v.Value, 64); err != nil { 324 return errors.Wrapf(err, "Expected a float but got %v", v.Value) 325 } 326 } 327 case "bool": 328 { 329 if _, err := strconv.ParseBool(v.Value); err != nil { 330 return errors.Wrapf(err, "Expected a bool but got %v", v.Value) 331 } 332 } 333 case "string": // Value is a valid string. No checks required. 334 default: 335 return errors.Errorf("Type %q not supported", typ) 336 } 337 } 338 } 339 340 return nil 341 } 342 343 func substituteVar(f string, res *string, vmap varMap) error { 344 if len(f) > 0 && f[0] == '$' { 345 va, ok := vmap[f] 346 if !ok || va.Type == "" { 347 return errors.Errorf("Variable not defined %v", f) 348 } 349 *res = va.Value 350 } 351 return nil 352 } 353 354 func substituteVariables(gq *GraphQuery, vmap varMap) error { 355 for k, v := range gq.Args { 356 // v won't be empty as its handled in parseGqlVariables. 357 val := gq.Args[k] 358 if err := substituteVar(v, &val, vmap); err != nil { 359 return err 360 } 361 gq.Args[k] = val 362 } 363 364 idVal, ok := gq.Args["id"] 365 if ok && len(gq.UID) == 0 { 366 if idVal == "" { 367 return errors.Errorf("Id can't be empty") 368 } 369 uids, err := parseID(idVal) 370 if err != nil { 371 return err 372 } 373 gq.UID = append(gq.UID, uids...) 374 // Deleting it here because we don't need to fill it in query.go. 375 delete(gq.Args, "id") 376 } 377 378 if gq.Func != nil { 379 if err := substituteVar(gq.Func.Attr, &gq.Func.Attr, vmap); err != nil { 380 return err 381 } 382 383 for idx, v := range gq.Func.Args { 384 if !v.IsGraphQLVar { 385 continue 386 } 387 if err := substituteVar(v.Value, &gq.Func.Args[idx].Value, vmap); err != nil { 388 return err 389 } 390 if gq.Func.Name == "regexp" { 391 // Value should have been populated from the map that the user gave us in the 392 // GraphQL variable map. Let's parse the expression and flags from the variable 393 // string. 394 ra, err := parseRegexArgs(gq.Func.Args[idx].Value) 395 if err != nil { 396 return err 397 } 398 // We modify the value of this arg and add a new arg for the flags. Regex functions 399 // should have two args. 400 gq.Func.Args[idx].Value = ra.expr 401 gq.Func.Args = append(gq.Func.Args, Arg{Value: ra.flags}) 402 } 403 } 404 } 405 406 for _, child := range gq.Children { 407 if err := substituteVariables(child, vmap); err != nil { 408 return err 409 } 410 } 411 if gq.Filter != nil { 412 if err := substituteVariablesFilter(gq.Filter, vmap); err != nil { 413 return err 414 } 415 } 416 return nil 417 } 418 419 func substituteVariablesFilter(f *FilterTree, vmap varMap) error { 420 if f.Func != nil { 421 if err := substituteVar(f.Func.Attr, &f.Func.Attr, vmap); err != nil { 422 return err 423 } 424 425 for idx, v := range f.Func.Args { 426 if f.Func.Name == uidFunc { 427 // This is to support GraphQL variables in uid functions. 428 idVal, ok := vmap[v.Value] 429 if !ok { 430 return errors.Errorf("Couldn't find value for GraphQL variable: [%s]", v.Value) 431 } 432 if idVal.Value == "" { 433 return errors.Errorf("Id can't be empty") 434 } 435 uids, err := parseID(idVal.Value) 436 if err != nil { 437 return err 438 } 439 f.Func.UID = append(f.Func.UID, uids...) 440 continue 441 } 442 443 if err := substituteVar(v.Value, &f.Func.Args[idx].Value, vmap); err != nil { 444 return err 445 } 446 } 447 } 448 449 for _, fChild := range f.Child { 450 if err := substituteVariablesFilter(fChild, vmap); err != nil { 451 return err 452 } 453 } 454 return nil 455 } 456 457 // Vars struct contains the list of variables defined and used by a 458 // query block. 459 type Vars struct { 460 Defines []string 461 Needs []string 462 } 463 464 // Result struct contains the Query list, its corresponding variable use list 465 // and the mutation block. 466 type Result struct { 467 Query []*GraphQuery 468 QueryVars []*Vars 469 Schema *pb.SchemaRequest 470 } 471 472 // Parse initializes and runs the lexer. It also constructs the GraphQuery subgraph 473 // from the lexed items. 474 func Parse(r Request) (Result, error) { 475 return ParseWithNeedVars(r, nil) 476 } 477 478 // ParseWithNeedVars performs parsing of a query with given needVars. 479 // 480 // The needVars parameter is passed in the case of upsert block. 481 // For example, when parsing the query block inside - 482 // upsert { 483 // query { 484 // me(func: eq(email, "someone@gmail.com"), first: 1) { 485 // v as uid 486 // } 487 // } 488 // 489 // mutation { 490 // set { 491 // uid(v) <name> "Some One" . 492 // uid(v) <email> "someone@gmail.com" . 493 // } 494 // } 495 // } 496 // 497 // The variable name v needs to be passed through the needVars parameter. Otherwise, an error 498 // is reported complaining that the variable v is defined but not used in the query block. 499 func ParseWithNeedVars(r Request, needVars []string) (res Result, rerr error) { 500 query := r.Str 501 vmap := convertToVarMap(r.Variables) 502 503 var lexer lex.Lexer 504 lexer.Reset(query) 505 lexer.Run(lexTopLevel) 506 if err := lexer.ValidateResult(); err != nil { 507 return res, err 508 } 509 510 var qu *GraphQuery 511 it := lexer.NewIterator() 512 fmap := make(fragmentMap) 513 for it.Next() { 514 item := it.Item() 515 switch item.Typ { 516 case itemOpType: 517 if item.Val == "mutation" { 518 return res, item.Errorf("Mutation block no longer allowed.") 519 } 520 if item.Val == "schema" { 521 if res.Schema != nil { 522 return res, item.Errorf("Only one schema block allowed ") 523 } 524 if res.Query != nil { 525 return res, item.Errorf("Schema block is not allowed with query block") 526 } 527 if res.Schema, rerr = getSchema(it); rerr != nil { 528 return res, rerr 529 } 530 } else if item.Val == "fragment" { 531 // TODO(jchiu0): This is to be done in ParseSchema once it is ready. 532 fnode, rerr := getFragment(it) 533 if rerr != nil { 534 return res, rerr 535 } 536 fmap[fnode.Name] = fnode 537 } else if item.Val == "query" { 538 if res.Schema != nil { 539 return res, item.Errorf("Schema block is not allowed with query block") 540 } 541 if qu, rerr = getVariablesAndQuery(it, vmap); rerr != nil { 542 return res, rerr 543 } 544 res.Query = append(res.Query, qu) 545 } 546 case itemLeftCurl: 547 if qu, rerr = getQuery(it); rerr != nil { 548 return res, rerr 549 } 550 res.Query = append(res.Query, qu) 551 case itemName: 552 it.Prev() 553 if qu, rerr = getQuery(it); rerr != nil { 554 return res, rerr 555 } 556 res.Query = append(res.Query, qu) 557 } 558 } 559 560 if len(res.Query) != 0 { 561 res.QueryVars = make([]*Vars, 0, len(res.Query)) 562 for i := 0; i < len(res.Query); i++ { 563 qu := res.Query[i] 564 // Try expanding fragments using fragment map. 565 if err := qu.expandFragments(fmap); err != nil { 566 return res, err 567 } 568 569 // Substitute all graphql variables with corresponding values 570 if err := substituteVariables(qu, vmap); err != nil { 571 return res, err 572 } 573 574 res.QueryVars = append(res.QueryVars, &Vars{}) 575 // Collect vars used and defined in Result struct. 576 qu.collectVars(res.QueryVars[i]) 577 } 578 579 allVars := res.QueryVars 580 // Add the variables that are needed outside the query block. 581 // For example, mutation block in upsert block will be using 582 // variables from the query block that is getting parsed here. 583 if len(needVars) != 0 { 584 allVars = append(allVars, &Vars{Needs: needVars}) 585 } 586 if err := checkDependency(allVars); err != nil { 587 return res, err 588 } 589 } 590 591 if err := validateResult(&res); err != nil { 592 return res, err 593 } 594 595 return res, nil 596 } 597 598 func validateResult(res *Result) error { 599 seenQueryAliases := make(map[string]bool) 600 for _, q := range res.Query { 601 if q.Alias == "var" || q.Alias == "shortest" { 602 continue 603 } 604 if _, found := seenQueryAliases[q.Alias]; found { 605 return errors.Errorf("Duplicate aliases not allowed: %v", q.Alias) 606 } 607 seenQueryAliases[q.Alias] = true 608 } 609 return nil 610 } 611 612 func flatten(vl []*Vars) (needs []string, defines []string) { 613 needs, defines = make([]string, 0, 10), make([]string, 0, 10) 614 for _, it := range vl { 615 needs = append(needs, it.Needs...) 616 defines = append(defines, it.Defines...) 617 } 618 return 619 } 620 621 func checkDependency(vl []*Vars) error { 622 needs, defines := flatten(vl) 623 624 needs = x.RemoveDuplicates(needs) 625 lenBefore := len(defines) 626 defines = x.RemoveDuplicates(defines) 627 628 if len(defines) != lenBefore { 629 return errors.Errorf("Some variables are declared multiple times.") 630 } 631 if len(defines) > len(needs) { 632 return errors.Errorf("Some variables are defined but not used\nDefined:%v\nUsed:%v\n", 633 defines, needs) 634 } 635 if len(defines) < len(needs) { 636 return errors.Errorf("Some variables are used but not defined\nDefined:%v\nUsed:%v\n", 637 defines, needs) 638 } 639 640 for i := 0; i < len(defines); i++ { 641 if defines[i] != needs[i] { 642 return errors.Errorf("Variables are not used properly. \nDefined:%v\nUsed:%v\n", 643 defines, needs) 644 } 645 } 646 return nil 647 } 648 649 func (gq *GraphQuery) collectVars(v *Vars) { 650 if gq.Var != "" { 651 v.Defines = append(v.Defines, gq.Var) 652 } 653 if gq.FacetVar != nil { 654 for _, va := range gq.FacetVar { 655 v.Defines = append(v.Defines, va) 656 } 657 } 658 for _, va := range gq.NeedsVar { 659 v.Needs = append(v.Needs, va.Name) 660 } 661 662 for _, ch := range gq.Children { 663 ch.collectVars(v) 664 } 665 if gq.Filter != nil { 666 gq.Filter.collectVars(v) 667 } 668 if gq.MathExp != nil { 669 gq.MathExp.collectVars(v) 670 } 671 672 shortestPathFrom := gq.ShortestPathArgs.From 673 if shortestPathFrom != nil && len(shortestPathFrom.NeedsVar) > 0 { 674 v.Needs = append(v.Needs, shortestPathFrom.NeedsVar[0].Name) 675 } 676 shortestPathTo := gq.ShortestPathArgs.To 677 if shortestPathTo != nil && len(shortestPathTo.NeedsVar) > 0 { 678 v.Needs = append(v.Needs, shortestPathTo.NeedsVar[0].Name) 679 } 680 } 681 682 func (f *MathTree) collectVars(v *Vars) { 683 if f == nil { 684 return 685 } 686 if f.Var != "" { 687 v.Needs = append(v.Needs, f.Var) 688 return 689 } 690 for _, fch := range f.Child { 691 fch.collectVars(v) 692 } 693 } 694 695 func (f *FilterTree) collectVars(v *Vars) { 696 if f.Func != nil { 697 for _, va := range f.Func.NeedsVar { 698 v.Needs = append(v.Needs, va.Name) 699 } 700 } 701 for _, fch := range f.Child { 702 fch.collectVars(v) 703 } 704 } 705 706 func (f *FilterTree) hasVars() bool { 707 if (f.Func != nil) && (len(f.Func.NeedsVar) > 0) { 708 return true 709 } 710 for _, fch := range f.Child { 711 if fch.hasVars() { 712 return true 713 } 714 } 715 return false 716 } 717 718 // getVariablesAndQuery checks if the query has a variable list and stores it in 719 // vmap. For variable list to be present, the query should have a name which is 720 // also checked for. It also calls getQuery to create the GraphQuery object tree. 721 func getVariablesAndQuery(it *lex.ItemIterator, vmap varMap) (gq *GraphQuery, rerr error) { 722 var name string 723 L2: 724 for it.Next() { 725 item := it.Item() 726 switch item.Typ { 727 case itemName: 728 if name != "" { 729 return nil, item.Errorf("Multiple word query name not allowed.") 730 } 731 name = item.Val 732 case itemLeftRound: 733 if name == "" { 734 return nil, item.Errorf("Variables can be defined only in named queries.") 735 } 736 737 if rerr = parseGqlVariables(it, vmap); rerr != nil { 738 return nil, rerr 739 } 740 741 if rerr = checkValueType(vmap); rerr != nil { 742 return nil, rerr 743 } 744 case itemLeftCurl: 745 if gq, rerr = getQuery(it); rerr != nil { 746 return nil, rerr 747 } 748 break L2 749 } 750 } 751 752 return gq, nil 753 } 754 755 func parseRecurseArgs(it *lex.ItemIterator, gq *GraphQuery) error { 756 if ok := trySkipItemTyp(it, itemLeftRound); !ok { 757 // We don't have a (, we can return. 758 return nil 759 } 760 761 var key, val string 762 var ok bool 763 for it.Next() { 764 item := it.Item() 765 if item.Typ != itemName { 766 return item.Errorf("Expected key inside @recurse()") 767 } 768 key = strings.ToLower(item.Val) 769 770 if ok := trySkipItemTyp(it, itemColon); !ok { 771 return it.Errorf("Expected colon(:) after %s", key) 772 } 773 774 if item, ok = tryParseItemType(it, itemName); !ok { 775 return item.Errorf("Expected value inside @recurse() for key: %s", key) 776 } 777 val = item.Val 778 779 switch key { 780 case "depth": 781 depth, err := strconv.ParseUint(val, 0, 64) 782 if err != nil { 783 return err 784 } 785 gq.RecurseArgs.Depth = depth 786 case "loop": 787 allowLoop, err := strconv.ParseBool(val) 788 if err != nil { 789 return err 790 } 791 gq.RecurseArgs.AllowLoop = allowLoop 792 default: 793 return item.Errorf("Unexpected key: [%s] inside @recurse block", key) 794 } 795 796 if _, ok := tryParseItemType(it, itemRightRound); ok { 797 return nil 798 } 799 800 if _, ok := tryParseItemType(it, itemComma); !ok { 801 return it.Errorf("Expected comma after value: %s inside recurse block", val) 802 } 803 } 804 return nil 805 } 806 807 // getQuery creates a GraphQuery object tree by calling getRoot 808 // and goDeep functions by looking at '{'. 809 func getQuery(it *lex.ItemIterator) (gq *GraphQuery, rerr error) { 810 // First, get the root 811 gq, rerr = getRoot(it) 812 if rerr != nil { 813 return nil, rerr 814 } 815 816 var seenFilter bool 817 L: 818 // Recurse to deeper levels through godeep. 819 if !it.Next() { 820 return nil, it.Errorf("Expecting more lexer items while parsing query") 821 } 822 823 item := it.Item() 824 if item.Typ == itemLeftCurl { 825 if rerr = godeep(it, gq); rerr != nil { 826 return nil, rerr 827 } 828 } else if item.Typ == itemAt { 829 it.Next() 830 item := it.Item() 831 if item.Typ == itemName { 832 switch strings.ToLower(item.Val) { 833 case "filter": 834 if seenFilter { 835 return nil, item.Errorf("Repeated filter at root") 836 } 837 seenFilter = true 838 filter, err := parseFilter(it) 839 if err != nil { 840 return nil, err 841 } 842 gq.Filter = filter 843 844 case "normalize": 845 gq.Normalize = true 846 case "cascade": 847 gq.Cascade = true 848 case "groupby": 849 gq.IsGroupby = true 850 if err := parseGroupby(it, gq); err != nil { 851 return nil, err 852 } 853 case "ignorereflex": 854 gq.IgnoreReflex = true 855 case "recurse": 856 gq.Recurse = true 857 if err := parseRecurseArgs(it, gq); err != nil { 858 return nil, err 859 } 860 default: 861 return nil, item.Errorf("Unknown directive [%s]", item.Val) 862 } 863 goto L 864 } 865 } else if item.Typ == itemRightCurl { 866 // Do nothing. 867 } else if item.Typ == itemName { 868 it.Prev() 869 return gq, nil 870 } else { 871 return nil, item.Errorf("Malformed Query. Missing {. Got %v", item.Val) 872 } 873 874 return gq, nil 875 } 876 877 // getFragment parses a fragment definition (not reference). 878 func getFragment(it *lex.ItemIterator) (*fragmentNode, error) { 879 var name string 880 for it.Next() { 881 item := it.Item() 882 if item.Typ == itemName { 883 v := strings.TrimSpace(item.Val) 884 if len(v) > 0 && name == "" { 885 // Currently, we take the first nontrivial token as the 886 // fragment name and ignore everything after that until we see 887 // a left curl. 888 name = v 889 } 890 } else if item.Typ == itemLeftCurl { 891 break 892 } else { 893 return nil, item.Errorf("Unexpected item in fragment: %v %v", item.Typ, item.Val) 894 } 895 } 896 if name == "" { 897 return nil, it.Errorf("Empty fragment name") 898 } 899 900 gq := &GraphQuery{ 901 Args: make(map[string]string), 902 } 903 if err := godeep(it, gq); err != nil { 904 return nil, err 905 } 906 fn := &fragmentNode{ 907 Name: name, 908 Gq: gq, 909 } 910 return fn, nil 911 } 912 913 // parses till rightSquare is found (parses [a, b]) excluding leftSquare 914 // This function can be reused for query later 915 func parseListItemNames(it *lex.ItemIterator) ([]string, error) { 916 var items []string 917 for it.Next() { 918 item := it.Item() 919 switch item.Typ { 920 case itemRightSquare: 921 return items, nil 922 case itemName: 923 val := collectName(it, item.Val) 924 items = append(items, val) 925 case itemComma: 926 it.Next() 927 item = it.Item() 928 if item.Typ != itemName { 929 return items, item.Errorf("Invalid scheam block") 930 } 931 val := collectName(it, item.Val) 932 items = append(items, val) 933 default: 934 return items, item.Errorf("Invalid schema block") 935 } 936 } 937 return items, it.Errorf("Expecting ] to end list but none was found") 938 } 939 940 // parseSchemaPredsOrTypes parses till rightround is found 941 func parseSchemaPredsOrTypes(it *lex.ItemIterator, s *pb.SchemaRequest) error { 942 // pred or type should be followed by colon 943 it.Next() 944 item := it.Item() 945 if item.Typ != itemName && !(item.Val == "pred" || item.Val == "type") { 946 return item.Errorf("Invalid schema block") 947 } 948 parseTypes := false 949 if item.Val == "type" { 950 parseTypes = true 951 } 952 953 it.Next() 954 item = it.Item() 955 if item.Typ != itemColon { 956 return item.Errorf("Invalid schema block") 957 } 958 959 // can be a or [a,b] 960 it.Next() 961 item = it.Item() 962 if item.Typ == itemName { 963 if parseTypes { 964 s.Types = append(s.Types, item.Val) 965 } else { 966 s.Predicates = append(s.Predicates, item.Val) 967 } 968 } else if item.Typ == itemLeftSquare { 969 names, err := parseListItemNames(it) 970 if err != nil { 971 return err 972 } 973 974 if parseTypes { 975 s.Types = names 976 } else { 977 s.Predicates = names 978 } 979 } else { 980 return item.Errorf("Invalid schema block") 981 } 982 983 it.Next() 984 item = it.Item() 985 if item.Typ == itemRightRound { 986 return nil 987 } 988 return item.Errorf("Invalid schema blocks") 989 } 990 991 // parses till rightcurl is found 992 func parseSchemaFields(it *lex.ItemIterator, s *pb.SchemaRequest) error { 993 for it.Next() { 994 item := it.Item() 995 switch item.Typ { 996 case itemRightCurl: 997 return nil 998 case itemName: 999 s.Fields = append(s.Fields, item.Val) 1000 default: 1001 return item.Errorf("Invalid schema block.") 1002 } 1003 } 1004 return it.Errorf("Expecting } to end fields list, but none was found") 1005 } 1006 1007 func getSchema(it *lex.ItemIterator) (*pb.SchemaRequest, error) { 1008 var s pb.SchemaRequest 1009 leftRoundSeen := false 1010 for it.Next() { 1011 item := it.Item() 1012 switch item.Typ { 1013 case itemLeftCurl: 1014 if err := parseSchemaFields(it, &s); err != nil { 1015 return nil, err 1016 } 1017 return &s, nil 1018 case itemLeftRound: 1019 if leftRoundSeen { 1020 return nil, item.Errorf("Too many left rounds in schema block") 1021 } 1022 leftRoundSeen = true 1023 if err := parseSchemaPredsOrTypes(it, &s); err != nil { 1024 return nil, err 1025 } 1026 default: 1027 return nil, item.Errorf("Invalid schema block") 1028 } 1029 } 1030 return nil, it.Errorf("Invalid schema block.") 1031 } 1032 1033 // parseGqlVariables parses the the graphQL variable declaration. 1034 func parseGqlVariables(it *lex.ItemIterator, vmap varMap) error { 1035 expectArg := true 1036 for it.Next() { 1037 var varName string 1038 // Get variable name. 1039 item := it.Item() 1040 if item.Typ == itemDollar { 1041 if !expectArg { 1042 return item.Errorf("Missing comma in var declaration") 1043 } 1044 it.Next() 1045 item = it.Item() 1046 if item.Typ == itemName { 1047 varName = fmt.Sprintf("$%s", item.Val) 1048 } else { 1049 return item.Errorf("Expecting a variable name. Got: %v", item) 1050 } 1051 } else if item.Typ == itemRightRound { 1052 if expectArg { 1053 return item.Errorf("Invalid comma in var block") 1054 } 1055 break 1056 } else if item.Typ == itemComma { 1057 if expectArg { 1058 return item.Errorf("Invalid comma in var block") 1059 } 1060 expectArg = true 1061 continue 1062 } else { 1063 return item.Errorf("Unexpected item in place of variable. Got: %v %v", item, 1064 item.Typ == itemDollar) 1065 } 1066 1067 it.Next() 1068 item = it.Item() 1069 if item.Typ != itemColon { 1070 return item.Errorf("Expecting a colon. Got: %v", item) 1071 } 1072 1073 // Get variable type. 1074 it.Next() 1075 item = it.Item() 1076 if item.Typ != itemName { 1077 return item.Errorf("Expecting a variable type. Got: %v", item) 1078 } 1079 1080 // Ensure that the type is not nil. 1081 varType := item.Val 1082 if varType == "" { 1083 return item.Errorf("Type of a variable can't be empty") 1084 } 1085 it.Next() 1086 item = it.Item() 1087 if item.Typ == itemMathOp && item.Val == "!" { 1088 varType += item.Val 1089 it.Next() 1090 item = it.Item() 1091 } 1092 // Insert the variable into the map. The variable might already be defiend 1093 // in the variable list passed with the query. 1094 if _, ok := vmap[varName]; ok { 1095 vmap[varName] = varInfo{ 1096 Value: vmap[varName].Value, 1097 Type: varType, 1098 } 1099 } else { 1100 vmap[varName] = varInfo{ 1101 Type: varType, 1102 } 1103 } 1104 1105 // Check for '=' sign and optional default value. 1106 if item.Typ == itemEqual { 1107 it.Next() 1108 it := it.Item() 1109 if it.Typ != itemName { 1110 return item.Errorf("Expecting default value of a variable. Got: %v", item) 1111 } 1112 1113 if varType[len(varType)-1] == '!' { 1114 return item.Errorf("Type ending with ! can't have default value: Got: %v", varType) 1115 } 1116 1117 // If value is empty replace, otherwise ignore the default value 1118 // as the intialised value will override the default value. 1119 if vmap[varName].Value == "" { 1120 uq, err := unquoteIfQuoted(it.Val) 1121 if err != nil { 1122 return err 1123 } 1124 vmap[varName] = varInfo{ 1125 Value: uq, 1126 Type: varType, 1127 } 1128 } 1129 } else if item.Typ == itemRightRound { 1130 break 1131 } else { 1132 // We consumed an extra item to see if it was an '=' sign, so move back. 1133 it.Prev() 1134 } 1135 expectArg = false 1136 } 1137 return nil 1138 } 1139 1140 // unquoteIfQuoted checks if str is quoted (starts and ends with quotes). If 1141 // so, it tries to unquote str possibly returning an error. Otherwise, the 1142 // original value is returned. 1143 func unquoteIfQuoted(str string) (string, error) { 1144 if len(str) < 2 || str[0] != quote || str[len(str)-1] != quote { 1145 return str, nil 1146 } 1147 uq, err := strconv.Unquote(str) 1148 return uq, errors.Wrapf(err, "could not unquote %q:", str) 1149 } 1150 1151 // parseArguments parses the arguments part of the GraphQL query root. 1152 func parseArguments(it *lex.ItemIterator, gq *GraphQuery) (result []pair, rerr error) { 1153 expectArg := true 1154 orderCount := 0 1155 for it.Next() { 1156 var p pair 1157 // Get key. 1158 item := it.Item() 1159 if item.Typ == itemName { 1160 if !expectArg { 1161 return result, item.Errorf("Expecting a comma. But got: %v", item.Val) 1162 } 1163 p.Key = collectName(it, item.Val) 1164 if isSortkey(p.Key) { 1165 orderCount++ 1166 } 1167 expectArg = false 1168 } else if item.Typ == itemRightRound { 1169 if expectArg { 1170 return result, item.Errorf("Expected argument but got ')'.") 1171 } 1172 break 1173 } else if item.Typ == itemComma { 1174 if expectArg { 1175 return result, item.Errorf("Expected Argument but got comma.") 1176 } 1177 expectArg = true 1178 continue 1179 } else { 1180 return result, item.Errorf("Expecting argument name. Got: %v", item) 1181 } 1182 1183 it.Next() 1184 item = it.Item() 1185 if item.Typ != itemColon { 1186 return result, item.Errorf("Expecting a colon. Got: %v in %v", item, gq.Attr) 1187 } 1188 1189 // Get value. 1190 it.Next() 1191 item = it.Item() 1192 var val string 1193 if item.Val == valueFunc { 1194 count, err := parseVarList(it, gq) 1195 if err != nil { 1196 return result, err 1197 } 1198 if count != 1 { 1199 return result, item.Errorf("Only one variable expected. Got %d", count) 1200 } 1201 gq.NeedsVar[len(gq.NeedsVar)-1].Typ = ValueVar 1202 p.Val = gq.NeedsVar[len(gq.NeedsVar)-1].Name 1203 result = append(result, p) 1204 if isSortkey(p.Key) && orderCount > 1 { 1205 return result, item.Errorf("Multiple sorting only allowed by predicates. Got: %+v", 1206 p.Val) 1207 } 1208 continue 1209 } 1210 1211 if item.Typ == itemDollar { 1212 val = "$" 1213 it.Next() 1214 item = it.Item() 1215 if item.Typ != itemName { 1216 return result, item.Errorf("Expecting argument value. Got: %v", item) 1217 } 1218 } else if item.Typ == itemMathOp { 1219 if item.Val != "+" && item.Val != "-" { 1220 return result, item.Errorf("Only Plus and minus are allowed unary ops. Got: %v", 1221 item.Val) 1222 } 1223 val = item.Val 1224 it.Next() 1225 item = it.Item() 1226 } else if item.Typ != itemName { 1227 return result, item.Errorf("Expecting argument value. Got: %v", item) 1228 } 1229 1230 p.Val = collectName(it, val+item.Val) 1231 1232 // Get language list, if present 1233 items, err := it.Peek(1) 1234 if err == nil && items[0].Typ == itemAt { 1235 it.Next() // consume '@' 1236 it.Next() // move forward 1237 langs, err := parseLanguageList(it) 1238 if err != nil { 1239 return nil, err 1240 } 1241 p.Val = p.Val + "@" + strings.Join(langs, ":") 1242 } 1243 1244 result = append(result, p) 1245 } 1246 return result, nil 1247 } 1248 1249 // debugString converts FilterTree to a string. Good for testing, debugging. 1250 // nolint: unused 1251 func (f *FilterTree) debugString() string { 1252 buf := bytes.NewBuffer(make([]byte, 0, 20)) 1253 f.stringHelper(buf) 1254 return buf.String() 1255 } 1256 1257 // stringHelper does simple DFS to convert FilterTree to string. 1258 // nolint: unused 1259 func (f *FilterTree) stringHelper(buf *bytes.Buffer) { 1260 x.AssertTrue(f != nil) 1261 if f.Func != nil && len(f.Func.Name) > 0 { 1262 // Leaf node. 1263 buf.WriteRune('(') 1264 buf.WriteString(f.Func.Name) 1265 1266 if len(f.Func.Attr) > 0 { 1267 buf.WriteRune(' ') 1268 if f.Func.IsCount { 1269 buf.WriteString("count(") 1270 } else if f.Func.IsValueVar { 1271 buf.WriteString("val(") 1272 } else if f.Func.IsLenVar { 1273 buf.WriteString("len(") 1274 } 1275 buf.WriteString(f.Func.Attr) 1276 if f.Func.IsCount || f.Func.IsValueVar || f.Func.IsLenVar { 1277 buf.WriteRune(')') 1278 } 1279 if len(f.Func.Lang) > 0 { 1280 buf.WriteRune('@') 1281 buf.WriteString(f.Func.Lang) 1282 } 1283 1284 for _, arg := range f.Func.Args { 1285 if arg.IsValueVar { 1286 buf.WriteString(" val(") 1287 } else { 1288 buf.WriteString(" \"") 1289 } 1290 buf.WriteString(arg.Value) 1291 if arg.IsValueVar { 1292 buf.WriteRune(')') 1293 } else { 1294 buf.WriteRune('"') 1295 } 1296 } 1297 } 1298 buf.WriteRune(')') 1299 return 1300 } 1301 // Non-leaf node. 1302 buf.WriteRune('(') 1303 switch f.Op { 1304 case "and": 1305 buf.WriteString("AND") 1306 case "or": 1307 buf.WriteString("OR") 1308 case "not": 1309 buf.WriteString("NOT") 1310 default: 1311 x.Fatalf("Unknown operator: %q", f.Op) 1312 } 1313 1314 for _, c := range f.Child { 1315 buf.WriteRune(' ') 1316 c.stringHelper(buf) 1317 } 1318 buf.WriteRune(')') 1319 } 1320 1321 type filterTreeStack struct{ a []*FilterTree } 1322 1323 func (s *filterTreeStack) empty() bool { return len(s.a) == 0 } 1324 func (s *filterTreeStack) size() int { return len(s.a) } 1325 func (s *filterTreeStack) push(t *FilterTree) { s.a = append(s.a, t) } 1326 1327 func (s *filterTreeStack) popAssert() *FilterTree { 1328 x.AssertTrue(!s.empty()) 1329 last := s.a[len(s.a)-1] 1330 s.a = s.a[:len(s.a)-1] 1331 return last 1332 } 1333 1334 func (s *filterTreeStack) pop() (*FilterTree, error) { 1335 if s.empty() { 1336 return nil, errors.Errorf("Empty stack") 1337 } 1338 last := s.a[len(s.a)-1] 1339 s.a = s.a[:len(s.a)-1] 1340 return last, nil 1341 } 1342 1343 func (s *filterTreeStack) peek() *FilterTree { 1344 x.AssertTruef(!s.empty(), "Trying to peek empty stack") 1345 return s.a[len(s.a)-1] 1346 } 1347 1348 func evalStack(opStack, valueStack *filterTreeStack) error { 1349 topOp, err := opStack.pop() 1350 if err != nil { 1351 return errors.Errorf("Invalid filter statement") 1352 } 1353 if topOp.Op == "not" { 1354 // Since "not" is a unary operator, just pop one value. 1355 topVal, err := valueStack.pop() 1356 if err != nil { 1357 return errors.Errorf("Invalid filter statement") 1358 } 1359 topOp.Child = []*FilterTree{topVal} 1360 } else { 1361 // "and" and "or" are binary operators, so pop two values. 1362 if valueStack.size() < 2 { 1363 return errors.Errorf("Invalid filter statement") 1364 } 1365 topVal1 := valueStack.popAssert() 1366 topVal2 := valueStack.popAssert() 1367 topOp.Child = []*FilterTree{topVal2, topVal1} 1368 } 1369 // Push the new value (tree) into the valueStack. 1370 valueStack.push(topOp) 1371 return nil 1372 } 1373 1374 func parseGeoArgs(it *lex.ItemIterator, g *Function) error { 1375 buf := new(bytes.Buffer) 1376 buf.WriteString("[") 1377 depth := 1 1378 for { 1379 if valid := it.Next(); !valid { 1380 return it.Errorf("Got EOF while parsing Geo tokens") 1381 } 1382 item := it.Item() 1383 switch item.Typ { 1384 case itemLeftSquare: 1385 buf.WriteString(item.Val) 1386 depth++ 1387 case itemRightSquare: 1388 buf.WriteString(item.Val) 1389 depth-- 1390 case itemMathOp, itemComma, itemName: 1391 // Writing tokens to buffer. 1392 buf.WriteString(item.Val) 1393 default: 1394 return item.Errorf("Found invalid item: %s while parsing geo arguments.", 1395 item.Val) 1396 } 1397 1398 if depth > 4 || depth < 0 { 1399 return item.Errorf("Invalid bracket sequence") 1400 } else if depth == 0 { 1401 break 1402 } 1403 } 1404 // Lets append the concatenated Geo token to Args. 1405 // TODO - See if we can directly encode to Geo format. 1406 g.Args = append(g.Args, Arg{Value: buf.String()}) 1407 items, err := it.Peek(1) 1408 if err != nil { 1409 return it.Errorf("Unexpected EOF while parsing args") 1410 } 1411 item := items[0] 1412 if item.Typ != itemRightRound && item.Typ != itemComma { 1413 return item.Errorf("Expected right round or comma. Got: %+v", 1414 items[0]) 1415 } 1416 return nil 1417 } 1418 1419 // parseIneqArgs will try to parse the arguments inside an array ([]). If the values 1420 // are prefixed with $ they are treated as Gql variables, otherwise they are used as scalar values. 1421 // Returns nil on success while appending arguments to the function Args slice. Otherwise 1422 // returns an error, which can be a parsing or value error. 1423 func parseIneqArgs(it *lex.ItemIterator, g *Function) error { 1424 var expectArg, isDollar bool 1425 1426 expectArg = true 1427 for it.Next() { 1428 item := it.Item() 1429 switch item.Typ { 1430 case itemRightSquare: 1431 return nil 1432 case itemDollar: 1433 if !expectArg { 1434 return item.Errorf("Missing comma in argument list declaration") 1435 } 1436 if item, ok := it.PeekOne(); !ok || item.Typ != itemName { 1437 return item.Errorf("Expecting a variable name. Got: %v", item) 1438 } 1439 isDollar = true 1440 continue 1441 case itemName: 1442 // This is not a $variable, just add the value. 1443 if !isDollar { 1444 val, err := getValueArg(item.Val) 1445 if err != nil { 1446 return err 1447 } 1448 g.Args = append(g.Args, Arg{Value: val}) 1449 break 1450 } 1451 // This is a $variable that must be expanded later. 1452 val := "$" + item.Val 1453 g.Args = append(g.Args, Arg{Value: val, IsGraphQLVar: true}) 1454 case itemComma: 1455 if expectArg { 1456 return item.Errorf("Invalid comma in argument list") 1457 } 1458 expectArg = true 1459 continue 1460 default: 1461 return item.Errorf("Invalid arg list") 1462 } 1463 expectArg = false 1464 isDollar = false 1465 } 1466 return it.Errorf("Expecting ] to end list but got %v instead", it.Item().Val) 1467 } 1468 1469 // getValueArg returns a space-trimmed and unquoted version of val. 1470 // Returns the cleaned string, otherwise empty string and an error. 1471 func getValueArg(val string) (string, error) { 1472 return unquoteIfQuoted(strings.TrimSpace(val)) 1473 } 1474 1475 func validFuncName(name string) bool { 1476 if isGeoFunc(name) || isInequalityFn(name) { 1477 return true 1478 } 1479 1480 switch name { 1481 case "regexp", "anyofterms", "allofterms", "alloftext", "anyoftext", 1482 "has", "uid", "uid_in", "anyof", "allof", "type", "match": 1483 return true 1484 } 1485 return false 1486 } 1487 1488 type regexArgs struct { 1489 expr string 1490 flags string 1491 } 1492 1493 func parseRegexArgs(val string) (regexArgs, error) { 1494 end := strings.LastIndex(val, "/") 1495 if end < 0 { 1496 return regexArgs{}, errors.Errorf("Unexpected error while parsing regex arg: %s", val) 1497 } 1498 expr := strings.Replace(val[1:end], "\\/", "/", -1) 1499 flags := "" 1500 if end+1 < len(val) { 1501 flags = val[end+1:] 1502 } 1503 1504 return regexArgs{expr, flags}, nil 1505 } 1506 1507 func parseFunction(it *lex.ItemIterator, gq *GraphQuery) (*Function, error) { 1508 function := &Function{} 1509 var expectArg, seenFuncArg, expectLang, isDollar bool 1510 L: 1511 for it.Next() { 1512 item := it.Item() 1513 if item.Typ != itemName { 1514 return nil, item.Errorf("Expected a function but got %q", item.Val) 1515 1516 } 1517 1518 name := collectName(it, item.Val) 1519 function.Name = strings.ToLower(name) 1520 if _, ok := tryParseItemType(it, itemLeftRound); !ok { 1521 return nil, it.Errorf("Expected ( after func name [%s]", function.Name) 1522 } 1523 1524 attrItemsAgo := -1 1525 expectArg = true 1526 for it.Next() { 1527 itemInFunc := it.Item() 1528 if attrItemsAgo >= 0 { 1529 attrItemsAgo++ 1530 } 1531 var val string 1532 if itemInFunc.Typ == itemRightRound { 1533 break L 1534 } else if itemInFunc.Typ == itemComma { 1535 if expectArg { 1536 return nil, itemInFunc.Errorf("Invalid use of comma.") 1537 } 1538 if isDollar { 1539 return nil, itemInFunc.Errorf("Invalid use of comma after dollar.") 1540 } 1541 expectArg = true 1542 continue 1543 } else if itemInFunc.Typ == itemLeftRound { 1544 // Function inside a function. 1545 if seenFuncArg { 1546 return nil, itemInFunc.Errorf("Multiple functions as arguments not allowed") 1547 } 1548 it.Prev() 1549 it.Prev() 1550 nestedFunc, err := parseFunction(it, gq) 1551 if err != nil { 1552 return nil, err 1553 } 1554 seenFuncArg = true 1555 if nestedFunc.Name == valueFunc { 1556 if len(nestedFunc.NeedsVar) > 1 { 1557 return nil, itemInFunc.Errorf("Multiple variables not allowed in a function") 1558 } 1559 // Variable is used in place of attribute, eq(val(a), 5) 1560 if len(function.Attr) == 0 { 1561 function.Attr = nestedFunc.NeedsVar[0].Name 1562 function.IsValueVar = true 1563 } else { 1564 // eq(name, val(a)) 1565 function.Args = append(function.Args, 1566 Arg{Value: nestedFunc.NeedsVar[0].Name, IsValueVar: true}) 1567 } 1568 function.NeedsVar = append(function.NeedsVar, nestedFunc.NeedsVar...) 1569 function.NeedsVar[0].Typ = ValueVar 1570 } else if nestedFunc.Name == lenFunc { 1571 if len(nestedFunc.NeedsVar) > 1 { 1572 return nil, 1573 itemInFunc.Errorf("Multiple variables not allowed in len function") 1574 } 1575 if !isInequalityFn(function.Name) { 1576 return nil, 1577 itemInFunc.Errorf("len function only allowed inside inequality" + 1578 " function") 1579 } 1580 function.Attr = nestedFunc.NeedsVar[0].Name 1581 function.IsLenVar = true 1582 function.NeedsVar = append(function.NeedsVar, nestedFunc.NeedsVar...) 1583 } else if nestedFunc.Name == countFunc { 1584 function.Attr = nestedFunc.Attr 1585 function.IsCount = true 1586 } else { 1587 return nil, itemInFunc.Errorf("Only val/count/len allowed as function "+ 1588 "within another. Got: %s", nestedFunc.Name) 1589 } 1590 expectArg = false 1591 continue 1592 } else if itemInFunc.Typ == itemAt { 1593 if attrItemsAgo != 1 { 1594 return nil, itemInFunc.Errorf("Invalid usage of '@' in function " + 1595 "argument, must only appear immediately after attr.") 1596 } 1597 expectLang = true 1598 continue 1599 } else if itemInFunc.Typ == itemMathOp { 1600 val = itemInFunc.Val 1601 it.Next() 1602 itemInFunc = it.Item() 1603 } else if itemInFunc.Typ == itemDollar { 1604 if isDollar { 1605 return nil, itemInFunc.Errorf("Invalid use of $ in func args") 1606 } 1607 isDollar = true 1608 continue 1609 } else if itemInFunc.Typ == itemRegex { 1610 ra, err := parseRegexArgs(itemInFunc.Val) 1611 if err != nil { 1612 return nil, err 1613 } 1614 function.Args = append(function.Args, Arg{Value: ra.expr}, Arg{Value: ra.flags}) 1615 expectArg = false 1616 continue 1617 // Lets reassemble the geo tokens. 1618 } else if itemInFunc.Typ == itemLeftSquare { 1619 var err error 1620 switch { 1621 case isGeoFunc(function.Name): 1622 err = parseGeoArgs(it, function) 1623 1624 case isInequalityFn(function.Name): 1625 err = parseIneqArgs(it, function) 1626 1627 default: 1628 err = itemInFunc.Errorf("Unexpected character [ while parsing request.") 1629 } 1630 if err != nil { 1631 return nil, err 1632 } 1633 expectArg = false 1634 continue 1635 } else if itemInFunc.Typ == itemRightSquare { 1636 if _, err := it.Peek(1); err != nil { 1637 return nil, 1638 itemInFunc.Errorf("Unexpected EOF while parsing args") 1639 } 1640 expectArg = false 1641 continue 1642 } else if itemInFunc.Typ != itemName { 1643 return nil, itemInFunc.Errorf("Expected arg after func [%s], but got item %v", 1644 function.Name, itemInFunc) 1645 } 1646 1647 item, ok := it.PeekOne() 1648 if !ok { 1649 return nil, item.Errorf("Unexpected item: %v", item) 1650 } 1651 // Part of function continue 1652 if item.Typ == itemLeftRound { 1653 continue 1654 } 1655 1656 if !expectArg && !expectLang { 1657 return nil, itemInFunc.Errorf("Expected comma or language but got: %s", 1658 itemInFunc.Val) 1659 } 1660 1661 vname := collectName(it, itemInFunc.Val) 1662 // TODO - Move this to a function. 1663 v := strings.Trim(vname, " \t") 1664 var err error 1665 v, err = unquoteIfQuoted(v) 1666 if err != nil { 1667 return nil, err 1668 } 1669 val += v 1670 1671 if isDollar { 1672 val = "$" + val 1673 isDollar = false 1674 if function.Name == uidFunc && gq != nil { 1675 if len(gq.Args["id"]) > 0 { 1676 return nil, itemInFunc.Errorf("Only one GraphQL variable " + 1677 "allowed inside uid function.") 1678 } 1679 gq.Args["id"] = val 1680 } else { 1681 function.Args = append(function.Args, Arg{Value: val, IsGraphQLVar: true}) 1682 } 1683 expectArg = false 1684 continue 1685 } 1686 1687 // Unlike other functions, uid function has no attribute, everything is args. 1688 if len(function.Attr) == 0 && function.Name != uidFunc && 1689 function.Name != typFunc { 1690 1691 if strings.ContainsRune(itemInFunc.Val, '"') { 1692 return nil, itemInFunc.Errorf("Attribute in function"+ 1693 " must not be quoted with \": %s", itemInFunc.Val) 1694 } 1695 function.Attr = val 1696 attrItemsAgo = 0 1697 } else if expectLang { 1698 if val == "*" { 1699 return nil, errors.Errorf( 1700 "The * symbol cannot be used as a valid language inside functions") 1701 } 1702 function.Lang = val 1703 expectLang = false 1704 } else if function.Name != uidFunc { 1705 // For UID function. we set g.UID 1706 function.Args = append(function.Args, Arg{Value: val}) 1707 } 1708 1709 if function.Name == "var" { 1710 return nil, itemInFunc.Errorf("Unexpected var(). Maybe you want to try using uid()") 1711 } 1712 1713 expectArg = false 1714 if function.Name == valueFunc { 1715 // E.g. @filter(gt(val(a), 10)) 1716 function.NeedsVar = append(function.NeedsVar, VarContext{ 1717 Name: val, 1718 Typ: ValueVar, 1719 }) 1720 } else if function.Name == lenFunc { 1721 // E.g. @filter(gt(len(a), 10)) 1722 // TODO(Aman): type could be ValueVar too! 1723 function.NeedsVar = append(function.NeedsVar, VarContext{ 1724 Name: val, 1725 Typ: UidVar, 1726 }) 1727 } else if function.Name == uidFunc { 1728 // uid function could take variables as well as actual uids. 1729 // If we can parse the value that means its an uid otherwise a variable. 1730 uid, err := strconv.ParseUint(val, 0, 64) 1731 switch e := err.(type) { 1732 case nil: 1733 // It could be uid function at root. 1734 if gq != nil { 1735 gq.UID = append(gq.UID, uid) 1736 // Or uid function in filter. 1737 } else { 1738 function.UID = append(function.UID, uid) 1739 } 1740 continue 1741 case *strconv.NumError: 1742 if e.Err == strconv.ErrRange { 1743 return nil, itemInFunc.Errorf("The uid value %q is too large.", val) 1744 } 1745 } 1746 // E.g. @filter(uid(a, b, c)) 1747 function.NeedsVar = append(function.NeedsVar, VarContext{ 1748 Name: val, 1749 Typ: UidVar, 1750 }) 1751 } 1752 } 1753 } 1754 1755 if function.Name != uidFunc && function.Name != typFunc && len(function.Attr) == 0 { 1756 return nil, it.Errorf("Got empty attr for function: [%s]", function.Name) 1757 } 1758 1759 if function.Name == typFunc && len(function.Args) != 1 { 1760 return nil, it.Errorf("type function only supports one argument. Got: %v", function.Args) 1761 } 1762 1763 return function, nil 1764 } 1765 1766 type facetRes struct { 1767 f *pb.FacetParams 1768 ft *FilterTree 1769 vmap map[string]string 1770 facetOrder string 1771 orderdesc bool 1772 } 1773 1774 func parseFacets(it *lex.ItemIterator) (res facetRes, err error) { 1775 res, ok, err := tryParseFacetList(it) 1776 if err != nil || ok { 1777 return res, err 1778 } 1779 1780 filterTree, err := parseFilter(it) 1781 res.ft = filterTree 1782 return res, err 1783 } 1784 1785 type facetItem struct { 1786 name string 1787 alias string 1788 varName string 1789 ordered bool 1790 orderdesc bool 1791 } 1792 1793 // If err != nil, an error happened, abandon parsing. If err == nil && parseOk == false, the 1794 // attempt to parse failed, no data was consumed, and there might be a valid alternate parse with a 1795 // different function. 1796 func tryParseFacetItem(it *lex.ItemIterator) (res facetItem, parseOk bool, err error) { 1797 // We parse this: 1798 // [{orderdesc|orderasc|alias}:] [varname as] name 1799 1800 savePos := it.Save() 1801 defer func() { 1802 if err == nil && !parseOk { 1803 it.Restore(savePos) 1804 } 1805 }() 1806 1807 item, ok := tryParseItemType(it, itemName) 1808 if !ok { 1809 return res, false, nil 1810 } 1811 1812 isOrderasc := item.Val == "orderasc" 1813 if _, ok := tryParseItemType(it, itemColon); ok { 1814 if isOrderasc || item.Val == "orderdesc" { 1815 res.ordered = true 1816 res.orderdesc = !isOrderasc 1817 } else { 1818 res.alias = item.Val 1819 } 1820 1821 // Step past colon. 1822 item, ok = tryParseItemType(it, itemName) 1823 if !ok { 1824 return res, false, item.Errorf("Expected name after colon") 1825 } 1826 } 1827 1828 // We've possibly set ordered, orderdesc, alias and now we have consumed another item, 1829 // which is a name. 1830 name1 := item.Val 1831 1832 // Now try to consume "as". 1833 if !trySkipItemVal(it, "as") { 1834 name1 = collectName(it, name1) 1835 res.name = name1 1836 return res, true, nil 1837 } 1838 item, ok = tryParseItemType(it, itemName) 1839 if !ok { 1840 return res, false, item.Errorf("Expected name in facet list") 1841 } 1842 1843 res.name = collectName(it, item.Val) 1844 res.varName = name1 1845 return res, true, nil 1846 } 1847 1848 // If err != nil, an error happened, abandon parsing. If err == nil && parseOk == false, the 1849 // attempt to parse failed, but there might be a valid alternate parse with a different function, 1850 // such as parseFilter. 1851 func tryParseFacetList(it *lex.ItemIterator) (res facetRes, parseOk bool, err error) { 1852 savePos := it.Save() 1853 defer func() { 1854 if err == nil && !parseOk { 1855 it.Restore(savePos) 1856 } 1857 }() 1858 1859 // Skip past '(' 1860 if _, ok := tryParseItemType(it, itemLeftRound); !ok { 1861 it.Restore(savePos) 1862 var facets pb.FacetParams 1863 facets.AllKeys = true 1864 res.f = &facets 1865 res.vmap = make(map[string]string) 1866 return res, true, nil 1867 } 1868 1869 facetVar := make(map[string]string) 1870 var facets pb.FacetParams 1871 var orderdesc bool 1872 var orderkey string 1873 1874 if _, ok := tryParseItemType(it, itemRightRound); ok { 1875 // @facets() just parses to an empty set of facets. 1876 res.f, res.vmap, res.facetOrder, res.orderdesc = &facets, facetVar, orderkey, orderdesc 1877 return res, true, nil 1878 } 1879 1880 for { 1881 // We've just consumed a leftRound or a comma. 1882 1883 // Parse a facet item. 1884 // copy the iterator first to facetItemIt so that it corresponds to the parsed facetItem 1885 // facetItemIt is used later for reporting errors with line and column numbers 1886 facetItemIt := it 1887 facetItem, ok, err := tryParseFacetItem(it) 1888 if !ok || err != nil { 1889 return res, ok, err 1890 } 1891 1892 // Combine the facetitem with our result. 1893 { 1894 if facetItem.varName != "" { 1895 if _, has := facetVar[facetItem.name]; has { 1896 return res, false, facetItemIt.Errorf("Duplicate variable mappings for facet %v", 1897 facetItem.name) 1898 } 1899 facetVar[facetItem.name] = facetItem.varName 1900 } 1901 facets.Param = append(facets.Param, &pb.FacetParam{ 1902 Key: facetItem.name, 1903 Alias: facetItem.alias, 1904 }) 1905 if facetItem.ordered { 1906 if orderkey != "" { 1907 return res, false, 1908 facetItemIt.Errorf("Invalid use of orderasc/orderdesc in facets") 1909 } 1910 orderdesc = facetItem.orderdesc 1911 orderkey = facetItem.name 1912 } 1913 } 1914 1915 // Now what? Either close-paren or a comma. 1916 if _, ok := tryParseItemType(it, itemRightRound); ok { 1917 sort.Slice(facets.Param, func(i, j int) bool { 1918 return facets.Param[i].Key < facets.Param[j].Key 1919 }) 1920 // deduplicate facets 1921 out := facets.Param[:0] 1922 flen := len(facets.Param) 1923 for i := 1; i < flen; i++ { 1924 if facets.Param[i-1].Key == facets.Param[i].Key { 1925 continue 1926 } 1927 out = append(out, facets.Param[i-1]) 1928 } 1929 out = append(out, facets.Param[flen-1]) 1930 facets.Param = out 1931 res.f, res.vmap, res.facetOrder, res.orderdesc = &facets, facetVar, orderkey, orderdesc 1932 return res, true, nil 1933 } 1934 if item, ok := tryParseItemType(it, itemComma); !ok { 1935 if len(facets.Param) < 2 { 1936 // We have only consumed ``'@facets' '(' <facetItem>`, which means parseFilter might 1937 // succeed. Return no-parse, no-error. 1938 return res, false, nil 1939 } 1940 // We've consumed `'@facets' '(' <facetItem> ',' <facetItem>`, so this is definitely 1941 // not a filter. Return an error. 1942 return res, false, item.Errorf( 1943 "Expected ',' or ')' in facet list: %s", item.Val) 1944 } 1945 } 1946 } 1947 1948 // parseGroupby parses the groupby directive. 1949 func parseGroupby(it *lex.ItemIterator, gq *GraphQuery) error { 1950 count := 0 1951 expectArg := true 1952 it.Next() 1953 item := it.Item() 1954 alias := "" 1955 if item.Typ != itemLeftRound { 1956 return item.Errorf("Expected a left round after groupby") 1957 } 1958 for it.Next() { 1959 item := it.Item() 1960 if item.Typ == itemRightRound { 1961 break 1962 } 1963 if item.Typ == itemComma { 1964 if expectArg { 1965 return item.Errorf("Expected a predicate but got comma") 1966 } 1967 expectArg = true 1968 } else if item.Typ == itemName { 1969 if !expectArg { 1970 return item.Errorf("Expected a comma or right round but got: %v", item.Val) 1971 } 1972 1973 val := collectName(it, item.Val) 1974 peekIt, err := it.Peek(1) 1975 if err != nil { 1976 return err 1977 } 1978 if peekIt[0].Typ == itemColon { 1979 if alias != "" { 1980 return item.Errorf("Expected predicate after %s:", alias) 1981 } 1982 alias = val 1983 it.Next() // Consume the itemColon 1984 continue 1985 } 1986 1987 var langs []string 1988 items, err := it.Peek(1) 1989 if err == nil && items[0].Typ == itemAt { 1990 it.Next() // consume '@' 1991 it.Next() // move forward 1992 langs, err = parseLanguageList(it) 1993 if err != nil { 1994 return err 1995 } 1996 } 1997 attrLang := GroupByAttr{ 1998 Attr: val, 1999 Alias: alias, 2000 Langs: langs, 2001 } 2002 alias = "" 2003 gq.GroupbyAttrs = append(gq.GroupbyAttrs, attrLang) 2004 count++ 2005 expectArg = false 2006 } 2007 } 2008 if expectArg { 2009 // use the initial item to report error line and column numbers 2010 return item.Errorf("Unnecessary comma in groupby()") 2011 } 2012 if count == 0 { 2013 return item.Errorf("Expected atleast one attribute in groupby") 2014 } 2015 return nil 2016 } 2017 2018 func parseType(it *lex.ItemIterator, gq *GraphQuery) error { 2019 it.Next() 2020 if it.Item().Typ != itemLeftRound { 2021 return it.Item().Errorf("Expected a left round after type") 2022 } 2023 2024 it.Next() 2025 if it.Item().Typ != itemName { 2026 return it.Item().Errorf("Expected a type name inside type directive") 2027 } 2028 typeName := it.Item().Val 2029 2030 it.Next() 2031 if it.Item().Typ != itemRightRound { 2032 return it.Item().Errorf("Expected ) after the type name in type directive") 2033 } 2034 2035 // For now @type(TypeName) is equivalent of filtering using the type function. 2036 // Later the type declarations will be used to ensure that the fields inside 2037 // each block correspond to the specified type. 2038 gq.Filter = &FilterTree{ 2039 Func: &Function{ 2040 Name: "type", 2041 Args: []Arg{ 2042 { 2043 Value: typeName, 2044 }, 2045 }, 2046 }, 2047 } 2048 2049 return nil 2050 } 2051 2052 // parseFilter parses the filter directive to produce a QueryFilter / parse tree. 2053 func parseFilter(it *lex.ItemIterator) (*FilterTree, error) { 2054 it.Next() 2055 item := it.Item() 2056 if item.Typ != itemLeftRound { 2057 return nil, item.Errorf("Expected ( after filter directive") 2058 } 2059 2060 // opStack is used to collect the operators in right order. 2061 opStack := new(filterTreeStack) 2062 opStack.push(&FilterTree{Op: "("}) // Push ( onto operator stack. 2063 // valueStack is used to collect the values. 2064 valueStack := new(filterTreeStack) 2065 2066 for it.Next() { 2067 item := it.Item() 2068 lval := strings.ToLower(item.Val) 2069 if lval == "and" || lval == "or" || lval == "not" { // Handle operators. 2070 op := lval 2071 opPred := filterOpPrecedence[op] 2072 x.AssertTruef(opPred > 0, "Expected opPred > 0: %d", opPred) 2073 // Evaluate the stack until we see an operator with strictly lower pred. 2074 for !opStack.empty() { 2075 topOp := opStack.peek() 2076 if filterOpPrecedence[topOp.Op] < opPred { 2077 break 2078 } 2079 err := evalStack(opStack, valueStack) 2080 if err != nil { 2081 return nil, err 2082 } 2083 } 2084 opStack.push(&FilterTree{Op: op}) // Push current operator. 2085 } else if item.Typ == itemName { // Value. 2086 it.Prev() 2087 f, err := parseFunction(it, nil) 2088 if err != nil { 2089 return nil, err 2090 } 2091 leaf := &FilterTree{Func: f} 2092 valueStack.push(leaf) 2093 } else if item.Typ == itemLeftRound { // Just push to op stack. 2094 opStack.push(&FilterTree{Op: "("}) 2095 2096 } else if item.Typ == itemRightRound { // Pop op stack until we see a (. 2097 for !opStack.empty() { 2098 topOp := opStack.peek() 2099 if topOp.Op == "(" { 2100 break 2101 } 2102 err := evalStack(opStack, valueStack) 2103 if err != nil { 2104 return nil, err 2105 } 2106 } 2107 _, err := opStack.pop() // Pop away the (. 2108 if err != nil { 2109 return nil, item.Errorf("Invalid filter statement") 2110 } 2111 if opStack.empty() { 2112 // The parentheses are balanced out. Let's break. 2113 break 2114 } 2115 } else { 2116 return nil, item.Errorf("Unexpected item while parsing @filter: %v", item) 2117 } 2118 } 2119 2120 // For filters, we start with ( and end with ). We expect to break out of loop 2121 // when the parentheses balance off, and at that point, opStack should be empty. 2122 // For other applications, typically after all items are 2123 // consumed, we will run a loop like "while opStack is nonempty, evalStack". 2124 // This is not needed here. 2125 if !opStack.empty() { 2126 return nil, item.Errorf("Unbalanced parentheses in @filter statement") 2127 } 2128 2129 if valueStack.empty() { 2130 // This happens when we have @filter(). We can either return an error or 2131 // ignore. Currently, let's just ignore and pretend there is no filter. 2132 return nil, nil 2133 } 2134 2135 if valueStack.size() != 1 { 2136 return nil, item.Errorf("Expected one item in value stack, but got %d", 2137 valueStack.size()) 2138 } 2139 return valueStack.pop() 2140 } 2141 2142 // Parses ID list. Only used for GraphQL variables. 2143 // TODO - Maybe get rid of this by lexing individual IDs. 2144 func parseID(val string) ([]uint64, error) { 2145 var uids []uint64 2146 val = x.WhiteSpace.Replace(val) 2147 if val[0] != '[' { 2148 uid, err := strconv.ParseUint(val, 0, 64) 2149 if err != nil { 2150 return nil, err 2151 } 2152 uids = append(uids, uid) 2153 return uids, nil 2154 } 2155 2156 if val[len(val)-1] != ']' { 2157 return nil, errors.Errorf("Invalid id list at root. Got: %+v", val) 2158 } 2159 var buf bytes.Buffer 2160 for _, c := range val[1:] { 2161 if c == ',' || c == ']' { 2162 if buf.Len() == 0 { 2163 continue 2164 } 2165 uid, err := strconv.ParseUint(buf.String(), 0, 64) 2166 if err != nil { 2167 return nil, err 2168 } 2169 uids = append(uids, uid) 2170 buf.Reset() 2171 continue 2172 } 2173 if c == '[' || c == ')' { 2174 return nil, errors.Errorf("Invalid id list at root. Got: %+v", val) 2175 } 2176 buf.WriteRune(c) 2177 } 2178 return uids, nil 2179 } 2180 2181 func parseVarList(it *lex.ItemIterator, gq *GraphQuery) (int, error) { 2182 count := 0 2183 expectArg := true 2184 it.Next() 2185 item := it.Item() 2186 if item.Typ != itemLeftRound { 2187 return count, item.Errorf("Expected a left round after var") 2188 } 2189 for it.Next() { 2190 item := it.Item() 2191 if item.Typ == itemRightRound { 2192 break 2193 } 2194 if item.Typ == itemComma { 2195 if expectArg { 2196 return count, item.Errorf("Expected a variable but got comma") 2197 } 2198 expectArg = true 2199 } else if item.Typ == itemName { 2200 if !expectArg { 2201 return count, item.Errorf("Expected a variable but got comma") 2202 } 2203 count++ 2204 gq.NeedsVar = append(gq.NeedsVar, VarContext{ 2205 Name: item.Val, 2206 Typ: UidVar, 2207 }) 2208 expectArg = false 2209 } 2210 } 2211 if expectArg { 2212 return count, item.Errorf("Unnecessary comma in val()") 2213 } 2214 return count, nil 2215 } 2216 2217 func parseDirective(it *lex.ItemIterator, curp *GraphQuery) error { 2218 valid := true 2219 it.Prev() 2220 item := it.Item() 2221 if item.Typ == itemLeftCurl { 2222 // Ideally we should check that curp was created at current depth. 2223 valid = false 2224 } 2225 it.Next() 2226 // No directive is allowed on pb.subgraph like expand all, value variables. 2227 if !valid || curp == nil || curp.IsInternal { 2228 return item.Errorf("Invalid use of directive.") 2229 } 2230 2231 it.Next() 2232 item = it.Item() 2233 peek, err := it.Peek(1) 2234 if err != nil || item.Typ != itemName { 2235 return item.Errorf("Expected directive or language list") 2236 } 2237 2238 if item.Val == "facets" { // because @facets can come w/t '()' 2239 res, err := parseFacets(it) 2240 if err != nil { 2241 return err 2242 } 2243 if res.f != nil { 2244 curp.FacetVar = res.vmap 2245 curp.FacetOrder = res.facetOrder 2246 curp.FacetDesc = res.orderdesc 2247 if curp.Facets != nil { 2248 return item.Errorf("Only one facets allowed") 2249 } 2250 curp.Facets = res.f 2251 } else if res.ft != nil { 2252 if curp.FacetsFilter != nil { 2253 return item.Errorf("Only one facets filter allowed") 2254 } 2255 if res.ft.hasVars() { 2256 return item.Errorf( 2257 "variables are not allowed in facets filter.") 2258 } 2259 curp.FacetsFilter = res.ft 2260 } else { 2261 return item.Errorf("Facets parsing failed.") 2262 } 2263 } else if peek[0].Typ == itemLeftRound { 2264 // this is directive 2265 switch item.Val { 2266 case "filter": 2267 if curp.Filter != nil { 2268 return item.Errorf("Use AND, OR and round brackets instead" + 2269 " of multiple filter directives.") 2270 } 2271 filter, err := parseFilter(it) 2272 if err != nil { 2273 return err 2274 } 2275 curp.Filter = filter 2276 case "groupby": 2277 if curp.IsGroupby { 2278 return item.Errorf("Only one group by directive allowed.") 2279 } 2280 curp.IsGroupby = true 2281 if err := parseGroupby(it, curp); err != nil { 2282 return err 2283 } 2284 case "type": 2285 err := parseType(it, curp) 2286 if err != nil { 2287 return err 2288 } 2289 default: 2290 return item.Errorf("Unknown directive [%s]", item.Val) 2291 } 2292 } else if len(curp.Attr) > 0 && len(curp.Langs) == 0 { 2293 // this is language list 2294 if curp.Langs, err = parseLanguageList(it); err != nil { 2295 return err 2296 } 2297 if len(curp.Langs) == 0 { 2298 return item.Errorf("Expected at least 1 language in list for %s", curp.Attr) 2299 } 2300 } else { 2301 return item.Errorf("Expected directive or language list, got @%s", item.Val) 2302 } 2303 return nil 2304 } 2305 2306 func parseLanguageList(it *lex.ItemIterator) ([]string, error) { 2307 item := it.Item() 2308 var langs []string 2309 for ; item.Typ == itemName || item.Typ == itemPeriod; item = it.Item() { 2310 langs = append(langs, item.Val) 2311 it.Next() 2312 if it.Item().Typ == itemColon { 2313 it.Next() 2314 } else { 2315 break 2316 } 2317 } 2318 if it.Item().Typ == itemPeriod { 2319 peekIt, err := it.Peek(1) 2320 if err != nil { 2321 return nil, err 2322 } 2323 if peekIt[0].Typ == itemPeriod { 2324 return nil, it.Errorf("Expected only one dot(.) while parsing language list.") 2325 } 2326 } 2327 it.Prev() 2328 2329 for _, lang := range langs { 2330 if lang == string(star) && len(langs) > 1 { 2331 return nil, errors.Errorf( 2332 "If * is used, no other languages are allowed in the language list. Found %v", 2333 langs) 2334 } 2335 } 2336 2337 return langs, nil 2338 } 2339 2340 func validKeyAtRoot(k string) bool { 2341 switch k { 2342 case "func", "orderasc", "orderdesc", "first", "offset", "after": 2343 return true 2344 case "from", "to", "numpaths", "minweight", "maxweight": 2345 // Specific to shortest path 2346 return true 2347 case "depth": 2348 return true 2349 } 2350 return false 2351 } 2352 2353 // Check for validity of key at non-root nodes. 2354 func validKey(k string) bool { 2355 switch k { 2356 case "orderasc", "orderdesc", "first", "offset", "after": 2357 return true 2358 } 2359 return false 2360 } 2361 2362 func attrAndLang(attrData string) (attr string, langs []string) { 2363 idx := strings.Index(attrData, "@") 2364 if idx < 0 { 2365 return attrData, langs 2366 } 2367 attr = attrData[:idx] 2368 langs = strings.Split(attrData[idx+1:], ":") 2369 return 2370 } 2371 2372 func isEmpty(gq *GraphQuery) bool { 2373 return gq.Func == nil && len(gq.NeedsVar) == 0 && len(gq.Args) == 0 && 2374 gq.ShortestPathArgs.From == nil && gq.ShortestPathArgs.To == nil 2375 } 2376 2377 // getRoot gets the root graph query object after parsing the args. 2378 func getRoot(it *lex.ItemIterator) (gq *GraphQuery, rerr error) { 2379 gq = &GraphQuery{ 2380 Args: make(map[string]string), 2381 } 2382 if !it.Next() { 2383 return nil, it.Errorf("Invalid query") 2384 } 2385 item := it.Item() 2386 if item.Typ != itemName { 2387 return nil, item.Errorf("Expected some name. Got: %v", item) 2388 } 2389 2390 peekIt, err := it.Peek(1) 2391 if err != nil { 2392 return nil, it.Errorf("Invalid Query") 2393 } 2394 if peekIt[0].Typ == itemName && strings.ToLower(peekIt[0].Val) == "as" { 2395 gq.Var = item.Val 2396 it.Next() // Consume the "AS". 2397 it.Next() 2398 item = it.Item() 2399 } 2400 2401 gq.Alias = item.Val 2402 if !it.Next() { 2403 return nil, item.Errorf("Invalid query") 2404 } 2405 item = it.Item() 2406 if item.Typ != itemLeftRound { 2407 return nil, item.Errorf("Expected Left round brackets. Got: %v", item) 2408 } 2409 2410 expectArg := true 2411 order := make(map[string]bool) 2412 // Parse in KV fashion. Depending on the value of key, decide the path. 2413 for it.Next() { 2414 var key string 2415 // Get key. 2416 item := it.Item() 2417 if item.Typ == itemName { 2418 if !expectArg { 2419 return nil, item.Errorf("Not expecting argument. Got: %v", item) 2420 } 2421 key = item.Val 2422 expectArg = false 2423 } else if item.Typ == itemRightRound { 2424 if isEmpty(gq) { 2425 // Used to do aggregation at root which would be fetched in another block. 2426 gq.IsEmpty = true 2427 } 2428 break 2429 } else if item.Typ == itemComma { 2430 if expectArg { 2431 return nil, item.Errorf("Expected Argument but got comma.") 2432 } 2433 expectArg = true 2434 continue 2435 } else { 2436 return nil, item.Errorf("Expecting argument name. Got: %v", item) 2437 } 2438 2439 if !validKeyAtRoot(key) { 2440 return nil, item.Errorf("Got invalid keyword: %s at root", key) 2441 } 2442 2443 if !it.Next() { 2444 return nil, item.Errorf("Invalid query") 2445 } 2446 item = it.Item() 2447 if item.Typ != itemColon { 2448 return nil, item.Errorf("Expecting a colon. Got: %v", item) 2449 } 2450 2451 switch key { 2452 case "func": 2453 // Store the generator function. 2454 if gq.Func != nil { 2455 return gq, item.Errorf("Only one function allowed at root") 2456 } 2457 gen, err := parseFunction(it, gq) 2458 if err != nil { 2459 return gq, err 2460 } 2461 if !validFuncName(gen.Name) { 2462 return nil, item.Errorf("Function name: %s is not valid.", gen.Name) 2463 } 2464 gq.Func = gen 2465 gq.NeedsVar = append(gq.NeedsVar, gen.NeedsVar...) 2466 case "from", "to": 2467 if gq.Alias != "shortest" { 2468 return gq, item.Errorf("from/to only allowed for shortest path queries") 2469 } 2470 2471 fn := &Function{} 2472 peekIt, err := it.Peek(1) 2473 if err != nil { 2474 return nil, item.Errorf("Invalid query") 2475 } 2476 2477 assignShortestPathFn := func(fn *Function, key string) { 2478 if key == "from" { 2479 gq.ShortestPathArgs.From = fn 2480 } else if key == "to" { 2481 gq.ShortestPathArgs.To = fn 2482 } 2483 } 2484 2485 if peekIt[0].Val == uidFunc { 2486 gen, err := parseFunction(it, gq) 2487 if err != nil { 2488 return gq, err 2489 } 2490 fn.NeedsVar = gen.NeedsVar 2491 fn.Name = gen.Name 2492 assignShortestPathFn(fn, key) 2493 continue 2494 } 2495 2496 // This means it's not a uid function, so it has to be an actual uid. 2497 it.Next() 2498 item := it.Item() 2499 val := collectName(it, item.Val) 2500 uid, err := strconv.ParseUint(val, 0, 64) 2501 switch e := err.(type) { 2502 case nil: 2503 fn.UID = append(fn.UID, uid) 2504 case *strconv.NumError: 2505 if e.Err == strconv.ErrRange { 2506 return nil, item.Errorf("The uid value %q is too large.", val) 2507 } 2508 return nil, 2509 item.Errorf("from/to in shortest path can only accept uid function or an uid."+ 2510 " Got: %s", val) 2511 } 2512 assignShortestPathFn(fn, key) 2513 2514 default: 2515 var val string 2516 if !it.Next() { 2517 return nil, it.Errorf("Invalid query") 2518 } 2519 item := it.Item() 2520 2521 if item.Typ == itemDollar { 2522 it.Next() 2523 item = it.Item() 2524 if item.Typ == itemName { 2525 val = fmt.Sprintf("$%s", item.Val) 2526 } else { 2527 return nil, item.Errorf("Expecting a variable name. Got: %v", item) 2528 } 2529 goto ASSIGN 2530 } else if item.Typ == itemMathOp { 2531 if item.Val != "+" && item.Val != "-" { 2532 return nil, 2533 item.Errorf("Only Plus and minus are allowed unary ops. Got: %v", 2534 item.Val) 2535 } 2536 val = item.Val 2537 it.Next() 2538 item = it.Item() 2539 } 2540 2541 if val == "" && item.Val == valueFunc { 2542 count, err := parseVarList(it, gq) 2543 if err != nil { 2544 return nil, err 2545 } 2546 if count != 1 { 2547 return nil, item.Errorf("Expected only one variable but got: %d", count) 2548 } 2549 // Modify the NeedsVar context here. 2550 gq.NeedsVar[len(gq.NeedsVar)-1].Typ = ValueVar 2551 } else { 2552 val = collectName(it, val+item.Val) 2553 // Get language list, if present 2554 items, err := it.Peek(1) 2555 if err == nil && items[0].Typ == itemLeftRound { 2556 if (key == "orderasc" || key == "orderdesc") && val != valueFunc { 2557 return nil, it.Errorf("Expected val(). Got %s() with order.", val) 2558 } 2559 } 2560 if err == nil && items[0].Typ == itemAt { 2561 it.Next() // consume '@' 2562 it.Next() // move forward 2563 langs, err := parseLanguageList(it) 2564 if err != nil { 2565 return nil, err 2566 } 2567 val = val + "@" + strings.Join(langs, ":") 2568 } 2569 2570 } 2571 2572 // TODO - Allow only order by one of variable/predicate for now. 2573 if val == "" { 2574 // This should only happen in cases like: orderasc: val(c) 2575 if len(gq.NeedsVar) == 0 { 2576 return nil, it.Errorf("unable to get value when parsing key value pairs") 2577 } 2578 val = gq.NeedsVar[len(gq.NeedsVar)-1].Name 2579 // Right now we only allow one sort by a variable 2580 if len(gq.Order) > 0 && isSortkey(key) { 2581 return nil, it.Errorf("Multiple sorting only allowed by predicates. "+ 2582 "Got: %+v", val) 2583 } 2584 } 2585 if isSortkey(key) { 2586 if order[val] { 2587 return nil, it.Errorf("Sorting by an attribute: [%s] can only be done once", val) 2588 } 2589 attr, langs := attrAndLang(val) 2590 gq.Order = append(gq.Order, 2591 &pb.Order{Attr: attr, Desc: key == "orderdesc", Langs: langs}) 2592 order[val] = true 2593 continue 2594 } 2595 2596 ASSIGN: 2597 if _, ok := gq.Args[key]; ok { 2598 return gq, it.Errorf("Repeated key %q at root", key) 2599 } 2600 gq.Args[key] = val 2601 } 2602 } 2603 2604 return gq, nil 2605 } 2606 2607 func isSortkey(k string) bool { 2608 return k == "orderasc" || k == "orderdesc" 2609 } 2610 2611 type countType int 2612 2613 const ( 2614 notSeen countType = iota // default value 2615 seen // when we see count keyword 2616 seenWithPred // when we see a predicate within count. 2617 ) 2618 2619 func validateEmptyBlockItem(it *lex.ItemIterator, val string) error { 2620 savePos := it.Save() 2621 defer func() { 2622 it.Restore(savePos) 2623 }() 2624 2625 fname := val 2626 // Could have alias so peek forward to get actual function name. 2627 skipped := trySkipItemTyp(it, itemColon) 2628 if skipped { 2629 item, ok := tryParseItemType(it, itemName) 2630 if !ok { 2631 return item.Errorf("Expected name. Got: %s", item.Val) 2632 } 2633 fname = item.Val 2634 } 2635 ok := trySkipItemTyp(it, itemLeftRound) 2636 if !ok || (!isMathBlock(fname) && !isAggregator(fname)) { 2637 return it.Errorf("Only aggregation/math functions allowed inside empty blocks."+ 2638 " Got: %v", fname) 2639 } 2640 return nil 2641 } 2642 2643 // godeep constructs the subgraph from the lexed items and a GraphQuery node. 2644 func godeep(it *lex.ItemIterator, gq *GraphQuery) error { 2645 if gq == nil { 2646 return it.Errorf("Bad nesting of predicates or functions") 2647 } 2648 var count countType 2649 var alias, varName string 2650 curp := gq // Used to track current node, for nesting. 2651 for it.Next() { 2652 item := it.Item() 2653 switch item.Typ { 2654 case lex.ItemEOF: 2655 return nil 2656 case itemRightCurl: 2657 return nil 2658 case itemPeriod: 2659 // looking for ... 2660 dots := 1 2661 for i := 0; i < 2; i++ { 2662 if it.Next() && it.Item().Typ == itemPeriod { 2663 dots++ 2664 } 2665 } 2666 if dots == 3 { 2667 it.Next() 2668 item = it.Item() 2669 if item.Typ == itemName { 2670 // item.Val is expected to start with "..." and to have len >3. 2671 gq.Children = append(gq.Children, &GraphQuery{fragment: item.Val}) 2672 // Unlike itemName, there is no nesting, so do not change "curp". 2673 } 2674 } else { 2675 return item.Errorf("Expected 3 periods (\"...\"), got %d.", dots) 2676 } 2677 case itemName: 2678 peekIt, err := it.Peek(1) 2679 if err != nil { 2680 return item.Errorf("Invalid query") 2681 } 2682 if peekIt[0].Typ == itemName && strings.ToLower(peekIt[0].Val) == "as" { 2683 varName = item.Val 2684 it.Next() // "As" was checked before. 2685 continue 2686 } 2687 2688 val := collectName(it, item.Val) 2689 valLower := strings.ToLower(val) 2690 2691 peekIt, err = it.Peek(1) 2692 if err != nil { 2693 return err 2694 } 2695 if peekIt[0].Typ == itemColon { 2696 alias = val 2697 it.Next() // Consume the itemcolon 2698 continue 2699 } 2700 2701 if gq.IsGroupby && (!isAggregator(val) && val != "count" && count != seen) { 2702 // Only aggregator or count allowed inside the groupby block. 2703 return it.Errorf("Only aggregator/count "+ 2704 "functions allowed inside @groupby. Got: %v", val) 2705 } 2706 2707 if gq.IsEmpty { 2708 if err := validateEmptyBlockItem(it, valLower); err != nil { 2709 return err 2710 } 2711 } 2712 2713 if valLower == "checkpwd" { 2714 child := &GraphQuery{ 2715 Args: make(map[string]string), 2716 Var: varName, 2717 Alias: alias, 2718 } 2719 varName, alias = "", "" 2720 it.Prev() 2721 if child.Func, err = parseFunction(it, gq); err != nil { 2722 return err 2723 } 2724 child.Func.Args = append(child.Func.Args, Arg{Value: child.Func.Attr}) 2725 child.Attr = child.Func.Attr 2726 gq.Children = append(gq.Children, child) 2727 curp = nil 2728 continue 2729 } else if isAggregator(valLower) { 2730 child := &GraphQuery{ 2731 Attr: valueFunc, 2732 Args: make(map[string]string), 2733 Var: varName, 2734 IsInternal: true, 2735 Alias: alias, 2736 } 2737 varName, alias = "", "" 2738 it.Next() 2739 if it.Item().Typ != itemLeftRound { 2740 it.Prev() 2741 goto Fall 2742 } 2743 it.Next() 2744 if gq.IsGroupby { 2745 item = it.Item() 2746 attr := collectName(it, item.Val) 2747 // Get language list, if present 2748 items, err := it.Peek(1) 2749 if err == nil && items[0].Typ == itemAt { 2750 it.Next() // consume '@' 2751 it.Next() // move forward 2752 if child.Langs, err = parseLanguageList(it); err != nil { 2753 return err 2754 } 2755 } 2756 child.Attr = attr 2757 child.IsInternal = false 2758 } else { 2759 if it.Item().Val != valueFunc { 2760 return it.Errorf("Only variables allowed in aggregate functions. Got: %v", 2761 it.Item().Val) 2762 } 2763 count, err := parseVarList(it, child) 2764 if err != nil { 2765 return err 2766 } 2767 if count != 1 { 2768 return it.Errorf("Expected one variable inside val() of"+ 2769 " aggregator but got %v", count) 2770 } 2771 child.NeedsVar[len(child.NeedsVar)-1].Typ = ValueVar 2772 } 2773 child.Func = &Function{ 2774 Name: valLower, 2775 NeedsVar: child.NeedsVar, 2776 } 2777 it.Next() // Skip the closing ')' 2778 gq.Children = append(gq.Children, child) 2779 curp = nil 2780 continue 2781 } else if isMathBlock(valLower) { 2782 if varName == "" && alias == "" { 2783 return it.Errorf("Function math should be used with a variable or have an alias") 2784 } 2785 mathTree, again, err := parseMathFunc(it, false) 2786 if err != nil { 2787 return err 2788 } 2789 if again { 2790 return it.Errorf("Comma encountered in math() at unexpected place.") 2791 } 2792 child := &GraphQuery{ 2793 Attr: val, 2794 Alias: alias, 2795 Args: make(map[string]string), 2796 Var: varName, 2797 MathExp: mathTree, 2798 IsInternal: true, 2799 } 2800 // TODO - See that if we can instead initialize this at the top. 2801 varName, alias = "", "" 2802 gq.Children = append(gq.Children, child) 2803 curp = nil 2804 continue 2805 } else if isExpandFunc(valLower) { 2806 if varName != "" { 2807 return it.Errorf("expand() cannot be used with a variable: %s", val) 2808 } 2809 if alias != "" { 2810 return it.Errorf("expand() cannot have an alias") 2811 } 2812 it.Next() // Consume the '(' 2813 if it.Item().Typ != itemLeftRound { 2814 return it.Errorf("Invalid use of expand()") 2815 } 2816 it.Next() 2817 item := it.Item() 2818 child := &GraphQuery{ 2819 Attr: val, 2820 Args: make(map[string]string), 2821 IsInternal: true, 2822 } 2823 switch item.Val { 2824 case valueFunc: 2825 count, err := parseVarList(it, child) 2826 if err != nil { 2827 return err 2828 } 2829 if count != 1 { 2830 return item.Errorf("Invalid use of expand(). Exactly one variable expected.") 2831 } 2832 child.NeedsVar[len(child.NeedsVar)-1].Typ = ListVar 2833 child.Expand = child.NeedsVar[len(child.NeedsVar)-1].Name 2834 case "_all_": 2835 child.Expand = "_all_" 2836 case "_forward_": 2837 child.Expand = "_forward_" 2838 case "_reverse_": 2839 child.Expand = "_reverse_" 2840 default: 2841 return item.Errorf("Invalid argument %v in expand()", item.Val) 2842 } 2843 it.Next() // Consume ')' 2844 gq.Children = append(gq.Children, child) 2845 // Note: curp is not set to nil. So it can have children, filters, etc. 2846 curp = child 2847 continue 2848 } else if valLower == "count" { 2849 if count != notSeen { 2850 return it.Errorf("Invalid mention of function count") 2851 } 2852 count = seen 2853 it.Next() 2854 item = it.Item() 2855 if item.Typ != itemLeftRound { 2856 it.Prev() 2857 count = notSeen 2858 goto Fall 2859 } 2860 2861 peekIt, err := it.Peek(2) 2862 if err != nil { 2863 return err 2864 } 2865 if peekIt[0].Typ == itemRightRound { 2866 return it.Errorf("Cannot use count(), please use count(uid)") 2867 } else if peekIt[0].Val == uidFunc && peekIt[1].Typ == itemRightRound { 2868 if gq.IsGroupby { 2869 // count(uid) case which occurs inside @groupby 2870 val = uidFunc 2871 // Skip uid) 2872 it.Next() 2873 it.Next() 2874 goto Fall 2875 } 2876 2877 count = notSeen 2878 gq.UidCount = true 2879 gq.Var = varName 2880 if alias != "" { 2881 gq.UidCountAlias = alias 2882 // This is a count(uid) node. 2883 // Reset the alias here after assigning to UidCountAlias, so that siblings 2884 // of this node don't get it. 2885 alias = "" 2886 } 2887 it.Next() 2888 it.Next() 2889 } 2890 continue 2891 } else if valLower == valueFunc { 2892 if varName != "" { 2893 return it.Errorf("Cannot assign a variable to val()") 2894 } 2895 if count == seen { 2896 return it.Errorf("Count of a variable is not allowed") 2897 } 2898 peekIt, err = it.Peek(1) 2899 if err != nil { 2900 return err 2901 } 2902 if peekIt[0].Typ != itemLeftRound { 2903 goto Fall 2904 } 2905 2906 child := &GraphQuery{ 2907 Attr: val, 2908 Args: make(map[string]string), 2909 IsInternal: true, 2910 Alias: alias, 2911 } 2912 alias = "" 2913 count, err := parseVarList(it, child) 2914 if err != nil { 2915 return err 2916 } 2917 if count != 1 { 2918 return it.Errorf("Invalid use of val(). Exactly one variable expected.") 2919 } 2920 // Only value vars can be retrieved. 2921 child.NeedsVar[len(child.NeedsVar)-1].Typ = ValueVar 2922 gq.Children = append(gq.Children, child) 2923 curp = nil 2924 continue 2925 } else if valLower == uidFunc { 2926 if count == seen { 2927 return it.Errorf("Count of a variable is not allowed") 2928 } 2929 peekIt, err = it.Peek(1) 2930 if err != nil { 2931 return err 2932 } 2933 if peekIt[0].Typ != itemLeftRound { 2934 goto Fall 2935 } 2936 return it.Errorf("Cannot do uid() of a variable") 2937 } 2938 Fall: 2939 if count == seenWithPred { 2940 return it.Errorf("Multiple predicates not allowed in single count.") 2941 } 2942 child := &GraphQuery{ 2943 Args: make(map[string]string), 2944 Attr: val, 2945 IsCount: count == seen, 2946 Var: varName, 2947 Alias: alias, 2948 } 2949 2950 if gq.IsCount { 2951 return it.Errorf("Cannot have children attributes when asking for count.") 2952 } 2953 gq.Children = append(gq.Children, child) 2954 varName, alias = "", "" 2955 curp = child 2956 if count == seen { 2957 count = seenWithPred 2958 } 2959 case itemLeftCurl: 2960 if curp == nil { 2961 return it.Errorf("Query syntax invalid.") 2962 } 2963 if len(curp.Langs) > 0 { 2964 return it.Errorf("Cannot have children for attr: %s with lang tags: %v", curp.Attr, 2965 curp.Langs) 2966 } 2967 if err := godeep(it, curp); err != nil { 2968 return err 2969 } 2970 case itemLeftRound: 2971 if curp == nil { 2972 return it.Errorf("Query syntax invalid.") 2973 } 2974 if curp.Attr == "" { 2975 return it.Errorf("Predicate name cannot be empty.") 2976 } 2977 args, err := parseArguments(it, curp) 2978 if err != nil { 2979 return err 2980 } 2981 // Stores args in GraphQuery, will be used later while retrieving results. 2982 order := make(map[string]bool) 2983 for _, p := range args { 2984 if !validKey(p.Key) { 2985 return it.Errorf("Got invalid keyword: %s", p.Key) 2986 } 2987 if _, ok := curp.Args[p.Key]; ok { 2988 return it.Errorf("Got repeated key %q at level %q", p.Key, curp.Attr) 2989 } 2990 if p.Val == "" { 2991 return it.Errorf("Got empty argument") 2992 } 2993 if p.Key == "orderasc" || p.Key == "orderdesc" { 2994 if order[p.Val] { 2995 return it.Errorf("Sorting by an attribute: [%s] "+ 2996 "can only be done once", p.Val) 2997 } 2998 attr, langs := attrAndLang(p.Val) 2999 curp.Order = append(curp.Order, 3000 &pb.Order{Attr: attr, Desc: p.Key == "orderdesc", Langs: langs}) 3001 order[p.Val] = true 3002 continue 3003 } 3004 3005 curp.Args[p.Key] = p.Val 3006 } 3007 case itemAt: 3008 err := parseDirective(it, curp) 3009 if err != nil { 3010 return err 3011 } 3012 3013 case itemRightRound: 3014 if count != seenWithPred { 3015 return it.Errorf("Invalid mention of brackets") 3016 } 3017 count = notSeen 3018 } 3019 } 3020 return nil 3021 } 3022 3023 func isAggregator(fname string) bool { 3024 return fname == "min" || fname == "max" || fname == "sum" || fname == "avg" 3025 } 3026 3027 func isExpandFunc(name string) bool { 3028 return name == "expand" 3029 } 3030 3031 func isMathBlock(name string) bool { 3032 return name == "math" 3033 } 3034 3035 func isGeoFunc(name string) bool { 3036 return name == "near" || name == "contains" || name == "within" || name == "intersects" 3037 } 3038 3039 func isInequalityFn(name string) bool { 3040 switch name { 3041 case "eq", "le", "ge", "gt", "lt": 3042 return true 3043 } 3044 return false 3045 } 3046 3047 // Name can have dashes or alphanumeric characters. Lexer lexes them as separate items. 3048 // We put it back together here. 3049 func collectName(it *lex.ItemIterator, val string) string { 3050 var dashOrName bool // false if expecting dash, true if expecting name 3051 for { 3052 items, err := it.Peek(1) 3053 if err == nil && ((items[0].Typ == itemName && dashOrName) || 3054 (items[0].Val == "-" && !dashOrName)) { 3055 it.Next() 3056 val += it.Item().Val 3057 dashOrName = !dashOrName 3058 } else { 3059 break 3060 } 3061 } 3062 return val 3063 } 3064 3065 // Steps the parser. 3066 func tryParseItemType(it *lex.ItemIterator, typ lex.ItemType) (lex.Item, bool) { 3067 item, ok := it.PeekOne() 3068 if !ok || item.Typ != typ { 3069 return item, false 3070 } 3071 it.Next() 3072 return item, true 3073 } 3074 3075 func trySkipItemVal(it *lex.ItemIterator, val string) bool { 3076 item, ok := it.PeekOne() 3077 if !ok || item.Val != val { 3078 return false 3079 } 3080 it.Next() 3081 return true 3082 } 3083 3084 func trySkipItemTyp(it *lex.ItemIterator, typ lex.ItemType) bool { 3085 item, ok := it.PeekOne() 3086 if !ok || item.Typ != typ { 3087 return false 3088 } 3089 it.Next() 3090 return true 3091 }