diff --git a/Makefile b/Makefile index fa363b5..6caf554 100644 --- a/Makefile +++ b/Makefile @@ -8,10 +8,35 @@ deps: go get -t ./... imports: $(SOURCES) + @echo imports @goimports -w $(SOURCES) build: $(SOURCES) - go build ./... + go build + +head: $(SOURCES) + go run scripts/createhead.go -- \ + char.go \ + sequence.go \ + choice.go \ + idset.go \ + results.go \ + context.go \ + nodehead.go \ + syntaxhead.go \ + > head.go + +generate: $(SOURCES) $(PARSERS) head + go run scripts/boot.go < syntax.treerack > self/self.go.next + @mv self/self.go{.next,} + @gofmt -s -w self/self.go + +regenerate: $(SOURCES) $(PARSERS) head + go run scripts/boot.go < syntax.treerack > self/self.go.next + @mv self/self.go{.next,} + go run scripts/boot.go < syntax.treerack > self/self.go.next + @mv self/self.go{.next,} + @gofmt -s -w self/self.go check: imports build $(PARSERS) go test -test.short -run ^Test @@ -39,21 +64,23 @@ cpu: cpu.out go tool pprof -top cpu.out fmt: $(SOURCES) + @echo fmt @gofmt -w -s $(SOURCES) check-fmt: $(SOURCES) + @echo check fmt @if [ "$$(gofmt -s -d $(SOURCES))" != "" ]; then false; else true; fi vet: - @go vet + go vet -precommit: fmt vet build check-full +precommit: regenerate fmt vet build check-full clean: - @rm -f *.test - @rm -f cpu.out - @rm -f .coverprofile - @go clean -i ./... + rm -f *.test + rm -f cpu.out + rm -f .coverprofile + go clean -i ./... ci-trigger: deps check-fmt build check-full ifeq ($(TRAVIS_BRANCH)_$(TRAVIS_PULL_REQUEST), master_false) diff --git a/boot.go b/boot.go index ec6631f..f775140 100644 --- a/boot.go +++ b/boot.go @@ -5,10 +5,6 @@ import "os" func bootSyntax() (*Syntax, error) { f, _ := os.Open("syntax.treerack") defer f.Close() - - // never fails: - doc, _ := parsegen(f) - s := &Syntax{} - return s, define(s, doc) + return s, s.ReadSyntax(f) } diff --git a/bootsyntax.go b/bootsyntax.go deleted file mode 100644 index c5ba048..0000000 --- a/bootsyntax.go +++ /dev/null @@ -1,284 +0,0 @@ -package treerack - -var bootSyntaxDefs = [][]string{{ - "chars", "space", "alias", " ", -}, { - "chars", "tab", "alias", "\\t", -}, { - "chars", "nl", "alias", "\\n", -}, { - "chars", "backspace", "alias", "\\b", -}, { - "chars", "formfeed", "alias", "\\f", -}, { - "chars", "carryreturn", "alias", "\\r", -}, { - "chars", "verticaltab", "alias", "\\v", -}, { - "choice", - "wschar", - "alias", - "space", - "tab", - "nl", - "backspace", - "formfeed", - "carryreturn", - "verticaltab", -}, { - "chars", "open-block-comment", "alias", "/*", -}, { - "chars", "close-block-comment", "alias", "*/", -}, { - "chars", "star", "alias", "*", -}, { - "class", "not-slash", "alias", "^/", -}, { - "class", "not-star", "alias", "^*", -}, { - "chars", "double-slash", "alias", "//", -}, { - "class", "not-nl", "alias", "^\\n", -}, { - "sequence", "not-block-close", "alias", "star", "not-slash", -}, { - "choice", "block-comment-char", "alias", "not-block-close", "not-star", -}, { - "sequence", "block-comment-body", "alias", "block-comment-char:0:-1", -}, { - "sequence", - "block-comment", - "alias", - "open-block-comment", - "block-comment-body", - "close-block-comment", -}, { - "sequence", "not-nls", "alias", "not-nl:0:-1", -}, { - "sequence", "line-comment", "alias", "double-slash", "not-nls", -}, { - "choice", "comment-segment", "alias", "block-comment", "line-comment", -}, { - "sequence", "wss", "alias", "wschar:0:-1", -}, { - "sequence", "optional-nl", "alias", "nl:0:1", -}, { - "choice", - "ws-no-nl", - "alias", - "space", - "tab", - "backspace", - "formfeed", - "carryreturn", - "verticaltab", -}, { - "sequence", - "continue-comment-segment", - "alias", - "ws-no-nl", - "optional-nl", - "ws-no-nl", - "comment-segment", -}, { - "sequence", "continue-comment", "alias", "continue-comment-segment:0:-1", -}, { - "sequence", - "comment", - "none", - "comment-segment", - "continue-comment", -}, { - "choice", "wsc", "alias", "wschar", "comment", -}, { - "sequence", "wscs", "alias", "wsc:0:-1", -}, { - "anything", "anything", "alias", -}, { - "chars", "any-char", "none", ".", -}, { - "chars", "open-square", "alias", "[", -}, { - "chars", "close-square", "alias", "]", -}, { - "chars", "class-not", "none", "^", -}, { - "chars", "dash", "alias", "-", -}, { - "sequence", "optional-class-not", "alias", "class-not:0:1", -}, { - "class", "not-class-control", "alias", "^\\\\\\[\\]\\^\\-", -}, { - "chars", "escape", "alias", "\\\\", -}, { - "sequence", "escaped-char", "alias", "escape", "anything", -}, { - "choice", "class-char", "none", "not-class-control", "escaped-char", -}, { - "sequence", "char-range", "none", "class-char", "dash", "class-char", -}, { - "choice", "char-or-range", "alias", "class-char", "char-range", -}, { - "sequence", "chars-or-ranges", "alias", "char-or-range:0:-1", -}, { - "sequence", "char-class", "none", "open-square", "optional-class-not", "chars-or-ranges", "close-square", -}, { - "chars", "double-quote", "alias", "\\\"", -}, { - "class", "not-char-sequence-control", "alias", "^\\\\\"", -}, { - "choice", "sequence-char", "none", "not-char-sequence-control", "escaped-char", -}, { - "sequence", "char-sequence-chars", "alias", "sequence-char:0:-1", -}, { - "sequence", "char-sequence", "none", "double-quote", "char-sequence-chars", "double-quote", -}, { - "choice", "terminal", "alias", "any-char", "char-class", "char-sequence", -}, { - "class", "symbol-char", "alias", symbolChars, -}, { - "sequence", "symbol-chars", "alias", "symbol-char:1:-1", -}, { - "sequence", "symbol", "none", "symbol-chars", -}, { - "chars", "open-paren", "alias", "(", -}, { - "chars", "close-paren", "alias", ")", -}, { - "sequence", "group", "alias", "open-paren", "wscs", "expression", "wscs", "close-paren", -}, { - "chars", "open-brace", "alias", "{", -}, { - "chars", "close-brace", "alias", "}", -}, { - "class", "digit", "alias", "0-9", -}, { - "sequence", "number", "alias", "digit:1:-1", -}, { - "sequence", "count", "none", "number", -}, { - "sequence", "count-quantifier", "none", "open-brace", "wscs", "count", "wscs", "close-brace", -}, { - "sequence", "range-from", "none", "number", -}, { - "sequence", "range-to", "none", "number", -}, { - "chars", "comma", "alias", ",", -}, { - "sequence", - "range-quantifier", - "none", - "open-brace", - "wscs", - "range-from", - "wscs", - "comma", - "wscs", - "range-to", - "close-brace", -}, { - "chars", "one-or-more", "none", "+", -}, { - "chars", "zero-or-more", "none", "*", -}, { - "chars", "zero-or-one", "none", "?", -}, { - "choice", - "quantity", - "alias", - "count-quantifier", - "range-quantifier", - "one-or-more", - "zero-or-more", - "zero-or-one", -}, { - "choice", "quantifiable", "alias", "terminal", "symbol", "group", -}, { - "choice", "item-choice", "alias", "terminal", "symbol", "group", -}, { - "sequence", "item", "none", "item-choice", "quantity:0:1", -}, { - "sequence", "item-continue", "alias", "wscs", "item", -}, { - "sequence", "items-continue", "alias", "item-continue:0:-1", -}, { - "sequence", "sequence", "none", "item", "items-continue", -}, { - "choice", "option", "alias", "terminal", "symbol", "group", "sequence", -}, { - "chars", "pipe", "alias", "|", -}, { - "sequence", "option-continue", "alias", "wscs", "pipe", "wscs", "option", -}, { - "sequence", "options-continue", "alias", "option-continue:1:-1", -}, { - "sequence", "choice", "none", "option", "options-continue", -}, { - "choice", - "expression", - "alias", - "terminal", - "symbol", - "group", - "sequence", - "choice", -}, { - "chars", "alias", "none", "alias", -}, { - "chars", "ws", "none", "ws", -}, { - "chars", "nows", "none", "nows", -}, { - "chars", "failpass", "none", "failpass", -}, { - "chars", "root", "none", "root", -}, { - "choice", "flag", "alias", "alias", "ws", "nows", "failpass", "root", -}, { - "chars", "colon", "alias", ":", -}, { - "sequence", "flag-tag", "alias", "colon", "flag", -}, { - "sequence", "flags", "alias", "flag-tag:0:-1", -}, { - "chars", "equal", "alias", "=", -}, { - "sequence", "definition", "none", "symbol", "flags", "wscs", "equal", "wscs", "expression", -}, { - "chars", "semicolon", "alias", ";", -}, { - "choice", "wsc-or-semicolon", "alias", "wsc", "semicolon", -}, { - "sequence", "wsc-or-semicolons", "alias", "wsc-or-semicolon:0:-1", -}, { - "sequence", - "subsequent-definition", - "alias", - "wscs", - "semicolon", - "wsc-or-semicolons", - "definition", -}, { - "sequence", - "subsequent-definitions", - "alias", - "subsequent-definition:0:-1", -}, { - "sequence", - "definitions", - "alias", - "definition", - "subsequent-definitions", -}, { - "sequence", - "opt-definitions", - "alias", - "definitions:0:1", -}, { - "sequence", - "syntax", - "root", - "wsc-or-semicolons", - "opt-definitions", - "wsc-or-semicolons", -}} diff --git a/char.go b/char.go index 0b58482..0ed206c 100644 --- a/char.go +++ b/char.go @@ -1,15 +1,5 @@ package treerack -import ( - "fmt" - "io" -) - -const ( - charClassEscape = '\\' - charClassBanned = "\\[]^-\b\f\n\r\t\v" -) - type charParser struct { name string id int @@ -23,70 +13,9 @@ type charBuilder struct { id int } -func newChar( - name string, - not bool, - chars []rune, - ranges [][]rune, -) *charParser { - return &charParser{ - name: name, - not: not, - chars: chars, - ranges: ranges, - } -} - -func (p *charParser) nodeName() string { return p.name } -func (p *charParser) setName(n string) { p.name = n } -func (p *charParser) nodeID() int { return p.id } -func (p *charParser) setID(id int) { p.id = id } -func (p *charParser) commitType() CommitType { return Alias } -func (p *charParser) setCommitType(ct CommitType) {} -func (p *charParser) preinit() {} -func (p *charParser) validate(*registry) error { return nil } -func (p *charParser) init(*registry) {} -func (p *charParser) addGeneralization(int) {} -func (p *charParser) parser() parser { return p } - -func (p *charParser) builder() builder { - return &charBuilder{ - id: p.id, - name: p.name, - } -} - -func (p *charParser) isSingleChar() bool { - return !p.not && len(p.chars) == 1 && len(p.ranges) == 0 -} - -func (p *charParser) format(_ *registry, f formatFlags) string { - if p.not && len(p.chars) == 0 && len(p.ranges) == 0 { - return "." - } - - esc := func(c ...rune) []rune { - return escape(charClassEscape, []rune(charClassBanned), c) - } - - var s []rune - s = append(s, '[') - - if p.not { - s = append(s, '^') - } - - s = append(s, esc(p.chars...)...) - - for i := range p.ranges { - s = append(s, esc(p.ranges[i][0])...) - s = append(s, '-') - s = append(s, esc(p.ranges[i][1])...) - } - - s = append(s, ']') - return string(s) -} +func (p *charParser) nodeName() string { return p.name } +func (p *charParser) nodeID() int { return p.id } +func (p *charParser) commitType() CommitType { return Alias } func matchChar(chars []rune, ranges [][]rune, not bool, char rune) bool { for _, ci := range chars { @@ -122,54 +51,9 @@ func (p *charParser) parse(c *context) { c.success(c.offset + 1) } -func (p *charParser) generate(w io.Writer, done map[string]bool) error { - if done[p.name] { - return nil - } - - done[p.name] = true - - var err error - fprintf := func(f string, args ...interface{}) { - if err != nil { - return - } - - _, err = fmt.Fprintf(w, f, args...) - } - - fprintf("var p%d = charParser{", p.id) - fprintf("id: %d, not: %t,", p.id, p.not) - - fprintf("chars: []rune{") - for i := range p.chars { - fprintf("%d,", p.chars[i]) - } - - fprintf("},") - - fprintf("ranges: [][]rune{") - for i := range p.ranges { - fprintf("{%d, %d},", p.ranges[i][0], p.ranges[i][1]) - } - - fprintf("}};") - return err -} - func (b *charBuilder) nodeName() string { return b.name } func (b *charBuilder) nodeID() int { return b.id } func (b *charBuilder) build(c *context) ([]*Node, bool) { return nil, false } - -func (b *charBuilder) generate(w io.Writer, done map[string]bool) error { - if done[b.name] { - return nil - } - - done[b.name] = true - _, err := fmt.Fprintf(w, "var b%d = charBuilder{};", b.id) - return err -} diff --git a/chardefine.go b/chardefine.go new file mode 100644 index 0000000..232b4f0 --- /dev/null +++ b/chardefine.go @@ -0,0 +1,118 @@ +package treerack + +import ( + "fmt" + "io" +) + +const ( + charClassEscape = '\\' + charClassBanned = "\\[]^-\b\f\n\r\t\v" +) + +func newChar( + name string, + not bool, + chars []rune, + ranges [][]rune, +) *charParser { + return &charParser{ + name: name, + not: not, + chars: chars, + ranges: ranges, + } +} + +func (p *charParser) setName(n string) { p.name = n } +func (p *charParser) setID(id int) { p.id = id } +func (p *charParser) setCommitType(ct CommitType) {} +func (p *charParser) preinit() {} +func (p *charParser) validate(*registry) error { return nil } +func (p *charParser) init(*registry) {} +func (p *charParser) addGeneralization(int) {} +func (p *charParser) parser() parser { return p } + +func (p *charParser) builder() builder { + return &charBuilder{ + id: p.id, + name: p.name, + } +} + +func (p *charParser) isSingleChar() bool { + return !p.not && len(p.chars) == 1 && len(p.ranges) == 0 +} + +func (p *charParser) format(_ *registry, f formatFlags) string { + if p.not && len(p.chars) == 0 && len(p.ranges) == 0 { + return "." + } + + esc := func(c ...rune) []rune { + return escape(charClassEscape, []rune(charClassBanned), c) + } + + var s []rune + s = append(s, '[') + + if p.not { + s = append(s, '^') + } + + s = append(s, esc(p.chars...)...) + + for i := range p.ranges { + s = append(s, esc(p.ranges[i][0])...) + s = append(s, '-') + s = append(s, esc(p.ranges[i][1])...) + } + + s = append(s, ']') + return string(s) +} + +func (p *charParser) generate(w io.Writer, done map[string]bool) error { + if done[p.name] { + return nil + } + + done[p.name] = true + + var err error + fprintf := func(f string, args ...interface{}) { + if err != nil { + return + } + + _, err = fmt.Fprintf(w, f, args...) + } + + fprintf("var p%d = charParser{", p.id) + fprintf("id: %d, not: %t,", p.id, p.not) + + fprintf("chars: []rune{") + for i := range p.chars { + fprintf("%d,", p.chars[i]) + } + + fprintf("},") + + fprintf("ranges: [][]rune{") + for i := range p.ranges { + fprintf("{%d, %d},", p.ranges[i][0], p.ranges[i][1]) + } + + fprintf("}};") + return err +} + +func (b *charBuilder) generate(w io.Writer, done map[string]bool) error { + if done[b.name] { + return nil + } + + done[b.name] = true + _, err := fmt.Fprintf(w, "var b%d = charBuilder{};", b.id) + return err +} diff --git a/choice.go b/choice.go index 1aff59a..833ad07 100644 --- a/choice.go +++ b/choice.go @@ -1,23 +1,5 @@ package treerack -import ( - "fmt" - "io" -) - -type choiceDefinition struct { - name string - id int - commit CommitType - options []string - optionDefs []definition - generalizations []int - cparser *choiceParser - cbuilder *choiceBuilder - validated bool - initialized bool -} - type choiceParser struct { name string id int @@ -33,127 +15,6 @@ type choiceBuilder struct { options []builder } -func newChoice(name string, ct CommitType, options []string) *choiceDefinition { - return &choiceDefinition{ - name: name, - commit: ct, - options: options, - } -} - -func (d *choiceDefinition) nodeName() string { return d.name } -func (d *choiceDefinition) setName(n string) { d.name = n } -func (d *choiceDefinition) nodeID() int { return d.id } -func (d *choiceDefinition) setID(id int) { d.id = id } -func (d *choiceDefinition) commitType() CommitType { return d.commit } -func (d *choiceDefinition) setCommitType(ct CommitType) { d.commit = ct } -func (d *choiceDefinition) preinit() {} - -func (d *choiceDefinition) validate(r *registry) error { - if d.validated { - return nil - } - - d.validated = true - for i := range d.options { - o, ok := r.definitions[d.options[i]] - if !ok { - return parserNotFound(d.options[i]) - } - - if err := o.validate(r); err != nil { - return err - } - } - - return nil -} - -func (d *choiceDefinition) createBuilder() { - d.cbuilder = &choiceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, - } -} - -func (d *choiceDefinition) initOptions(r *registry) { - for _, o := range d.options { - def := r.definitions[o] - d.optionDefs = append(d.optionDefs, def) - def.init(r) - d.cbuilder.options = append(d.cbuilder.options, def.builder()) - def.addGeneralization(d.id) - } -} - -func (d *choiceDefinition) init(r *registry) { - if d.initialized { - return - } - - d.initialized = true - d.createBuilder() - d.initOptions(r) -} - -func (d *choiceDefinition) addGeneralization(g int) { - if intsContain(d.generalizations, g) { - return - } - - d.generalizations = append(d.generalizations, g) - for _, o := range d.optionDefs { - o.addGeneralization(g) - } -} - -func (d *choiceDefinition) createParser() { - d.cparser = &choiceParser{ - name: d.name, - id: d.id, - commit: d.commit, - generalizations: d.generalizations, - } -} - -func (d *choiceDefinition) createOptionParsers() { - for _, def := range d.optionDefs { - option := def.parser() - d.cparser.options = append(d.cparser.options, option) - } -} - -func (d *choiceDefinition) parser() parser { - if d.cparser != nil { - return d.cparser - } - - d.createParser() - d.createOptionParsers() - return d.cparser -} - -func (d *choiceDefinition) builder() builder { return d.cbuilder } - -func (d *choiceDefinition) format(r *registry, f formatFlags) string { - var chars []rune - for i := range d.options { - if i > 0 { - chars = append(chars, []rune(" | ")...) - } - - optionDef, _ := r.definition(d.options[i]) - if optionDef.commitType()&userDefined != 0 { - chars = append(chars, []rune(optionDef.nodeName())...) - } else { - chars = append(chars, []rune(optionDef.format(r, f))...) - } - } - - return string(chars) -} - func (p *choiceParser) nodeName() string { return p.name } func (p *choiceParser) nodeID() int { return p.id } func (p *choiceParser) commitType() CommitType { return p.commit } @@ -248,50 +109,6 @@ func (p *choiceParser) parse(c *context) { c.results.unmarkPending(from, p.id) } -func (p *choiceParser) generate(w io.Writer, done map[string]bool) error { - if done[p.name] { - return nil - } - - done[p.name] = true - - var err error - fprintf := func(f string, args ...interface{}) { - if err != nil { - return - } - - _, err = fmt.Fprintf(w, f, args...) - } - - fprintf("var p%d = choiceParser{", p.id) - fprintf("id: %d, commit: %d,", p.id, p.commit) - if p.commitType()&userDefined != 0 { - fprintf("name: \"%s\",", p.name) - } - - fprintf("generalizations: []int{") - for i := range p.generalizations { - fprintf("%d,", p.generalizations[i]) - } - - fprintf("}};") - - for i := range p.options { - if err := p.options[i].generate(w, done); err != nil { - return err - } - } - - fprintf("p%d.options = []parser{", p.id) - for i := range p.options { - fprintf("&p%d,", p.options[i].nodeID()) - } - - fprintf("};") - return err -} - func (b *choiceBuilder) nodeName() string { return b.name } func (b *choiceBuilder) nodeID() int { return b.id } @@ -339,42 +156,3 @@ func (b *choiceBuilder) build(c *context) ([]*Node, bool) { tokens: c.tokens, }}, true } - -func (b *choiceBuilder) generate(w io.Writer, done map[string]bool) error { - if done[b.name] { - return nil - } - - done[b.name] = true - - var err error - fprintf := func(f string, args ...interface{}) { - if err != nil { - return - } - - _, err = fmt.Fprintf(w, f, args...) - } - - fprintf("var b%d = choiceBuilder{", b.id) - fprintf("id: %d, commit: %d,", b.id, b.commit) - if b.commit&Alias == 0 { - fprintf("name: \"%s\",", b.name) - } - - fprintf("};") - - for i := range b.options { - if err := b.options[i].generate(w, done); err != nil { - return err - } - } - - fprintf("b%d.options = []builder{", b.id) - for i := range b.options { - fprintf("&b%d,", b.options[i].nodeID()) - } - - fprintf("};") - return err -} diff --git a/choicedefine.go b/choicedefine.go new file mode 100644 index 0000000..16f8735 --- /dev/null +++ b/choicedefine.go @@ -0,0 +1,223 @@ +package treerack + +import ( + "fmt" + "io" +) + +type choiceDefinition struct { + name string + id int + commit CommitType + options []string + optionDefs []definition + generalizations []int + cparser *choiceParser + cbuilder *choiceBuilder + validated bool + initialized bool +} + +func (d *choiceDefinition) nodeName() string { return d.name } +func (d *choiceDefinition) setName(n string) { d.name = n } +func (d *choiceDefinition) nodeID() int { return d.id } +func (d *choiceDefinition) setID(id int) { d.id = id } +func (d *choiceDefinition) commitType() CommitType { return d.commit } +func (d *choiceDefinition) setCommitType(ct CommitType) { d.commit = ct } +func (d *choiceDefinition) preinit() {} + +func newChoice(name string, ct CommitType, options []string) *choiceDefinition { + return &choiceDefinition{ + name: name, + commit: ct, + options: options, + } +} + +func (d *choiceDefinition) validate(r *registry) error { + if d.validated { + return nil + } + + d.validated = true + for i := range d.options { + o, ok := r.definitions[d.options[i]] + if !ok { + return parserNotFound(d.options[i]) + } + + if err := o.validate(r); err != nil { + return err + } + } + + return nil +} + +func (d *choiceDefinition) createBuilder() { + d.cbuilder = &choiceBuilder{ + name: d.name, + id: d.id, + commit: d.commit, + } +} + +func (d *choiceDefinition) initOptions(r *registry) { + for _, o := range d.options { + def := r.definitions[o] + d.optionDefs = append(d.optionDefs, def) + def.init(r) + d.cbuilder.options = append(d.cbuilder.options, def.builder()) + def.addGeneralization(d.id) + } +} + +func (d *choiceDefinition) init(r *registry) { + if d.initialized { + return + } + + d.initialized = true + d.createBuilder() + d.initOptions(r) +} + +func (d *choiceDefinition) addGeneralization(g int) { + if intsContain(d.generalizations, g) { + return + } + + d.generalizations = append(d.generalizations, g) + for _, o := range d.optionDefs { + o.addGeneralization(g) + } +} + +func (d *choiceDefinition) createParser() { + d.cparser = &choiceParser{ + name: d.name, + id: d.id, + commit: d.commit, + generalizations: d.generalizations, + } +} + +func (d *choiceDefinition) createOptionParsers() { + for _, def := range d.optionDefs { + option := def.parser() + d.cparser.options = append(d.cparser.options, option) + } +} + +func (d *choiceDefinition) parser() parser { + if d.cparser != nil { + return d.cparser + } + + d.createParser() + d.createOptionParsers() + return d.cparser +} + +func (d *choiceDefinition) builder() builder { return d.cbuilder } + +func (d *choiceDefinition) format(r *registry, f formatFlags) string { + var chars []rune + for i := range d.options { + if i > 0 { + chars = append(chars, []rune(" | ")...) + } + + optionDef, _ := r.definition(d.options[i]) + if optionDef.commitType()&userDefined != 0 { + chars = append(chars, []rune(optionDef.nodeName())...) + } else { + chars = append(chars, []rune(optionDef.format(r, f))...) + } + } + + return string(chars) +} + +func (p *choiceParser) generate(w io.Writer, done map[string]bool) error { + if done[p.name] { + return nil + } + + done[p.name] = true + + var err error + fprintf := func(f string, args ...interface{}) { + if err != nil { + return + } + + _, err = fmt.Fprintf(w, f, args...) + } + + fprintf("var p%d = choiceParser{", p.id) + fprintf("id: %d, commit: %d,", p.id, p.commit) + if p.commitType()&userDefined != 0 { + fprintf("name: \"%s\",", p.name) + } + + fprintf("generalizations: []int{") + for i := range p.generalizations { + fprintf("%d,", p.generalizations[i]) + } + + fprintf("}};") + + for i := range p.options { + if err := p.options[i].(generator).generate(w, done); err != nil { + return err + } + } + + fprintf("p%d.options = []parser{", p.id) + for i := range p.options { + fprintf("&p%d,", p.options[i].nodeID()) + } + + fprintf("};") + return err +} + +func (b *choiceBuilder) generate(w io.Writer, done map[string]bool) error { + if done[b.name] { + return nil + } + + done[b.name] = true + + var err error + fprintf := func(f string, args ...interface{}) { + if err != nil { + return + } + + _, err = fmt.Fprintf(w, f, args...) + } + + fprintf("var b%d = choiceBuilder{", b.id) + fprintf("id: %d, commit: %d,", b.id, b.commit) + if b.commit&Alias == 0 { + fprintf("name: \"%s\",", b.name) + } + + fprintf("};") + + for i := range b.options { + if err := b.options[i].(generator).generate(w, done); err != nil { + return err + } + } + + fprintf("b%d.options = []builder{", b.id) + for i := range b.options { + fprintf("&b%d,", b.options[i].nodeID()) + } + + fprintf("};") + return err +} diff --git a/context.go b/context.go index ee8a150..80ae302 100644 --- a/context.go +++ b/context.go @@ -130,14 +130,14 @@ func (c *context) parseError(p parser) error { } func (c *context) finalizeParse(root parser) error { - p := c.failingParser - if p == nil { - p = root + fp := c.failingParser + if fp == nil { + fp = root } to, match, found := c.results.longestResult(0, root.nodeID()) if !found || !match || found && match && to < c.readOffset { - return c.parseError(p) + return c.parseError(fp) } c.read() diff --git a/gendoc.go b/gendoc.go new file mode 100644 index 0000000..cab240d --- /dev/null +++ b/gendoc.go @@ -0,0 +1,23 @@ +package treerack + +// The below doc doesn't apply to treerack's source code +// only to the source code generated with treerack. +const gendoc = ` +/* +This file was generated by treerack (https://github.com/aryszka/treerack). + +The contents of this file fall under different licenses. + +The code between the "// head" and "// eo head" lines falls under the same +license as the source code of treerack (https://github.com/aryszka/treerack), +unless explicitly stated otherwise, if treerack's license allows changing the +license of this source code. + +Treerack's license: MIT https://opensource.org/licenses/MIT +where YEAR=2018, COPYRIGHT HOLDER=Arpad Ryszka (arpad.ryszka@gmail.com) + +The rest of the content of this file falls under the same license as the one +that the user of treerack generating this file declares for it, or it is +unlicensed. +*/ +` diff --git a/head.go b/head.go new file mode 100644 index 0000000..3b2fbe8 --- /dev/null +++ b/head.go @@ -0,0 +1,4 @@ +package treerack + +// generated with scripts/createhead.go +const headCode = "import (\n\t\"strconv\"\n\t\"io\"\n\t\"strings\"\n\t\"unicode\"\n\t\"fmt\"\n\t\"bufio\"\n\t\"errors\"\n)\n\ntype charParser struct {\n\tname\tstring\n\tid\tint\n\tnot\tbool\n\tchars\t[]rune\n\tranges\t[][]rune\n}\ntype charBuilder struct {\n\tname\tstring\n\tid\tint\n}\n\nfunc (p *charParser) nodeName() string {\n\treturn p.name\n}\nfunc (p *charParser) nodeID() int {\n\treturn p.id\n}\nfunc (p *charParser) commitType() CommitType {\n\treturn Alias\n}\nfunc matchChar(chars []rune, ranges [][]rune, not bool, char rune) bool {\n\tfor _, ci := range chars {\n\t\tif ci == char {\n\t\t\treturn !not\n\t\t}\n\t}\n\tfor _, ri := range ranges {\n\t\tif char >= ri[0] && char <= ri[1] {\n\t\t\treturn !not\n\t\t}\n\t}\n\treturn not\n}\nfunc (p *charParser) match(t rune) bool {\n\treturn matchChar(p.chars, p.ranges, p.not, t)\n}\nfunc (p *charParser) parse(c *context) {\n\tif tok, ok := c.token(); !ok || !p.match(tok) {\n\t\tif c.offset > c.failOffset {\n\t\t\tc.failOffset = c.offset\n\t\t\tc.failingParser = nil\n\t\t}\n\t\tc.fail(c.offset)\n\t\treturn\n\t}\n\tc.success(c.offset + 1)\n}\nfunc (b *charBuilder) nodeName() string {\n\treturn b.name\n}\nfunc (b *charBuilder) nodeID() int {\n\treturn b.id\n}\nfunc (b *charBuilder) build(c *context) ([]*Node, bool) {\n\treturn nil, false\n}\n\ntype sequenceParser struct {\n\tname\t\tstring\n\tid\t\tint\n\tcommit\t\tCommitType\n\titems\t\t[]parser\n\tranges\t\t[][]int\n\tgeneralizations\t[]int\n\tallChars\tbool\n}\ntype sequenceBuilder struct {\n\tname\t\tstring\n\tid\t\tint\n\tcommit\t\tCommitType\n\titems\t\t[]builder\n\tranges\t\t[][]int\n\tallChars\tbool\n}\n\nfunc (p *sequenceParser) nodeName() string {\n\treturn p.name\n}\nfunc (p *sequenceParser) nodeID() int {\n\treturn p.id\n}\nfunc (p *sequenceParser) commitType() CommitType {\n\treturn p.commit\n}\nfunc (p *sequenceParser) parse(c *context) {\n\tif !p.allChars {\n\t\tif c.results.pending(c.offset, p.id) {\n\t\t\tc.fail(c.offset)\n\t\t\treturn\n\t\t}\n\t\tc.results.markPending(c.offset, p.id)\n\t}\n\tvar (\n\t\tcurrentCount\tint\n\t\tparsed\t\tbool\n\t)\n\titemIndex := 0\n\tfrom := c.offset\n\tto := c.offset\n\tfor itemIndex < len(p.items) {\n\t\tp.items[itemIndex].parse(c)\n\t\tif !c.matchLast {\n\t\t\tif currentCount >= p.ranges[itemIndex][0] {\n\t\t\t\titemIndex++\n\t\t\t\tcurrentCount = 0\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif c.failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 && p.commit&FailPass == 0 {\n\t\t\t\tc.failingParser = p\n\t\t\t}\n\t\t\tc.fail(from)\n\t\t\tif !p.allChars {\n\t\t\t\tc.results.unmarkPending(from, p.id)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tparsed = c.offset > to\n\t\tif parsed {\n\t\t\tcurrentCount++\n\t\t}\n\t\tto = c.offset\n\t\tif !parsed || p.ranges[itemIndex][1] > 0 && currentCount == p.ranges[itemIndex][1] {\n\t\t\titemIndex++\n\t\t\tcurrentCount = 0\n\t\t}\n\t}\n\tfor _, g := range p.generalizations {\n\t\tif c.results.pending(from, g) {\n\t\t\tc.results.setMatch(from, g, to)\n\t\t}\n\t}\n\tif to > c.failOffset {\n\t\tc.failOffset = -1\n\t\tc.failingParser = nil\n\t}\n\tc.results.setMatch(from, p.id, to)\n\tc.success(to)\n\tif !p.allChars {\n\t\tc.results.unmarkPending(from, p.id)\n\t}\n}\nfunc (b *sequenceBuilder) nodeName() string {\n\treturn b.name\n}\nfunc (b *sequenceBuilder) nodeID() int {\n\treturn b.id\n}\nfunc (b *sequenceBuilder) build(c *context) ([]*Node, bool) {\n\tto, ok := c.results.longestMatch(c.offset, b.id)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\tfrom := c.offset\n\tparsed := to > from\n\tif b.allChars {\n\t\tc.offset = to\n\t\tif b.commit&Alias != 0 {\n\t\t\treturn nil, true\n\t\t}\n\t\treturn []*Node{{Name: b.name, From: from, To: to, tokens: c.tokens}}, true\n\t} else if parsed {\n\t\tc.results.dropMatchTo(c.offset, b.id, to)\n\t} else {\n\t\tif c.results.pending(c.offset, b.id) {\n\t\t\treturn nil, false\n\t\t}\n\t\tc.results.markPending(c.offset, b.id)\n\t}\n\tvar (\n\t\titemIndex\tint\n\t\tcurrentCount\tint\n\t\tnodes\t\t[]*Node\n\t)\n\tfor itemIndex < len(b.items) {\n\t\titemFrom := c.offset\n\t\tn, ok := b.items[itemIndex].build(c)\n\t\tif !ok {\n\t\t\titemIndex++\n\t\t\tcurrentCount = 0\n\t\t\tcontinue\n\t\t}\n\t\tif c.offset > itemFrom {\n\t\t\tnodes = append(nodes, n...)\n\t\t\tcurrentCount++\n\t\t\tif b.ranges[itemIndex][1] > 0 && currentCount == b.ranges[itemIndex][1] {\n\t\t\t\titemIndex++\n\t\t\t\tcurrentCount = 0\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif currentCount < b.ranges[itemIndex][0] {\n\t\t\tfor i := 0; i < b.ranges[itemIndex][0]-currentCount; i++ {\n\t\t\t\tnodes = append(nodes, n...)\n\t\t\t}\n\t\t}\n\t\titemIndex++\n\t\tcurrentCount = 0\n\t}\n\tif !parsed {\n\t\tc.results.unmarkPending(from, b.id)\n\t}\n\tif b.commit&Alias != 0 {\n\t\treturn nodes, true\n\t}\n\treturn []*Node{{Name: b.name, From: from, To: to, Nodes: nodes, tokens: c.tokens}}, true\n}\n\ntype choiceParser struct {\n\tname\t\tstring\n\tid\t\tint\n\tcommit\t\tCommitType\n\toptions\t\t[]parser\n\tgeneralizations\t[]int\n}\ntype choiceBuilder struct {\n\tname\tstring\n\tid\tint\n\tcommit\tCommitType\n\toptions\t[]builder\n}\n\nfunc (p *choiceParser) nodeName() string {\n\treturn p.name\n}\nfunc (p *choiceParser) nodeID() int {\n\treturn p.id\n}\nfunc (p *choiceParser) commitType() CommitType {\n\treturn p.commit\n}\nfunc (p *choiceParser) parse(c *context) {\n\tif c.fromResults(p) {\n\t\treturn\n\t}\n\tif c.results.pending(c.offset, p.id) {\n\t\tc.fail(c.offset)\n\t\treturn\n\t}\n\tc.results.markPending(c.offset, p.id)\n\tvar (\n\t\tmatch\t\tbool\n\t\toptionIndex\tint\n\t\tfoundMatch\tbool\n\t\tfailingParser\tparser\n\t)\n\tfrom := c.offset\n\tto := c.offset\n\tinitialFailOffset := c.failOffset\n\tinitialFailingParser := c.failingParser\n\tfailOffset := initialFailOffset\n\tfor {\n\t\tfoundMatch = false\n\t\toptionIndex = 0\n\t\tfor optionIndex < len(p.options) {\n\t\t\tp.options[optionIndex].parse(c)\n\t\t\toptionIndex++\n\t\t\tif !c.matchLast {\n\t\t\t\tif c.failOffset > failOffset {\n\t\t\t\t\tfailOffset = c.failOffset\n\t\t\t\t\tfailingParser = c.failingParser\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !c.matchLast || match && c.offset <= to {\n\t\t\t\tc.offset = from\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tmatch = true\n\t\t\tfoundMatch = true\n\t\t\tto = c.offset\n\t\t\tc.offset = from\n\t\t\tc.results.setMatch(from, p.id, to)\n\t\t}\n\t\tif !foundMatch {\n\t\t\tbreak\n\t\t}\n\t}\n\tif match {\n\t\tif failOffset > to {\n\t\t\tc.failOffset = failOffset\n\t\t\tc.failingParser = failingParser\n\t\t} else if to > initialFailOffset {\n\t\t\tc.failOffset = -1\n\t\t\tc.failingParser = nil\n\t\t} else {\n\t\t\tc.failOffset = initialFailOffset\n\t\t\tc.failingParser = initialFailingParser\n\t\t}\n\t\tc.success(to)\n\t\tc.results.unmarkPending(from, p.id)\n\t\treturn\n\t}\n\tif failOffset > initialFailOffset {\n\t\tc.failOffset = failOffset\n\t\tc.failingParser = failingParser\n\t\tif c.failingParser == nil && p.commitType()&userDefined != 0 && p.commitType()&Whitespace == 0 && p.commitType()&FailPass == 0 {\n\t\t\tc.failingParser = p\n\t\t}\n\t}\n\tc.results.setNoMatch(from, p.id)\n\tc.fail(from)\n\tc.results.unmarkPending(from, p.id)\n}\nfunc (b *choiceBuilder) nodeName() string {\n\treturn b.name\n}\nfunc (b *choiceBuilder) nodeID() int {\n\treturn b.id\n}\nfunc (b *choiceBuilder) build(c *context) ([]*Node, bool) {\n\tto, ok := c.results.longestMatch(c.offset, b.id)\n\tif !ok {\n\t\treturn nil, false\n\t}\n\tfrom := c.offset\n\tparsed := to > from\n\tif parsed {\n\t\tc.results.dropMatchTo(c.offset, b.id, to)\n\t} else {\n\t\tif c.results.pending(c.offset, b.id) {\n\t\t\treturn nil, false\n\t\t}\n\t\tc.results.markPending(c.offset, b.id)\n\t}\n\tvar option builder\n\tfor _, o := range b.options {\n\t\tif c.results.hasMatchTo(c.offset, o.nodeID(), to) {\n\t\t\toption = o\n\t\t\tbreak\n\t\t}\n\t}\n\tn, _ := option.build(c)\n\tif !parsed {\n\t\tc.results.unmarkPending(from, b.id)\n\t}\n\tif b.commit&Alias != 0 {\n\t\treturn n, true\n\t}\n\treturn []*Node{{Name: b.name, From: from, To: to, Nodes: n, tokens: c.tokens}}, true\n}\n\ntype idSet struct{ ids []uint }\n\nfunc divModBits(id int) (int, int) {\n\treturn id / strconv.IntSize, id % strconv.IntSize\n}\nfunc (s *idSet) set(id int) {\n\td, m := divModBits(id)\n\tif d >= len(s.ids) {\n\t\tif d < cap(s.ids) {\n\t\t\ts.ids = s.ids[:d+1]\n\t\t} else {\n\t\t\ts.ids = s.ids[:cap(s.ids)]\n\t\t\tfor i := cap(s.ids); i <= d; i++ {\n\t\t\t\ts.ids = append(s.ids, 0)\n\t\t\t}\n\t\t}\n\t}\n\ts.ids[d] |= 1 << uint(m)\n}\nfunc (s *idSet) unset(id int) {\n\td, m := divModBits(id)\n\tif d >= len(s.ids) {\n\t\treturn\n\t}\n\ts.ids[d] &^= 1 << uint(m)\n}\nfunc (s *idSet) has(id int) bool {\n\td, m := divModBits(id)\n\tif d >= len(s.ids) {\n\t\treturn false\n\t}\n\treturn s.ids[d]&(1< offset {\n\t\treturn ints\n\t}\n\tif cap(ints) > offset {\n\t\tints = ints[:offset+1]\n\t\treturn ints\n\t}\n\tints = ints[:cap(ints)]\n\tfor i := len(ints); i <= offset; i++ {\n\t\tints = append(ints, nil)\n\t}\n\treturn ints\n}\nfunc ensureOffsetIDs(ids []*idSet, offset int) []*idSet {\n\tif len(ids) > offset {\n\t\treturn ids\n\t}\n\tif cap(ids) > offset {\n\t\tids = ids[:offset+1]\n\t\treturn ids\n\t}\n\tids = ids[:cap(ids)]\n\tfor i := len(ids); i <= offset; i++ {\n\t\tids = append(ids, nil)\n\t}\n\treturn ids\n}\nfunc (r *results) setMatch(offset, id, to int) {\n\tr.match = ensureOffsetInts(r.match, offset)\n\tfor i := 0; i < len(r.match[offset]); i += 2 {\n\t\tif r.match[offset][i] != id || r.match[offset][i+1] != to {\n\t\t\tcontinue\n\t\t}\n\t\treturn\n\t}\n\tr.match[offset] = append(r.match[offset], id, to)\n}\nfunc (r *results) setNoMatch(offset, id int) {\n\tif len(r.match) > offset {\n\t\tfor i := 0; i < len(r.match[offset]); i += 2 {\n\t\t\tif r.match[offset][i] != id {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t}\n\tr.noMatch = ensureOffsetIDs(r.noMatch, offset)\n\tif r.noMatch[offset] == nil {\n\t\tr.noMatch[offset] = &idSet{}\n\t}\n\tr.noMatch[offset].set(id)\n}\nfunc (r *results) hasMatchTo(offset, id, to int) bool {\n\tif len(r.match) <= offset {\n\t\treturn false\n\t}\n\tfor i := 0; i < len(r.match[offset]); i += 2 {\n\t\tif r.match[offset][i] != id {\n\t\t\tcontinue\n\t\t}\n\t\tif r.match[offset][i+1] == to {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\nfunc (r *results) longestMatch(offset, id int) (int, bool) {\n\tif len(r.match) <= offset {\n\t\treturn 0, false\n\t}\n\tvar found bool\n\tto := -1\n\tfor i := 0; i < len(r.match[offset]); i += 2 {\n\t\tif r.match[offset][i] != id {\n\t\t\tcontinue\n\t\t}\n\t\tif r.match[offset][i+1] > to {\n\t\t\tto = r.match[offset][i+1]\n\t\t}\n\t\tfound = true\n\t}\n\treturn to, found\n}\nfunc (r *results) longestResult(offset, id int) (int, bool, bool) {\n\tif len(r.noMatch) > offset && r.noMatch[offset] != nil && r.noMatch[offset].has(id) {\n\t\treturn 0, false, true\n\t}\n\tto, ok := r.longestMatch(offset, id)\n\treturn to, ok, ok\n}\nfunc (r *results) dropMatchTo(offset, id, to int) {\n\tfor i := 0; i < len(r.match[offset]); i += 2 {\n\t\tif r.match[offset][i] != id {\n\t\t\tcontinue\n\t\t}\n\t\tif r.match[offset][i+1] == to {\n\t\t\tr.match[offset][i] = -1\n\t\t\treturn\n\t\t}\n\t}\n}\nfunc (r *results) resetPending() {\n\tr.isPending = nil\n}\nfunc (r *results) pending(offset, id int) bool {\n\tif len(r.isPending) <= id {\n\t\treturn false\n\t}\n\tfor i := range r.isPending[id] {\n\t\tif r.isPending[id][i] == offset {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\nfunc (r *results) markPending(offset, id int) {\n\tr.isPending = ensureOffsetInts(r.isPending, id)\n\tfor i := range r.isPending[id] {\n\t\tif r.isPending[id][i] == -1 {\n\t\t\tr.isPending[id][i] = offset\n\t\t\treturn\n\t\t}\n\t}\n\tr.isPending[id] = append(r.isPending[id], offset)\n}\nfunc (r *results) unmarkPending(offset, id int) {\n\tfor i := range r.isPending[id] {\n\t\tif r.isPending[id][i] == offset {\n\t\t\tr.isPending[id][i] = -1\n\t\t\tbreak\n\t\t}\n\t}\n}\n\ntype context struct {\n\treader\t\tio.RuneReader\n\toffset\t\tint\n\treadOffset\tint\n\tconsumed\tint\n\tfailOffset\tint\n\tfailingParser\tparser\n\treadErr\t\terror\n\teof\t\tbool\n\tresults\t\t*results\n\ttokens\t\t[]rune\n\tmatchLast\tbool\n}\n\nfunc newContext(r io.RuneReader) *context {\n\treturn &context{reader: r, results: &results{}, failOffset: -1}\n}\nfunc (c *context) read() bool {\n\tif c.eof || c.readErr != nil {\n\t\treturn false\n\t}\n\ttoken, n, err := c.reader.ReadRune()\n\tif err != nil {\n\t\tif err == io.EOF {\n\t\t\tif n == 0 {\n\t\t\t\tc.eof = true\n\t\t\t\treturn false\n\t\t\t}\n\t\t} else {\n\t\t\tc.readErr = err\n\t\t\treturn false\n\t\t}\n\t}\n\tc.readOffset++\n\tif token == unicode.ReplacementChar {\n\t\tc.readErr = ErrInvalidUnicodeCharacter\n\t\treturn false\n\t}\n\tc.tokens = append(c.tokens, token)\n\treturn true\n}\nfunc (c *context) token() (rune, bool) {\n\tif c.offset == c.readOffset {\n\t\tif !c.read() {\n\t\t\treturn 0, false\n\t\t}\n\t}\n\treturn c.tokens[c.offset], true\n}\nfunc (c *context) fromResults(p parser) bool {\n\tto, m, ok := c.results.longestResult(c.offset, p.nodeID())\n\tif !ok {\n\t\treturn false\n\t}\n\tif m {\n\t\tc.success(to)\n\t} else {\n\t\tc.fail(c.offset)\n\t}\n\treturn true\n}\nfunc (c *context) success(to int) {\n\tc.offset = to\n\tc.matchLast = true\n\tif to > c.consumed {\n\t\tc.consumed = to\n\t}\n}\nfunc (c *context) fail(offset int) {\n\tc.offset = offset\n\tc.matchLast = false\n}\nfunc findLine(tokens []rune, offset int) (line, column int) {\n\ttokens = tokens[:offset]\n\tfor i := range tokens {\n\t\tcolumn++\n\t\tif tokens[i] == '\\n' {\n\t\t\tcolumn = 0\n\t\t\tline++\n\t\t}\n\t}\n\treturn\n}\nfunc (c *context) parseError(p parser) error {\n\tdefinition := p.nodeName()\n\tflagIndex := strings.Index(definition, \":\")\n\tif flagIndex > 0 {\n\t\tdefinition = definition[:flagIndex]\n\t}\n\tif c.failingParser == nil {\n\t\tc.failOffset = c.consumed\n\t}\n\tline, col := findLine(c.tokens, c.failOffset)\n\treturn &ParseError{Offset: c.failOffset, Line: line, Column: col, Definition: definition}\n}\nfunc (c *context) finalizeParse(root parser) error {\n\tfp := c.failingParser\n\tif fp == nil {\n\t\tfp = root\n\t}\n\tto, match, found := c.results.longestResult(0, root.nodeID())\n\tif !found || !match || found && match && to < c.readOffset {\n\t\treturn c.parseError(fp)\n\t}\n\tc.read()\n\tif c.eof {\n\t\treturn nil\n\t}\n\tif c.readErr != nil {\n\t\treturn c.readErr\n\t}\n\treturn c.parseError(root)\n}\n\ntype Node struct {\n\tName\t\tstring\n\tNodes\t\t[]*Node\n\tFrom, To\tint\n\ttokens\t\t[]rune\n}\n\nfunc (n *Node) Tokens() []rune {\n\tdefer func() {\n\t\tif err := recover(); err != nil {\n\t\t\tprintln(len(n.tokens), n.From, n.To)\n\t\t\tpanic(err)\n\t\t}\n\t}()\n\treturn n.tokens\n}\nfunc (n *Node) String() string {\n\treturn fmt.Sprintf(\"%s:%d:%d:%s\", n.Name, n.From, n.To, n.Text())\n}\nfunc (n *Node) Text() string {\n\treturn string(n.Tokens()[n.From:n.To])\n}\n\ntype CommitType int\n\nconst (\n\tNone\tCommitType\t= 0\n\tAlias\tCommitType\t= 1 << iota\n\tWhitespace\n\tNoWhitespace\n\tFailPass\n\tRoot\n\tuserDefined\n)\n\ntype formatFlags int\n\nconst (\n\tformatNone\tformatFlags\t= 0\n\tformatPretty\tformatFlags\t= 1 << iota\n\tformatIncludeComments\n)\n\ntype ParseError struct {\n\tInput\t\tstring\n\tOffset\t\tint\n\tLine\t\tint\n\tColumn\t\tint\n\tDefinition\tstring\n}\ntype parser interface {\n\tnodeName() string\n\tnodeID() int\n\tcommitType() CommitType\n\tparse(*context)\n}\ntype builder interface {\n\tnodeName() string\n\tnodeID() int\n\tbuild(*context) ([]*Node, bool)\n}\n\nvar ErrInvalidUnicodeCharacter = errors.New(\"invalid unicode character\")\n\nfunc (pe *ParseError) Error() string {\n\treturn fmt.Sprintf(\"%s:%d:%d:parse failed, parsing: %s\", pe.Input, pe.Line+1, pe.Column+1, pe.Definition)\n}\nfunc parse(r io.Reader, p parser, b builder) (*Node, error) {\n\tc := newContext(bufio.NewReader(r))\n\tp.parse(c)\n\tif c.readErr != nil {\n\t\treturn nil, c.readErr\n\t}\n\tif err := c.finalizeParse(p); err != nil {\n\t\tif perr, ok := err.(*ParseError); ok {\n\t\t\tperr.Input = \"\"\n\t\t}\n\t\treturn nil, err\n\t}\n\tc.offset = 0\n\tc.results.resetPending()\n\tn, _ := b.build(c)\n\treturn n[0], nil\n}\n" diff --git a/node.go b/node.go index 3ad0392..5c4140a 100644 --- a/node.go +++ b/node.go @@ -1,13 +1,6 @@ package treerack -import "fmt" - -type Node struct { - Name string - Nodes []*Node - From, To int - tokens []rune -} +import "github.com/aryszka/treerack/self" func mapNodes(m func(n *Node) *Node, n []*Node) []*Node { var nn []*Node @@ -29,10 +22,17 @@ func filterNodes(f func(n *Node) bool, n []*Node) []*Node { return nn } -func (n *Node) String() string { - return fmt.Sprintf("%s:%d:%d:%s", n.Name, n.From, n.To, n.Text()) -} +func mapSelfNode(n *self.Node) *Node { + nn := Node{ + Name: n.Name, + From: n.From, + To: n.To, + tokens: n.Tokens(), + } -func (n *Node) Text() string { - return string(n.tokens[n.From:n.To]) + for i := range n.Nodes { + nn.Nodes = append(nn.Nodes, mapSelfNode(n.Nodes[i])) + } + + return &nn } diff --git a/nodehead.go b/nodehead.go new file mode 100644 index 0000000..9942c45 --- /dev/null +++ b/nodehead.go @@ -0,0 +1,28 @@ +package treerack + +import "fmt" + +type Node struct { + Name string + Nodes []*Node + From, To int + tokens []rune +} + +func (n *Node) Tokens() []rune { + defer func() { + if err := recover(); err != nil { + println(len(n.tokens), n.From, n.To) + panic(err) + } + }() + return n.tokens +} + +func (n *Node) String() string { + return fmt.Sprintf("%s:%d:%d:%s", n.Name, n.From, n.To, n.Text()) +} + +func (n *Node) Text() string { + return string(n.Tokens()[n.From:n.To]) +} diff --git a/notes.txt b/notes.txt index bdd63c0..ec1193a 100644 --- a/notes.txt +++ b/notes.txt @@ -34,6 +34,8 @@ test all docs warn nows usage in docs, e.g. spaces in symbol = [a-z]+ test error report on invalid flag report unused definitions +simplify generated output +parse hashed, storing only the results [optimization] try preallocate larger store chunks diff --git a/parsegen.go b/parsegen.go deleted file mode 100644 index df9348b..0000000 --- a/parsegen.go +++ /dev/null @@ -1,625 +0,0 @@ -package treerack - -import ( - "bufio" - "io" -) - -func parsegen(r io.Reader) (*Node, error) { - var p188 = sequenceParser{id: 188, commit: 32, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} - var p186 = choiceParser{id: 186, commit: 2, generalizations: []int{}} - var p185 = choiceParser{id: 185, commit: 70, name: "wsc", generalizations: []int{186}} - var p171 = choiceParser{id: 171, commit: 66, name: "wschar", generalizations: []int{185, 186}} - var p63 = sequenceParser{id: 63, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{171, 185, 186}} - var p28 = charParser{id: 28, not: false, chars: []rune{32}, ranges: [][]rune{}} - p63.items = []parser{&p28} - var p121 = sequenceParser{id: 121, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{171, 185, 186}} - var p17 = charParser{id: 17, not: false, chars: []rune{9}, ranges: [][]rune{}} - p121.items = []parser{&p17} - var p79 = sequenceParser{id: 79, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{171, 185, 186}} - var p53 = charParser{id: 53, not: false, chars: []rune{10}, ranges: [][]rune{}} - p79.items = []parser{&p53} - var p114 = sequenceParser{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{171, 185, 186}} - var p96 = charParser{id: 96, not: false, chars: []rune{8}, ranges: [][]rune{}} - p114.items = []parser{&p96} - var p141 = sequenceParser{id: 141, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{171, 185, 186}} - var p9 = charParser{id: 9, not: false, chars: []rune{12}, ranges: [][]rune{}} - p141.items = []parser{&p9} - var p47 = sequenceParser{id: 47, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{171, 185, 186}} - var p87 = charParser{id: 87, not: false, chars: []rune{13}, ranges: [][]rune{}} - p47.items = []parser{&p87} - var p40 = sequenceParser{id: 40, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{171, 185, 186}} - var p18 = charParser{id: 18, not: false, chars: []rune{11}, ranges: [][]rune{}} - p40.items = []parser{&p18} - p171.options = []parser{&p63, &p121, &p79, &p114, &p141, &p47, &p40} - var p90 = sequenceParser{id: 90, commit: 72, allChars: false, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{185, 186}} - var p142 = choiceParser{id: 142, commit: 74, name: "comment-segment", generalizations: []int{}} - var p80 = sequenceParser{id: 80, commit: 74, allChars: false, name: "line-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{142}} - var p41 = sequenceParser{id: 41, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} - var p65 = charParser{id: 65, not: false, chars: []rune{47}, ranges: [][]rune{}} - var p148 = charParser{id: 148, not: false, chars: []rune{47}, ranges: [][]rune{}} - p41.items = []parser{&p65, &p148} - var p55 = sequenceParser{id: 55, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p124 = charParser{id: 124, not: true, chars: []rune{10}, ranges: [][]rune{}} - p55.items = []parser{&p124} - p80.items = []parser{&p41, &p55} - var p48 = sequenceParser{id: 48, commit: 74, allChars: false, name: "block-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{142}} - var p97 = sequenceParser{id: 97, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} - var p64 = charParser{id: 64, not: false, chars: []rune{47}, ranges: [][]rune{}} - var p54 = charParser{id: 54, not: false, chars: []rune{42}, ranges: [][]rune{}} - p97.items = []parser{&p64, &p54} - var p89 = choiceParser{id: 89, commit: 10, generalizations: []int{}} - var p104 = sequenceParser{id: 104, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{89}} - var p29 = sequenceParser{id: 29, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p88 = charParser{id: 88, not: false, chars: []rune{42}, ranges: [][]rune{}} - p29.items = []parser{&p88} - var p122 = sequenceParser{id: 122, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p131 = charParser{id: 131, not: true, chars: []rune{47}, ranges: [][]rune{}} - p122.items = []parser{&p131} - p104.items = []parser{&p29, &p122} - var p159 = sequenceParser{id: 159, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{89}} - var p123 = charParser{id: 123, not: true, chars: []rune{42}, ranges: [][]rune{}} - p159.items = []parser{&p123} - p89.options = []parser{&p104, &p159} - var p19 = sequenceParser{id: 19, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} - var p153 = charParser{id: 153, not: false, chars: []rune{42}, ranges: [][]rune{}} - var p24 = charParser{id: 24, not: false, chars: []rune{47}, ranges: [][]rune{}} - p19.items = []parser{&p153, &p24} - p48.items = []parser{&p97, &p89, &p19} - p142.options = []parser{&p80, &p48} - var p3 = sequenceParser{id: 3, commit: 10, allChars: false, ranges: [][]int{{0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{}} - var p160 = choiceParser{id: 160, commit: 74, name: "ws-no-nl", generalizations: []int{}} - var p66 = sequenceParser{id: 66, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{160}} - var p109 = charParser{id: 109, not: false, chars: []rune{32}, ranges: [][]rune{}} - p66.items = []parser{&p109} - var p180 = sequenceParser{id: 180, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{160}} - var p30 = charParser{id: 30, not: false, chars: []rune{9}, ranges: [][]rune{}} - p180.items = []parser{&p30} - var p136 = sequenceParser{id: 136, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{160}} - var p125 = charParser{id: 125, not: false, chars: []rune{8}, ranges: [][]rune{}} - p136.items = []parser{&p125} - var p118 = sequenceParser{id: 118, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{160}} - var p31 = charParser{id: 31, not: false, chars: []rune{12}, ranges: [][]rune{}} - p118.items = []parser{&p31} - var p49 = sequenceParser{id: 49, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{160}} - var p73 = charParser{id: 73, not: false, chars: []rune{13}, ranges: [][]rune{}} - p49.items = []parser{&p73} - var p182 = sequenceParser{id: 182, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{160}} - var p181 = charParser{id: 181, not: false, chars: []rune{11}, ranges: [][]rune{}} - p182.items = []parser{&p181} - p160.options = []parser{&p66, &p180, &p136, &p118, &p49, &p182} - var p137 = sequenceParser{id: 137, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p105 = charParser{id: 105, not: false, chars: []rune{10}, ranges: [][]rune{}} - p137.items = []parser{&p105} - p3.items = []parser{&p160, &p137, &p160, &p142} - p90.items = []parser{&p142, &p3} - p185.options = []parser{&p171, &p90} - p186.options = []parser{&p185} - var p187 = sequenceParser{id: 187, commit: 66, allChars: false, name: "syntax:wsroot", ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}, generalizations: []int{}} - var p70 = sequenceParser{id: 70, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{}} - var p36 = sequenceParser{id: 36, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p140 = charParser{id: 140, not: false, chars: []rune{59}, ranges: [][]rune{}} - p36.items = []parser{&p140} - var p69 = sequenceParser{id: 69, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} - p69.items = []parser{&p186, &p36} - p70.items = []parser{&p36, &p69} - var p35 = sequenceParser{id: 35, commit: 66, allChars: false, name: "definitions", ranges: [][]int{{1, 1}, {0, 1}}, generalizations: []int{}} - var p165 = sequenceParser{id: 165, commit: 64, allChars: false, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{}} - var p95 = sequenceParser{id: 95, commit: 74, allChars: false, name: "definition-name", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} - var p42 = sequenceParser{id: 42, commit: 72, allChars: false, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{14, 128, 94}} - var p144 = sequenceParser{id: 144, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p169 = charParser{id: 169, not: true, chars: []rune{92, 32, 10, 9, 8, 12, 13, 11, 47, 46, 91, 93, 34, 123, 125, 94, 43, 42, 63, 124, 40, 41, 58, 61, 59}, ranges: [][]rune{}} - p144.items = []parser{&p169} - p42.items = []parser{&p144} - var p77 = sequenceParser{id: 77, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} - var p155 = sequenceParser{id: 155, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p147 = charParser{id: 147, not: false, chars: []rune{58}, ranges: [][]rune{}} - p155.items = []parser{&p147} - var p52 = choiceParser{id: 52, commit: 66, name: "flag", generalizations: []int{}} - var p139 = sequenceParser{id: 139, commit: 72, allChars: true, name: "alias", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{52}} - var p15 = charParser{id: 15, not: false, chars: []rune{97}, ranges: [][]rune{}} - var p99 = charParser{id: 99, not: false, chars: []rune{108}, ranges: [][]rune{}} - var p174 = charParser{id: 174, not: false, chars: []rune{105}, ranges: [][]rune{}} - var p135 = charParser{id: 135, not: false, chars: []rune{97}, ranges: [][]rune{}} - var p16 = charParser{id: 16, not: false, chars: []rune{115}, ranges: [][]rune{}} - p139.items = []parser{&p15, &p99, &p174, &p135, &p16} - var p157 = sequenceParser{id: 157, commit: 72, allChars: true, name: "ws", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{52}} - var p43 = charParser{id: 43, not: false, chars: []rune{119}, ranges: [][]rune{}} - var p39 = charParser{id: 39, not: false, chars: []rune{115}, ranges: [][]rune{}} - p157.items = []parser{&p43, &p39} - var p116 = sequenceParser{id: 116, commit: 72, allChars: true, name: "nows", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{52}} - var p22 = charParser{id: 22, not: false, chars: []rune{110}, ranges: [][]rune{}} - var p145 = charParser{id: 145, not: false, chars: []rune{111}, ranges: [][]rune{}} - var p113 = charParser{id: 113, not: false, chars: []rune{119}, ranges: [][]rune{}} - var p1 = charParser{id: 1, not: false, chars: []rune{115}, ranges: [][]rune{}} - p116.items = []parser{&p22, &p145, &p113, &p1} - var p2 = sequenceParser{id: 2, commit: 72, allChars: true, name: "failpass", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{52}} - var p23 = charParser{id: 23, not: false, chars: []rune{102}, ranges: [][]rune{}} - var p82 = charParser{id: 82, not: false, chars: []rune{97}, ranges: [][]rune{}} - var p62 = charParser{id: 62, not: false, chars: []rune{105}, ranges: [][]rune{}} - var p59 = charParser{id: 59, not: false, chars: []rune{108}, ranges: [][]rune{}} - var p44 = charParser{id: 44, not: false, chars: []rune{112}, ranges: [][]rune{}} - var p100 = charParser{id: 100, not: false, chars: []rune{97}, ranges: [][]rune{}} - var p158 = charParser{id: 158, not: false, chars: []rune{115}, ranges: [][]rune{}} - var p103 = charParser{id: 103, not: false, chars: []rune{115}, ranges: [][]rune{}} - p2.items = []parser{&p23, &p82, &p62, &p59, &p44, &p100, &p158, &p103} - var p177 = sequenceParser{id: 177, commit: 72, allChars: true, name: "root", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{52}} - var p76 = charParser{id: 76, not: false, chars: []rune{114}, ranges: [][]rune{}} - var p83 = charParser{id: 83, not: false, chars: []rune{111}, ranges: [][]rune{}} - var p78 = charParser{id: 78, not: false, chars: []rune{111}, ranges: [][]rune{}} - var p45 = charParser{id: 45, not: false, chars: []rune{116}, ranges: [][]rune{}} - p177.items = []parser{&p76, &p83, &p78, &p45} - p52.options = []parser{&p139, &p157, &p116, &p2, &p177} - p77.items = []parser{&p155, &p52} - p95.items = []parser{&p42, &p77} - var p13 = sequenceParser{id: 13, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p117 = charParser{id: 117, not: false, chars: []rune{61}, ranges: [][]rune{}} - p13.items = []parser{&p117} - var p14 = choiceParser{id: 14, commit: 66, name: "expression", generalizations: []int{}} - var p168 = choiceParser{id: 168, commit: 66, name: "terminal", generalizations: []int{14, 128, 94}} - var p91 = sequenceParser{id: 91, commit: 72, allChars: true, name: "any-char", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{168, 14, 128, 94}} - var p106 = charParser{id: 106, not: false, chars: []rune{46}, ranges: [][]rune{}} - p91.items = []parser{&p106} - var p143 = sequenceParser{id: 143, commit: 72, allChars: false, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{168, 14, 128, 94}} - var p111 = sequenceParser{id: 111, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p81 = charParser{id: 81, not: false, chars: []rune{91}, ranges: [][]rune{}} - p111.items = []parser{&p81} - var p50 = sequenceParser{id: 50, commit: 72, allChars: true, name: "class-not", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p119 = charParser{id: 119, not: false, chars: []rune{94}, ranges: [][]rune{}} - p50.items = []parser{&p119} - var p149 = choiceParser{id: 149, commit: 10, generalizations: []int{}} - var p98 = choiceParser{id: 98, commit: 72, name: "class-char", generalizations: []int{149}} - var p166 = sequenceParser{id: 166, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{98, 149}} - var p107 = charParser{id: 107, not: true, chars: []rune{92, 91, 93, 94, 45}, ranges: [][]rune{}} - p166.items = []parser{&p107} - var p110 = sequenceParser{id: 110, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{98, 149}} - var p133 = sequenceParser{id: 133, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p132 = charParser{id: 132, not: false, chars: []rune{92}, ranges: [][]rune{}} - p133.items = []parser{&p132} - var p162 = sequenceParser{id: 162, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p161 = charParser{id: 161, not: true, chars: []rune{}, ranges: [][]rune{}} - p162.items = []parser{&p161} - p110.items = []parser{&p133, &p162} - p98.options = []parser{&p166, &p110} - var p4 = sequenceParser{id: 4, commit: 72, allChars: false, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{149}} - var p167 = sequenceParser{id: 167, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p175 = charParser{id: 175, not: false, chars: []rune{45}, ranges: [][]rune{}} - p167.items = []parser{&p175} - p4.items = []parser{&p98, &p167, &p98} - p149.options = []parser{&p98, &p4} - var p5 = sequenceParser{id: 5, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p183 = charParser{id: 183, not: false, chars: []rune{93}, ranges: [][]rune{}} - p5.items = []parser{&p183} - p143.items = []parser{&p111, &p50, &p149, &p5} - var p84 = sequenceParser{id: 84, commit: 72, allChars: false, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{168, 14, 128, 94}} - var p101 = sequenceParser{id: 101, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p150 = charParser{id: 150, not: false, chars: []rune{34}, ranges: [][]rune{}} - p101.items = []parser{&p150} - var p172 = choiceParser{id: 172, commit: 72, name: "sequence-char", generalizations: []int{}} - var p67 = sequenceParser{id: 67, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{172}} - var p74 = charParser{id: 74, not: true, chars: []rune{92, 34}, ranges: [][]rune{}} - p67.items = []parser{&p74} - var p32 = sequenceParser{id: 32, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{172}} - var p108 = sequenceParser{id: 108, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p184 = charParser{id: 184, not: false, chars: []rune{92}, ranges: [][]rune{}} - p108.items = []parser{&p184} - var p10 = sequenceParser{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p68 = charParser{id: 68, not: true, chars: []rune{}, ranges: [][]rune{}} - p10.items = []parser{&p68} - p32.items = []parser{&p108, &p10} - p172.options = []parser{&p67, &p32} - var p25 = sequenceParser{id: 25, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p37 = charParser{id: 37, not: false, chars: []rune{34}, ranges: [][]rune{}} - p25.items = []parser{&p37} - p84.items = []parser{&p101, &p172, &p25} - p168.options = []parser{&p91, &p143, &p84} - var p21 = sequenceParser{id: 21, commit: 66, allChars: false, name: "group", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{14, 128, 94}} - var p154 = sequenceParser{id: 154, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p56 = charParser{id: 56, not: false, chars: []rune{40}, ranges: [][]rune{}} - p154.items = []parser{&p56} - var p120 = sequenceParser{id: 120, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p20 = charParser{id: 20, not: false, chars: []rune{41}, ranges: [][]rune{}} - p120.items = []parser{&p20} - p21.items = []parser{&p154, &p186, &p14, &p186, &p120} - var p8 = sequenceParser{id: 8, commit: 64, allChars: false, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{14, 94}} - var p115 = sequenceParser{id: 115, commit: 72, allChars: false, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}, generalizations: []int{}} - var p128 = choiceParser{id: 128, commit: 10, generalizations: []int{}} - p128.options = []parser{&p168, &p42, &p21} - var p179 = choiceParser{id: 179, commit: 66, name: "quantity", generalizations: []int{}} - var p152 = sequenceParser{id: 152, commit: 64, allChars: false, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{179}} - var p170 = sequenceParser{id: 170, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p151 = charParser{id: 151, not: false, chars: []rune{123}, ranges: [][]rune{}} - p170.items = []parser{&p151} - var p127 = sequenceParser{id: 127, commit: 64, allChars: false, name: "count", ranges: [][]int{{1, 1}}, generalizations: []int{}} - var p51 = sequenceParser{id: 51, commit: 74, allChars: false, name: "number", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{}} - var p176 = sequenceParser{id: 176, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p126 = charParser{id: 126, not: false, chars: []rune{}, ranges: [][]rune{{48, 57}}} - p176.items = []parser{&p126} - p51.items = []parser{&p176} - p127.items = []parser{&p51} - var p6 = sequenceParser{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p26 = charParser{id: 26, not: false, chars: []rune{125}, ranges: [][]rune{}} - p6.items = []parser{&p26} - p152.items = []parser{&p170, &p186, &p127, &p186, &p6} - var p92 = sequenceParser{id: 92, commit: 64, allChars: false, name: "range-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{179}} - var p85 = sequenceParser{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p75 = charParser{id: 75, not: false, chars: []rune{123}, ranges: [][]rune{}} - p85.items = []parser{&p75} - var p102 = sequenceParser{id: 102, commit: 64, allChars: false, name: "range-from", ranges: [][]int{{1, 1}}, generalizations: []int{}} - p102.items = []parser{&p51} - var p112 = sequenceParser{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p86 = charParser{id: 86, not: false, chars: []rune{44}, ranges: [][]rune{}} - p112.items = []parser{&p86} - var p138 = sequenceParser{id: 138, commit: 64, allChars: false, name: "range-to", ranges: [][]int{{1, 1}}, generalizations: []int{}} - p138.items = []parser{&p51} - var p57 = sequenceParser{id: 57, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p58 = charParser{id: 58, not: false, chars: []rune{125}, ranges: [][]rune{}} - p57.items = []parser{&p58} - p92.items = []parser{&p85, &p186, &p102, &p186, &p112, &p186, &p138, &p186, &p57} - var p38 = sequenceParser{id: 38, commit: 72, allChars: true, name: "one-or-more", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{179}} - var p163 = charParser{id: 163, not: false, chars: []rune{43}, ranges: [][]rune{}} - p38.items = []parser{&p163} - var p178 = sequenceParser{id: 178, commit: 72, allChars: true, name: "zero-or-more", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{179}} - var p93 = charParser{id: 93, not: false, chars: []rune{42}, ranges: [][]rune{}} - p178.items = []parser{&p93} - var p156 = sequenceParser{id: 156, commit: 72, allChars: true, name: "zero-or-one", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{179}} - var p146 = charParser{id: 146, not: false, chars: []rune{63}, ranges: [][]rune{}} - p156.items = []parser{&p146} - p179.options = []parser{&p152, &p92, &p38, &p178, &p156} - p115.items = []parser{&p128, &p179} - var p7 = sequenceParser{id: 7, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} - p7.items = []parser{&p186, &p115} - p8.items = []parser{&p115, &p7} - var p61 = sequenceParser{id: 61, commit: 64, allChars: false, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{14}} - var p94 = choiceParser{id: 94, commit: 66, name: "option", generalizations: []int{}} - p94.options = []parser{&p168, &p42, &p21, &p8} - var p11 = sequenceParser{id: 11, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}, generalizations: []int{}} - var p134 = sequenceParser{id: 134, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p173 = charParser{id: 173, not: false, chars: []rune{124}, ranges: [][]rune{}} - p134.items = []parser{&p173} - p11.items = []parser{&p134, &p186, &p94} - var p60 = sequenceParser{id: 60, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} - p60.items = []parser{&p186, &p11} - p61.items = []parser{&p94, &p186, &p11, &p60} - p14.options = []parser{&p168, &p42, &p21, &p8, &p61} - p165.items = []parser{&p95, &p186, &p13, &p186, &p14} - var p34 = sequenceParser{id: 34, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} - var p130 = sequenceParser{id: 130, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}, generalizations: []int{}} - var p12 = sequenceParser{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p27 = charParser{id: 27, not: false, chars: []rune{59}, ranges: [][]rune{}} - p12.items = []parser{&p27} - var p129 = sequenceParser{id: 129, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} - p129.items = []parser{&p186, &p12} - p130.items = []parser{&p12, &p129, &p186, &p165} - var p33 = sequenceParser{id: 33, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} - p33.items = []parser{&p186, &p130} - p34.items = []parser{&p186, &p130, &p33} - p35.items = []parser{&p165, &p34} - var p72 = sequenceParser{id: 72, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} - var p46 = sequenceParser{id: 46, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} - var p164 = charParser{id: 164, not: false, chars: []rune{59}, ranges: [][]rune{}} - p46.items = []parser{&p164} - var p71 = sequenceParser{id: 71, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} - p71.items = []parser{&p186, &p46} - p72.items = []parser{&p186, &p46, &p71} - p187.items = []parser{&p70, &p186, &p35, &p72} - p188.items = []parser{&p186, &p187, &p186} - var b188 = sequenceBuilder{id: 188, commit: 32, allChars: false, name: "syntax", ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var b186 = choiceBuilder{id: 186, commit: 2} - var b185 = choiceBuilder{id: 185, commit: 70} - var b171 = choiceBuilder{id: 171, commit: 66} - var b63 = sequenceBuilder{id: 63, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b28 = charBuilder{} - b63.items = []builder{&b28} - var b121 = sequenceBuilder{id: 121, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b17 = charBuilder{} - b121.items = []builder{&b17} - var b79 = sequenceBuilder{id: 79, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b53 = charBuilder{} - b79.items = []builder{&b53} - var b114 = sequenceBuilder{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b96 = charBuilder{} - b114.items = []builder{&b96} - var b141 = sequenceBuilder{id: 141, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b9 = charBuilder{} - b141.items = []builder{&b9} - var b47 = sequenceBuilder{id: 47, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b87 = charBuilder{} - b47.items = []builder{&b87} - var b40 = sequenceBuilder{id: 40, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b18 = charBuilder{} - b40.items = []builder{&b18} - b171.options = []builder{&b63, &b121, &b79, &b114, &b141, &b47, &b40} - var b90 = sequenceBuilder{id: 90, commit: 72, allChars: false, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} - var b142 = choiceBuilder{id: 142, commit: 74} - var b80 = sequenceBuilder{id: 80, commit: 74, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} - var b41 = sequenceBuilder{id: 41, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b65 = charBuilder{} - var b148 = charBuilder{} - b41.items = []builder{&b65, &b148} - var b55 = sequenceBuilder{id: 55, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b124 = charBuilder{} - b55.items = []builder{&b124} - b80.items = []builder{&b41, &b55} - var b48 = sequenceBuilder{id: 48, commit: 74, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}} - var b97 = sequenceBuilder{id: 97, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b64 = charBuilder{} - var b54 = charBuilder{} - b97.items = []builder{&b64, &b54} - var b89 = choiceBuilder{id: 89, commit: 10} - var b104 = sequenceBuilder{id: 104, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b29 = sequenceBuilder{id: 29, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b88 = charBuilder{} - b29.items = []builder{&b88} - var b122 = sequenceBuilder{id: 122, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b131 = charBuilder{} - b122.items = []builder{&b131} - b104.items = []builder{&b29, &b122} - var b159 = sequenceBuilder{id: 159, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b123 = charBuilder{} - b159.items = []builder{&b123} - b89.options = []builder{&b104, &b159} - var b19 = sequenceBuilder{id: 19, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b153 = charBuilder{} - var b24 = charBuilder{} - b19.items = []builder{&b153, &b24} - b48.items = []builder{&b97, &b89, &b19} - b142.options = []builder{&b80, &b48} - var b3 = sequenceBuilder{id: 3, commit: 10, allChars: false, ranges: [][]int{{0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}} - var b160 = choiceBuilder{id: 160, commit: 74} - var b66 = sequenceBuilder{id: 66, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b109 = charBuilder{} - b66.items = []builder{&b109} - var b180 = sequenceBuilder{id: 180, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b30 = charBuilder{} - b180.items = []builder{&b30} - var b136 = sequenceBuilder{id: 136, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b125 = charBuilder{} - b136.items = []builder{&b125} - var b118 = sequenceBuilder{id: 118, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b31 = charBuilder{} - b118.items = []builder{&b31} - var b49 = sequenceBuilder{id: 49, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b73 = charBuilder{} - b49.items = []builder{&b73} - var b182 = sequenceBuilder{id: 182, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b181 = charBuilder{} - b182.items = []builder{&b181} - b160.options = []builder{&b66, &b180, &b136, &b118, &b49, &b182} - var b137 = sequenceBuilder{id: 137, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b105 = charBuilder{} - b137.items = []builder{&b105} - b3.items = []builder{&b160, &b137, &b160, &b142} - b90.items = []builder{&b142, &b3} - b185.options = []builder{&b171, &b90} - b186.options = []builder{&b185} - var b187 = sequenceBuilder{id: 187, commit: 66, allChars: false, ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} - var b70 = sequenceBuilder{id: 70, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}}} - var b36 = sequenceBuilder{id: 36, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b140 = charBuilder{} - b36.items = []builder{&b140} - var b69 = sequenceBuilder{id: 69, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} - b69.items = []builder{&b186, &b36} - b70.items = []builder{&b36, &b69} - var b35 = sequenceBuilder{id: 35, commit: 66, allChars: false, ranges: [][]int{{1, 1}, {0, 1}}} - var b165 = sequenceBuilder{id: 165, commit: 64, allChars: false, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} - var b95 = sequenceBuilder{id: 95, commit: 74, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} - var b42 = sequenceBuilder{id: 42, commit: 72, allChars: false, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}} - var b144 = sequenceBuilder{id: 144, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b169 = charBuilder{} - b144.items = []builder{&b169} - b42.items = []builder{&b144} - var b77 = sequenceBuilder{id: 77, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b155 = sequenceBuilder{id: 155, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b147 = charBuilder{} - b155.items = []builder{&b147} - var b52 = choiceBuilder{id: 52, commit: 66} - var b139 = sequenceBuilder{id: 139, commit: 72, allChars: true, name: "alias", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b15 = charBuilder{} - var b99 = charBuilder{} - var b174 = charBuilder{} - var b135 = charBuilder{} - var b16 = charBuilder{} - b139.items = []builder{&b15, &b99, &b174, &b135, &b16} - var b157 = sequenceBuilder{id: 157, commit: 72, allChars: true, name: "ws", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b43 = charBuilder{} - var b39 = charBuilder{} - b157.items = []builder{&b43, &b39} - var b116 = sequenceBuilder{id: 116, commit: 72, allChars: true, name: "nows", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b22 = charBuilder{} - var b145 = charBuilder{} - var b113 = charBuilder{} - var b1 = charBuilder{} - b116.items = []builder{&b22, &b145, &b113, &b1} - var b2 = sequenceBuilder{id: 2, commit: 72, allChars: true, name: "failpass", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b23 = charBuilder{} - var b82 = charBuilder{} - var b62 = charBuilder{} - var b59 = charBuilder{} - var b44 = charBuilder{} - var b100 = charBuilder{} - var b158 = charBuilder{} - var b103 = charBuilder{} - b2.items = []builder{&b23, &b82, &b62, &b59, &b44, &b100, &b158, &b103} - var b177 = sequenceBuilder{id: 177, commit: 72, allChars: true, name: "root", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b76 = charBuilder{} - var b83 = charBuilder{} - var b78 = charBuilder{} - var b45 = charBuilder{} - b177.items = []builder{&b76, &b83, &b78, &b45} - b52.options = []builder{&b139, &b157, &b116, &b2, &b177} - b77.items = []builder{&b155, &b52} - b95.items = []builder{&b42, &b77} - var b13 = sequenceBuilder{id: 13, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b117 = charBuilder{} - b13.items = []builder{&b117} - var b14 = choiceBuilder{id: 14, commit: 66} - var b168 = choiceBuilder{id: 168, commit: 66} - var b91 = sequenceBuilder{id: 91, commit: 72, allChars: true, name: "any-char", ranges: [][]int{{1, 1}, {1, 1}}} - var b106 = charBuilder{} - b91.items = []builder{&b106} - var b143 = sequenceBuilder{id: 143, commit: 72, allChars: false, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}} - var b111 = sequenceBuilder{id: 111, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b81 = charBuilder{} - b111.items = []builder{&b81} - var b50 = sequenceBuilder{id: 50, commit: 72, allChars: true, name: "class-not", ranges: [][]int{{1, 1}, {1, 1}}} - var b119 = charBuilder{} - b50.items = []builder{&b119} - var b149 = choiceBuilder{id: 149, commit: 10} - var b98 = choiceBuilder{id: 98, commit: 72, name: "class-char"} - var b166 = sequenceBuilder{id: 166, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b107 = charBuilder{} - b166.items = []builder{&b107} - var b110 = sequenceBuilder{id: 110, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b133 = sequenceBuilder{id: 133, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b132 = charBuilder{} - b133.items = []builder{&b132} - var b162 = sequenceBuilder{id: 162, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b161 = charBuilder{} - b162.items = []builder{&b161} - b110.items = []builder{&b133, &b162} - b98.options = []builder{&b166, &b110} - var b4 = sequenceBuilder{id: 4, commit: 72, allChars: false, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b167 = sequenceBuilder{id: 167, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b175 = charBuilder{} - b167.items = []builder{&b175} - b4.items = []builder{&b98, &b167, &b98} - b149.options = []builder{&b98, &b4} - var b5 = sequenceBuilder{id: 5, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b183 = charBuilder{} - b5.items = []builder{&b183} - b143.items = []builder{&b111, &b50, &b149, &b5} - var b84 = sequenceBuilder{id: 84, commit: 72, allChars: false, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}} - var b101 = sequenceBuilder{id: 101, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b150 = charBuilder{} - b101.items = []builder{&b150} - var b172 = choiceBuilder{id: 172, commit: 72, name: "sequence-char"} - var b67 = sequenceBuilder{id: 67, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b74 = charBuilder{} - b67.items = []builder{&b74} - var b32 = sequenceBuilder{id: 32, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b108 = sequenceBuilder{id: 108, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b184 = charBuilder{} - b108.items = []builder{&b184} - var b10 = sequenceBuilder{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b68 = charBuilder{} - b10.items = []builder{&b68} - b32.items = []builder{&b108, &b10} - b172.options = []builder{&b67, &b32} - var b25 = sequenceBuilder{id: 25, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b37 = charBuilder{} - b25.items = []builder{&b37} - b84.items = []builder{&b101, &b172, &b25} - b168.options = []builder{&b91, &b143, &b84} - var b21 = sequenceBuilder{id: 21, commit: 66, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} - var b154 = sequenceBuilder{id: 154, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b56 = charBuilder{} - b154.items = []builder{&b56} - var b120 = sequenceBuilder{id: 120, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b20 = charBuilder{} - b120.items = []builder{&b20} - b21.items = []builder{&b154, &b186, &b14, &b186, &b120} - var b8 = sequenceBuilder{id: 8, commit: 64, allChars: false, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}} - var b115 = sequenceBuilder{id: 115, commit: 72, allChars: false, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} - var b128 = choiceBuilder{id: 128, commit: 10} - b128.options = []builder{&b168, &b42, &b21} - var b179 = choiceBuilder{id: 179, commit: 66} - var b152 = sequenceBuilder{id: 152, commit: 64, allChars: false, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} - var b170 = sequenceBuilder{id: 170, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b151 = charBuilder{} - b170.items = []builder{&b151} - var b127 = sequenceBuilder{id: 127, commit: 64, allChars: false, name: "count", ranges: [][]int{{1, 1}}} - var b51 = sequenceBuilder{id: 51, commit: 74, allChars: false, ranges: [][]int{{1, -1}, {1, -1}}} - var b176 = sequenceBuilder{id: 176, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b126 = charBuilder{} - b176.items = []builder{&b126} - b51.items = []builder{&b176} - b127.items = []builder{&b51} - var b6 = sequenceBuilder{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b26 = charBuilder{} - b6.items = []builder{&b26} - b152.items = []builder{&b170, &b186, &b127, &b186, &b6} - var b92 = sequenceBuilder{id: 92, commit: 64, allChars: false, name: "range-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}} - var b85 = sequenceBuilder{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b75 = charBuilder{} - b85.items = []builder{&b75} - var b102 = sequenceBuilder{id: 102, commit: 64, allChars: false, name: "range-from", ranges: [][]int{{1, 1}}} - b102.items = []builder{&b51} - var b112 = sequenceBuilder{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b86 = charBuilder{} - b112.items = []builder{&b86} - var b138 = sequenceBuilder{id: 138, commit: 64, allChars: false, name: "range-to", ranges: [][]int{{1, 1}}} - b138.items = []builder{&b51} - var b57 = sequenceBuilder{id: 57, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b58 = charBuilder{} - b57.items = []builder{&b58} - b92.items = []builder{&b85, &b186, &b102, &b186, &b112, &b186, &b138, &b186, &b57} - var b38 = sequenceBuilder{id: 38, commit: 72, allChars: true, name: "one-or-more", ranges: [][]int{{1, 1}, {1, 1}}} - var b163 = charBuilder{} - b38.items = []builder{&b163} - var b178 = sequenceBuilder{id: 178, commit: 72, allChars: true, name: "zero-or-more", ranges: [][]int{{1, 1}, {1, 1}}} - var b93 = charBuilder{} - b178.items = []builder{&b93} - var b156 = sequenceBuilder{id: 156, commit: 72, allChars: true, name: "zero-or-one", ranges: [][]int{{1, 1}, {1, 1}}} - var b146 = charBuilder{} - b156.items = []builder{&b146} - b179.options = []builder{&b152, &b92, &b38, &b178, &b156} - b115.items = []builder{&b128, &b179} - var b7 = sequenceBuilder{id: 7, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} - b7.items = []builder{&b186, &b115} - b8.items = []builder{&b115, &b7} - var b61 = sequenceBuilder{id: 61, commit: 64, allChars: false, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} - var b94 = choiceBuilder{id: 94, commit: 66} - b94.options = []builder{&b168, &b42, &b21, &b8} - var b11 = sequenceBuilder{id: 11, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}} - var b134 = sequenceBuilder{id: 134, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b173 = charBuilder{} - b134.items = []builder{&b173} - b11.items = []builder{&b134, &b186, &b94} - var b60 = sequenceBuilder{id: 60, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} - b60.items = []builder{&b186, &b11} - b61.items = []builder{&b94, &b186, &b11, &b60} - b14.options = []builder{&b168, &b42, &b21, &b8, &b61} - b165.items = []builder{&b95, &b186, &b13, &b186, &b14} - var b34 = sequenceBuilder{id: 34, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var b130 = sequenceBuilder{id: 130, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}} - var b12 = sequenceBuilder{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b27 = charBuilder{} - b12.items = []builder{&b27} - var b129 = sequenceBuilder{id: 129, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} - b129.items = []builder{&b186, &b12} - b130.items = []builder{&b12, &b129, &b186, &b165} - var b33 = sequenceBuilder{id: 33, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} - b33.items = []builder{&b186, &b130} - b34.items = []builder{&b186, &b130, &b33} - b35.items = []builder{&b165, &b34} - var b72 = sequenceBuilder{id: 72, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var b46 = sequenceBuilder{id: 46, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b164 = charBuilder{} - b46.items = []builder{&b164} - var b71 = sequenceBuilder{id: 71, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} - b71.items = []builder{&b186, &b46} - b72.items = []builder{&b186, &b46, &b71} - b187.items = []builder{&b70, &b186, &b35, &b72} - b188.items = []builder{&b186, &b187, &b186} - - c := newContext(bufio.NewReader(r)) - p188.parse(c) - if c.readErr != nil { - return nil, c.readErr - } - - if err := c.finalizeParse(&p188); err != nil { - if perr, ok := err.(*ParseError); ok { - perr.Input = "" - } - - return nil, err - } - - c.offset = 0 - c.results.resetPending() - - n, _ := b188.build(c) - return n[0], nil -} diff --git a/scripts/boot.go b/scripts/boot.go index d24773c..83e20d6 100644 --- a/scripts/boot.go +++ b/scripts/boot.go @@ -7,11 +7,6 @@ import ( "github.com/aryszka/treerack" ) -const ( - syntaxPath = "syntax.treerack" - outputPath = "parser.go" -) - func main() { s := &treerack.Syntax{} @@ -19,7 +14,7 @@ func main() { log.Fatalln(err) } - if err := s.Generate(os.Stdout); err != nil { + if err := s.Generate(treerack.GeneratorOptions{PackageName: "self"}, os.Stdout); err != nil { log.Fatalln(err) } } diff --git a/scripts/createhead.go b/scripts/createhead.go new file mode 100644 index 0000000..c0460c5 --- /dev/null +++ b/scripts/createhead.go @@ -0,0 +1,102 @@ +package main + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "io" + "log" + "os" + "strconv" + "strings" +) + +func concatGo(w io.Writer, r ...io.Reader) error { + var others []ast.Decl + imports := &ast.GenDecl{ + Tok: token.IMPORT, + Lparen: 1, + Rparen: 1, + } + + importPaths := make(map[string]bool) + for i := range r { + f, err := parser.ParseFile(token.NewFileSet(), "", r[i], 0) + if err != nil { + return err + } + + for j := range f.Decls { + d := f.Decls[j] + switch dd := d.(type) { + case *ast.GenDecl: + if dd.Tok != token.IMPORT { + others = append(others, d) + continue + } + + for k := range dd.Specs { + i := dd.Specs[k].(*ast.ImportSpec) + path := i.Path.Value + name := "" + if i.Name != nil { + name = i.Name.Name + } + + key := "(" + name + ")" + path + if importPaths[key] { + continue + } + + importPaths[key] = true + imports.Specs = append(imports.Specs, i) + } + default: + others = append(others, d) + } + } + } + + return printer.Fprint(w, token.NewFileSet(), &ast.File{ + Name: &ast.Ident{Name: ""}, + Decls: append([]ast.Decl{imports}, others...), + }) +} + +func removePackage(gO string) string { + // so we know that it's the first line + nl := strings.Index(gO, "\n") + return gO[nl+2:] +} + +func main() { + var packageName string + flag.StringVar(&packageName, "package", "treerack", "package name of the generated code file") + flag.Parse() + + var files []io.Reader + for _, fn := range flag.Args() { + f, err := os.Open(fn) + if err != nil { + log.Fatalln(err) + } + + defer f.Close() + files = append(files, f) + } + + var headCode bytes.Buffer + if err := concatGo(&headCode, files...); err != nil { + log.Fatalln(err) + } + + code := headCode.String() + code = removePackage(code) + quotedCode := strconv.Quote(code) + + fmt.Printf("package %s\n\n// generated with scripts/createhead.go\nconst headCode=%s", packageName, quotedCode) +} diff --git a/self/self.go b/self/self.go new file mode 100644 index 0000000..f20e804 --- /dev/null +++ b/self/self.go @@ -0,0 +1,1345 @@ +/* +This file was generated by treerack (https://github.com/aryszka/treerack). + +The contents of this file fall under different licenses. + +The code between the "// head" and "// eo head" lines falls under the same +license as the source code of treerack (https://github.com/aryszka/treerack), +unless explicitly stated otherwise, if treerack's license allows changing the +license of this source code. + +Treerack's license: MIT https://opensource.org/licenses/MIT +where YEAR=2018, COPYRIGHT HOLDER=Arpad Ryszka (arpad.ryszka@gmail.com) + +The rest of the content of this file falls under the same license as the one +that the user of treerack generating this file declares for it, or it is +unlicensed. +*/ + +package self + +import ( + "bufio" + "errors" + "fmt" + "io" + "strconv" + "strings" + "unicode" +) + +type charParser struct { + name string + id int + not bool + chars []rune + ranges [][]rune +} +type charBuilder struct { + name string + id int +} + +func (p *charParser) nodeName() string { + return p.name +} +func (p *charParser) nodeID() int { + return p.id +} +func (p *charParser) commitType() CommitType { + return Alias +} +func matchChar(chars []rune, ranges [][]rune, not bool, char rune) bool { + for _, ci := range chars { + if ci == char { + return !not + } + } + for _, ri := range ranges { + if char >= ri[0] && char <= ri[1] { + return !not + } + } + return not +} +func (p *charParser) match(t rune) bool { + return matchChar(p.chars, p.ranges, p.not, t) +} +func (p *charParser) parse(c *context) { + if tok, ok := c.token(); !ok || !p.match(tok) { + if c.offset > c.failOffset { + c.failOffset = c.offset + c.failingParser = nil + } + c.fail(c.offset) + return + } + c.success(c.offset + 1) +} +func (b *charBuilder) nodeName() string { + return b.name +} +func (b *charBuilder) nodeID() int { + return b.id +} +func (b *charBuilder) build(c *context) ([]*Node, bool) { + return nil, false +} + +type sequenceParser struct { + name string + id int + commit CommitType + items []parser + ranges [][]int + generalizations []int + allChars bool +} +type sequenceBuilder struct { + name string + id int + commit CommitType + items []builder + ranges [][]int + allChars bool +} + +func (p *sequenceParser) nodeName() string { + return p.name +} +func (p *sequenceParser) nodeID() int { + return p.id +} +func (p *sequenceParser) commitType() CommitType { + return p.commit +} +func (p *sequenceParser) parse(c *context) { + if !p.allChars { + if c.results.pending(c.offset, p.id) { + c.fail(c.offset) + return + } + c.results.markPending(c.offset, p.id) + } + var ( + currentCount int + parsed bool + ) + itemIndex := 0 + from := c.offset + to := c.offset + for itemIndex < len(p.items) { + p.items[itemIndex].parse(c) + if !c.matchLast { + if currentCount >= p.ranges[itemIndex][0] { + itemIndex++ + currentCount = 0 + continue + } + if c.failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 && p.commit&FailPass == 0 { + c.failingParser = p + } + c.fail(from) + if !p.allChars { + c.results.unmarkPending(from, p.id) + } + return + } + parsed = c.offset > to + if parsed { + currentCount++ + } + to = c.offset + if !parsed || p.ranges[itemIndex][1] > 0 && currentCount == p.ranges[itemIndex][1] { + itemIndex++ + currentCount = 0 + } + } + for _, g := range p.generalizations { + if c.results.pending(from, g) { + c.results.setMatch(from, g, to) + } + } + if to > c.failOffset { + c.failOffset = -1 + c.failingParser = nil + } + c.results.setMatch(from, p.id, to) + c.success(to) + if !p.allChars { + c.results.unmarkPending(from, p.id) + } +} +func (b *sequenceBuilder) nodeName() string { + return b.name +} +func (b *sequenceBuilder) nodeID() int { + return b.id +} +func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { + to, ok := c.results.longestMatch(c.offset, b.id) + if !ok { + return nil, false + } + from := c.offset + parsed := to > from + if b.allChars { + c.offset = to + if b.commit&Alias != 0 { + return nil, true + } + return []*Node{{Name: b.name, From: from, To: to, tokens: c.tokens}}, true + } else if parsed { + c.results.dropMatchTo(c.offset, b.id, to) + } else { + if c.results.pending(c.offset, b.id) { + return nil, false + } + c.results.markPending(c.offset, b.id) + } + var ( + itemIndex int + currentCount int + nodes []*Node + ) + for itemIndex < len(b.items) { + itemFrom := c.offset + n, ok := b.items[itemIndex].build(c) + if !ok { + itemIndex++ + currentCount = 0 + continue + } + if c.offset > itemFrom { + nodes = append(nodes, n...) + currentCount++ + if b.ranges[itemIndex][1] > 0 && currentCount == b.ranges[itemIndex][1] { + itemIndex++ + currentCount = 0 + } + continue + } + if currentCount < b.ranges[itemIndex][0] { + for i := 0; i < b.ranges[itemIndex][0]-currentCount; i++ { + nodes = append(nodes, n...) + } + } + itemIndex++ + currentCount = 0 + } + if !parsed { + c.results.unmarkPending(from, b.id) + } + if b.commit&Alias != 0 { + return nodes, true + } + return []*Node{{Name: b.name, From: from, To: to, Nodes: nodes, tokens: c.tokens}}, true +} + +type choiceParser struct { + name string + id int + commit CommitType + options []parser + generalizations []int +} +type choiceBuilder struct { + name string + id int + commit CommitType + options []builder +} + +func (p *choiceParser) nodeName() string { + return p.name +} +func (p *choiceParser) nodeID() int { + return p.id +} +func (p *choiceParser) commitType() CommitType { + return p.commit +} +func (p *choiceParser) parse(c *context) { + if c.fromResults(p) { + return + } + if c.results.pending(c.offset, p.id) { + c.fail(c.offset) + return + } + c.results.markPending(c.offset, p.id) + var ( + match bool + optionIndex int + foundMatch bool + failingParser parser + ) + from := c.offset + to := c.offset + initialFailOffset := c.failOffset + initialFailingParser := c.failingParser + failOffset := initialFailOffset + for { + foundMatch = false + optionIndex = 0 + for optionIndex < len(p.options) { + p.options[optionIndex].parse(c) + optionIndex++ + if !c.matchLast { + if c.failOffset > failOffset { + failOffset = c.failOffset + failingParser = c.failingParser + } + } + if !c.matchLast || match && c.offset <= to { + c.offset = from + continue + } + match = true + foundMatch = true + to = c.offset + c.offset = from + c.results.setMatch(from, p.id, to) + } + if !foundMatch { + break + } + } + if match { + if failOffset > to { + c.failOffset = failOffset + c.failingParser = failingParser + } else if to > initialFailOffset { + c.failOffset = -1 + c.failingParser = nil + } else { + c.failOffset = initialFailOffset + c.failingParser = initialFailingParser + } + c.success(to) + c.results.unmarkPending(from, p.id) + return + } + if failOffset > initialFailOffset { + c.failOffset = failOffset + c.failingParser = failingParser + if c.failingParser == nil && p.commitType()&userDefined != 0 && p.commitType()&Whitespace == 0 && p.commitType()&FailPass == 0 { + c.failingParser = p + } + } + c.results.setNoMatch(from, p.id) + c.fail(from) + c.results.unmarkPending(from, p.id) +} +func (b *choiceBuilder) nodeName() string { + return b.name +} +func (b *choiceBuilder) nodeID() int { + return b.id +} +func (b *choiceBuilder) build(c *context) ([]*Node, bool) { + to, ok := c.results.longestMatch(c.offset, b.id) + if !ok { + return nil, false + } + from := c.offset + parsed := to > from + if parsed { + c.results.dropMatchTo(c.offset, b.id, to) + } else { + if c.results.pending(c.offset, b.id) { + return nil, false + } + c.results.markPending(c.offset, b.id) + } + var option builder + for _, o := range b.options { + if c.results.hasMatchTo(c.offset, o.nodeID(), to) { + option = o + break + } + } + n, _ := option.build(c) + if !parsed { + c.results.unmarkPending(from, b.id) + } + if b.commit&Alias != 0 { + return n, true + } + return []*Node{{Name: b.name, From: from, To: to, Nodes: n, tokens: c.tokens}}, true +} + +type idSet struct{ ids []uint } + +func divModBits(id int) (int, int) { + return id / strconv.IntSize, id % strconv.IntSize +} +func (s *idSet) set(id int) { + d, m := divModBits(id) + if d >= len(s.ids) { + if d < cap(s.ids) { + s.ids = s.ids[:d+1] + } else { + s.ids = s.ids[:cap(s.ids)] + for i := cap(s.ids); i <= d; i++ { + s.ids = append(s.ids, 0) + } + } + } + s.ids[d] |= 1 << uint(m) +} +func (s *idSet) unset(id int) { + d, m := divModBits(id) + if d >= len(s.ids) { + return + } + s.ids[d] &^= 1 << uint(m) +} +func (s *idSet) has(id int) bool { + d, m := divModBits(id) + if d >= len(s.ids) { + return false + } + return s.ids[d]&(1< offset { + return ints + } + if cap(ints) > offset { + ints = ints[:offset+1] + return ints + } + ints = ints[:cap(ints)] + for i := len(ints); i <= offset; i++ { + ints = append(ints, nil) + } + return ints +} +func ensureOffsetIDs(ids []*idSet, offset int) []*idSet { + if len(ids) > offset { + return ids + } + if cap(ids) > offset { + ids = ids[:offset+1] + return ids + } + ids = ids[:cap(ids)] + for i := len(ids); i <= offset; i++ { + ids = append(ids, nil) + } + return ids +} +func (r *results) setMatch(offset, id, to int) { + r.match = ensureOffsetInts(r.match, offset) + for i := 0; i < len(r.match[offset]); i += 2 { + if r.match[offset][i] != id || r.match[offset][i+1] != to { + continue + } + return + } + r.match[offset] = append(r.match[offset], id, to) +} +func (r *results) setNoMatch(offset, id int) { + if len(r.match) > offset { + for i := 0; i < len(r.match[offset]); i += 2 { + if r.match[offset][i] != id { + continue + } + return + } + } + r.noMatch = ensureOffsetIDs(r.noMatch, offset) + if r.noMatch[offset] == nil { + r.noMatch[offset] = &idSet{} + } + r.noMatch[offset].set(id) +} +func (r *results) hasMatchTo(offset, id, to int) bool { + if len(r.match) <= offset { + return false + } + for i := 0; i < len(r.match[offset]); i += 2 { + if r.match[offset][i] != id { + continue + } + if r.match[offset][i+1] == to { + return true + } + } + return false +} +func (r *results) longestMatch(offset, id int) (int, bool) { + if len(r.match) <= offset { + return 0, false + } + var found bool + to := -1 + for i := 0; i < len(r.match[offset]); i += 2 { + if r.match[offset][i] != id { + continue + } + if r.match[offset][i+1] > to { + to = r.match[offset][i+1] + } + found = true + } + return to, found +} +func (r *results) longestResult(offset, id int) (int, bool, bool) { + if len(r.noMatch) > offset && r.noMatch[offset] != nil && r.noMatch[offset].has(id) { + return 0, false, true + } + to, ok := r.longestMatch(offset, id) + return to, ok, ok +} +func (r *results) dropMatchTo(offset, id, to int) { + for i := 0; i < len(r.match[offset]); i += 2 { + if r.match[offset][i] != id { + continue + } + if r.match[offset][i+1] == to { + r.match[offset][i] = -1 + return + } + } +} +func (r *results) resetPending() { + r.isPending = nil +} +func (r *results) pending(offset, id int) bool { + if len(r.isPending) <= id { + return false + } + for i := range r.isPending[id] { + if r.isPending[id][i] == offset { + return true + } + } + return false +} +func (r *results) markPending(offset, id int) { + r.isPending = ensureOffsetInts(r.isPending, id) + for i := range r.isPending[id] { + if r.isPending[id][i] == -1 { + r.isPending[id][i] = offset + return + } + } + r.isPending[id] = append(r.isPending[id], offset) +} +func (r *results) unmarkPending(offset, id int) { + for i := range r.isPending[id] { + if r.isPending[id][i] == offset { + r.isPending[id][i] = -1 + break + } + } +} + +type context struct { + reader io.RuneReader + offset int + readOffset int + consumed int + failOffset int + failingParser parser + readErr error + eof bool + results *results + tokens []rune + matchLast bool +} + +func newContext(r io.RuneReader) *context { + return &context{reader: r, results: &results{}, failOffset: -1} +} +func (c *context) read() bool { + if c.eof || c.readErr != nil { + return false + } + token, n, err := c.reader.ReadRune() + if err != nil { + if err == io.EOF { + if n == 0 { + c.eof = true + return false + } + } else { + c.readErr = err + return false + } + } + c.readOffset++ + if token == unicode.ReplacementChar { + c.readErr = ErrInvalidUnicodeCharacter + return false + } + c.tokens = append(c.tokens, token) + return true +} +func (c *context) token() (rune, bool) { + if c.offset == c.readOffset { + if !c.read() { + return 0, false + } + } + return c.tokens[c.offset], true +} +func (c *context) fromResults(p parser) bool { + to, m, ok := c.results.longestResult(c.offset, p.nodeID()) + if !ok { + return false + } + if m { + c.success(to) + } else { + c.fail(c.offset) + } + return true +} +func (c *context) success(to int) { + c.offset = to + c.matchLast = true + if to > c.consumed { + c.consumed = to + } +} +func (c *context) fail(offset int) { + c.offset = offset + c.matchLast = false +} +func findLine(tokens []rune, offset int) (line, column int) { + tokens = tokens[:offset] + for i := range tokens { + column++ + if tokens[i] == '\n' { + column = 0 + line++ + } + } + return +} +func (c *context) parseError(p parser) error { + definition := p.nodeName() + flagIndex := strings.Index(definition, ":") + if flagIndex > 0 { + definition = definition[:flagIndex] + } + if c.failingParser == nil { + c.failOffset = c.consumed + } + line, col := findLine(c.tokens, c.failOffset) + return &ParseError{Offset: c.failOffset, Line: line, Column: col, Definition: definition} +} +func (c *context) finalizeParse(root parser) error { + fp := c.failingParser + if fp == nil { + fp = root + } + to, match, found := c.results.longestResult(0, root.nodeID()) + if !found || !match || found && match && to < c.readOffset { + return c.parseError(fp) + } + c.read() + if c.eof { + return nil + } + if c.readErr != nil { + return c.readErr + } + return c.parseError(root) +} + +type Node struct { + Name string + Nodes []*Node + From, To int + tokens []rune +} + +func (n *Node) Tokens() []rune { + defer func() { + if err := recover(); err != nil { + println(len(n.tokens), n.From, n.To) + panic(err) + } + }() + return n.tokens +} +func (n *Node) String() string { + return fmt.Sprintf("%s:%d:%d:%s", n.Name, n.From, n.To, n.Text()) +} +func (n *Node) Text() string { + return string(n.Tokens()[n.From:n.To]) +} + +type CommitType int + +const ( + None CommitType = 0 + Alias CommitType = 1 << iota + Whitespace + NoWhitespace + FailPass + Root + userDefined +) + +type formatFlags int + +const ( + formatNone formatFlags = 0 + formatPretty formatFlags = 1 << iota + formatIncludeComments +) + +type ParseError struct { + Input string + Offset int + Line int + Column int + Definition string +} +type parser interface { + nodeName() string + nodeID() int + commitType() CommitType + parse(*context) +} +type builder interface { + nodeName() string + nodeID() int + build(*context) ([]*Node, bool) +} + +var ErrInvalidUnicodeCharacter = errors.New("invalid unicode character") + +func (pe *ParseError) Error() string { + return fmt.Sprintf("%s:%d:%d:parse failed, parsing: %s", pe.Input, pe.Line+1, pe.Column+1, pe.Definition) +} +func parse(r io.Reader, p parser, b builder) (*Node, error) { + c := newContext(bufio.NewReader(r)) + p.parse(c) + if c.readErr != nil { + return nil, c.readErr + } + if err := c.finalizeParse(p); err != nil { + if perr, ok := err.(*ParseError); ok { + perr.Input = "" + } + return nil, err + } + c.offset = 0 + c.results.resetPending() + n, _ := b.build(c) + return n[0], nil +} + +func Parse(r io.Reader) (*Node, error) { + var p188 = sequenceParser{id: 188, commit: 32, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} + var p186 = choiceParser{id: 186, commit: 2, generalizations: []int{}} + var p185 = choiceParser{id: 185, commit: 70, name: "wsc", generalizations: []int{186}} + var p17 = choiceParser{id: 17, commit: 66, name: "wschar", generalizations: []int{185, 186}} + var p109 = sequenceParser{id: 109, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{17, 185, 186}} + var p108 = charParser{id: 108, not: false, chars: []rune{32}, ranges: [][]rune{}} + p109.items = []parser{&p108} + var p170 = sequenceParser{id: 170, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{17, 185, 186}} + var p137 = charParser{id: 137, not: false, chars: []rune{9}, ranges: [][]rune{}} + p170.items = []parser{&p137} + var p54 = sequenceParser{id: 54, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{17, 185, 186}} + var p147 = charParser{id: 147, not: false, chars: []rune{10}, ranges: [][]rune{}} + p54.items = []parser{&p147} + var p64 = sequenceParser{id: 64, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{17, 185, 186}} + var p157 = charParser{id: 157, not: false, chars: []rune{8}, ranges: [][]rune{}} + p64.items = []parser{&p157} + var p72 = sequenceParser{id: 72, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{17, 185, 186}} + var p121 = charParser{id: 121, not: false, chars: []rune{12}, ranges: [][]rune{}} + p72.items = []parser{&p121} + var p19 = sequenceParser{id: 19, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{17, 185, 186}} + var p16 = charParser{id: 16, not: false, chars: []rune{13}, ranges: [][]rune{}} + p19.items = []parser{&p16} + var p5 = sequenceParser{id: 5, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{17, 185, 186}} + var p73 = charParser{id: 73, not: false, chars: []rune{11}, ranges: [][]rune{}} + p5.items = []parser{&p73} + p17.options = []parser{&p109, &p170, &p54, &p64, &p72, &p19, &p5} + var p58 = sequenceParser{id: 58, commit: 72, allChars: false, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{185, 186}} + var p43 = choiceParser{id: 43, commit: 74, name: "comment-segment", generalizations: []int{}} + var p144 = sequenceParser{id: 144, commit: 74, allChars: false, name: "line-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{43}} + var p138 = sequenceParser{id: 138, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} + var p42 = charParser{id: 42, not: false, chars: []rune{47}, ranges: [][]rune{}} + var p35 = charParser{id: 35, not: false, chars: []rune{47}, ranges: [][]rune{}} + p138.items = []parser{&p42, &p35} + var p30 = sequenceParser{id: 30, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p166 = charParser{id: 166, not: true, chars: []rune{10}, ranges: [][]rune{}} + p30.items = []parser{&p166} + p144.items = []parser{&p138, &p30} + var p90 = sequenceParser{id: 90, commit: 74, allChars: false, name: "block-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{43}} + var p129 = sequenceParser{id: 129, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} + var p158 = charParser{id: 158, not: false, chars: []rune{47}, ranges: [][]rune{}} + var p95 = charParser{id: 95, not: false, chars: []rune{42}, ranges: [][]rune{}} + p129.items = []parser{&p158, &p95} + var p6 = choiceParser{id: 6, commit: 10, generalizations: []int{}} + var p153 = sequenceParser{id: 153, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{6}} + var p101 = sequenceParser{id: 101, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p148 = charParser{id: 148, not: false, chars: []rune{42}, ranges: [][]rune{}} + p101.items = []parser{&p148} + var p13 = sequenceParser{id: 13, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p142 = charParser{id: 142, not: true, chars: []rune{47}, ranges: [][]rune{}} + p13.items = []parser{&p142} + p153.items = []parser{&p101, &p13} + var p143 = sequenceParser{id: 143, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{6}} + var p83 = charParser{id: 83, not: true, chars: []rune{42}, ranges: [][]rune{}} + p143.items = []parser{&p83} + p6.options = []parser{&p153, &p143} + var p89 = sequenceParser{id: 89, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} + var p96 = charParser{id: 96, not: false, chars: []rune{42}, ranges: [][]rune{}} + var p130 = charParser{id: 130, not: false, chars: []rune{47}, ranges: [][]rune{}} + p89.items = []parser{&p96, &p130} + p90.items = []parser{&p129, &p6, &p89} + p43.options = []parser{&p144, &p90} + var p31 = sequenceParser{id: 31, commit: 10, allChars: false, ranges: [][]int{{0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{}} + var p57 = choiceParser{id: 57, commit: 74, name: "ws-no-nl", generalizations: []int{}} + var p50 = sequenceParser{id: 50, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{57}} + var p167 = charParser{id: 167, not: false, chars: []rune{32}, ranges: [][]rune{}} + p50.items = []parser{&p167} + var p151 = sequenceParser{id: 151, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{57}} + var p114 = charParser{id: 114, not: false, chars: []rune{9}, ranges: [][]rune{}} + p151.items = []parser{&p114} + var p145 = sequenceParser{id: 145, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{57}} + var p36 = charParser{id: 36, not: false, chars: []rune{8}, ranges: [][]rune{}} + p145.items = []parser{&p36} + var p140 = sequenceParser{id: 140, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{57}} + var p122 = charParser{id: 122, not: false, chars: []rune{12}, ranges: [][]rune{}} + p140.items = []parser{&p122} + var p178 = sequenceParser{id: 178, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{57}} + var p77 = charParser{id: 77, not: false, chars: []rune{13}, ranges: [][]rune{}} + p178.items = []parser{&p77} + var p66 = sequenceParser{id: 66, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{57}} + var p37 = charParser{id: 37, not: false, chars: []rune{11}, ranges: [][]rune{}} + p66.items = []parser{&p37} + p57.options = []parser{&p50, &p151, &p145, &p140, &p178, &p66} + var p141 = sequenceParser{id: 141, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p51 = charParser{id: 51, not: false, chars: []rune{10}, ranges: [][]rune{}} + p141.items = []parser{&p51} + p31.items = []parser{&p57, &p141, &p57, &p43} + p58.items = []parser{&p43, &p31} + p185.options = []parser{&p17, &p58} + p186.options = []parser{&p185} + var p187 = sequenceParser{id: 187, commit: 66, allChars: false, name: "syntax:wsroot", ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}, generalizations: []int{}} + var p182 = sequenceParser{id: 182, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{}} + var p120 = sequenceParser{id: 120, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p119 = charParser{id: 119, not: false, chars: []rune{59}, ranges: [][]rune{}} + p120.items = []parser{&p119} + var p181 = sequenceParser{id: 181, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} + p181.items = []parser{&p186, &p120} + p182.items = []parser{&p120, &p181} + var p165 = sequenceParser{id: 165, commit: 66, allChars: false, name: "definitions", ranges: [][]int{{1, 1}, {0, 1}}, generalizations: []int{}} + var p46 = sequenceParser{id: 46, commit: 64, allChars: false, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{}} + var p18 = sequenceParser{id: 18, commit: 74, allChars: false, name: "definition-name", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} + var p8 = sequenceParser{id: 8, commit: 72, allChars: false, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{15, 21, 171}} + var p7 = sequenceParser{id: 7, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p154 = charParser{id: 154, not: true, chars: []rune{92, 32, 10, 9, 8, 12, 13, 11, 47, 46, 91, 93, 34, 123, 125, 94, 43, 42, 63, 124, 40, 41, 58, 61, 59}, ranges: [][]rune{}} + p7.items = []parser{&p154} + p8.items = []parser{&p7} + var p24 = sequenceParser{id: 24, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{}} + var p69 = sequenceParser{id: 69, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p162 = charParser{id: 162, not: false, chars: []rune{58}, ranges: [][]rune{}} + p69.items = []parser{&p162} + var p56 = choiceParser{id: 56, commit: 66, name: "flag", generalizations: []int{}} + var p169 = sequenceParser{id: 169, commit: 72, allChars: true, name: "alias", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{56}} + var p175 = charParser{id: 175, not: false, chars: []rune{97}, ranges: [][]rune{}} + var p68 = charParser{id: 68, not: false, chars: []rune{108}, ranges: [][]rune{}} + var p4 = charParser{id: 4, not: false, chars: []rune{105}, ranges: [][]rune{}} + var p22 = charParser{id: 22, not: false, chars: []rune{97}, ranges: [][]rune{}} + var p97 = charParser{id: 97, not: false, chars: []rune{115}, ranges: [][]rune{}} + p169.items = []parser{&p175, &p68, &p4, &p22, &p97} + var p11 = sequenceParser{id: 11, commit: 72, allChars: true, name: "ws", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{56}} + var p150 = charParser{id: 150, not: false, chars: []rune{119}, ranges: [][]rune{}} + var p45 = charParser{id: 45, not: false, chars: []rune{115}, ranges: [][]rune{}} + p11.items = []parser{&p150, &p45} + var p23 = sequenceParser{id: 23, commit: 72, allChars: true, name: "nows", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{56}} + var p136 = charParser{id: 136, not: false, chars: []rune{110}, ranges: [][]rune{}} + var p55 = charParser{id: 55, not: false, chars: []rune{111}, ranges: [][]rune{}} + var p33 = charParser{id: 33, not: false, chars: []rune{119}, ranges: [][]rune{}} + var p39 = charParser{id: 39, not: false, chars: []rune{115}, ranges: [][]rune{}} + p23.items = []parser{&p136, &p55, &p33, &p39} + var p12 = sequenceParser{id: 12, commit: 72, allChars: true, name: "failpass", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{56}} + var p81 = charParser{id: 81, not: false, chars: []rune{102}, ranges: [][]rune{}} + var p62 = charParser{id: 62, not: false, chars: []rune{97}, ranges: [][]rune{}} + var p156 = charParser{id: 156, not: false, chars: []rune{105}, ranges: [][]rune{}} + var p74 = charParser{id: 74, not: false, chars: []rune{108}, ranges: [][]rune{}} + var p118 = charParser{id: 118, not: false, chars: []rune{112}, ranges: [][]rune{}} + var p40 = charParser{id: 40, not: false, chars: []rune{97}, ranges: [][]rune{}} + var p75 = charParser{id: 75, not: false, chars: []rune{115}, ranges: [][]rune{}} + var p113 = charParser{id: 113, not: false, chars: []rune{115}, ranges: [][]rune{}} + p12.items = []parser{&p81, &p62, &p156, &p74, &p118, &p40, &p75, &p113} + var p29 = sequenceParser{id: 29, commit: 72, allChars: true, name: "root", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{56}} + var p76 = charParser{id: 76, not: false, chars: []rune{114}, ranges: [][]rune{}} + var p176 = charParser{id: 176, not: false, chars: []rune{111}, ranges: [][]rune{}} + var p107 = charParser{id: 107, not: false, chars: []rune{111}, ranges: [][]rune{}} + var p128 = charParser{id: 128, not: false, chars: []rune{116}, ranges: [][]rune{}} + p29.items = []parser{&p76, &p176, &p107, &p128} + p56.options = []parser{&p169, &p11, &p23, &p12, &p29} + p24.items = []parser{&p69, &p56} + p18.items = []parser{&p8, &p24} + var p177 = sequenceParser{id: 177, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p63 = charParser{id: 63, not: false, chars: []rune{61}, ranges: [][]rune{}} + p177.items = []parser{&p63} + var p15 = choiceParser{id: 15, commit: 66, name: "expression", generalizations: []int{}} + var p88 = choiceParser{id: 88, commit: 66, name: "terminal", generalizations: []int{15, 21, 171}} + var p179 = sequenceParser{id: 179, commit: 72, allChars: true, name: "any-char", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{88, 15, 21, 171}} + var p67 = charParser{id: 67, not: false, chars: []rune{46}, ranges: [][]rune{}} + p179.items = []parser{&p67} + var p173 = sequenceParser{id: 173, commit: 72, allChars: false, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{88, 15, 21, 171}} + var p131 = sequenceParser{id: 131, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p20 = charParser{id: 20, not: false, chars: []rune{91}, ranges: [][]rune{}} + p131.items = []parser{&p20} + var p87 = sequenceParser{id: 87, commit: 72, allChars: true, name: "class-not", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p91 = charParser{id: 91, not: false, chars: []rune{94}, ranges: [][]rune{}} + p87.items = []parser{&p91} + var p110 = choiceParser{id: 110, commit: 10, generalizations: []int{}} + var p65 = choiceParser{id: 65, commit: 72, name: "class-char", generalizations: []int{110}} + var p1 = sequenceParser{id: 1, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{65, 110}} + var p102 = charParser{id: 102, not: true, chars: []rune{92, 91, 93, 94, 45}, ranges: [][]rune{}} + p1.items = []parser{&p102} + var p38 = sequenceParser{id: 38, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{65, 110}} + var p116 = sequenceParser{id: 116, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p28 = charParser{id: 28, not: false, chars: []rune{92}, ranges: [][]rune{}} + p116.items = []parser{&p28} + var p172 = sequenceParser{id: 172, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p123 = charParser{id: 123, not: true, chars: []rune{}, ranges: [][]rune{}} + p172.items = []parser{&p123} + p38.items = []parser{&p116, &p172} + p65.options = []parser{&p1, &p38} + var p117 = sequenceParser{id: 117, commit: 72, allChars: false, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{110}} + var p159 = sequenceParser{id: 159, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p115 = charParser{id: 115, not: false, chars: []rune{45}, ranges: [][]rune{}} + p159.items = []parser{&p115} + p117.items = []parser{&p65, &p159, &p65} + p110.options = []parser{&p65, &p117} + var p103 = sequenceParser{id: 103, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p132 = charParser{id: 132, not: false, chars: []rune{93}, ranges: [][]rune{}} + p103.items = []parser{&p132} + p173.items = []parser{&p131, &p87, &p110, &p103} + var p3 = sequenceParser{id: 3, commit: 72, allChars: false, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{88, 15, 21, 171}} + var p152 = sequenceParser{id: 152, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p84 = charParser{id: 84, not: false, chars: []rune{34}, ranges: [][]rune{}} + p152.items = []parser{&p84} + var p52 = choiceParser{id: 52, commit: 72, name: "sequence-char", generalizations: []int{}} + var p32 = sequenceParser{id: 32, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{52}} + var p14 = charParser{id: 14, not: true, chars: []rune{92, 34}, ranges: [][]rune{}} + p32.items = []parser{&p14} + var p160 = sequenceParser{id: 160, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{52}} + var p2 = sequenceParser{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p124 = charParser{id: 124, not: false, chars: []rune{92}, ranges: [][]rune{}} + p2.items = []parser{&p124} + var p133 = sequenceParser{id: 133, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p47 = charParser{id: 47, not: true, chars: []rune{}, ranges: [][]rune{}} + p133.items = []parser{&p47} + p160.items = []parser{&p2, &p133} + p52.options = []parser{&p32, &p160} + var p125 = sequenceParser{id: 125, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p48 = charParser{id: 48, not: false, chars: []rune{34}, ranges: [][]rune{}} + p125.items = []parser{&p48} + p3.items = []parser{&p152, &p52, &p125} + p88.options = []parser{&p179, &p173, &p3} + var p174 = sequenceParser{id: 174, commit: 66, allChars: false, name: "group", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{15, 21, 171}} + var p85 = sequenceParser{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p149 = charParser{id: 149, not: false, chars: []rune{40}, ranges: [][]rune{}} + p85.items = []parser{&p149} + var p25 = sequenceParser{id: 25, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p79 = charParser{id: 79, not: false, chars: []rune{41}, ranges: [][]rune{}} + p25.items = []parser{&p79} + p174.items = []parser{&p85, &p186, &p15, &p186, &p25} + var p106 = sequenceParser{id: 106, commit: 64, allChars: false, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{15, 171}} + var p61 = sequenceParser{id: 61, commit: 72, allChars: false, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}, generalizations: []int{}} + var p21 = choiceParser{id: 21, commit: 10, generalizations: []int{}} + p21.options = []parser{&p88, &p8, &p174} + var p10 = choiceParser{id: 10, commit: 66, name: "quantity", generalizations: []int{}} + var p139 = sequenceParser{id: 139, commit: 64, allChars: false, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{10}} + var p27 = sequenceParser{id: 27, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p9 = charParser{id: 9, not: false, chars: []rune{123}, ranges: [][]rune{}} + p27.items = []parser{&p9} + var p86 = sequenceParser{id: 86, commit: 64, allChars: false, name: "count", ranges: [][]int{{1, 1}}, generalizations: []int{}} + var p92 = sequenceParser{id: 92, commit: 74, allChars: false, name: "number", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{}} + var p134 = sequenceParser{id: 134, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p126 = charParser{id: 126, not: false, chars: []rune{}, ranges: [][]rune{{48, 57}}} + p134.items = []parser{&p126} + p92.items = []parser{&p134} + p86.items = []parser{&p92} + var p93 = sequenceParser{id: 93, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p78 = charParser{id: 78, not: false, chars: []rune{125}, ranges: [][]rune{}} + p93.items = []parser{&p78} + p139.items = []parser{&p27, &p186, &p86, &p186, &p93} + var p146 = sequenceParser{id: 146, commit: 64, allChars: false, name: "range-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{10}} + var p44 = sequenceParser{id: 44, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p94 = charParser{id: 94, not: false, chars: []rune{123}, ranges: [][]rune{}} + p44.items = []parser{&p94} + var p127 = sequenceParser{id: 127, commit: 64, allChars: false, name: "range-from", ranges: [][]int{{1, 1}}, generalizations: []int{}} + p127.items = []parser{&p92} + var p49 = sequenceParser{id: 49, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p59 = charParser{id: 59, not: false, chars: []rune{44}, ranges: [][]rune{}} + p49.items = []parser{&p59} + var p26 = sequenceParser{id: 26, commit: 64, allChars: false, name: "range-to", ranges: [][]int{{1, 1}}, generalizations: []int{}} + p26.items = []parser{&p92} + var p135 = sequenceParser{id: 135, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p53 = charParser{id: 53, not: false, chars: []rune{125}, ranges: [][]rune{}} + p135.items = []parser{&p53} + p146.items = []parser{&p44, &p186, &p127, &p186, &p49, &p186, &p26, &p186, &p135} + var p161 = sequenceParser{id: 161, commit: 72, allChars: true, name: "one-or-more", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{10}} + var p60 = charParser{id: 60, not: false, chars: []rune{43}, ranges: [][]rune{}} + p161.items = []parser{&p60} + var p104 = sequenceParser{id: 104, commit: 72, allChars: true, name: "zero-or-more", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{10}} + var p111 = charParser{id: 111, not: false, chars: []rune{42}, ranges: [][]rune{}} + p104.items = []parser{&p111} + var p155 = sequenceParser{id: 155, commit: 72, allChars: true, name: "zero-or-one", ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{10}} + var p98 = charParser{id: 98, not: false, chars: []rune{63}, ranges: [][]rune{}} + p155.items = []parser{&p98} + p10.options = []parser{&p139, &p146, &p161, &p104, &p155} + p61.items = []parser{&p21, &p10} + var p105 = sequenceParser{id: 105, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} + p105.items = []parser{&p186, &p61} + p106.items = []parser{&p61, &p105} + var p100 = sequenceParser{id: 100, commit: 64, allChars: false, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{15}} + var p171 = choiceParser{id: 171, commit: 66, name: "option", generalizations: []int{}} + p171.options = []parser{&p88, &p8, &p174, &p106} + var p168 = sequenceParser{id: 168, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}, generalizations: []int{}} + var p80 = sequenceParser{id: 80, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p112 = charParser{id: 112, not: false, chars: []rune{124}, ranges: [][]rune{}} + p80.items = []parser{&p112} + p168.items = []parser{&p80, &p186, &p171} + var p99 = sequenceParser{id: 99, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} + p99.items = []parser{&p186, &p168} + p100.items = []parser{&p171, &p186, &p168, &p99} + p15.options = []parser{&p88, &p8, &p174, &p106, &p100} + p46.items = []parser{&p18, &p186, &p177, &p186, &p15} + var p164 = sequenceParser{id: 164, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} + var p71 = sequenceParser{id: 71, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}, generalizations: []int{}} + var p34 = sequenceParser{id: 34, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p180 = charParser{id: 180, not: false, chars: []rune{59}, ranges: [][]rune{}} + p34.items = []parser{&p180} + var p70 = sequenceParser{id: 70, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} + p70.items = []parser{&p186, &p34} + p71.items = []parser{&p34, &p70, &p186, &p46} + var p163 = sequenceParser{id: 163, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} + p163.items = []parser{&p186, &p71} + p164.items = []parser{&p186, &p71, &p163} + p165.items = []parser{&p46, &p164} + var p184 = sequenceParser{id: 184, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}, generalizations: []int{}} + var p82 = sequenceParser{id: 82, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{}} + var p41 = charParser{id: 41, not: false, chars: []rune{59}, ranges: [][]rune{}} + p82.items = []parser{&p41} + var p183 = sequenceParser{id: 183, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}, generalizations: []int{}} + p183.items = []parser{&p186, &p82} + p184.items = []parser{&p186, &p82, &p183} + p187.items = []parser{&p182, &p186, &p165, &p184} + p188.items = []parser{&p186, &p187, &p186} + var b188 = sequenceBuilder{id: 188, commit: 32, allChars: false, name: "syntax", ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var b186 = choiceBuilder{id: 186, commit: 2} + var b185 = choiceBuilder{id: 185, commit: 70} + var b17 = choiceBuilder{id: 17, commit: 66} + var b109 = sequenceBuilder{id: 109, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b108 = charBuilder{} + b109.items = []builder{&b108} + var b170 = sequenceBuilder{id: 170, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b137 = charBuilder{} + b170.items = []builder{&b137} + var b54 = sequenceBuilder{id: 54, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b147 = charBuilder{} + b54.items = []builder{&b147} + var b64 = sequenceBuilder{id: 64, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b157 = charBuilder{} + b64.items = []builder{&b157} + var b72 = sequenceBuilder{id: 72, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b121 = charBuilder{} + b72.items = []builder{&b121} + var b19 = sequenceBuilder{id: 19, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b16 = charBuilder{} + b19.items = []builder{&b16} + var b5 = sequenceBuilder{id: 5, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b73 = charBuilder{} + b5.items = []builder{&b73} + b17.options = []builder{&b109, &b170, &b54, &b64, &b72, &b19, &b5} + var b58 = sequenceBuilder{id: 58, commit: 72, allChars: false, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} + var b43 = choiceBuilder{id: 43, commit: 74} + var b144 = sequenceBuilder{id: 144, commit: 74, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} + var b138 = sequenceBuilder{id: 138, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b42 = charBuilder{} + var b35 = charBuilder{} + b138.items = []builder{&b42, &b35} + var b30 = sequenceBuilder{id: 30, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b166 = charBuilder{} + b30.items = []builder{&b166} + b144.items = []builder{&b138, &b30} + var b90 = sequenceBuilder{id: 90, commit: 74, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}} + var b129 = sequenceBuilder{id: 129, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b158 = charBuilder{} + var b95 = charBuilder{} + b129.items = []builder{&b158, &b95} + var b6 = choiceBuilder{id: 6, commit: 10} + var b153 = sequenceBuilder{id: 153, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b101 = sequenceBuilder{id: 101, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b148 = charBuilder{} + b101.items = []builder{&b148} + var b13 = sequenceBuilder{id: 13, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b142 = charBuilder{} + b13.items = []builder{&b142} + b153.items = []builder{&b101, &b13} + var b143 = sequenceBuilder{id: 143, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b83 = charBuilder{} + b143.items = []builder{&b83} + b6.options = []builder{&b153, &b143} + var b89 = sequenceBuilder{id: 89, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b96 = charBuilder{} + var b130 = charBuilder{} + b89.items = []builder{&b96, &b130} + b90.items = []builder{&b129, &b6, &b89} + b43.options = []builder{&b144, &b90} + var b31 = sequenceBuilder{id: 31, commit: 10, allChars: false, ranges: [][]int{{0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}} + var b57 = choiceBuilder{id: 57, commit: 74} + var b50 = sequenceBuilder{id: 50, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b167 = charBuilder{} + b50.items = []builder{&b167} + var b151 = sequenceBuilder{id: 151, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b114 = charBuilder{} + b151.items = []builder{&b114} + var b145 = sequenceBuilder{id: 145, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b36 = charBuilder{} + b145.items = []builder{&b36} + var b140 = sequenceBuilder{id: 140, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b122 = charBuilder{} + b140.items = []builder{&b122} + var b178 = sequenceBuilder{id: 178, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b77 = charBuilder{} + b178.items = []builder{&b77} + var b66 = sequenceBuilder{id: 66, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b37 = charBuilder{} + b66.items = []builder{&b37} + b57.options = []builder{&b50, &b151, &b145, &b140, &b178, &b66} + var b141 = sequenceBuilder{id: 141, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b51 = charBuilder{} + b141.items = []builder{&b51} + b31.items = []builder{&b57, &b141, &b57, &b43} + b58.items = []builder{&b43, &b31} + b185.options = []builder{&b17, &b58} + b186.options = []builder{&b185} + var b187 = sequenceBuilder{id: 187, commit: 66, allChars: false, ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} + var b182 = sequenceBuilder{id: 182, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}}} + var b120 = sequenceBuilder{id: 120, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b119 = charBuilder{} + b120.items = []builder{&b119} + var b181 = sequenceBuilder{id: 181, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} + b181.items = []builder{&b186, &b120} + b182.items = []builder{&b120, &b181} + var b165 = sequenceBuilder{id: 165, commit: 66, allChars: false, ranges: [][]int{{1, 1}, {0, 1}}} + var b46 = sequenceBuilder{id: 46, commit: 64, allChars: false, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} + var b18 = sequenceBuilder{id: 18, commit: 74, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} + var b8 = sequenceBuilder{id: 8, commit: 72, allChars: false, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}} + var b7 = sequenceBuilder{id: 7, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b154 = charBuilder{} + b7.items = []builder{&b154} + b8.items = []builder{&b7} + var b24 = sequenceBuilder{id: 24, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b69 = sequenceBuilder{id: 69, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b162 = charBuilder{} + b69.items = []builder{&b162} + var b56 = choiceBuilder{id: 56, commit: 66} + var b169 = sequenceBuilder{id: 169, commit: 72, allChars: true, name: "alias", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b175 = charBuilder{} + var b68 = charBuilder{} + var b4 = charBuilder{} + var b22 = charBuilder{} + var b97 = charBuilder{} + b169.items = []builder{&b175, &b68, &b4, &b22, &b97} + var b11 = sequenceBuilder{id: 11, commit: 72, allChars: true, name: "ws", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b150 = charBuilder{} + var b45 = charBuilder{} + b11.items = []builder{&b150, &b45} + var b23 = sequenceBuilder{id: 23, commit: 72, allChars: true, name: "nows", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b136 = charBuilder{} + var b55 = charBuilder{} + var b33 = charBuilder{} + var b39 = charBuilder{} + b23.items = []builder{&b136, &b55, &b33, &b39} + var b12 = sequenceBuilder{id: 12, commit: 72, allChars: true, name: "failpass", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b81 = charBuilder{} + var b62 = charBuilder{} + var b156 = charBuilder{} + var b74 = charBuilder{} + var b118 = charBuilder{} + var b40 = charBuilder{} + var b75 = charBuilder{} + var b113 = charBuilder{} + b12.items = []builder{&b81, &b62, &b156, &b74, &b118, &b40, &b75, &b113} + var b29 = sequenceBuilder{id: 29, commit: 72, allChars: true, name: "root", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b76 = charBuilder{} + var b176 = charBuilder{} + var b107 = charBuilder{} + var b128 = charBuilder{} + b29.items = []builder{&b76, &b176, &b107, &b128} + b56.options = []builder{&b169, &b11, &b23, &b12, &b29} + b24.items = []builder{&b69, &b56} + b18.items = []builder{&b8, &b24} + var b177 = sequenceBuilder{id: 177, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b63 = charBuilder{} + b177.items = []builder{&b63} + var b15 = choiceBuilder{id: 15, commit: 66} + var b88 = choiceBuilder{id: 88, commit: 66} + var b179 = sequenceBuilder{id: 179, commit: 72, allChars: true, name: "any-char", ranges: [][]int{{1, 1}, {1, 1}}} + var b67 = charBuilder{} + b179.items = []builder{&b67} + var b173 = sequenceBuilder{id: 173, commit: 72, allChars: false, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}} + var b131 = sequenceBuilder{id: 131, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b20 = charBuilder{} + b131.items = []builder{&b20} + var b87 = sequenceBuilder{id: 87, commit: 72, allChars: true, name: "class-not", ranges: [][]int{{1, 1}, {1, 1}}} + var b91 = charBuilder{} + b87.items = []builder{&b91} + var b110 = choiceBuilder{id: 110, commit: 10} + var b65 = choiceBuilder{id: 65, commit: 72, name: "class-char"} + var b1 = sequenceBuilder{id: 1, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b102 = charBuilder{} + b1.items = []builder{&b102} + var b38 = sequenceBuilder{id: 38, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b116 = sequenceBuilder{id: 116, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b28 = charBuilder{} + b116.items = []builder{&b28} + var b172 = sequenceBuilder{id: 172, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b123 = charBuilder{} + b172.items = []builder{&b123} + b38.items = []builder{&b116, &b172} + b65.options = []builder{&b1, &b38} + var b117 = sequenceBuilder{id: 117, commit: 72, allChars: false, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b159 = sequenceBuilder{id: 159, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b115 = charBuilder{} + b159.items = []builder{&b115} + b117.items = []builder{&b65, &b159, &b65} + b110.options = []builder{&b65, &b117} + var b103 = sequenceBuilder{id: 103, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b132 = charBuilder{} + b103.items = []builder{&b132} + b173.items = []builder{&b131, &b87, &b110, &b103} + var b3 = sequenceBuilder{id: 3, commit: 72, allChars: false, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}} + var b152 = sequenceBuilder{id: 152, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b84 = charBuilder{} + b152.items = []builder{&b84} + var b52 = choiceBuilder{id: 52, commit: 72, name: "sequence-char"} + var b32 = sequenceBuilder{id: 32, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b14 = charBuilder{} + b32.items = []builder{&b14} + var b160 = sequenceBuilder{id: 160, commit: 10, allChars: false, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b2 = sequenceBuilder{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b124 = charBuilder{} + b2.items = []builder{&b124} + var b133 = sequenceBuilder{id: 133, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b47 = charBuilder{} + b133.items = []builder{&b47} + b160.items = []builder{&b2, &b133} + b52.options = []builder{&b32, &b160} + var b125 = sequenceBuilder{id: 125, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b48 = charBuilder{} + b125.items = []builder{&b48} + b3.items = []builder{&b152, &b52, &b125} + b88.options = []builder{&b179, &b173, &b3} + var b174 = sequenceBuilder{id: 174, commit: 66, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} + var b85 = sequenceBuilder{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b149 = charBuilder{} + b85.items = []builder{&b149} + var b25 = sequenceBuilder{id: 25, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b79 = charBuilder{} + b25.items = []builder{&b79} + b174.items = []builder{&b85, &b186, &b15, &b186, &b25} + var b106 = sequenceBuilder{id: 106, commit: 64, allChars: false, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}} + var b61 = sequenceBuilder{id: 61, commit: 72, allChars: false, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} + var b21 = choiceBuilder{id: 21, commit: 10} + b21.options = []builder{&b88, &b8, &b174} + var b10 = choiceBuilder{id: 10, commit: 66} + var b139 = sequenceBuilder{id: 139, commit: 64, allChars: false, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} + var b27 = sequenceBuilder{id: 27, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b9 = charBuilder{} + b27.items = []builder{&b9} + var b86 = sequenceBuilder{id: 86, commit: 64, allChars: false, name: "count", ranges: [][]int{{1, 1}}} + var b92 = sequenceBuilder{id: 92, commit: 74, allChars: false, ranges: [][]int{{1, -1}, {1, -1}}} + var b134 = sequenceBuilder{id: 134, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b126 = charBuilder{} + b134.items = []builder{&b126} + b92.items = []builder{&b134} + b86.items = []builder{&b92} + var b93 = sequenceBuilder{id: 93, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b78 = charBuilder{} + b93.items = []builder{&b78} + b139.items = []builder{&b27, &b186, &b86, &b186, &b93} + var b146 = sequenceBuilder{id: 146, commit: 64, allChars: false, name: "range-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}} + var b44 = sequenceBuilder{id: 44, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b94 = charBuilder{} + b44.items = []builder{&b94} + var b127 = sequenceBuilder{id: 127, commit: 64, allChars: false, name: "range-from", ranges: [][]int{{1, 1}}} + b127.items = []builder{&b92} + var b49 = sequenceBuilder{id: 49, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b59 = charBuilder{} + b49.items = []builder{&b59} + var b26 = sequenceBuilder{id: 26, commit: 64, allChars: false, name: "range-to", ranges: [][]int{{1, 1}}} + b26.items = []builder{&b92} + var b135 = sequenceBuilder{id: 135, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b53 = charBuilder{} + b135.items = []builder{&b53} + b146.items = []builder{&b44, &b186, &b127, &b186, &b49, &b186, &b26, &b186, &b135} + var b161 = sequenceBuilder{id: 161, commit: 72, allChars: true, name: "one-or-more", ranges: [][]int{{1, 1}, {1, 1}}} + var b60 = charBuilder{} + b161.items = []builder{&b60} + var b104 = sequenceBuilder{id: 104, commit: 72, allChars: true, name: "zero-or-more", ranges: [][]int{{1, 1}, {1, 1}}} + var b111 = charBuilder{} + b104.items = []builder{&b111} + var b155 = sequenceBuilder{id: 155, commit: 72, allChars: true, name: "zero-or-one", ranges: [][]int{{1, 1}, {1, 1}}} + var b98 = charBuilder{} + b155.items = []builder{&b98} + b10.options = []builder{&b139, &b146, &b161, &b104, &b155} + b61.items = []builder{&b21, &b10} + var b105 = sequenceBuilder{id: 105, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} + b105.items = []builder{&b186, &b61} + b106.items = []builder{&b61, &b105} + var b100 = sequenceBuilder{id: 100, commit: 64, allChars: false, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} + var b171 = choiceBuilder{id: 171, commit: 66} + b171.options = []builder{&b88, &b8, &b174, &b106} + var b168 = sequenceBuilder{id: 168, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}} + var b80 = sequenceBuilder{id: 80, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b112 = charBuilder{} + b80.items = []builder{&b112} + b168.items = []builder{&b80, &b186, &b171} + var b99 = sequenceBuilder{id: 99, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} + b99.items = []builder{&b186, &b168} + b100.items = []builder{&b171, &b186, &b168, &b99} + b15.options = []builder{&b88, &b8, &b174, &b106, &b100} + b46.items = []builder{&b18, &b186, &b177, &b186, &b15} + var b164 = sequenceBuilder{id: 164, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var b71 = sequenceBuilder{id: 71, commit: 2, allChars: false, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}} + var b34 = sequenceBuilder{id: 34, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b180 = charBuilder{} + b34.items = []builder{&b180} + var b70 = sequenceBuilder{id: 70, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} + b70.items = []builder{&b186, &b34} + b71.items = []builder{&b34, &b70, &b186, &b46} + var b163 = sequenceBuilder{id: 163, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} + b163.items = []builder{&b186, &b71} + b164.items = []builder{&b186, &b71, &b163} + b165.items = []builder{&b46, &b164} + var b184 = sequenceBuilder{id: 184, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var b82 = sequenceBuilder{id: 82, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b41 = charBuilder{} + b82.items = []builder{&b41} + var b183 = sequenceBuilder{id: 183, commit: 2, allChars: false, ranges: [][]int{{0, -1}, {1, 1}}} + b183.items = []builder{&b186, &b82} + b184.items = []builder{&b186, &b82, &b183} + b187.items = []builder{&b182, &b186, &b165, &b184} + b188.items = []builder{&b186, &b187, &b186} + + return parse(r, &p188, &b188) +} diff --git a/sequence.go b/sequence.go index 0338b5e..8dd26fc 100644 --- a/sequence.go +++ b/sequence.go @@ -1,27 +1,5 @@ package treerack -import ( - "fmt" - "io" - "strconv" -) - -type sequenceDefinition struct { - name string - id int - commit CommitType - originalItems []SequenceItem - items []SequenceItem - itemDefs []definition - ranges [][]int - generalizations []int - sbuilder *sequenceBuilder - sparser *sequenceParser - allChars bool - validated bool - initialized bool -} - type sequenceParser struct { name string id int @@ -41,263 +19,6 @@ type sequenceBuilder struct { allChars bool } -func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition { - original := make([]SequenceItem, len(items)) - for i := range items { - original[i] = items[i] - } - - return &sequenceDefinition{ - name: name, - commit: ct, - items: items, - originalItems: original, - } -} - -func (d *sequenceDefinition) nodeName() string { return d.name } -func (d *sequenceDefinition) setName(n string) { d.name = n } -func (d *sequenceDefinition) nodeID() int { return d.id } -func (d *sequenceDefinition) setID(id int) { d.id = id } -func (d *sequenceDefinition) commitType() CommitType { return d.commit } -func (d *sequenceDefinition) setCommitType(ct CommitType) { d.commit = ct } - -func normalizeItemRange(item SequenceItem) SequenceItem { - if item.Min == 0 && item.Max == 0 { - item.Min, item.Max = 1, 1 - return item - } - - if item.Min <= 0 { - item.Min = 0 - } - - if item.Max <= 0 { - item.Max = -1 - } - - return item -} - -func (d *sequenceDefinition) initRanges() { - for i, item := range d.items { - item = normalizeItemRange(item) - d.items[i] = item - d.ranges = append(d.ranges, []int{item.Min, item.Max}) - } -} - -func (d *sequenceDefinition) preinit() { - d.initRanges() -} - -func (d *sequenceDefinition) validate(r *registry) error { - if d.validated { - return nil - } - - d.validated = true - for i := range d.items { - ii, ok := r.definition(d.items[i].Name) - if !ok { - return parserNotFound(d.items[i].Name) - } - - if err := ii.validate(r); err != nil { - return err - } - } - - return nil -} - -func (d *sequenceDefinition) createBuilder() { - d.sbuilder = &sequenceBuilder{ - name: d.name, - id: d.id, - commit: d.commit, - ranges: d.ranges, - } -} - -func (d *sequenceDefinition) initItems(r *registry) { - allChars := true - for _, item := range d.items { - def := r.definitions[item.Name] - d.itemDefs = append(d.itemDefs, def) - def.init(r) - d.sbuilder.items = append(d.sbuilder.items, def.builder()) - if allChars { - if _, isChar := def.(*charParser); !isChar { - allChars = false - } - } - } - - d.sbuilder.allChars = allChars - d.allChars = allChars -} - -func (d *sequenceDefinition) init(r *registry) { - if d.initialized { - return - } - - d.initialized = true - d.initRanges() - d.createBuilder() - d.initItems(r) -} - -func (d *sequenceDefinition) addGeneralization(g int) { - if intsContain(d.generalizations, g) { - return - } - - d.generalizations = append(d.generalizations, g) -} - -func (d *sequenceDefinition) createParser() { - d.sparser = &sequenceParser{ - name: d.name, - id: d.id, - commit: d.commit, - generalizations: d.generalizations, - allChars: d.allChars, - ranges: d.ranges, - } -} - -func (d *sequenceDefinition) createItemParsers() { - for _, item := range d.itemDefs { - pi := item.parser() - d.sparser.items = append(d.sparser.items, pi) - } -} - -func (d *sequenceDefinition) parser() parser { - if d.sparser != nil { - return d.sparser - } - - d.createParser() - d.createItemParsers() - return d.sparser -} - -func (d *sequenceDefinition) builder() builder { return d.sbuilder } - -func (d *sequenceDefinition) isCharSequence(r *registry) bool { - for i := range d.originalItems { - item := normalizeItemRange(d.originalItems[i]) - if item.Min != 1 || item.Max != 1 { - return false - } - - itemDef, _ := r.definition(d.originalItems[i].Name) - c, ok := itemDef.(*charParser) - if !ok || !c.isSingleChar() { - return false - } - } - - return true -} - -func (d *sequenceDefinition) format(r *registry, f formatFlags) string { - if d.isCharSequence(r) { - if len(d.originalItems) == 1 { - itemDef, _ := r.definition(d.originalItems[0].Name) - c, _ := itemDef.(*charParser) - return c.format(r, f) - } - - var chars []rune - for i := range d.originalItems { - itemDef, _ := r.definition(d.originalItems[i].Name) - c, _ := itemDef.(*charParser) - chars = append(chars, c.chars[0]) - } - - chars = escape(charClassEscape, []rune(charClassBanned), chars) - return string(append([]rune{'"'}, append(chars, '"')...)) - } - - var chars []rune - for i := range d.originalItems { - if len(chars) > 0 { - chars = append(chars, ' ') - } - - item := normalizeItemRange(d.originalItems[i]) - needsQuantifier := item.Min != 1 || item.Max != 1 - - itemDef, _ := r.definition(item.Name) - isSymbol := itemDef.commitType()&userDefined != 0 - - ch, isChoice := itemDef.(*choiceDefinition) - isChoiceOfMultiple := isChoice && len(ch.options) > 1 - - seq, isSequence := itemDef.(*sequenceDefinition) - isSequenceOfMultiple := isSequence && len(seq.originalItems) > 1 && !seq.isCharSequence(r) - - needsGrouping := isChoiceOfMultiple || isSequenceOfMultiple - - if isSymbol { - chars = append(chars, []rune(itemDef.nodeName())...) - } else { - if needsGrouping { - chars = append(chars, '(') - } - - chars = append(chars, []rune(itemDef.format(r, f))...) - - if needsGrouping { - chars = append(chars, ')') - } - } - - if !needsQuantifier { - continue - } - - if item.Min == 0 && item.Max == 1 { - chars = append(chars, '?') - continue - } - - if item.Min == 0 && item.Max < 0 { - chars = append(chars, '*') - continue - } - - if item.Min == 1 && item.Max < 0 { - chars = append(chars, '+') - continue - } - - chars = append(chars, '{') - - if item.Min == item.Max { - chars = append(chars, []rune(strconv.Itoa(item.Min))...) - } else { - if item.Min > 0 { - chars = append(chars, []rune(strconv.Itoa(item.Min))...) - } - - chars = append(chars, ',') - - if item.Max >= 0 { - chars = append(chars, []rune(strconv.Itoa(item.Max))...) - } - } - - chars = append(chars, '}') - } - - return string(chars) -} - func (p *sequenceParser) nodeName() string { return p.name } func (p *sequenceParser) nodeID() int { return p.id } func (p *sequenceParser) commitType() CommitType { return p.commit } @@ -376,57 +97,6 @@ func (p *sequenceParser) parse(c *context) { } } -func (p *sequenceParser) generate(w io.Writer, done map[string]bool) error { - if done[p.name] { - return nil - } - - done[p.name] = true - - var err error - fprintf := func(f string, args ...interface{}) { - if err != nil { - return - } - - _, err = fmt.Fprintf(w, f, args...) - } - - fprintf("var p%d = sequenceParser{", p.id) - fprintf("id: %d, commit: %d, allChars: %t,", p.id, p.commit, p.allChars) - if p.commit&userDefined != 0 { - fprintf("name: \"%s\",", p.name) - } - - fprintf("ranges: [][]int{") - for i := range p.ranges { - fprintf("{%d, %d},", p.ranges[i][0], p.ranges[i][1]) - } - - fprintf("},") - - fprintf("generalizations: []int{") - for i := range p.generalizations { - fprintf("%d,", p.generalizations[i]) - } - - fprintf("}};") - - for i := range p.items { - if err := p.items[i].generate(w, done); err != nil { - return err - } - } - - fprintf("p%d.items = []parser{", p.id) - for i := range p.items { - fprintf("&p%d,", p.items[i].nodeID()) - } - - fprintf("};") - return err -} - func (b *sequenceBuilder) nodeName() string { return b.name } func (b *sequenceBuilder) nodeID() int { return b.id } @@ -514,47 +184,3 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { tokens: c.tokens, }}, true } - -func (b *sequenceBuilder) generate(w io.Writer, done map[string]bool) error { - if done[b.name] { - return nil - } - - done[b.name] = true - - var err error - fprintf := func(f string, args ...interface{}) { - if err != nil { - return - } - - _, err = fmt.Fprintf(w, f, args...) - } - - fprintf("var b%d = sequenceBuilder{", b.id) - fprintf("id: %d, commit: %d, allChars: %t,", b.id, b.commit, b.allChars) - if b.commit&Alias == 0 { - fprintf("name: \"%s\",", b.name) - } - - fprintf("ranges: [][]int{") - for i := range b.ranges { - fprintf("{%d, %d},", b.ranges[i][0], b.ranges[i][1]) - } - - fprintf("}};") - - for i := range b.items { - if err := b.items[i].generate(w, done); err != nil { - return err - } - } - - fprintf("b%d.items = []builder{", b.id) - for i := range b.items { - fprintf("&b%d,", b.items[i].nodeID()) - } - - fprintf("};") - return err -} diff --git a/sequencedefine.go b/sequencedefine.go new file mode 100644 index 0000000..dede5e3 --- /dev/null +++ b/sequencedefine.go @@ -0,0 +1,375 @@ +package treerack + +import ( + "fmt" + "io" + "strconv" +) + +type sequenceDefinition struct { + name string + id int + commit CommitType + originalItems []SequenceItem + items []SequenceItem + itemDefs []definition + ranges [][]int + generalizations []int + sbuilder *sequenceBuilder + sparser *sequenceParser + allChars bool + validated bool + initialized bool +} + +func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition { + original := make([]SequenceItem, len(items)) + for i := range items { + original[i] = items[i] + } + + return &sequenceDefinition{ + name: name, + commit: ct, + items: items, + originalItems: original, + } +} + +func (d *sequenceDefinition) nodeName() string { return d.name } +func (d *sequenceDefinition) setName(n string) { d.name = n } +func (d *sequenceDefinition) nodeID() int { return d.id } +func (d *sequenceDefinition) setID(id int) { d.id = id } +func (d *sequenceDefinition) commitType() CommitType { return d.commit } +func (d *sequenceDefinition) setCommitType(ct CommitType) { d.commit = ct } + +func normalizeItemRange(item SequenceItem) SequenceItem { + if item.Min == 0 && item.Max == 0 { + item.Min, item.Max = 1, 1 + return item + } + + if item.Min <= 0 { + item.Min = 0 + } + + if item.Max <= 0 { + item.Max = -1 + } + + return item +} + +func (d *sequenceDefinition) initRanges() { + for i, item := range d.items { + item = normalizeItemRange(item) + d.items[i] = item + d.ranges = append(d.ranges, []int{item.Min, item.Max}) + } +} + +func (d *sequenceDefinition) preinit() { + d.initRanges() +} + +func (d *sequenceDefinition) validate(r *registry) error { + if d.validated { + return nil + } + + d.validated = true + for i := range d.items { + ii, ok := r.definition(d.items[i].Name) + if !ok { + return parserNotFound(d.items[i].Name) + } + + if err := ii.validate(r); err != nil { + return err + } + } + + return nil +} + +func (d *sequenceDefinition) createBuilder() { + d.sbuilder = &sequenceBuilder{ + name: d.name, + id: d.id, + commit: d.commit, + ranges: d.ranges, + } +} + +func (d *sequenceDefinition) initItems(r *registry) { + allChars := true + for _, item := range d.items { + def := r.definitions[item.Name] + d.itemDefs = append(d.itemDefs, def) + def.init(r) + d.sbuilder.items = append(d.sbuilder.items, def.builder()) + if allChars { + if _, isChar := def.(*charParser); !isChar { + allChars = false + } + } + } + + d.sbuilder.allChars = allChars + d.allChars = allChars +} + +func (d *sequenceDefinition) init(r *registry) { + if d.initialized { + return + } + + d.initialized = true + d.initRanges() + d.createBuilder() + d.initItems(r) +} + +func (d *sequenceDefinition) addGeneralization(g int) { + if intsContain(d.generalizations, g) { + return + } + + d.generalizations = append(d.generalizations, g) +} + +func (d *sequenceDefinition) createParser() { + d.sparser = &sequenceParser{ + name: d.name, + id: d.id, + commit: d.commit, + generalizations: d.generalizations, + allChars: d.allChars, + ranges: d.ranges, + } +} + +func (d *sequenceDefinition) createItemParsers() { + for _, item := range d.itemDefs { + pi := item.parser() + d.sparser.items = append(d.sparser.items, pi) + } +} + +func (d *sequenceDefinition) parser() parser { + if d.sparser != nil { + return d.sparser + } + + d.createParser() + d.createItemParsers() + return d.sparser +} + +func (d *sequenceDefinition) builder() builder { return d.sbuilder } + +func (d *sequenceDefinition) isCharSequence(r *registry) bool { + for i := range d.originalItems { + item := normalizeItemRange(d.originalItems[i]) + if item.Min != 1 || item.Max != 1 { + return false + } + + itemDef, _ := r.definition(d.originalItems[i].Name) + c, ok := itemDef.(*charParser) + if !ok || !c.isSingleChar() { + return false + } + } + + return true +} + +func (d *sequenceDefinition) format(r *registry, f formatFlags) string { + if d.isCharSequence(r) { + if len(d.originalItems) == 1 { + itemDef, _ := r.definition(d.originalItems[0].Name) + c, _ := itemDef.(*charParser) + return c.format(r, f) + } + + var chars []rune + for i := range d.originalItems { + itemDef, _ := r.definition(d.originalItems[i].Name) + c, _ := itemDef.(*charParser) + chars = append(chars, c.chars[0]) + } + + chars = escape(charClassEscape, []rune(charClassBanned), chars) + return string(append([]rune{'"'}, append(chars, '"')...)) + } + + var chars []rune + for i := range d.originalItems { + if len(chars) > 0 { + chars = append(chars, ' ') + } + + item := normalizeItemRange(d.originalItems[i]) + needsQuantifier := item.Min != 1 || item.Max != 1 + + itemDef, _ := r.definition(item.Name) + isSymbol := itemDef.commitType()&userDefined != 0 + + ch, isChoice := itemDef.(*choiceDefinition) + isChoiceOfMultiple := isChoice && len(ch.options) > 1 + + seq, isSequence := itemDef.(*sequenceDefinition) + isSequenceOfMultiple := isSequence && len(seq.originalItems) > 1 && !seq.isCharSequence(r) + + needsGrouping := isChoiceOfMultiple || isSequenceOfMultiple + + if isSymbol { + chars = append(chars, []rune(itemDef.nodeName())...) + } else { + if needsGrouping { + chars = append(chars, '(') + } + + chars = append(chars, []rune(itemDef.format(r, f))...) + + if needsGrouping { + chars = append(chars, ')') + } + } + + if !needsQuantifier { + continue + } + + if item.Min == 0 && item.Max == 1 { + chars = append(chars, '?') + continue + } + + if item.Min == 0 && item.Max < 0 { + chars = append(chars, '*') + continue + } + + if item.Min == 1 && item.Max < 0 { + chars = append(chars, '+') + continue + } + + chars = append(chars, '{') + + if item.Min == item.Max { + chars = append(chars, []rune(strconv.Itoa(item.Min))...) + } else { + if item.Min > 0 { + chars = append(chars, []rune(strconv.Itoa(item.Min))...) + } + + chars = append(chars, ',') + + if item.Max >= 0 { + chars = append(chars, []rune(strconv.Itoa(item.Max))...) + } + } + + chars = append(chars, '}') + } + + return string(chars) +} + +func (p *sequenceParser) generate(w io.Writer, done map[string]bool) error { + if done[p.name] { + return nil + } + + done[p.name] = true + + var err error + fprintf := func(f string, args ...interface{}) { + if err != nil { + return + } + + _, err = fmt.Fprintf(w, f, args...) + } + + fprintf("var p%d = sequenceParser{", p.id) + fprintf("id: %d, commit: %d, allChars: %t,", p.id, p.commit, p.allChars) + if p.commit&userDefined != 0 { + fprintf("name: \"%s\",", p.name) + } + + fprintf("ranges: [][]int{") + for i := range p.ranges { + fprintf("{%d, %d},", p.ranges[i][0], p.ranges[i][1]) + } + + fprintf("},") + + fprintf("generalizations: []int{") + for i := range p.generalizations { + fprintf("%d,", p.generalizations[i]) + } + + fprintf("}};") + + for i := range p.items { + if err := p.items[i].(generator).generate(w, done); err != nil { + return err + } + } + + fprintf("p%d.items = []parser{", p.id) + for i := range p.items { + fprintf("&p%d,", p.items[i].nodeID()) + } + + fprintf("};") + return err +} + +func (b *sequenceBuilder) generate(w io.Writer, done map[string]bool) error { + if done[b.name] { + return nil + } + + done[b.name] = true + + var err error + fprintf := func(f string, args ...interface{}) { + if err != nil { + return + } + + _, err = fmt.Fprintf(w, f, args...) + } + + fprintf("var b%d = sequenceBuilder{", b.id) + fprintf("id: %d, commit: %d, allChars: %t,", b.id, b.commit, b.allChars) + if b.commit&Alias == 0 { + fprintf("name: \"%s\",", b.name) + } + + fprintf("ranges: [][]int{") + for i := range b.ranges { + fprintf("{%d, %d},", b.ranges[i][0], b.ranges[i][1]) + } + + fprintf("}};") + + for i := range b.items { + if err := b.items[i].(generator).generate(w, done); err != nil { + return err + } + } + + fprintf("b%d.items = []builder{", b.id) + for i := range b.items { + fprintf("&b%d,", b.items[i].nodeID()) + } + + fprintf("};") + return err +} diff --git a/syntax.go b/syntax.go index cdf5043..21db0d0 100644 --- a/syntax.go +++ b/syntax.go @@ -1,31 +1,11 @@ package treerack import ( - "bufio" "errors" "fmt" "io" -) -type CommitType int - -const ( - None CommitType = 0 - Alias CommitType = 1 << iota - Whitespace - NoWhitespace - FailPass - Root - - userDefined -) - -type formatFlags int - -const ( - formatNone formatFlags = 0 - formatPretty formatFlags = 1 << iota - formatIncludeComments + "github.com/aryszka/treerack/self" ) // if min=0&&max=0, it means min=1,max=1 @@ -36,33 +16,6 @@ type SequenceItem struct { Min, Max int } -// ParseError is returned when the input text doesn't match -// the used syntax during parsing. -type ParseError struct { - - // Input is the name of the input file or if not - // available. - Input string - - // Offset is the index of the right-most failing - // token in the input text. - Offset int - - // Line tells the line index of the right-most failing - // token in the input text. - // - // It is zero-based, and for error reporting, it is - // recommended to increment it by one. - Line int - - // Column tells the column index of the right-most failing - // token in the input text. - Column int - - // Definition tells the right-most unmatched parser definition. - Definition string -} - type Syntax struct { registry *registry initialized bool @@ -73,6 +26,15 @@ type Syntax struct { builder builder } +type GeneratorOptions struct { + PackageName string +} + +// applied in a non-type-checked way +type generator interface { + generate(io.Writer, map[string]bool) error +} + type definition interface { nodeName() string setName(string) @@ -89,36 +51,16 @@ type definition interface { format(*registry, formatFlags) string } -type parser interface { - nodeName() string - nodeID() int - commitType() CommitType - parse(*context) - generate(io.Writer, map[string]bool) error -} - -type builder interface { - nodeName() string - nodeID() int - build(*context) ([]*Node, bool) - generate(io.Writer, map[string]bool) error -} - var ( - ErrSyntaxInitialized = errors.New("syntax initialized") - ErrInitFailed = errors.New("init failed") - ErrNoParsersDefined = errors.New("no parsers defined") - ErrInvalidInput = errors.New("invalid input") - ErrInvalidUnicodeCharacter = errors.New("invalid unicode character") - ErrInvalidEscapeCharacter = errors.New("invalid escape character") - ErrUnexpectedCharacter = errors.New("unexpected character") - ErrInvalidSyntax = errors.New("invalid syntax") - ErrRootAlias = errors.New("root node cannot be an alias") - ErrRootWhitespace = errors.New("root node cannot be a whitespace") - ErrRootFailPass = errors.New("root node cannot pass failing definition") - ErrNotImplemented = errors.New("not implemented") - ErrMultipleRoots = errors.New("multiple roots") - ErrInvalidSymbolName = errors.New("invalid symbol name") + ErrSyntaxInitialized = errors.New("syntax initialized") + ErrInitFailed = errors.New("init failed") + ErrNoParsersDefined = errors.New("no parsers defined") + ErrInvalidEscapeCharacter = errors.New("invalid escape character") + ErrRootAlias = errors.New("root node cannot be an alias") + ErrRootWhitespace = errors.New("root node cannot be a whitespace") + ErrRootFailPass = errors.New("root node cannot pass failing definition") + ErrMultipleRoots = errors.New("multiple roots") + ErrInvalidSymbolName = errors.New("invalid symbol name") ) func duplicateDefinition(name string) error { @@ -215,6 +157,10 @@ func isValidSymbol(n string) bool { } +// func (pe *ParseError) Verbose() string { +// return "" +// } + func intsContain(is []int, i int) bool { for _, ii := range is { if ii == i { @@ -225,20 +171,6 @@ func intsContain(is []int, i int) bool { return false } -func (pe *ParseError) Error() string { - return fmt.Sprintf( - "%s:%d:%d:parse failed, parsing: %s", - pe.Input, - pe.Line+1, - pe.Column+1, - pe.Definition, - ) -} - -// func (pe *ParseError) Verbose() string { -// return "" -// } - func (s *Syntax) applyRoot(d definition) error { explicitRoot := d.commitType()&Root != 0 if explicitRoot && s.explicitRoot { @@ -369,16 +301,12 @@ func (s *Syntax) ReadSyntax(r io.Reader) error { return ErrSyntaxInitialized } - b, err := bootSyntax() - if err != nil { - return err - } - - n, err := b.Parse(r) + sn, err := self.Parse(r) if err != nil { return err } + n := mapSelfNode(sn) return define(s, n) } @@ -430,59 +358,68 @@ func (s *Syntax) Init() error { return nil } -func (s *Syntax) Generate(w io.Writer) error { +func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error { if err := s.Init(); err != nil { return err } - if _, err := fmt.Fprint(w, ` -package treerack - -import ( - "bufio" - "io" -) - -func parsegen(r io.Reader) (*Node, error) { -`); err != nil { - return err + if o.PackageName == "" { + o.PackageName = "main" } + var err error + fprintf := func(f string, args ...interface{}) { + if err != nil { + return + } + + _, err = fmt.Fprintf(w, f, args...) + } + + fprint := func(args ...interface{}) { + if err != nil { + return + } + + _, err = fmt.Fprint(w, args...) + } + + fprintln := func() { + fprint("\n") + } + + fprint(gendoc) + fprintln() + fprintln() + + fprintf("package %s", o.PackageName) + fprintln() + fprintln() + + // generate headCode with scripts/createhead.go + fprint(headCode) + fprintln() + fprintln() + + fprint(`func Parse(r io.Reader) (*Node, error) {`) + fprintln() + done := make(map[string]bool) - if err := s.parser.generate(w, done); err != nil { + if err := s.parser.(generator).generate(w, done); err != nil { return err } done = make(map[string]bool) - if err := s.builder.generate(w, done); err != nil { + if err := s.builder.(generator).generate(w, done); err != nil { return err } - if _, err := fmt.Fprintf(w, ` - - c := newContext(bufio.NewReader(r)) - p%d.parse(c) - if c.readErr != nil { - return nil, c.readErr - } - - if err := c.finalizeParse(&p%d); err != nil { - if perr, ok := err.(*ParseError); ok { - perr.Input = "" - } - - return nil, err - } - - c.offset = 0 - c.results.resetPending() - - n, _ := b%d.build(c) - return n[0], nil -} - `, s.parser.nodeID(), s.parser.nodeID(), s.builder.nodeID()); err != nil { - return err - } + fprintln() + fprintln() + fprintf(`return parse(r, &p%d, &b%d)`, s.parser.nodeID(), s.builder.nodeID()) + fprintln() + fprint(`}`) + fprintln() return nil } @@ -492,23 +429,5 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) { return nil, err } - c := newContext(bufio.NewReader(r)) - s.parser.parse(c) - if c.readErr != nil { - return nil, c.readErr - } - - if err := c.finalizeParse(s.parser); err != nil { - if perr, ok := err.(*ParseError); ok { - perr.Input = "" - } - - return nil, err - } - - c.offset = 0 - c.results.resetPending() - - n, _ := s.builder.build(c) - return n[0], nil + return parse(r, s.parser, s.builder) } diff --git a/syntax_test.go b/syntax_test.go index 15a87e9..90605b8 100644 --- a/syntax_test.go +++ b/syntax_test.go @@ -376,7 +376,7 @@ func TestGenerateSyntax(t *testing.T) { return } - if err := s.Generate(bytes.NewBuffer(nil)); err == nil { + if err := s.Generate(GeneratorOptions{}, bytes.NewBuffer(nil)); err == nil { t.Error(err) } }) @@ -388,7 +388,7 @@ func TestGenerateSyntax(t *testing.T) { return } - if err := s.Generate(bytes.NewBuffer(nil)); err == nil { + if err := s.Generate(GeneratorOptions{}, bytes.NewBuffer(nil)); err == nil { t.Error(err) } }) diff --git a/syntaxhead.go b/syntaxhead.go new file mode 100644 index 0000000..c79def7 --- /dev/null +++ b/syntaxhead.go @@ -0,0 +1,103 @@ +package treerack + +import ( + "bufio" + "errors" + "fmt" + "io" +) + +type CommitType int + +const ( + None CommitType = 0 + Alias CommitType = 1 << iota + Whitespace + NoWhitespace + FailPass + Root + + userDefined +) + +type formatFlags int + +const ( + formatNone formatFlags = 0 + formatPretty formatFlags = 1 << iota + formatIncludeComments +) + +// ParseError is returned when the input text doesn't match +// the used syntax during parsing. +type ParseError struct { + + // Input is the name of the input file or if not + // available. + Input string + + // Offset is the index of the right-most failing + // token in the input text. + Offset int + + // Line tells the line index of the right-most failing + // token in the input text. + // + // It is zero-based, and for error reporting, it is + // recommended to increment it by one. + Line int + + // Column tells the column index of the right-most failing + // token in the input text. + Column int + + // Definition tells the right-most unmatched parser definition. + Definition string +} + +type parser interface { + nodeName() string + nodeID() int + commitType() CommitType + parse(*context) +} + +type builder interface { + nodeName() string + nodeID() int + build(*context) ([]*Node, bool) +} + +var ErrInvalidUnicodeCharacter = errors.New("invalid unicode character") + +func (pe *ParseError) Error() string { + return fmt.Sprintf( + "%s:%d:%d:parse failed, parsing: %s", + pe.Input, + pe.Line+1, + pe.Column+1, + pe.Definition, + ) +} + +func parse(r io.Reader, p parser, b builder) (*Node, error) { + c := newContext(bufio.NewReader(r)) + p.parse(c) + if c.readErr != nil { + return nil, c.readErr + } + + if err := c.finalizeParse(p); err != nil { + if perr, ok := err.(*ParseError); ok { + perr.Input = "" + } + + return nil, err + } + + c.offset = 0 + c.results.resetPending() + + n, _ := b.build(c) + return n[0], nil +}