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 ¬Expr{
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: ¬Expr{
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}