From 7b2eaa5c7affe0e86c6646537aa3388a382ced2a Mon Sep 17 00:00:00 2001 From: Arpad Ryszka Date: Sat, 2 Feb 2019 18:07:10 +0100 Subject: [PATCH] add keyword commit type --- choice.go | 13 ++ context.go | 31 ++- define.go | 4 + head.go | 2 +- keyword_test.go | 23 +++ parse_test.go | 2 +- self/self.go | 502 +++++++++++++++++++++++++++--------------------- sequence.go | 16 ++ syntax.go | 120 +++++++++--- syntax.treerack | 4 +- syntax_test.go | 14 +- syntaxhead.go | 6 +- 12 files changed, 473 insertions(+), 264 deletions(-) create mode 100644 keyword_test.go diff --git a/choice.go b/choice.go index 2998e45..c50f71c 100644 --- a/choice.go +++ b/choice.go @@ -78,6 +78,19 @@ func (p *choiceParser) parse(c *context) { } if match { + if p.commit&NoKeyword != 0 && c.isKeyword(from, to) { + if c.failingParser == nil && + p.commit&userDefined != 0 && + p.commit&Whitespace == 0 && + p.commit&FailPass == 0 { + c.failingParser = p + } + + c.fail(from) + c.results.unmarkPending(from, p.id) + return + } + if failOffset > to { c.failOffset = failOffset c.failingParser = failingParser diff --git a/context.go b/context.go index 80ae302..607717c 100644 --- a/context.go +++ b/context.go @@ -8,9 +8,11 @@ import ( type context struct { reader io.RuneReader + keywords []parser offset int readOffset int consumed int + offsetLimit int failOffset int failingParser parser readErr error @@ -20,11 +22,13 @@ type context struct { matchLast bool } -func newContext(r io.RuneReader) *context { +func newContext(r io.RuneReader, keywords []parser) *context { return &context{ - reader: r, - results: &results{}, - failOffset: -1, + reader: r, + keywords: keywords, + results: &results{}, + offsetLimit: -1, + failOffset: -1, } } @@ -58,6 +62,10 @@ func (c *context) read() bool { } func (c *context) token() (rune, bool) { + if c.offset == c.offsetLimit { + return 0, false + } + if c.offset == c.readOffset { if !c.read() { return 0, false @@ -82,6 +90,21 @@ func (c *context) fromResults(p parser) bool { return true } +func (c *context) isKeyword(from, to int) bool { + ol := c.offsetLimit + c.offsetLimit = to + defer func() { c.offsetLimit = ol }() + for _, kw := range c.keywords { + c.offset = from + kw.parse(c) + if c.matchLast && c.offset == to { + return true + } + } + + return false +} + func (c *context) success(to int) { c.offset = to c.matchLast = true diff --git a/define.go b/define.go index 737c3bf..6bc8600 100644 --- a/define.go +++ b/define.go @@ -20,6 +20,10 @@ func flagsToCommitType(n []*Node) CommitType { ct |= Whitespace case "nows": ct |= NoWhitespace + case "kw": + ct |= Keyword + case "nokw": + ct |= NoKeyword case "failpass": ct |= FailPass case "root": diff --git a/head.go b/head.go index d33d511..ca6f19a 100644 --- a/head.go +++ b/head.go @@ -1,4 +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\tgeneralizations\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\tc.offset = from\n\t\t\tif c.fromResults(p) {\n\t\t\t\tif to > c.failOffset {\n\t\t\t\t\tc.failOffset = -1\n\t\t\t\t\tc.failingParser = nil\n\t\t\t\t}\n\t\t\t\tif !p.allChars {\n\t\t\t\t\tc.results.unmarkPending(from, p.id)\n\t\t\t\t}\n\t\t\t\treturn\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.dropMatchTo(c.offset, g, to)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.markPending(c.offset, g)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.unmarkPending(from, g)\n\t\t}\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\t\tstring\n\tid\t\tint\n\tcommit\t\tCommitType\n\toptions\t\t[]builder\n\tgeneralizations\t[]int\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.dropMatchTo(c.offset, g, to)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.markPending(c.offset, g)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.unmarkPending(from, g)\n\t\t}\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\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 parseInput(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" +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\tgeneralizations\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\tc.offset = from\n\t\t\tif c.fromResults(p) {\n\t\t\t\tif to > c.failOffset {\n\t\t\t\t\tc.failOffset = -1\n\t\t\t\t\tc.failingParser = nil\n\t\t\t\t}\n\t\t\t\tif !p.allChars {\n\t\t\t\t\tc.results.unmarkPending(from, p.id)\n\t\t\t\t}\n\t\t\t\treturn\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\tif p.commit&NoKeyword != 0 && c.isKeyword(from, to) {\n\t\tif c.failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 && p.commit&FailPass == 0 {\n\t\t\tc.failingParser = p\n\t\t}\n\t\tc.fail(from)\n\t\tif !p.allChars {\n\t\t\tc.results.unmarkPending(from, p.id)\n\t\t}\n\t\treturn\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.dropMatchTo(c.offset, g, to)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.markPending(c.offset, g)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.unmarkPending(from, g)\n\t\t}\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\t\tstring\n\tid\t\tint\n\tcommit\t\tCommitType\n\toptions\t\t[]builder\n\tgeneralizations\t[]int\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 p.commit&NoKeyword != 0 && c.isKeyword(from, to) {\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\tc.results.unmarkPending(from, p.id)\n\t\t\treturn\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.dropMatchTo(c.offset, g, to)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.markPending(c.offset, g)\n\t\t}\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\tfor _, g := range b.generalizations {\n\t\t\tc.results.unmarkPending(from, g)\n\t\t}\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\tkeywords\t[]parser\n\toffset\t\tint\n\treadOffset\tint\n\tconsumed\tint\n\toffsetLimit\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, keywords []parser) *context {\n\treturn &context{reader: r, keywords: keywords, results: &results{}, offsetLimit: -1, 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.offsetLimit {\n\t\treturn 0, false\n\t}\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) isKeyword(from, to int) bool {\n\tol := c.offsetLimit\n\tc.offsetLimit = to\n\tdefer func() {\n\t\tc.offsetLimit = ol\n\t}()\n\tfor _, kw := range c.keywords {\n\t\tc.offset = from\n\t\tkw.parse(c)\n\t\tif c.matchLast && c.offset == to {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\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\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\tKeyword\n\tNoKeyword\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 parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) {\n\tc := newContext(bufio.NewReader(r), kw)\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/keyword_test.go b/keyword_test.go new file mode 100644 index 0000000..c9fc243 --- /dev/null +++ b/keyword_test.go @@ -0,0 +1,23 @@ +package treerack + +import "testing" + +func TestKeyword(t *testing.T) { + const syntax = ` + keywords:kw = "foo" | "bar"; + symbol:nokw = [a-z]+; + ` + + runTests(t, syntax, []testItem{{ + title: "keyword", + text: "foo", + fail: true, + }, { + title: "not keyword", + text: "baz", + ignorePosition: true, + node: &Node{ + Name: "symbol", + }, + }}) +} diff --git a/parse_test.go b/parse_test.go index 750e394..d05e531 100644 --- a/parse_test.go +++ b/parse_test.go @@ -742,7 +742,7 @@ func TestCharBuildNoop(t *testing.T) { c := newChar("foo", false, nil, nil) c.init(newRegistry()) b := c.builder() - ctx := newContext(bufio.NewReader(bytes.NewBuffer(nil))) + ctx := newContext(bufio.NewReader(bytes.NewBuffer(nil)), nil) if n, ok := b.build(ctx); len(n) != 0 || ok { t.Error("char build not noop") } diff --git a/self/self.go b/self/self.go index cb88c8d..a1732b7 100644 --- a/self/self.go +++ b/self/self.go @@ -167,6 +167,16 @@ func (p *sequenceParser) parse(c *context) { currentCount = 0 } } + if p.commit&NoKeyword != 0 && c.isKeyword(from, to) { + 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 + } for _, g := range p.generalizations { if c.results.pending(from, g) { c.results.setMatch(from, g, to) @@ -328,6 +338,14 @@ func (p *choiceParser) parse(c *context) { } } if match { + if p.commit&NoKeyword != 0 && c.isKeyword(from, to) { + if c.failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 && p.commit&FailPass == 0 { + c.failingParser = p + } + c.fail(from) + c.results.unmarkPending(from, p.id) + return + } if failOffset > to { c.failOffset = failOffset c.failingParser = failingParser @@ -577,9 +595,11 @@ func (r *results) unmarkPending(offset, id int) { type context struct { reader io.RuneReader + keywords []parser offset int readOffset int consumed int + offsetLimit int failOffset int failingParser parser readErr error @@ -589,8 +609,8 @@ type context struct { matchLast bool } -func newContext(r io.RuneReader) *context { - return &context{reader: r, results: &results{}, failOffset: -1} +func newContext(r io.RuneReader, keywords []parser) *context { + return &context{reader: r, keywords: keywords, results: &results{}, offsetLimit: -1, failOffset: -1} } func (c *context) read() bool { if c.eof || c.readErr != nil { @@ -617,6 +637,9 @@ func (c *context) read() bool { return true } func (c *context) token() (rune, bool) { + if c.offset == c.offsetLimit { + return 0, false + } if c.offset == c.readOffset { if !c.read() { return 0, false @@ -636,6 +659,21 @@ func (c *context) fromResults(p parser) bool { } return true } +func (c *context) isKeyword(from, to int) bool { + ol := c.offsetLimit + c.offsetLimit = to + defer func() { + c.offsetLimit = ol + }() + for _, kw := range c.keywords { + c.offset = from + kw.parse(c) + if c.matchLast && c.offset == to { + return true + } + } + return false +} func (c *context) success(to int) { c.offset = to c.matchLast = true @@ -713,6 +751,8 @@ const ( Alias CommitType = 1 << iota Whitespace NoWhitespace + Keyword + NoKeyword FailPass Root userDefined @@ -750,8 +790,8 @@ 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 parseInput(r io.Reader, p parser, b builder) (*Node, error) { - c := newContext(bufio.NewReader(r)) +func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) { + c := newContext(bufio.NewReader(r), kw) p.parse(c) if c.readErr != nil { return nil, c.readErr @@ -769,35 +809,35 @@ func parseInput(r io.Reader, p parser, b builder) (*Node, error) { } func Parse(r io.Reader) (*Node, error) { - var p188 = sequenceParser{id: 188, commit: 32, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var p186 = choiceParser{id: 186, commit: 2} - var p185 = choiceParser{id: 185, commit: 70, name: "wsc", generalizations: []int{186}} - var p15 = choiceParser{id: 15, commit: 66, name: "wschar", generalizations: []int{185, 186}} - var p2 = sequenceParser{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var p196 = sequenceParser{id: 196, commit: 128, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var p194 = choiceParser{id: 194, commit: 2} + var p193 = choiceParser{id: 193, commit: 262, name: "wsc", generalizations: []int{194}} + var p15 = choiceParser{id: 15, commit: 258, name: "wschar", generalizations: []int{193, 194}} + var p2 = sequenceParser{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var p1 = charParser{id: 1, chars: []rune{32}} p2.items = []parser{&p1} - var p4 = sequenceParser{id: 4, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var p4 = sequenceParser{id: 4, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var p3 = charParser{id: 3, chars: []rune{9}} p4.items = []parser{&p3} - var p6 = sequenceParser{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var p6 = sequenceParser{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var p5 = charParser{id: 5, chars: []rune{10}} p6.items = []parser{&p5} - var p8 = sequenceParser{id: 8, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var p8 = sequenceParser{id: 8, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var p7 = charParser{id: 7, chars: []rune{8}} p8.items = []parser{&p7} - var p10 = sequenceParser{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var p10 = sequenceParser{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var p9 = charParser{id: 9, chars: []rune{12}} p10.items = []parser{&p9} - var p12 = sequenceParser{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var p12 = sequenceParser{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var p11 = charParser{id: 11, chars: []rune{13}} p12.items = []parser{&p11} - var p14 = sequenceParser{id: 14, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var p14 = sequenceParser{id: 14, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var p13 = charParser{id: 13, chars: []rune{11}} p14.items = []parser{&p13} p15.options = []parser{&p2, &p4, &p6, &p8, &p10, &p12, &p14} - var p54 = sequenceParser{id: 54, commit: 72, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{185, 186}} - var p37 = choiceParser{id: 37, commit: 74, name: "comment-segment"} - var p36 = sequenceParser{id: 36, commit: 74, name: "line-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{37}} + var p54 = sequenceParser{id: 54, commit: 264, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{193, 194}} + var p37 = choiceParser{id: 37, commit: 266, name: "comment-segment"} + var p36 = sequenceParser{id: 36, commit: 266, name: "line-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{37}} var p33 = sequenceParser{id: 33, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var p31 = charParser{id: 31, chars: []rune{47}} var p32 = charParser{id: 32, chars: []rune{47}} @@ -806,7 +846,7 @@ func Parse(r io.Reader) (*Node, error) { var p34 = charParser{id: 34, not: true, chars: []rune{10}} p35.items = []parser{&p34} p36.items = []parser{&p33, &p35} - var p30 = sequenceParser{id: 30, commit: 74, name: "block-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{37}} + var p30 = sequenceParser{id: 30, commit: 266, name: "block-comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{37}} var p18 = sequenceParser{id: 18, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var p16 = charParser{id: 16, chars: []rune{47}} var p17 = charParser{id: 17, chars: []rune{42}} @@ -831,7 +871,7 @@ func Parse(r io.Reader) (*Node, error) { p30.items = []parser{&p18, &p26, &p29} p37.options = []parser{&p36, &p30} var p53 = sequenceParser{id: 53, commit: 10, ranges: [][]int{{0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}} - var p50 = choiceParser{id: 50, commit: 74, name: "ws-no-nl"} + var p50 = choiceParser{id: 50, commit: 266, name: "ws-no-nl"} var p39 = sequenceParser{id: 39, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}} var p38 = charParser{id: 38, chars: []rune{32}} p39.items = []parser{&p38} @@ -856,82 +896,92 @@ func Parse(r io.Reader) (*Node, error) { p52.items = []parser{&p51} p53.items = []parser{&p50, &p52, &p50, &p37} p54.items = []parser{&p37, &p53} - p185.options = []parser{&p15, &p54} - p186.options = []parser{&p185} - var p187 = sequenceParser{id: 187, commit: 66, name: "syntax:wsroot", ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} - var p182 = sequenceParser{id: 182, commit: 2, ranges: [][]int{{1, 1}, {0, -1}}} - var p178 = sequenceParser{id: 178, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var p177 = charParser{id: 177, chars: []rune{59}} - p178.items = []parser{&p177} - var p181 = sequenceParser{id: 181, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - p181.items = []parser{&p186, &p178} - p182.items = []parser{&p178, &p181} - var p176 = sequenceParser{id: 176, commit: 66, name: "definitions", ranges: [][]int{{1, 1}, {0, 1}}} - var p169 = sequenceParser{id: 169, commit: 64, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} - var p166 = sequenceParser{id: 166, commit: 74, name: "definition-name", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} - var p92 = sequenceParser{id: 92, commit: 72, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{133, 123, 127}} + p193.options = []parser{&p15, &p54} + p194.options = []parser{&p193} + var p195 = sequenceParser{id: 195, commit: 258, name: "syntax:wsroot", ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} + var p190 = sequenceParser{id: 190, commit: 2, ranges: [][]int{{1, 1}, {0, -1}}} + var p186 = sequenceParser{id: 186, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var p185 = charParser{id: 185, chars: []rune{59}} + p186.items = []parser{&p185} + var p189 = sequenceParser{id: 189, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + p189.items = []parser{&p194, &p186} + p190.items = []parser{&p186, &p189} + var p184 = sequenceParser{id: 184, commit: 258, name: "definitions", ranges: [][]int{{1, 1}, {0, 1}}} + var p177 = sequenceParser{id: 177, commit: 256, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} + var p174 = sequenceParser{id: 174, commit: 266, name: "definition-name", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} + var p92 = sequenceParser{id: 92, commit: 264, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{133, 123, 127}} var p91 = sequenceParser{id: 91, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p90 = charParser{id: 90, 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}} p91.items = []parser{&p90} p92.items = []parser{&p91} - var p165 = sequenceParser{id: 165, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var p164 = sequenceParser{id: 164, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var p163 = charParser{id: 163, chars: []rune{58}} - p164.items = []parser{&p163} - var p162 = choiceParser{id: 162, commit: 66, name: "flag"} - var p139 = sequenceParser{id: 139, commit: 72, name: "alias", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} + var p173 = sequenceParser{id: 173, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var p172 = sequenceParser{id: 172, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var p171 = charParser{id: 171, chars: []rune{58}} + p172.items = []parser{&p171} + var p170 = choiceParser{id: 170, commit: 258, name: "flag"} + var p139 = sequenceParser{id: 139, commit: 264, name: "alias", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var p134 = charParser{id: 134, chars: []rune{97}} var p135 = charParser{id: 135, chars: []rune{108}} var p136 = charParser{id: 136, chars: []rune{105}} var p137 = charParser{id: 137, chars: []rune{97}} var p138 = charParser{id: 138, chars: []rune{115}} p139.items = []parser{&p134, &p135, &p136, &p137, &p138} - var p142 = sequenceParser{id: 142, commit: 72, name: "ws", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} + var p142 = sequenceParser{id: 142, commit: 264, name: "ws", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var p140 = charParser{id: 140, chars: []rune{119}} var p141 = charParser{id: 141, chars: []rune{115}} p142.items = []parser{&p140, &p141} - var p147 = sequenceParser{id: 147, commit: 72, name: "nows", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} + var p147 = sequenceParser{id: 147, commit: 264, name: "nows", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var p143 = charParser{id: 143, chars: []rune{110}} var p144 = charParser{id: 144, chars: []rune{111}} var p145 = charParser{id: 145, chars: []rune{119}} var p146 = charParser{id: 146, chars: []rune{115}} p147.items = []parser{&p143, &p144, &p145, &p146} - var p156 = sequenceParser{id: 156, commit: 72, name: "failpass", allChars: true, 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{162}} - var p148 = charParser{id: 148, chars: []rune{102}} - var p149 = charParser{id: 149, chars: []rune{97}} - var p150 = charParser{id: 150, chars: []rune{105}} - var p151 = charParser{id: 151, chars: []rune{108}} - var p152 = charParser{id: 152, chars: []rune{112}} - var p153 = charParser{id: 153, chars: []rune{97}} - var p154 = charParser{id: 154, chars: []rune{115}} - var p155 = charParser{id: 155, chars: []rune{115}} - p156.items = []parser{&p148, &p149, &p150, &p151, &p152, &p153, &p154, &p155} - var p161 = sequenceParser{id: 161, commit: 72, name: "root", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} - var p157 = charParser{id: 157, chars: []rune{114}} - var p158 = charParser{id: 158, chars: []rune{111}} - var p159 = charParser{id: 159, chars: []rune{111}} - var p160 = charParser{id: 160, chars: []rune{116}} - p161.items = []parser{&p157, &p158, &p159, &p160} - p162.options = []parser{&p139, &p142, &p147, &p156, &p161} - p165.items = []parser{&p164, &p162} - p166.items = []parser{&p92, &p165} - var p168 = sequenceParser{id: 168, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var p167 = charParser{id: 167, chars: []rune{61}} - p168.items = []parser{&p167} - var p133 = choiceParser{id: 133, commit: 66, name: "expression"} - var p89 = choiceParser{id: 89, commit: 66, name: "terminal", generalizations: []int{133, 123, 127}} - var p56 = sequenceParser{id: 56, commit: 72, name: "any-char", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} + var p150 = sequenceParser{id: 150, commit: 264, name: "kw", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} + var p148 = charParser{id: 148, chars: []rune{107}} + var p149 = charParser{id: 149, chars: []rune{119}} + p150.items = []parser{&p148, &p149} + var p155 = sequenceParser{id: 155, commit: 264, name: "nokw", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} + var p151 = charParser{id: 151, chars: []rune{110}} + var p152 = charParser{id: 152, chars: []rune{111}} + var p153 = charParser{id: 153, chars: []rune{107}} + var p154 = charParser{id: 154, chars: []rune{119}} + p155.items = []parser{&p151, &p152, &p153, &p154} + var p164 = sequenceParser{id: 164, commit: 264, name: "failpass", allChars: true, 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{170}} + var p156 = charParser{id: 156, chars: []rune{102}} + var p157 = charParser{id: 157, chars: []rune{97}} + var p158 = charParser{id: 158, chars: []rune{105}} + var p159 = charParser{id: 159, chars: []rune{108}} + var p160 = charParser{id: 160, chars: []rune{112}} + var p161 = charParser{id: 161, chars: []rune{97}} + var p162 = charParser{id: 162, chars: []rune{115}} + var p163 = charParser{id: 163, chars: []rune{115}} + p164.items = []parser{&p156, &p157, &p158, &p159, &p160, &p161, &p162, &p163} + var p169 = sequenceParser{id: 169, commit: 264, name: "root", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} + var p165 = charParser{id: 165, chars: []rune{114}} + var p166 = charParser{id: 166, chars: []rune{111}} + var p167 = charParser{id: 167, chars: []rune{111}} + var p168 = charParser{id: 168, chars: []rune{116}} + p169.items = []parser{&p165, &p166, &p167, &p168} + p170.options = []parser{&p139, &p142, &p147, &p150, &p155, &p164, &p169} + p173.items = []parser{&p172, &p170} + p174.items = []parser{&p92, &p173} + var p176 = sequenceParser{id: 176, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var p175 = charParser{id: 175, chars: []rune{61}} + p176.items = []parser{&p175} + var p133 = choiceParser{id: 133, commit: 258, name: "expression"} + var p89 = choiceParser{id: 89, commit: 258, name: "terminal", generalizations: []int{133, 123, 127}} + var p56 = sequenceParser{id: 56, commit: 264, name: "any-char", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} var p55 = charParser{id: 55, chars: []rune{46}} p56.items = []parser{&p55} - var p75 = sequenceParser{id: 75, commit: 72, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} + var p75 = sequenceParser{id: 75, commit: 264, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} var p71 = sequenceParser{id: 71, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p70 = charParser{id: 70, chars: []rune{91}} p71.items = []parser{&p70} - var p58 = sequenceParser{id: 58, commit: 72, name: "class-not", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var p58 = sequenceParser{id: 58, commit: 264, name: "class-not", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p57 = charParser{id: 57, chars: []rune{94}} p58.items = []parser{&p57} var p72 = choiceParser{id: 72, commit: 10} - var p66 = choiceParser{id: 66, commit: 72, name: "class-char", generalizations: []int{72}} + var p66 = choiceParser{id: 66, commit: 264, name: "class-char", generalizations: []int{72}} var p60 = sequenceParser{id: 60, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{66, 72}} var p59 = charParser{id: 59, not: true, chars: []rune{92, 91, 93, 94, 45}} p60.items = []parser{&p59} @@ -944,7 +994,7 @@ func Parse(r io.Reader) (*Node, error) { p64.items = []parser{&p63} p65.items = []parser{&p62, &p64} p66.options = []parser{&p60, &p65} - var p69 = sequenceParser{id: 69, commit: 72, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{72}} + var p69 = sequenceParser{id: 69, commit: 264, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{72}} var p68 = sequenceParser{id: 68, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p67 = charParser{id: 67, chars: []rune{45}} p68.items = []parser{&p67} @@ -954,11 +1004,11 @@ func Parse(r io.Reader) (*Node, error) { var p73 = charParser{id: 73, chars: []rune{93}} p74.items = []parser{&p73} p75.items = []parser{&p71, &p58, &p72, &p74} - var p88 = sequenceParser{id: 88, commit: 72, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} + var p88 = sequenceParser{id: 88, commit: 264, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} var p85 = sequenceParser{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p84 = charParser{id: 84, chars: []rune{34}} p85.items = []parser{&p84} - var p83 = choiceParser{id: 83, commit: 72, name: "sequence-char"} + var p83 = choiceParser{id: 83, commit: 264, name: "sequence-char"} var p77 = sequenceParser{id: 77, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{83}} var p76 = charParser{id: 76, not: true, chars: []rune{92, 34}} p77.items = []parser{&p76} @@ -976,25 +1026,25 @@ func Parse(r io.Reader) (*Node, error) { p87.items = []parser{&p86} p88.items = []parser{&p85, &p83, &p87} p89.options = []parser{&p56, &p75, &p88} - var p97 = sequenceParser{id: 97, commit: 66, name: "group", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{133, 123, 127}} + var p97 = sequenceParser{id: 97, commit: 258, name: "group", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{133, 123, 127}} var p94 = sequenceParser{id: 94, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p93 = charParser{id: 93, chars: []rune{40}} p94.items = []parser{&p93} var p96 = sequenceParser{id: 96, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p95 = charParser{id: 95, chars: []rune{41}} p96.items = []parser{&p95} - p97.items = []parser{&p94, &p186, &p133, &p186, &p96} - var p126 = sequenceParser{id: 126, commit: 64, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{133, 127}} - var p124 = sequenceParser{id: 124, commit: 72, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} + p97.items = []parser{&p94, &p194, &p133, &p194, &p96} + var p126 = sequenceParser{id: 126, commit: 256, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{133, 127}} + var p124 = sequenceParser{id: 124, commit: 264, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} var p123 = choiceParser{id: 123, commit: 10} p123.options = []parser{&p89, &p92, &p97} - var p122 = choiceParser{id: 122, commit: 66, name: "quantity"} - var p106 = sequenceParser{id: 106, commit: 64, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{122}} + var p122 = choiceParser{id: 122, commit: 258, name: "quantity"} + var p106 = sequenceParser{id: 106, commit: 256, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{122}} var p103 = sequenceParser{id: 103, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p102 = charParser{id: 102, chars: []rune{123}} p103.items = []parser{&p102} - var p101 = sequenceParser{id: 101, commit: 64, name: "count", ranges: [][]int{{1, 1}}} - var p100 = sequenceParser{id: 100, commit: 74, name: "number", ranges: [][]int{{1, -1}, {1, -1}}} + var p101 = sequenceParser{id: 101, commit: 256, name: "count", ranges: [][]int{{1, 1}}} + var p100 = sequenceParser{id: 100, commit: 266, name: "number", ranges: [][]int{{1, -1}, {1, -1}}} var p99 = sequenceParser{id: 99, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p98 = charParser{id: 98, ranges: [][]rune{{48, 57}}} p99.items = []parser{&p98} @@ -1003,99 +1053,99 @@ func Parse(r io.Reader) (*Node, error) { var p105 = sequenceParser{id: 105, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p104 = charParser{id: 104, chars: []rune{125}} p105.items = []parser{&p104} - p106.items = []parser{&p103, &p186, &p101, &p186, &p105} - var p115 = sequenceParser{id: 115, commit: 64, 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{122}} + p106.items = []parser{&p103, &p194, &p101, &p194, &p105} + var p115 = sequenceParser{id: 115, commit: 256, 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{122}} var p110 = sequenceParser{id: 110, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p109 = charParser{id: 109, chars: []rune{123}} p110.items = []parser{&p109} - var p107 = sequenceParser{id: 107, commit: 64, name: "range-from", ranges: [][]int{{1, 1}}} + var p107 = sequenceParser{id: 107, commit: 256, name: "range-from", ranges: [][]int{{1, 1}}} p107.items = []parser{&p100} var p112 = sequenceParser{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p111 = charParser{id: 111, chars: []rune{44}} p112.items = []parser{&p111} - var p108 = sequenceParser{id: 108, commit: 64, name: "range-to", ranges: [][]int{{1, 1}}} + var p108 = sequenceParser{id: 108, commit: 256, name: "range-to", ranges: [][]int{{1, 1}}} p108.items = []parser{&p100} var p114 = sequenceParser{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p113 = charParser{id: 113, chars: []rune{125}} p114.items = []parser{&p113} - p115.items = []parser{&p110, &p186, &p107, &p186, &p112, &p186, &p108, &p186, &p114} - var p117 = sequenceParser{id: 117, commit: 72, name: "one-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} + p115.items = []parser{&p110, &p194, &p107, &p194, &p112, &p194, &p108, &p194, &p114} + var p117 = sequenceParser{id: 117, commit: 264, name: "one-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} var p116 = charParser{id: 116, chars: []rune{43}} p117.items = []parser{&p116} - var p119 = sequenceParser{id: 119, commit: 72, name: "zero-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} + var p119 = sequenceParser{id: 119, commit: 264, name: "zero-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} var p118 = charParser{id: 118, chars: []rune{42}} p119.items = []parser{&p118} - var p121 = sequenceParser{id: 121, commit: 72, name: "zero-or-one", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} + var p121 = sequenceParser{id: 121, commit: 264, name: "zero-or-one", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} var p120 = charParser{id: 120, chars: []rune{63}} p121.items = []parser{&p120} p122.options = []parser{&p106, &p115, &p117, &p119, &p121} p124.items = []parser{&p123, &p122} var p125 = sequenceParser{id: 125, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - p125.items = []parser{&p186, &p124} + p125.items = []parser{&p194, &p124} p126.items = []parser{&p124, &p125} - var p132 = sequenceParser{id: 132, commit: 64, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{133}} - var p127 = choiceParser{id: 127, commit: 66, name: "option"} + var p132 = sequenceParser{id: 132, commit: 256, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{133}} + var p127 = choiceParser{id: 127, commit: 258, name: "option"} p127.options = []parser{&p89, &p92, &p97, &p126} var p130 = sequenceParser{id: 130, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}} var p129 = sequenceParser{id: 129, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p128 = charParser{id: 128, chars: []rune{124}} p129.items = []parser{&p128} - p130.items = []parser{&p129, &p186, &p127} + p130.items = []parser{&p129, &p194, &p127} var p131 = sequenceParser{id: 131, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - p131.items = []parser{&p186, &p130} - p132.items = []parser{&p127, &p186, &p130, &p131} + p131.items = []parser{&p194, &p130} + p132.items = []parser{&p127, &p194, &p130, &p131} p133.options = []parser{&p89, &p92, &p97, &p126, &p132} - p169.items = []parser{&p166, &p186, &p168, &p186, &p133} - var p175 = sequenceParser{id: 175, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var p173 = sequenceParser{id: 173, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}} - var p171 = sequenceParser{id: 171, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var p170 = charParser{id: 170, chars: []rune{59}} - p171.items = []parser{&p170} - var p172 = sequenceParser{id: 172, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - p172.items = []parser{&p186, &p171} - p173.items = []parser{&p171, &p172, &p186, &p169} - var p174 = sequenceParser{id: 174, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - p174.items = []parser{&p186, &p173} - p175.items = []parser{&p186, &p173, &p174} - p176.items = []parser{&p169, &p175} - var p184 = sequenceParser{id: 184, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var p180 = sequenceParser{id: 180, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var p179 = charParser{id: 179, chars: []rune{59}} - p180.items = []parser{&p179} - var p183 = sequenceParser{id: 183, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - p183.items = []parser{&p186, &p180} - p184.items = []parser{&p186, &p180, &p183} - p187.items = []parser{&p182, &p186, &p176, &p184} - p188.items = []parser{&p186, &p187, &p186} - var b188 = sequenceBuilder{id: 188, commit: 32, name: "syntax", ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var b186 = choiceBuilder{id: 186, commit: 2} - var b185 = choiceBuilder{id: 185, commit: 70, generalizations: []int{186}} - var b15 = choiceBuilder{id: 15, commit: 66, generalizations: []int{185, 186}} - var b2 = sequenceBuilder{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + p177.items = []parser{&p174, &p194, &p176, &p194, &p133} + var p183 = sequenceParser{id: 183, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var p181 = sequenceParser{id: 181, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}} + var p179 = sequenceParser{id: 179, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var p178 = charParser{id: 178, chars: []rune{59}} + p179.items = []parser{&p178} + var p180 = sequenceParser{id: 180, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + p180.items = []parser{&p194, &p179} + p181.items = []parser{&p179, &p180, &p194, &p177} + var p182 = sequenceParser{id: 182, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + p182.items = []parser{&p194, &p181} + p183.items = []parser{&p194, &p181, &p182} + p184.items = []parser{&p177, &p183} + var p192 = sequenceParser{id: 192, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var p188 = sequenceParser{id: 188, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var p187 = charParser{id: 187, chars: []rune{59}} + p188.items = []parser{&p187} + var p191 = sequenceParser{id: 191, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + p191.items = []parser{&p194, &p188} + p192.items = []parser{&p194, &p188, &p191} + p195.items = []parser{&p190, &p194, &p184, &p192} + p196.items = []parser{&p194, &p195, &p194} + var b196 = sequenceBuilder{id: 196, commit: 128, name: "syntax", ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var b194 = choiceBuilder{id: 194, commit: 2} + var b193 = choiceBuilder{id: 193, commit: 262, generalizations: []int{194}} + var b15 = choiceBuilder{id: 15, commit: 258, generalizations: []int{193, 194}} + var b2 = sequenceBuilder{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var b1 = charBuilder{} b2.items = []builder{&b1} - var b4 = sequenceBuilder{id: 4, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var b4 = sequenceBuilder{id: 4, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var b3 = charBuilder{} b4.items = []builder{&b3} - var b6 = sequenceBuilder{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var b6 = sequenceBuilder{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var b5 = charBuilder{} b6.items = []builder{&b5} - var b8 = sequenceBuilder{id: 8, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var b8 = sequenceBuilder{id: 8, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var b7 = charBuilder{} b8.items = []builder{&b7} - var b10 = sequenceBuilder{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var b10 = sequenceBuilder{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var b9 = charBuilder{} b10.items = []builder{&b9} - var b12 = sequenceBuilder{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var b12 = sequenceBuilder{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var b11 = charBuilder{} b12.items = []builder{&b11} - var b14 = sequenceBuilder{id: 14, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} + var b14 = sequenceBuilder{id: 14, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}} var b13 = charBuilder{} b14.items = []builder{&b13} b15.options = []builder{&b2, &b4, &b6, &b8, &b10, &b12, &b14} - var b54 = sequenceBuilder{id: 54, commit: 72, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{185, 186}} - var b37 = choiceBuilder{id: 37, commit: 74} - var b36 = sequenceBuilder{id: 36, commit: 74, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{37}} + var b54 = sequenceBuilder{id: 54, commit: 264, name: "comment", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{193, 194}} + var b37 = choiceBuilder{id: 37, commit: 266} + var b36 = sequenceBuilder{id: 36, commit: 266, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{37}} var b33 = sequenceBuilder{id: 33, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var b31 = charBuilder{} var b32 = charBuilder{} @@ -1104,7 +1154,7 @@ func Parse(r io.Reader) (*Node, error) { var b34 = charBuilder{} b35.items = []builder{&b34} b36.items = []builder{&b33, &b35} - var b30 = sequenceBuilder{id: 30, commit: 74, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{37}} + var b30 = sequenceBuilder{id: 30, commit: 266, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{37}} var b18 = sequenceBuilder{id: 18, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var b16 = charBuilder{} var b17 = charBuilder{} @@ -1129,7 +1179,7 @@ func Parse(r io.Reader) (*Node, error) { b30.items = []builder{&b18, &b26, &b29} b37.options = []builder{&b36, &b30} var b53 = sequenceBuilder{id: 53, commit: 10, ranges: [][]int{{0, -1}, {0, 1}, {0, -1}, {1, 1}, {0, -1}, {0, 1}, {0, -1}, {1, 1}}} - var b50 = choiceBuilder{id: 50, commit: 74} + var b50 = choiceBuilder{id: 50, commit: 266} var b39 = sequenceBuilder{id: 39, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}} var b38 = charBuilder{} b39.items = []builder{&b38} @@ -1154,82 +1204,92 @@ func Parse(r io.Reader) (*Node, error) { b52.items = []builder{&b51} b53.items = []builder{&b50, &b52, &b50, &b37} b54.items = []builder{&b37, &b53} - b185.options = []builder{&b15, &b54} - b186.options = []builder{&b185} - var b187 = sequenceBuilder{id: 187, commit: 66, ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} - var b182 = sequenceBuilder{id: 182, commit: 2, ranges: [][]int{{1, 1}, {0, -1}}} - var b178 = sequenceBuilder{id: 178, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b177 = charBuilder{} - b178.items = []builder{&b177} - var b181 = sequenceBuilder{id: 181, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - b181.items = []builder{&b186, &b178} - b182.items = []builder{&b178, &b181} - var b176 = sequenceBuilder{id: 176, commit: 66, ranges: [][]int{{1, 1}, {0, 1}}} - var b169 = sequenceBuilder{id: 169, commit: 64, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} - var b166 = sequenceBuilder{id: 166, commit: 74, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} - var b92 = sequenceBuilder{id: 92, commit: 72, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{133, 123, 127}} + b193.options = []builder{&b15, &b54} + b194.options = []builder{&b193} + var b195 = sequenceBuilder{id: 195, commit: 258, ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} + var b190 = sequenceBuilder{id: 190, commit: 2, ranges: [][]int{{1, 1}, {0, -1}}} + var b186 = sequenceBuilder{id: 186, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b185 = charBuilder{} + b186.items = []builder{&b185} + var b189 = sequenceBuilder{id: 189, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + b189.items = []builder{&b194, &b186} + b190.items = []builder{&b186, &b189} + var b184 = sequenceBuilder{id: 184, commit: 258, ranges: [][]int{{1, 1}, {0, 1}}} + var b177 = sequenceBuilder{id: 177, commit: 256, name: "definition", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} + var b174 = sequenceBuilder{id: 174, commit: 266, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} + var b92 = sequenceBuilder{id: 92, commit: 264, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{133, 123, 127}} var b91 = sequenceBuilder{id: 91, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b90 = charBuilder{} b91.items = []builder{&b90} b92.items = []builder{&b91} - var b165 = sequenceBuilder{id: 165, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} - var b164 = sequenceBuilder{id: 164, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b163 = charBuilder{} - b164.items = []builder{&b163} - var b162 = choiceBuilder{id: 162, commit: 66} - var b139 = sequenceBuilder{id: 139, commit: 72, name: "alias", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} + var b173 = sequenceBuilder{id: 173, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} + var b172 = sequenceBuilder{id: 172, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b171 = charBuilder{} + b172.items = []builder{&b171} + var b170 = choiceBuilder{id: 170, commit: 258} + var b139 = sequenceBuilder{id: 139, commit: 264, name: "alias", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var b134 = charBuilder{} var b135 = charBuilder{} var b136 = charBuilder{} var b137 = charBuilder{} var b138 = charBuilder{} b139.items = []builder{&b134, &b135, &b136, &b137, &b138} - var b142 = sequenceBuilder{id: 142, commit: 72, name: "ws", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} + var b142 = sequenceBuilder{id: 142, commit: 264, name: "ws", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var b140 = charBuilder{} var b141 = charBuilder{} b142.items = []builder{&b140, &b141} - var b147 = sequenceBuilder{id: 147, commit: 72, name: "nows", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} + var b147 = sequenceBuilder{id: 147, commit: 264, name: "nows", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var b143 = charBuilder{} var b144 = charBuilder{} var b145 = charBuilder{} var b146 = charBuilder{} b147.items = []builder{&b143, &b144, &b145, &b146} - var b156 = sequenceBuilder{id: 156, commit: 72, name: "failpass", allChars: true, 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{162}} + var b150 = sequenceBuilder{id: 150, commit: 264, name: "kw", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var b148 = charBuilder{} var b149 = charBuilder{} - var b150 = charBuilder{} + b150.items = []builder{&b148, &b149} + var b155 = sequenceBuilder{id: 155, commit: 264, name: "nokw", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} var b151 = charBuilder{} var b152 = charBuilder{} var b153 = charBuilder{} var b154 = charBuilder{} - var b155 = charBuilder{} - b156.items = []builder{&b148, &b149, &b150, &b151, &b152, &b153, &b154, &b155} - var b161 = sequenceBuilder{id: 161, commit: 72, name: "root", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{162}} + b155.items = []builder{&b151, &b152, &b153, &b154} + var b164 = sequenceBuilder{id: 164, commit: 264, name: "failpass", allChars: true, 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{170}} + var b156 = charBuilder{} var b157 = charBuilder{} var b158 = charBuilder{} var b159 = charBuilder{} var b160 = charBuilder{} - b161.items = []builder{&b157, &b158, &b159, &b160} - b162.options = []builder{&b139, &b142, &b147, &b156, &b161} - b165.items = []builder{&b164, &b162} - b166.items = []builder{&b92, &b165} - var b168 = sequenceBuilder{id: 168, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b161 = charBuilder{} + var b162 = charBuilder{} + var b163 = charBuilder{} + b164.items = []builder{&b156, &b157, &b158, &b159, &b160, &b161, &b162, &b163} + var b169 = sequenceBuilder{id: 169, commit: 264, name: "root", allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{170}} + var b165 = charBuilder{} + var b166 = charBuilder{} var b167 = charBuilder{} - b168.items = []builder{&b167} - var b133 = choiceBuilder{id: 133, commit: 66} - var b89 = choiceBuilder{id: 89, commit: 66, generalizations: []int{133, 123, 127}} - var b56 = sequenceBuilder{id: 56, commit: 72, name: "any-char", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} + var b168 = charBuilder{} + b169.items = []builder{&b165, &b166, &b167, &b168} + b170.options = []builder{&b139, &b142, &b147, &b150, &b155, &b164, &b169} + b173.items = []builder{&b172, &b170} + b174.items = []builder{&b92, &b173} + var b176 = sequenceBuilder{id: 176, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b175 = charBuilder{} + b176.items = []builder{&b175} + var b133 = choiceBuilder{id: 133, commit: 258} + var b89 = choiceBuilder{id: 89, commit: 258, generalizations: []int{133, 123, 127}} + var b56 = sequenceBuilder{id: 56, commit: 264, name: "any-char", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} var b55 = charBuilder{} b56.items = []builder{&b55} - var b75 = sequenceBuilder{id: 75, commit: 72, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} + var b75 = sequenceBuilder{id: 75, commit: 264, name: "char-class", ranges: [][]int{{1, 1}, {0, 1}, {0, -1}, {1, 1}, {1, 1}, {0, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} var b71 = sequenceBuilder{id: 71, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b70 = charBuilder{} b71.items = []builder{&b70} - var b58 = sequenceBuilder{id: 58, commit: 72, name: "class-not", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b58 = sequenceBuilder{id: 58, commit: 264, name: "class-not", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b57 = charBuilder{} b58.items = []builder{&b57} var b72 = choiceBuilder{id: 72, commit: 10} - var b66 = choiceBuilder{id: 66, commit: 72, name: "class-char", generalizations: []int{72}} + var b66 = choiceBuilder{id: 66, commit: 264, name: "class-char", generalizations: []int{72}} var b60 = sequenceBuilder{id: 60, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{66, 72}} var b59 = charBuilder{} b60.items = []builder{&b59} @@ -1242,7 +1302,7 @@ func Parse(r io.Reader) (*Node, error) { b64.items = []builder{&b63} b65.items = []builder{&b62, &b64} b66.options = []builder{&b60, &b65} - var b69 = sequenceBuilder{id: 69, commit: 72, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{72}} + var b69 = sequenceBuilder{id: 69, commit: 264, name: "char-range", ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{72}} var b68 = sequenceBuilder{id: 68, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b67 = charBuilder{} b68.items = []builder{&b67} @@ -1252,11 +1312,11 @@ func Parse(r io.Reader) (*Node, error) { var b73 = charBuilder{} b74.items = []builder{&b73} b75.items = []builder{&b71, &b58, &b72, &b74} - var b88 = sequenceBuilder{id: 88, commit: 72, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} + var b88 = sequenceBuilder{id: 88, commit: 264, name: "char-sequence", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{89, 133, 123, 127}} var b85 = sequenceBuilder{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b84 = charBuilder{} b85.items = []builder{&b84} - var b83 = choiceBuilder{id: 83, commit: 72, name: "sequence-char"} + var b83 = choiceBuilder{id: 83, commit: 264, name: "sequence-char"} var b77 = sequenceBuilder{id: 77, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{83}} var b76 = charBuilder{} b77.items = []builder{&b76} @@ -1274,25 +1334,25 @@ func Parse(r io.Reader) (*Node, error) { b87.items = []builder{&b86} b88.items = []builder{&b85, &b83, &b87} b89.options = []builder{&b56, &b75, &b88} - var b97 = sequenceBuilder{id: 97, commit: 66, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{133, 123, 127}} + var b97 = sequenceBuilder{id: 97, commit: 258, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{133, 123, 127}} var b94 = sequenceBuilder{id: 94, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b93 = charBuilder{} b94.items = []builder{&b93} var b96 = sequenceBuilder{id: 96, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b95 = charBuilder{} b96.items = []builder{&b95} - b97.items = []builder{&b94, &b186, &b133, &b186, &b96} - var b126 = sequenceBuilder{id: 126, commit: 64, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{133, 127}} - var b124 = sequenceBuilder{id: 124, commit: 72, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} + b97.items = []builder{&b94, &b194, &b133, &b194, &b96} + var b126 = sequenceBuilder{id: 126, commit: 256, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{133, 127}} + var b124 = sequenceBuilder{id: 124, commit: 264, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} var b123 = choiceBuilder{id: 123, commit: 10} b123.options = []builder{&b89, &b92, &b97} - var b122 = choiceBuilder{id: 122, commit: 66} - var b106 = sequenceBuilder{id: 106, commit: 64, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{122}} + var b122 = choiceBuilder{id: 122, commit: 258} + var b106 = sequenceBuilder{id: 106, commit: 256, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}, generalizations: []int{122}} var b103 = sequenceBuilder{id: 103, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b102 = charBuilder{} b103.items = []builder{&b102} - var b101 = sequenceBuilder{id: 101, commit: 64, name: "count", ranges: [][]int{{1, 1}}} - var b100 = sequenceBuilder{id: 100, commit: 74, ranges: [][]int{{1, -1}, {1, -1}}} + var b101 = sequenceBuilder{id: 101, commit: 256, name: "count", ranges: [][]int{{1, 1}}} + var b100 = sequenceBuilder{id: 100, commit: 266, ranges: [][]int{{1, -1}, {1, -1}}} var b99 = sequenceBuilder{id: 99, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b98 = charBuilder{} b99.items = []builder{&b98} @@ -1301,70 +1361,72 @@ func Parse(r io.Reader) (*Node, error) { var b105 = sequenceBuilder{id: 105, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b104 = charBuilder{} b105.items = []builder{&b104} - b106.items = []builder{&b103, &b186, &b101, &b186, &b105} - var b115 = sequenceBuilder{id: 115, commit: 64, 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{122}} + b106.items = []builder{&b103, &b194, &b101, &b194, &b105} + var b115 = sequenceBuilder{id: 115, commit: 256, 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{122}} var b110 = sequenceBuilder{id: 110, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b109 = charBuilder{} b110.items = []builder{&b109} - var b107 = sequenceBuilder{id: 107, commit: 64, name: "range-from", ranges: [][]int{{1, 1}}} + var b107 = sequenceBuilder{id: 107, commit: 256, name: "range-from", ranges: [][]int{{1, 1}}} b107.items = []builder{&b100} var b112 = sequenceBuilder{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b111 = charBuilder{} b112.items = []builder{&b111} - var b108 = sequenceBuilder{id: 108, commit: 64, name: "range-to", ranges: [][]int{{1, 1}}} + var b108 = sequenceBuilder{id: 108, commit: 256, name: "range-to", ranges: [][]int{{1, 1}}} b108.items = []builder{&b100} var b114 = sequenceBuilder{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b113 = charBuilder{} b114.items = []builder{&b113} - b115.items = []builder{&b110, &b186, &b107, &b186, &b112, &b186, &b108, &b186, &b114} - var b117 = sequenceBuilder{id: 117, commit: 72, name: "one-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} + b115.items = []builder{&b110, &b194, &b107, &b194, &b112, &b194, &b108, &b194, &b114} + var b117 = sequenceBuilder{id: 117, commit: 264, name: "one-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} var b116 = charBuilder{} b117.items = []builder{&b116} - var b119 = sequenceBuilder{id: 119, commit: 72, name: "zero-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} + var b119 = sequenceBuilder{id: 119, commit: 264, name: "zero-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} var b118 = charBuilder{} b119.items = []builder{&b118} - var b121 = sequenceBuilder{id: 121, commit: 72, name: "zero-or-one", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} + var b121 = sequenceBuilder{id: 121, commit: 264, name: "zero-or-one", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} var b120 = charBuilder{} b121.items = []builder{&b120} b122.options = []builder{&b106, &b115, &b117, &b119, &b121} b124.items = []builder{&b123, &b122} var b125 = sequenceBuilder{id: 125, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - b125.items = []builder{&b186, &b124} + b125.items = []builder{&b194, &b124} b126.items = []builder{&b124, &b125} - var b132 = sequenceBuilder{id: 132, commit: 64, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{133}} - var b127 = choiceBuilder{id: 127, commit: 66} + var b132 = sequenceBuilder{id: 132, commit: 256, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}, generalizations: []int{133}} + var b127 = choiceBuilder{id: 127, commit: 258} b127.options = []builder{&b89, &b92, &b97, &b126} var b130 = sequenceBuilder{id: 130, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}} var b129 = sequenceBuilder{id: 129, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b128 = charBuilder{} b129.items = []builder{&b128} - b130.items = []builder{&b129, &b186, &b127} + b130.items = []builder{&b129, &b194, &b127} var b131 = sequenceBuilder{id: 131, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - b131.items = []builder{&b186, &b130} - b132.items = []builder{&b127, &b186, &b130, &b131} + b131.items = []builder{&b194, &b130} + b132.items = []builder{&b127, &b194, &b130, &b131} b133.options = []builder{&b89, &b92, &b97, &b126, &b132} - b169.items = []builder{&b166, &b186, &b168, &b186, &b133} - var b175 = sequenceBuilder{id: 175, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var b173 = sequenceBuilder{id: 173, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}} - var b171 = sequenceBuilder{id: 171, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b170 = charBuilder{} - b171.items = []builder{&b170} - var b172 = sequenceBuilder{id: 172, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - b172.items = []builder{&b186, &b171} - b173.items = []builder{&b171, &b172, &b186, &b169} - var b174 = sequenceBuilder{id: 174, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - b174.items = []builder{&b186, &b173} - b175.items = []builder{&b186, &b173, &b174} - b176.items = []builder{&b169, &b175} - var b184 = sequenceBuilder{id: 184, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} - var b180 = sequenceBuilder{id: 180, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} - var b179 = charBuilder{} - b180.items = []builder{&b179} - var b183 = sequenceBuilder{id: 183, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} - b183.items = []builder{&b186, &b180} - b184.items = []builder{&b186, &b180, &b183} - b187.items = []builder{&b182, &b186, &b176, &b184} - b188.items = []builder{&b186, &b187, &b186} + b177.items = []builder{&b174, &b194, &b176, &b194, &b133} + var b183 = sequenceBuilder{id: 183, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var b181 = sequenceBuilder{id: 181, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {0, -1}, {1, 1}}} + var b179 = sequenceBuilder{id: 179, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b178 = charBuilder{} + b179.items = []builder{&b178} + var b180 = sequenceBuilder{id: 180, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + b180.items = []builder{&b194, &b179} + b181.items = []builder{&b179, &b180, &b194, &b177} + var b182 = sequenceBuilder{id: 182, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + b182.items = []builder{&b194, &b181} + b183.items = []builder{&b194, &b181, &b182} + b184.items = []builder{&b177, &b183} + var b192 = sequenceBuilder{id: 192, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} + var b188 = sequenceBuilder{id: 188, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} + var b187 = charBuilder{} + b188.items = []builder{&b187} + var b191 = sequenceBuilder{id: 191, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} + b191.items = []builder{&b194, &b188} + b192.items = []builder{&b194, &b188, &b191} + b195.items = []builder{&b190, &b194, &b184, &b192} + b196.items = []builder{&b194, &b195, &b194} - return parseInput(r, &p188, &b188) + var keywords = []parser{} + + return parseInput(r, &p196, &b196, keywords) } diff --git a/sequence.go b/sequence.go index bfdc9d1..190be11 100644 --- a/sequence.go +++ b/sequence.go @@ -94,6 +94,22 @@ func (p *sequenceParser) parse(c *context) { } } + if p.commit&NoKeyword != 0 && c.isKeyword(from, to) { + 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 + } + for _, g := range p.generalizations { if c.results.pending(from, g) { c.results.setMatch(from, g, to) diff --git a/syntax.go b/syntax.go index d180935..229b8a7 100644 --- a/syntax.go +++ b/syntax.go @@ -21,9 +21,8 @@ type Syntax struct { initialized bool initFailed bool explicitRoot bool + keywords []definition root definition - parser parser - builder builder } type GeneratorOptions struct { @@ -57,13 +56,33 @@ var ( 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 (ct CommitType) String() string { + switch ct { + case None: + return "none" + case Alias: + return "alias" + case Whitespace: + return "whitespace" + case NoWhitespace: + return "no-whitespace" + case Keyword: + return "keyword" + case NoKeyword: + return "no-keyword" + case FailPass: + return "fail-pass" + case Root: + return "root" + default: + return "unknown" + } +} + func duplicateDefinition(name string) error { return fmt.Errorf("duplicate definition: %s", name) } @@ -100,6 +119,36 @@ func intsContain(is []int, i int) bool { return false } +var incompatibleCommitTypes = map[CommitType][]CommitType{ + Alias: {Root}, + Whitespace: {Keyword, NoKeyword, FailPass, Root}, + Keyword: {NoKeyword, Root}, + FailPass: {Root}, +} + +func (s *Syntax) checkCommitType(d definition) error { + for ct, ict := range incompatibleCommitTypes { + if d.commitType()&ct == 0 { + continue + } + + for _, cti := range ict { + if d.commitType()&cti == 0 { + continue + } + + return fmt.Errorf( + "incompatible commit types in %s: %v and %v", + d.nodeName(), + ct, + cti, + ) + } + } + + return nil +} + func (s *Syntax) applyRoot(d definition) error { explicitRoot := d.commitType()&Root != 0 if explicitRoot && s.explicitRoot { @@ -131,10 +180,18 @@ func (s *Syntax) register(d definition) error { s.registry = newRegistry() } + if err := s.checkCommitType(d); err != nil { + return err + } + if err := s.applyRoot(d); err != nil { return err } + if d.commitType()&Keyword != 0 { + s.keywords = append(s.keywords, d) + } + return s.registry.setDefinition(d) } @@ -252,20 +309,12 @@ func (s *Syntax) Init() error { return ErrNoParsersDefined } - if s.root.commitType()&Alias != 0 { - return ErrRootAlias - } - - if s.root.commitType()&Whitespace != 0 { - return ErrRootWhitespace - } - - if s.root.commitType()&FailPass != 0 { - return ErrRootFailPass + if err := s.checkCommitType(s.root); err != nil { + return err } defs := s.registry.definitions - for i := range s.registry.definitions { + for i := range defs { defs[i].preinit() } @@ -274,15 +323,23 @@ func (s *Syntax) Init() error { s.registry = newRegistry(defs...) } + for i := range s.keywords { + if err := s.keywords[i].validate(s.registry); err != nil { + s.initFailed = true + return err + } + } + if err := s.root.validate(s.registry); err != nil { s.initFailed = true return err } - s.root.init(s.registry) - s.parser = s.root.parser() - s.builder = s.root.builder() + for i := range s.keywords { + s.keywords[i].init(s.registry) + } + s.root.init(s.registry) s.initialized = true return nil } @@ -339,18 +396,26 @@ func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error { fprintln() done := make(map[string]bool) - if err := s.parser.(generator).generate(w, done); err != nil { + if err := s.root.parser().(generator).generate(w, done); err != nil { return err } done = make(map[string]bool) - if err := s.builder.(generator).generate(w, done); err != nil { + if err := s.root.builder().(generator).generate(w, done); err != nil { return err } fprintln() fprintln() - fprintf(`return parseInput(r, &p%d, &b%d)`, s.parser.nodeID(), s.builder.nodeID()) + fprint(`var keywords = []parser{`) + for i := range s.keywords { + fprintf(`&p%d, `, s.keywords[i].nodeID()) + } + fprint(`}`) + + fprintln() + fprintln() + fprintf(`return parseInput(r, &p%d, &b%d, keywords)`, s.root.parser().nodeID(), s.root.builder().nodeID()) fprintln() fprint(`}`) fprintln() @@ -358,10 +423,19 @@ func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error { return nil } +func (s *Syntax) keywordParsers() []parser { + var p []parser + for _, kw := range s.keywords { + p = append(p, kw.parser()) + } + + return p +} + func (s *Syntax) Parse(r io.Reader) (*Node, error) { if err := s.Init(); err != nil { return nil, err } - return parseInput(r, s.parser, s.builder) + return parseInput(r, s.root.parser(), s.root.builder(), s.keywordParsers()) } diff --git a/syntax.treerack b/syntax.treerack index 3b839ff..44d1551 100644 --- a/syntax.treerack +++ b/syntax.treerack @@ -59,9 +59,11 @@ expression:alias = terminal alias = "alias"; ws = "ws"; nows = "nows"; +kw = "kw"; +nokw = "nokw"; failpass = "failpass"; root = "root"; -flag:alias = alias | ws | nows | failpass | root; +flag:alias = alias | ws | nows | kw | nokw | failpass | root; definition-name:alias:nows = symbol (":" flag)*; definition = definition-name "=" expression; diff --git a/syntax_test.go b/syntax_test.go index 635e64a..92b8f11 100644 --- a/syntax_test.go +++ b/syntax_test.go @@ -137,24 +137,14 @@ func TestInit(t *testing.T) { t.Run("root is an alias", func(t *testing.T) { s := &Syntax{} - if err := s.AnyChar("a", Root|Alias); err != nil { - t.Error(err) - return - } - - if err := s.Init(); err == nil { + if err := s.AnyChar("a", Root|Alias); err == nil { t.Error("failed to fail") } }) t.Run("root is whitespace", func(t *testing.T) { s := &Syntax{} - if err := s.AnyChar("a", Root|Whitespace); err != nil { - t.Error(err) - return - } - - if err := s.Init(); err == nil { + if err := s.AnyChar("a", Root|Whitespace); err == nil { t.Error("failed to fail") } }) diff --git a/syntaxhead.go b/syntaxhead.go index b89ffce..0173f36 100644 --- a/syntaxhead.go +++ b/syntaxhead.go @@ -14,6 +14,8 @@ const ( Alias CommitType = 1 << iota Whitespace NoWhitespace + Keyword + NoKeyword FailPass Root @@ -80,8 +82,8 @@ func (pe *ParseError) Error() string { ) } -func parseInput(r io.Reader, p parser, b builder) (*Node, error) { - c := newContext(bufio.NewReader(r)) +func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) { + c := newContext(bufio.NewReader(r), kw) p.parse(c) if c.readErr != nil { return nil, c.readErr