this repo has no description
at main 39 kB view raw
1// Code generated by pigeon; DO NOT EDIT. 2 3package parser 4 5import ( 6 "bytes" 7 "errors" 8 "fmt" 9 "io" 10 "io/ioutil" 11 "math" 12 "os" 13 "sort" 14 "strconv" 15 "strings" 16 "sync" 17 "unicode" 18 "unicode/utf8" 19) 20 21type Attribute struct { 22 Type string 23 Value string 24} 25 26type AddCommand struct { 27 Description string 28 Attributes []Attribute 29} 30 31func MakeAdd(description interface{}, attributes interface{}) (*AddCommand, error) { 32 attribs, _ := attributes.([]Attribute) 33 return &AddCommand{Description: description.(string), Attributes: attribs}, nil 34} 35 36func MakeAttributes(attributes interface{}) ([]Attribute, error) { 37 ats := attributes.([]interface{}) 38 39 attribs := make([]Attribute, 0) 40 for _, p := range ats { 41 pa := p.([]interface{}) 42 px := pa[1:] 43 for _, pi := range px { 44 ps := pi.(*Attribute) 45 attribs = append(attribs, *ps) 46 } 47 } 48 return attribs, nil 49} 50 51var g = &grammar{ 52 rules: []*rule{ 53 { 54 name: "Add", 55 pos: position{line: 36, col: 1, offset: 688}, 56 expr: &actionExpr{ 57 pos: position{line: 36, col: 8, offset: 695}, 58 run: (*parser).callonAdd1, 59 expr: &seqExpr{ 60 pos: position{line: 36, col: 8, offset: 695}, 61 exprs: []interface{}{ 62 &labeledExpr{ 63 pos: position{line: 36, col: 8, offset: 695}, 64 label: "desc", 65 expr: &ruleRefExpr{ 66 pos: position{line: 36, col: 13, offset: 700}, 67 name: "Description", 68 }, 69 }, 70 &labeledExpr{ 71 pos: position{line: 36, col: 25, offset: 712}, 72 label: "attributes", 73 expr: &zeroOrOneExpr{ 74 pos: position{line: 36, col: 36, offset: 723}, 75 expr: &ruleRefExpr{ 76 pos: position{line: 36, col: 36, offset: 723}, 77 name: "Attributes", 78 }, 79 }, 80 }, 81 }, 82 }, 83 }, 84 }, 85 { 86 name: "Description", 87 pos: position{line: 40, col: 1, offset: 776}, 88 expr: &actionExpr{ 89 pos: position{line: 40, col: 16, offset: 791}, 90 run: (*parser).callonDescription1, 91 expr: &oneOrMoreExpr{ 92 pos: position{line: 40, col: 16, offset: 791}, 93 expr: &seqExpr{ 94 pos: position{line: 40, col: 17, offset: 792}, 95 exprs: []interface{}{ 96 &notExpr{ 97 pos: position{line: 40, col: 17, offset: 792}, 98 expr: &ruleRefExpr{ 99 pos: position{line: 40, col: 18, offset: 793}, 100 name: "Attribute", 101 }, 102 }, 103 &anyMatcher{ 104 line: 40, col: 28, offset: 803, 105 }, 106 }, 107 }, 108 }, 109 }, 110 }, 111 { 112 name: "Attributes", 113 pos: position{line: 44, col: 1, offset: 841}, 114 expr: &actionExpr{ 115 pos: position{line: 44, col: 15, offset: 855}, 116 run: (*parser).callonAttributes1, 117 expr: &labeledExpr{ 118 pos: position{line: 44, col: 15, offset: 855}, 119 label: "attributes", 120 expr: &zeroOrMoreExpr{ 121 pos: position{line: 44, col: 26, offset: 866}, 122 expr: &seqExpr{ 123 pos: position{line: 44, col: 27, offset: 867}, 124 exprs: []interface{}{ 125 &ruleRefExpr{ 126 pos: position{line: 44, col: 27, offset: 867}, 127 name: "_", 128 }, 129 &ruleRefExpr{ 130 pos: position{line: 44, col: 29, offset: 869}, 131 name: "Attribute", 132 }, 133 }, 134 }, 135 }, 136 }, 137 }, 138 }, 139 { 140 name: "Attribute", 141 pos: position{line: 47, col: 1, offset: 921}, 142 expr: &choiceExpr{ 143 pos: position{line: 47, col: 14, offset: 934}, 144 alternatives: []interface{}{ 145 &ruleRefExpr{ 146 pos: position{line: 47, col: 14, offset: 934}, 147 name: "Project", 148 }, 149 &ruleRefExpr{ 150 pos: position{line: 47, col: 24, offset: 944}, 151 name: "Priority", 152 }, 153 &ruleRefExpr{ 154 pos: position{line: 47, col: 35, offset: 955}, 155 name: "Tag", 156 }, 157 }, 158 }, 159 }, 160 { 161 name: "Project", 162 pos: position{line: 49, col: 1, offset: 961}, 163 expr: &actionExpr{ 164 pos: position{line: 49, col: 12, offset: 972}, 165 run: (*parser).callonProject1, 166 expr: &seqExpr{ 167 pos: position{line: 49, col: 12, offset: 972}, 168 exprs: []interface{}{ 169 &choiceExpr{ 170 pos: position{line: 49, col: 13, offset: 973}, 171 alternatives: []interface{}{ 172 &litMatcher{ 173 pos: position{line: 49, col: 13, offset: 973}, 174 val: "pro:", 175 ignoreCase: false, 176 want: "\"pro:\"", 177 }, 178 &litMatcher{ 179 pos: position{line: 49, col: 22, offset: 982}, 180 val: "project:", 181 ignoreCase: false, 182 want: "\"project:\"", 183 }, 184 }, 185 }, 186 &labeledExpr{ 187 pos: position{line: 49, col: 34, offset: 994}, 188 label: "value", 189 expr: &ruleRefExpr{ 190 pos: position{line: 49, col: 40, offset: 1000}, 191 name: "Word", 192 }, 193 }, 194 }, 195 }, 196 }, 197 }, 198 { 199 name: "Priority", 200 pos: position{line: 52, col: 1, offset: 1072}, 201 expr: &actionExpr{ 202 pos: position{line: 52, col: 13, offset: 1084}, 203 run: (*parser).callonPriority1, 204 expr: &seqExpr{ 205 pos: position{line: 52, col: 13, offset: 1084}, 206 exprs: []interface{}{ 207 &litMatcher{ 208 pos: position{line: 52, col: 13, offset: 1084}, 209 val: "priority:", 210 ignoreCase: false, 211 want: "\"priority:\"", 212 }, 213 &labeledExpr{ 214 pos: position{line: 52, col: 25, offset: 1096}, 215 label: "value", 216 expr: &charClassMatcher{ 217 pos: position{line: 52, col: 31, offset: 1102}, 218 val: "[HML]", 219 chars: []rune{'H', 'M', 'L'}, 220 ignoreCase: false, 221 inverted: false, 222 }, 223 }, 224 }, 225 }, 226 }, 227 }, 228 { 229 name: "Tag", 230 pos: position{line: 56, col: 1, offset: 1177}, 231 expr: &actionExpr{ 232 pos: position{line: 56, col: 8, offset: 1184}, 233 run: (*parser).callonTag1, 234 expr: &seqExpr{ 235 pos: position{line: 56, col: 8, offset: 1184}, 236 exprs: []interface{}{ 237 &litMatcher{ 238 pos: position{line: 56, col: 8, offset: 1184}, 239 val: "+", 240 ignoreCase: false, 241 want: "\"+\"", 242 }, 243 &labeledExpr{ 244 pos: position{line: 56, col: 12, offset: 1188}, 245 label: "value", 246 expr: &ruleRefExpr{ 247 pos: position{line: 56, col: 18, offset: 1194}, 248 name: "Word", 249 }, 250 }, 251 }, 252 }, 253 }, 254 }, 255 { 256 name: "Word", 257 pos: position{line: 60, col: 1, offset: 1263}, 258 expr: &actionExpr{ 259 pos: position{line: 60, col: 9, offset: 1271}, 260 run: (*parser).callonWord1, 261 expr: &oneOrMoreExpr{ 262 pos: position{line: 60, col: 9, offset: 1271}, 263 expr: &charClassMatcher{ 264 pos: position{line: 60, col: 9, offset: 1271}, 265 val: "[a-zA-Z0-9_-]", 266 chars: []rune{'_', '-'}, 267 ranges: []rune{'a', 'z', 'A', 'Z', '0', '9'}, 268 ignoreCase: false, 269 inverted: false, 270 }, 271 }, 272 }, 273 }, 274 { 275 name: "_", 276 pos: position{line: 63, col: 1, offset: 1319}, 277 expr: &zeroOrMoreExpr{ 278 pos: position{line: 63, col: 6, offset: 1324}, 279 expr: &charClassMatcher{ 280 pos: position{line: 63, col: 6, offset: 1324}, 281 val: "[ \\t]", 282 chars: []rune{' ', '\t'}, 283 ignoreCase: false, 284 inverted: false, 285 }, 286 }, 287 }, 288 { 289 name: "EOF", 290 pos: position{line: 65, col: 1, offset: 1332}, 291 expr: &notExpr{ 292 pos: position{line: 65, col: 7, offset: 1338}, 293 expr: &anyMatcher{ 294 line: 65, col: 8, offset: 1339, 295 }, 296 }, 297 }, 298 }, 299} 300 301func (c *current) onAdd1(desc, attributes interface{}) (interface{}, error) { 302 return MakeAdd(desc, attributes) 303} 304 305func (p *parser) callonAdd1() (interface{}, error) { 306 stack := p.vstack[len(p.vstack)-1] 307 _ = stack 308 return p.cur.onAdd1(stack["desc"], stack["attributes"]) 309} 310 311func (c *current) onDescription1() (interface{}, error) { 312 return string(c.text), nil 313} 314 315func (p *parser) callonDescription1() (interface{}, error) { 316 stack := p.vstack[len(p.vstack)-1] 317 _ = stack 318 return p.cur.onDescription1() 319} 320 321func (c *current) onAttributes1(attributes interface{}) (interface{}, error) { 322 return MakeAttributes(attributes) 323} 324 325func (p *parser) callonAttributes1() (interface{}, error) { 326 stack := p.vstack[len(p.vstack)-1] 327 _ = stack 328 return p.cur.onAttributes1(stack["attributes"]) 329} 330 331func (c *current) onProject1(value interface{}) (interface{}, error) { 332 return &Attribute{Type: "project", Value: value.(string)}, nil 333} 334 335func (p *parser) callonProject1() (interface{}, error) { 336 stack := p.vstack[len(p.vstack)-1] 337 _ = stack 338 return p.cur.onProject1(stack["value"]) 339} 340 341func (c *current) onPriority1(value interface{}) (interface{}, error) { 342 return &Attribute{Type: "priority", Value: value.(string)}, nil 343} 344 345func (p *parser) callonPriority1() (interface{}, error) { 346 stack := p.vstack[len(p.vstack)-1] 347 _ = stack 348 return p.cur.onPriority1(stack["value"]) 349} 350 351func (c *current) onTag1(value interface{}) (interface{}, error) { 352 return &Attribute{Type: "tag", Value: value.(string)}, nil 353} 354 355func (p *parser) callonTag1() (interface{}, error) { 356 stack := p.vstack[len(p.vstack)-1] 357 _ = stack 358 return p.cur.onTag1(stack["value"]) 359} 360 361func (c *current) onWord1() (interface{}, error) { 362 return string(c.text), nil 363} 364 365func (p *parser) callonWord1() (interface{}, error) { 366 stack := p.vstack[len(p.vstack)-1] 367 _ = stack 368 return p.cur.onWord1() 369} 370 371var ( 372 // errNoRule is returned when the grammar to parse has no rule. 373 errNoRule = errors.New("grammar has no rule") 374 375 // errInvalidEntrypoint is returned when the specified entrypoint rule 376 // does not exit. 377 errInvalidEntrypoint = errors.New("invalid entrypoint") 378 379 // errInvalidEncoding is returned when the source is not properly 380 // utf8-encoded. 381 errInvalidEncoding = errors.New("invalid encoding") 382 383 // errMaxExprCnt is used to signal that the maximum number of 384 // expressions have been parsed. 385 errMaxExprCnt = errors.New("max number of expresssions parsed") 386) 387 388// Option is a function that can set an option on the parser. It returns 389// the previous setting as an Option. 390type Option func(*parser) Option 391 392// MaxExpressions creates an Option to stop parsing after the provided 393// number of expressions have been parsed, if the value is 0 then the parser will 394// parse for as many steps as needed (possibly an infinite number). 395// 396// The default for maxExprCnt is 0. 397func MaxExpressions(maxExprCnt uint64) Option { 398 return func(p *parser) Option { 399 oldMaxExprCnt := p.maxExprCnt 400 p.maxExprCnt = maxExprCnt 401 return MaxExpressions(oldMaxExprCnt) 402 } 403} 404 405// Entrypoint creates an Option to set the rule name to use as entrypoint. 406// The rule name must have been specified in the -alternate-entrypoints 407// if generating the parser with the -optimize-grammar flag, otherwise 408// it may have been optimized out. Passing an empty string sets the 409// entrypoint to the first rule in the grammar. 410// 411// The default is to start parsing at the first rule in the grammar. 412func Entrypoint(ruleName string) Option { 413 return func(p *parser) Option { 414 oldEntrypoint := p.entrypoint 415 p.entrypoint = ruleName 416 if ruleName == "" { 417 p.entrypoint = g.rules[0].name 418 } 419 return Entrypoint(oldEntrypoint) 420 } 421} 422 423// Statistics adds a user provided Stats struct to the parser to allow 424// the user to process the results after the parsing has finished. 425// Also the key for the "no match" counter is set. 426// 427// Example usage: 428// 429// input := "input" 430// stats := Stats{} 431// _, err := Parse("input-file", []byte(input), Statistics(&stats, "no match")) 432// if err != nil { 433// log.Panicln(err) 434// } 435// b, err := json.MarshalIndent(stats.ChoiceAltCnt, "", " ") 436// if err != nil { 437// log.Panicln(err) 438// } 439// fmt.Println(string(b)) 440func Statistics(stats *Stats, choiceNoMatch string) Option { 441 return func(p *parser) Option { 442 oldStats := p.Stats 443 p.Stats = stats 444 oldChoiceNoMatch := p.choiceNoMatch 445 p.choiceNoMatch = choiceNoMatch 446 if p.Stats.ChoiceAltCnt == nil { 447 p.Stats.ChoiceAltCnt = make(map[string]map[string]int) 448 } 449 return Statistics(oldStats, oldChoiceNoMatch) 450 } 451} 452 453// Debug creates an Option to set the debug flag to b. When set to true, 454// debugging information is printed to stdout while parsing. 455// 456// The default is false. 457func Debug(b bool) Option { 458 return func(p *parser) Option { 459 old := p.debug 460 p.debug = b 461 return Debug(old) 462 } 463} 464 465// Memoize creates an Option to set the memoize flag to b. When set to true, 466// the parser will cache all results so each expression is evaluated only 467// once. This guarantees linear parsing time even for pathological cases, 468// at the expense of more memory and slower times for typical cases. 469// 470// The default is false. 471func Memoize(b bool) Option { 472 return func(p *parser) Option { 473 old := p.memoize 474 p.memoize = b 475 return Memoize(old) 476 } 477} 478 479// AllowInvalidUTF8 creates an Option to allow invalid UTF-8 bytes. 480// Every invalid UTF-8 byte is treated as a utf8.RuneError (U+FFFD) 481// by character class matchers and is matched by the any matcher. 482// The returned matched value, c.text and c.offset are NOT affected. 483// 484// The default is false. 485func AllowInvalidUTF8(b bool) Option { 486 return func(p *parser) Option { 487 old := p.allowInvalidUTF8 488 p.allowInvalidUTF8 = b 489 return AllowInvalidUTF8(old) 490 } 491} 492 493// Recover creates an Option to set the recover flag to b. When set to 494// true, this causes the parser to recover from panics and convert it 495// to an error. Setting it to false can be useful while debugging to 496// access the full stack trace. 497// 498// The default is true. 499func Recover(b bool) Option { 500 return func(p *parser) Option { 501 old := p.recover 502 p.recover = b 503 return Recover(old) 504 } 505} 506 507// GlobalStore creates an Option to set a key to a certain value in 508// the globalStore. 509func GlobalStore(key string, value interface{}) Option { 510 return func(p *parser) Option { 511 old := p.cur.globalStore[key] 512 p.cur.globalStore[key] = value 513 return GlobalStore(key, old) 514 } 515} 516 517// InitState creates an Option to set a key to a certain value in 518// the global "state" store. 519func InitState(key string, value interface{}) Option { 520 return func(p *parser) Option { 521 old := p.cur.state[key] 522 p.cur.state[key] = value 523 return InitState(key, old) 524 } 525} 526 527// ParseFile parses the file identified by filename. 528func ParseFile(filename string, opts ...Option) (i interface{}, err error) { 529 f, err := os.Open(filename) 530 if err != nil { 531 return nil, err 532 } 533 defer func() { 534 if closeErr := f.Close(); closeErr != nil { 535 err = closeErr 536 } 537 }() 538 return ParseReader(filename, f, opts...) 539} 540 541// ParseReader parses the data from r using filename as information in the 542// error messages. 543func ParseReader(filename string, r io.Reader, opts ...Option) (interface{}, error) { 544 b, err := ioutil.ReadAll(r) 545 if err != nil { 546 return nil, err 547 } 548 549 return Parse(filename, b, opts...) 550} 551 552// Parse parses the data from b using filename as information in the 553// error messages. 554func Parse(filename string, b []byte, opts ...Option) (interface{}, error) { 555 return newParser(filename, b, opts...).parse(g) 556} 557 558// position records a position in the text. 559type position struct { 560 line, col, offset int 561} 562 563func (p position) String() string { 564 return strconv.Itoa(p.line) + ":" + strconv.Itoa(p.col) + " [" + strconv.Itoa(p.offset) + "]" 565} 566 567// savepoint stores all state required to go back to this point in the 568// parser. 569type savepoint struct { 570 position 571 rn rune 572 w int 573} 574 575type current struct { 576 pos position // start position of the match 577 text []byte // raw text of the match 578 579 // state is a store for arbitrary key,value pairs that the user wants to be 580 // tied to the backtracking of the parser. 581 // This is always rolled back if a parsing rule fails. 582 state storeDict 583 584 // globalStore is a general store for the user to store arbitrary key-value 585 // pairs that they need to manage and that they do not want tied to the 586 // backtracking of the parser. This is only modified by the user and never 587 // rolled back by the parser. It is always up to the user to keep this in a 588 // consistent state. 589 globalStore storeDict 590} 591 592type storeDict map[string]interface{} 593 594// the AST types... 595 596type grammar struct { 597 pos position 598 rules []*rule 599} 600 601type rule struct { 602 pos position 603 name string 604 displayName string 605 expr interface{} 606} 607 608type choiceExpr struct { 609 pos position 610 alternatives []interface{} 611} 612 613type actionExpr struct { 614 pos position 615 expr interface{} 616 run func(*parser) (interface{}, error) 617} 618 619type recoveryExpr struct { 620 pos position 621 expr interface{} 622 recoverExpr interface{} 623 failureLabel []string 624} 625 626type seqExpr struct { 627 pos position 628 exprs []interface{} 629} 630 631type throwExpr struct { 632 pos position 633 label string 634} 635 636type labeledExpr struct { 637 pos position 638 label string 639 expr interface{} 640} 641 642type expr struct { 643 pos position 644 expr interface{} 645} 646 647type andExpr expr 648type notExpr expr 649type zeroOrOneExpr expr 650type zeroOrMoreExpr expr 651type oneOrMoreExpr expr 652 653type ruleRefExpr struct { 654 pos position 655 name string 656} 657 658type stateCodeExpr struct { 659 pos position 660 run func(*parser) error 661} 662 663type andCodeExpr struct { 664 pos position 665 run func(*parser) (bool, error) 666} 667 668type notCodeExpr struct { 669 pos position 670 run func(*parser) (bool, error) 671} 672 673type litMatcher struct { 674 pos position 675 val string 676 ignoreCase bool 677 want string 678} 679 680type charClassMatcher struct { 681 pos position 682 val string 683 basicLatinChars [128]bool 684 chars []rune 685 ranges []rune 686 classes []*unicode.RangeTable 687 ignoreCase bool 688 inverted bool 689} 690 691type anyMatcher position 692 693// errList cumulates the errors found by the parser. 694type errList []error 695 696func (e *errList) add(err error) { 697 *e = append(*e, err) 698} 699 700func (e errList) err() error { 701 if len(e) == 0 { 702 return nil 703 } 704 e.dedupe() 705 return e 706} 707 708func (e *errList) dedupe() { 709 var cleaned []error 710 set := make(map[string]bool) 711 for _, err := range *e { 712 if msg := err.Error(); !set[msg] { 713 set[msg] = true 714 cleaned = append(cleaned, err) 715 } 716 } 717 *e = cleaned 718} 719 720func (e errList) Error() string { 721 switch len(e) { 722 case 0: 723 return "" 724 case 1: 725 return e[0].Error() 726 default: 727 var buf bytes.Buffer 728 729 for i, err := range e { 730 if i > 0 { 731 buf.WriteRune('\n') 732 } 733 buf.WriteString(err.Error()) 734 } 735 return buf.String() 736 } 737} 738 739// parserError wraps an error with a prefix indicating the rule in which 740// the error occurred. The original error is stored in the Inner field. 741type parserError struct { 742 Inner error 743 pos position 744 prefix string 745 expected []string 746} 747 748// Error returns the error message. 749func (p *parserError) Error() string { 750 return p.prefix + ": " + p.Inner.Error() 751} 752 753// newParser creates a parser with the specified input source and options. 754func newParser(filename string, b []byte, opts ...Option) *parser { 755 stats := Stats{ 756 ChoiceAltCnt: make(map[string]map[string]int), 757 } 758 759 p := &parser{ 760 filename: filename, 761 errs: new(errList), 762 data: b, 763 pt: savepoint{position: position{line: 1}}, 764 recover: true, 765 cur: current{ 766 state: make(storeDict), 767 globalStore: make(storeDict), 768 }, 769 maxFailPos: position{col: 1, line: 1}, 770 maxFailExpected: make([]string, 0, 20), 771 Stats: &stats, 772 // start rule is rule [0] unless an alternate entrypoint is specified 773 entrypoint: g.rules[0].name, 774 } 775 p.setOptions(opts) 776 777 if p.maxExprCnt == 0 { 778 p.maxExprCnt = math.MaxUint64 779 } 780 781 return p 782} 783 784// setOptions applies the options to the parser. 785func (p *parser) setOptions(opts []Option) { 786 for _, opt := range opts { 787 opt(p) 788 } 789} 790 791type resultTuple struct { 792 v interface{} 793 b bool 794 end savepoint 795} 796 797const choiceNoMatch = -1 798 799// Stats stores some statistics, gathered during parsing 800type Stats struct { 801 // ExprCnt counts the number of expressions processed during parsing 802 // This value is compared to the maximum number of expressions allowed 803 // (set by the MaxExpressions option). 804 ExprCnt uint64 805 806 // ChoiceAltCnt is used to count for each ordered choice expression, 807 // which alternative is used how may times. 808 // These numbers allow to optimize the order of the ordered choice expression 809 // to increase the performance of the parser 810 // 811 // The outer key of ChoiceAltCnt is composed of the name of the rule as well 812 // as the line and the column of the ordered choice. 813 // The inner key of ChoiceAltCnt is the number (one-based) of the matching alternative. 814 // For each alternative the number of matches are counted. If an ordered choice does not 815 // match, a special counter is incremented. The name of this counter is set with 816 // the parser option Statistics. 817 // For an alternative to be included in ChoiceAltCnt, it has to match at least once. 818 ChoiceAltCnt map[string]map[string]int 819} 820 821type parser struct { 822 filename string 823 pt savepoint 824 cur current 825 826 data []byte 827 errs *errList 828 829 depth int 830 recover bool 831 debug bool 832 833 memoize bool 834 // memoization table for the packrat algorithm: 835 // map[offset in source] map[expression or rule] {value, match} 836 memo map[int]map[interface{}]resultTuple 837 838 // rules table, maps the rule identifier to the rule node 839 rules map[string]*rule 840 // variables stack, map of label to value 841 vstack []map[string]interface{} 842 // rule stack, allows identification of the current rule in errors 843 rstack []*rule 844 845 // parse fail 846 maxFailPos position 847 maxFailExpected []string 848 maxFailInvertExpected bool 849 850 // max number of expressions to be parsed 851 maxExprCnt uint64 852 // entrypoint for the parser 853 entrypoint string 854 855 allowInvalidUTF8 bool 856 857 *Stats 858 859 choiceNoMatch string 860 // recovery expression stack, keeps track of the currently available recovery expression, these are traversed in reverse 861 recoveryStack []map[string]interface{} 862} 863 864// push a variable set on the vstack. 865func (p *parser) pushV() { 866 if cap(p.vstack) == len(p.vstack) { 867 // create new empty slot in the stack 868 p.vstack = append(p.vstack, nil) 869 } else { 870 // slice to 1 more 871 p.vstack = p.vstack[:len(p.vstack)+1] 872 } 873 874 // get the last args set 875 m := p.vstack[len(p.vstack)-1] 876 if m != nil && len(m) == 0 { 877 // empty map, all good 878 return 879 } 880 881 m = make(map[string]interface{}) 882 p.vstack[len(p.vstack)-1] = m 883} 884 885// pop a variable set from the vstack. 886func (p *parser) popV() { 887 // if the map is not empty, clear it 888 m := p.vstack[len(p.vstack)-1] 889 if len(m) > 0 { 890 // GC that map 891 p.vstack[len(p.vstack)-1] = nil 892 } 893 p.vstack = p.vstack[:len(p.vstack)-1] 894} 895 896// push a recovery expression with its labels to the recoveryStack 897func (p *parser) pushRecovery(labels []string, expr interface{}) { 898 if cap(p.recoveryStack) == len(p.recoveryStack) { 899 // create new empty slot in the stack 900 p.recoveryStack = append(p.recoveryStack, nil) 901 } else { 902 // slice to 1 more 903 p.recoveryStack = p.recoveryStack[:len(p.recoveryStack)+1] 904 } 905 906 m := make(map[string]interface{}, len(labels)) 907 for _, fl := range labels { 908 m[fl] = expr 909 } 910 p.recoveryStack[len(p.recoveryStack)-1] = m 911} 912 913// pop a recovery expression from the recoveryStack 914func (p *parser) popRecovery() { 915 // GC that map 916 p.recoveryStack[len(p.recoveryStack)-1] = nil 917 918 p.recoveryStack = p.recoveryStack[:len(p.recoveryStack)-1] 919} 920 921func (p *parser) print(prefix, s string) string { 922 if !p.debug { 923 return s 924 } 925 926 fmt.Printf("%s %d:%d:%d: %s [%#U]\n", 927 prefix, p.pt.line, p.pt.col, p.pt.offset, s, p.pt.rn) 928 return s 929} 930 931func (p *parser) in(s string) string { 932 p.depth++ 933 return p.print(strings.Repeat(" ", p.depth)+">", s) 934} 935 936func (p *parser) out(s string) string { 937 p.depth-- 938 return p.print(strings.Repeat(" ", p.depth)+"<", s) 939} 940 941func (p *parser) addErr(err error) { 942 p.addErrAt(err, p.pt.position, []string{}) 943} 944 945func (p *parser) addErrAt(err error, pos position, expected []string) { 946 var buf bytes.Buffer 947 if p.filename != "" { 948 buf.WriteString(p.filename) 949 } 950 if buf.Len() > 0 { 951 buf.WriteString(":") 952 } 953 buf.WriteString(fmt.Sprintf("%d:%d (%d)", pos.line, pos.col, pos.offset)) 954 if len(p.rstack) > 0 { 955 if buf.Len() > 0 { 956 buf.WriteString(": ") 957 } 958 rule := p.rstack[len(p.rstack)-1] 959 if rule.displayName != "" { 960 buf.WriteString("rule " + rule.displayName) 961 } else { 962 buf.WriteString("rule " + rule.name) 963 } 964 } 965 pe := &parserError{Inner: err, pos: pos, prefix: buf.String(), expected: expected} 966 p.errs.add(pe) 967} 968 969func (p *parser) failAt(fail bool, pos position, want string) { 970 // process fail if parsing fails and not inverted or parsing succeeds and invert is set 971 if fail == p.maxFailInvertExpected { 972 if pos.offset < p.maxFailPos.offset { 973 return 974 } 975 976 if pos.offset > p.maxFailPos.offset { 977 p.maxFailPos = pos 978 p.maxFailExpected = p.maxFailExpected[:0] 979 } 980 981 if p.maxFailInvertExpected { 982 want = "!" + want 983 } 984 p.maxFailExpected = append(p.maxFailExpected, want) 985 } 986} 987 988// read advances the parser to the next rune. 989func (p *parser) read() { 990 p.pt.offset += p.pt.w 991 rn, n := utf8.DecodeRune(p.data[p.pt.offset:]) 992 p.pt.rn = rn 993 p.pt.w = n 994 p.pt.col++ 995 if rn == '\n' { 996 p.pt.line++ 997 p.pt.col = 0 998 } 999 1000 if rn == utf8.RuneError && n == 1 { // see utf8.DecodeRune 1001 if !p.allowInvalidUTF8 { 1002 p.addErr(errInvalidEncoding) 1003 } 1004 } 1005} 1006 1007// restore parser position to the savepoint pt. 1008func (p *parser) restore(pt savepoint) { 1009 if p.debug { 1010 defer p.out(p.in("restore")) 1011 } 1012 if pt.offset == p.pt.offset { 1013 return 1014 } 1015 p.pt = pt 1016} 1017 1018// Cloner is implemented by any value that has a Clone method, which returns a 1019// copy of the value. This is mainly used for types which are not passed by 1020// value (e.g map, slice, chan) or structs that contain such types. 1021// 1022// This is used in conjunction with the global state feature to create proper 1023// copies of the state to allow the parser to properly restore the state in 1024// the case of backtracking. 1025type Cloner interface { 1026 Clone() interface{} 1027} 1028 1029var statePool = &sync.Pool{ 1030 New: func() interface{} { return make(storeDict) }, 1031} 1032 1033func (sd storeDict) Discard() { 1034 for k := range sd { 1035 delete(sd, k) 1036 } 1037 statePool.Put(sd) 1038} 1039 1040// clone and return parser current state. 1041func (p *parser) cloneState() storeDict { 1042 if p.debug { 1043 defer p.out(p.in("cloneState")) 1044 } 1045 1046 state := statePool.Get().(storeDict) 1047 for k, v := range p.cur.state { 1048 if c, ok := v.(Cloner); ok { 1049 state[k] = c.Clone() 1050 } else { 1051 state[k] = v 1052 } 1053 } 1054 return state 1055} 1056 1057// restore parser current state to the state storeDict. 1058// every restoreState should applied only one time for every cloned state 1059func (p *parser) restoreState(state storeDict) { 1060 if p.debug { 1061 defer p.out(p.in("restoreState")) 1062 } 1063 p.cur.state.Discard() 1064 p.cur.state = state 1065} 1066 1067// get the slice of bytes from the savepoint start to the current position. 1068func (p *parser) sliceFrom(start savepoint) []byte { 1069 return p.data[start.position.offset:p.pt.position.offset] 1070} 1071 1072func (p *parser) getMemoized(node interface{}) (resultTuple, bool) { 1073 if len(p.memo) == 0 { 1074 return resultTuple{}, false 1075 } 1076 m := p.memo[p.pt.offset] 1077 if len(m) == 0 { 1078 return resultTuple{}, false 1079 } 1080 res, ok := m[node] 1081 return res, ok 1082} 1083 1084func (p *parser) setMemoized(pt savepoint, node interface{}, tuple resultTuple) { 1085 if p.memo == nil { 1086 p.memo = make(map[int]map[interface{}]resultTuple) 1087 } 1088 m := p.memo[pt.offset] 1089 if m == nil { 1090 m = make(map[interface{}]resultTuple) 1091 p.memo[pt.offset] = m 1092 } 1093 m[node] = tuple 1094} 1095 1096func (p *parser) buildRulesTable(g *grammar) { 1097 p.rules = make(map[string]*rule, len(g.rules)) 1098 for _, r := range g.rules { 1099 p.rules[r.name] = r 1100 } 1101} 1102 1103func (p *parser) parse(g *grammar) (val interface{}, err error) { 1104 if len(g.rules) == 0 { 1105 p.addErr(errNoRule) 1106 return nil, p.errs.err() 1107 } 1108 1109 // TODO : not super critical but this could be generated 1110 p.buildRulesTable(g) 1111 1112 if p.recover { 1113 // panic can be used in action code to stop parsing immediately 1114 // and return the panic as an error. 1115 defer func() { 1116 if e := recover(); e != nil { 1117 if p.debug { 1118 defer p.out(p.in("panic handler")) 1119 } 1120 val = nil 1121 switch e := e.(type) { 1122 case error: 1123 p.addErr(e) 1124 default: 1125 p.addErr(fmt.Errorf("%v", e)) 1126 } 1127 err = p.errs.err() 1128 } 1129 }() 1130 } 1131 1132 startRule, ok := p.rules[p.entrypoint] 1133 if !ok { 1134 p.addErr(errInvalidEntrypoint) 1135 return nil, p.errs.err() 1136 } 1137 1138 p.read() // advance to first rune 1139 val, ok = p.parseRule(startRule) 1140 if !ok { 1141 if len(*p.errs) == 0 { 1142 // If parsing fails, but no errors have been recorded, the expected values 1143 // for the farthest parser position are returned as error. 1144 maxFailExpectedMap := make(map[string]struct{}, len(p.maxFailExpected)) 1145 for _, v := range p.maxFailExpected { 1146 maxFailExpectedMap[v] = struct{}{} 1147 } 1148 expected := make([]string, 0, len(maxFailExpectedMap)) 1149 eof := false 1150 if _, ok := maxFailExpectedMap["!."]; ok { 1151 delete(maxFailExpectedMap, "!.") 1152 eof = true 1153 } 1154 for k := range maxFailExpectedMap { 1155 expected = append(expected, k) 1156 } 1157 sort.Strings(expected) 1158 if eof { 1159 expected = append(expected, "EOF") 1160 } 1161 p.addErrAt(errors.New("no match found, expected: "+listJoin(expected, ", ", "or")), p.maxFailPos, expected) 1162 } 1163 1164 return nil, p.errs.err() 1165 } 1166 return val, p.errs.err() 1167} 1168 1169func listJoin(list []string, sep string, lastSep string) string { 1170 switch len(list) { 1171 case 0: 1172 return "" 1173 case 1: 1174 return list[0] 1175 default: 1176 return strings.Join(list[:len(list)-1], sep) + " " + lastSep + " " + list[len(list)-1] 1177 } 1178} 1179 1180func (p *parser) parseRule(rule *rule) (interface{}, bool) { 1181 if p.debug { 1182 defer p.out(p.in("parseRule " + rule.name)) 1183 } 1184 1185 if p.memoize { 1186 res, ok := p.getMemoized(rule) 1187 if ok { 1188 p.restore(res.end) 1189 return res.v, res.b 1190 } 1191 } 1192 1193 start := p.pt 1194 p.rstack = append(p.rstack, rule) 1195 p.pushV() 1196 val, ok := p.parseExpr(rule.expr) 1197 p.popV() 1198 p.rstack = p.rstack[:len(p.rstack)-1] 1199 if ok && p.debug { 1200 p.print(strings.Repeat(" ", p.depth)+"MATCH", string(p.sliceFrom(start))) 1201 } 1202 1203 if p.memoize { 1204 p.setMemoized(start, rule, resultTuple{val, ok, p.pt}) 1205 } 1206 return val, ok 1207} 1208 1209func (p *parser) parseExpr(expr interface{}) (interface{}, bool) { 1210 var pt savepoint 1211 1212 if p.memoize { 1213 res, ok := p.getMemoized(expr) 1214 if ok { 1215 p.restore(res.end) 1216 return res.v, res.b 1217 } 1218 pt = p.pt 1219 } 1220 1221 p.ExprCnt++ 1222 if p.ExprCnt > p.maxExprCnt { 1223 panic(errMaxExprCnt) 1224 } 1225 1226 var val interface{} 1227 var ok bool 1228 switch expr := expr.(type) { 1229 case *actionExpr: 1230 val, ok = p.parseActionExpr(expr) 1231 case *andCodeExpr: 1232 val, ok = p.parseAndCodeExpr(expr) 1233 case *andExpr: 1234 val, ok = p.parseAndExpr(expr) 1235 case *anyMatcher: 1236 val, ok = p.parseAnyMatcher(expr) 1237 case *charClassMatcher: 1238 val, ok = p.parseCharClassMatcher(expr) 1239 case *choiceExpr: 1240 val, ok = p.parseChoiceExpr(expr) 1241 case *labeledExpr: 1242 val, ok = p.parseLabeledExpr(expr) 1243 case *litMatcher: 1244 val, ok = p.parseLitMatcher(expr) 1245 case *notCodeExpr: 1246 val, ok = p.parseNotCodeExpr(expr) 1247 case *notExpr: 1248 val, ok = p.parseNotExpr(expr) 1249 case *oneOrMoreExpr: 1250 val, ok = p.parseOneOrMoreExpr(expr) 1251 case *recoveryExpr: 1252 val, ok = p.parseRecoveryExpr(expr) 1253 case *ruleRefExpr: 1254 val, ok = p.parseRuleRefExpr(expr) 1255 case *seqExpr: 1256 val, ok = p.parseSeqExpr(expr) 1257 case *stateCodeExpr: 1258 val, ok = p.parseStateCodeExpr(expr) 1259 case *throwExpr: 1260 val, ok = p.parseThrowExpr(expr) 1261 case *zeroOrMoreExpr: 1262 val, ok = p.parseZeroOrMoreExpr(expr) 1263 case *zeroOrOneExpr: 1264 val, ok = p.parseZeroOrOneExpr(expr) 1265 default: 1266 panic(fmt.Sprintf("unknown expression type %T", expr)) 1267 } 1268 if p.memoize { 1269 p.setMemoized(pt, expr, resultTuple{val, ok, p.pt}) 1270 } 1271 return val, ok 1272} 1273 1274func (p *parser) parseActionExpr(act *actionExpr) (interface{}, bool) { 1275 if p.debug { 1276 defer p.out(p.in("parseActionExpr")) 1277 } 1278 1279 start := p.pt 1280 val, ok := p.parseExpr(act.expr) 1281 if ok { 1282 p.cur.pos = start.position 1283 p.cur.text = p.sliceFrom(start) 1284 state := p.cloneState() 1285 actVal, err := act.run(p) 1286 if err != nil { 1287 p.addErrAt(err, start.position, []string{}) 1288 } 1289 p.restoreState(state) 1290 1291 val = actVal 1292 } 1293 if ok && p.debug { 1294 p.print(strings.Repeat(" ", p.depth)+"MATCH", string(p.sliceFrom(start))) 1295 } 1296 return val, ok 1297} 1298 1299func (p *parser) parseAndCodeExpr(and *andCodeExpr) (interface{}, bool) { 1300 if p.debug { 1301 defer p.out(p.in("parseAndCodeExpr")) 1302 } 1303 1304 state := p.cloneState() 1305 1306 ok, err := and.run(p) 1307 if err != nil { 1308 p.addErr(err) 1309 } 1310 p.restoreState(state) 1311 1312 return nil, ok 1313} 1314 1315func (p *parser) parseAndExpr(and *andExpr) (interface{}, bool) { 1316 if p.debug { 1317 defer p.out(p.in("parseAndExpr")) 1318 } 1319 1320 pt := p.pt 1321 state := p.cloneState() 1322 p.pushV() 1323 _, ok := p.parseExpr(and.expr) 1324 p.popV() 1325 p.restoreState(state) 1326 p.restore(pt) 1327 1328 return nil, ok 1329} 1330 1331func (p *parser) parseAnyMatcher(any *anyMatcher) (interface{}, bool) { 1332 if p.debug { 1333 defer p.out(p.in("parseAnyMatcher")) 1334 } 1335 1336 if p.pt.rn == utf8.RuneError && p.pt.w == 0 { 1337 // EOF - see utf8.DecodeRune 1338 p.failAt(false, p.pt.position, ".") 1339 return nil, false 1340 } 1341 start := p.pt 1342 p.read() 1343 p.failAt(true, start.position, ".") 1344 return p.sliceFrom(start), true 1345} 1346 1347func (p *parser) parseCharClassMatcher(chr *charClassMatcher) (interface{}, bool) { 1348 if p.debug { 1349 defer p.out(p.in("parseCharClassMatcher")) 1350 } 1351 1352 cur := p.pt.rn 1353 start := p.pt 1354 1355 // can't match EOF 1356 if cur == utf8.RuneError && p.pt.w == 0 { // see utf8.DecodeRune 1357 p.failAt(false, start.position, chr.val) 1358 return nil, false 1359 } 1360 1361 if chr.ignoreCase { 1362 cur = unicode.ToLower(cur) 1363 } 1364 1365 // try to match in the list of available chars 1366 for _, rn := range chr.chars { 1367 if rn == cur { 1368 if chr.inverted { 1369 p.failAt(false, start.position, chr.val) 1370 return nil, false 1371 } 1372 p.read() 1373 p.failAt(true, start.position, chr.val) 1374 return p.sliceFrom(start), true 1375 } 1376 } 1377 1378 // try to match in the list of ranges 1379 for i := 0; i < len(chr.ranges); i += 2 { 1380 if cur >= chr.ranges[i] && cur <= chr.ranges[i+1] { 1381 if chr.inverted { 1382 p.failAt(false, start.position, chr.val) 1383 return nil, false 1384 } 1385 p.read() 1386 p.failAt(true, start.position, chr.val) 1387 return p.sliceFrom(start), true 1388 } 1389 } 1390 1391 // try to match in the list of Unicode classes 1392 for _, cl := range chr.classes { 1393 if unicode.Is(cl, cur) { 1394 if chr.inverted { 1395 p.failAt(false, start.position, chr.val) 1396 return nil, false 1397 } 1398 p.read() 1399 p.failAt(true, start.position, chr.val) 1400 return p.sliceFrom(start), true 1401 } 1402 } 1403 1404 if chr.inverted { 1405 p.read() 1406 p.failAt(true, start.position, chr.val) 1407 return p.sliceFrom(start), true 1408 } 1409 p.failAt(false, start.position, chr.val) 1410 return nil, false 1411} 1412 1413func (p *parser) incChoiceAltCnt(ch *choiceExpr, altI int) { 1414 choiceIdent := fmt.Sprintf("%s %d:%d", p.rstack[len(p.rstack)-1].name, ch.pos.line, ch.pos.col) 1415 m := p.ChoiceAltCnt[choiceIdent] 1416 if m == nil { 1417 m = make(map[string]int) 1418 p.ChoiceAltCnt[choiceIdent] = m 1419 } 1420 // We increment altI by 1, so the keys do not start at 0 1421 alt := strconv.Itoa(altI + 1) 1422 if altI == choiceNoMatch { 1423 alt = p.choiceNoMatch 1424 } 1425 m[alt]++ 1426} 1427 1428func (p *parser) parseChoiceExpr(ch *choiceExpr) (interface{}, bool) { 1429 if p.debug { 1430 defer p.out(p.in("parseChoiceExpr")) 1431 } 1432 1433 for altI, alt := range ch.alternatives { 1434 // dummy assignment to prevent compile error if optimized 1435 _ = altI 1436 1437 state := p.cloneState() 1438 1439 p.pushV() 1440 val, ok := p.parseExpr(alt) 1441 p.popV() 1442 if ok { 1443 p.incChoiceAltCnt(ch, altI) 1444 return val, ok 1445 } 1446 p.restoreState(state) 1447 } 1448 p.incChoiceAltCnt(ch, choiceNoMatch) 1449 return nil, false 1450} 1451 1452func (p *parser) parseLabeledExpr(lab *labeledExpr) (interface{}, bool) { 1453 if p.debug { 1454 defer p.out(p.in("parseLabeledExpr")) 1455 } 1456 1457 p.pushV() 1458 val, ok := p.parseExpr(lab.expr) 1459 p.popV() 1460 if ok && lab.label != "" { 1461 m := p.vstack[len(p.vstack)-1] 1462 m[lab.label] = val 1463 } 1464 return val, ok 1465} 1466 1467func (p *parser) parseLitMatcher(lit *litMatcher) (interface{}, bool) { 1468 if p.debug { 1469 defer p.out(p.in("parseLitMatcher")) 1470 } 1471 1472 start := p.pt 1473 for _, want := range lit.val { 1474 cur := p.pt.rn 1475 if lit.ignoreCase { 1476 cur = unicode.ToLower(cur) 1477 } 1478 if cur != want { 1479 p.failAt(false, start.position, lit.want) 1480 p.restore(start) 1481 return nil, false 1482 } 1483 p.read() 1484 } 1485 p.failAt(true, start.position, lit.want) 1486 return p.sliceFrom(start), true 1487} 1488 1489func (p *parser) parseNotCodeExpr(not *notCodeExpr) (interface{}, bool) { 1490 if p.debug { 1491 defer p.out(p.in("parseNotCodeExpr")) 1492 } 1493 1494 state := p.cloneState() 1495 1496 ok, err := not.run(p) 1497 if err != nil { 1498 p.addErr(err) 1499 } 1500 p.restoreState(state) 1501 1502 return nil, !ok 1503} 1504 1505func (p *parser) parseNotExpr(not *notExpr) (interface{}, bool) { 1506 if p.debug { 1507 defer p.out(p.in("parseNotExpr")) 1508 } 1509 1510 pt := p.pt 1511 state := p.cloneState() 1512 p.pushV() 1513 p.maxFailInvertExpected = !p.maxFailInvertExpected 1514 _, ok := p.parseExpr(not.expr) 1515 p.maxFailInvertExpected = !p.maxFailInvertExpected 1516 p.popV() 1517 p.restoreState(state) 1518 p.restore(pt) 1519 1520 return nil, !ok 1521} 1522 1523func (p *parser) parseOneOrMoreExpr(expr *oneOrMoreExpr) (interface{}, bool) { 1524 if p.debug { 1525 defer p.out(p.in("parseOneOrMoreExpr")) 1526 } 1527 1528 var vals []interface{} 1529 1530 for { 1531 p.pushV() 1532 val, ok := p.parseExpr(expr.expr) 1533 p.popV() 1534 if !ok { 1535 if len(vals) == 0 { 1536 // did not match once, no match 1537 return nil, false 1538 } 1539 return vals, true 1540 } 1541 vals = append(vals, val) 1542 } 1543} 1544 1545func (p *parser) parseRecoveryExpr(recover *recoveryExpr) (interface{}, bool) { 1546 if p.debug { 1547 defer p.out(p.in("parseRecoveryExpr (" + strings.Join(recover.failureLabel, ",") + ")")) 1548 } 1549 1550 p.pushRecovery(recover.failureLabel, recover.recoverExpr) 1551 val, ok := p.parseExpr(recover.expr) 1552 p.popRecovery() 1553 1554 return val, ok 1555} 1556 1557func (p *parser) parseRuleRefExpr(ref *ruleRefExpr) (interface{}, bool) { 1558 if p.debug { 1559 defer p.out(p.in("parseRuleRefExpr " + ref.name)) 1560 } 1561 1562 if ref.name == "" { 1563 panic(fmt.Sprintf("%s: invalid rule: missing name", ref.pos)) 1564 } 1565 1566 rule := p.rules[ref.name] 1567 if rule == nil { 1568 p.addErr(fmt.Errorf("undefined rule: %s", ref.name)) 1569 return nil, false 1570 } 1571 return p.parseRule(rule) 1572} 1573 1574func (p *parser) parseSeqExpr(seq *seqExpr) (interface{}, bool) { 1575 if p.debug { 1576 defer p.out(p.in("parseSeqExpr")) 1577 } 1578 1579 vals := make([]interface{}, 0, len(seq.exprs)) 1580 1581 pt := p.pt 1582 state := p.cloneState() 1583 for _, expr := range seq.exprs { 1584 val, ok := p.parseExpr(expr) 1585 if !ok { 1586 p.restoreState(state) 1587 p.restore(pt) 1588 return nil, false 1589 } 1590 vals = append(vals, val) 1591 } 1592 return vals, true 1593} 1594 1595func (p *parser) parseStateCodeExpr(state *stateCodeExpr) (interface{}, bool) { 1596 if p.debug { 1597 defer p.out(p.in("parseStateCodeExpr")) 1598 } 1599 1600 err := state.run(p) 1601 if err != nil { 1602 p.addErr(err) 1603 } 1604 return nil, true 1605} 1606 1607func (p *parser) parseThrowExpr(expr *throwExpr) (interface{}, bool) { 1608 if p.debug { 1609 defer p.out(p.in("parseThrowExpr")) 1610 } 1611 1612 for i := len(p.recoveryStack) - 1; i >= 0; i-- { 1613 if recoverExpr, ok := p.recoveryStack[i][expr.label]; ok { 1614 if val, ok := p.parseExpr(recoverExpr); ok { 1615 return val, ok 1616 } 1617 } 1618 } 1619 1620 return nil, false 1621} 1622 1623func (p *parser) parseZeroOrMoreExpr(expr *zeroOrMoreExpr) (interface{}, bool) { 1624 if p.debug { 1625 defer p.out(p.in("parseZeroOrMoreExpr")) 1626 } 1627 1628 var vals []interface{} 1629 1630 for { 1631 p.pushV() 1632 val, ok := p.parseExpr(expr.expr) 1633 p.popV() 1634 if !ok { 1635 return vals, true 1636 } 1637 vals = append(vals, val) 1638 } 1639} 1640 1641func (p *parser) parseZeroOrOneExpr(expr *zeroOrOneExpr) (interface{}, bool) { 1642 if p.debug { 1643 defer p.out(p.in("parseZeroOrOneExpr")) 1644 } 1645 1646 p.pushV() 1647 val, _ := p.parseExpr(expr.expr) 1648 p.popV() 1649 // whether it matched or not, consider it a match 1650 return val, true 1651}