5 lines
23 KiB
Go
5 lines
23 KiB
Go
package treerack
|
|
|
|
// generated with script/createhead.go
|
|
const headCode = "import (\n\t\"strconv\"\n\t\"io\"\n\t\"strings\"\n\t\"fmt\"\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 | failPass\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\tc.trace(p, c.offset, c.offset, Enter)\n\tif !p.allChars {\n\t\tif c.results.pending(c.offset, p.id) {\n\t\t\tc.trace(p, c.offset, c.offset, Fail, \"same position recursion\")\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, itemIndex\tint\n\t\tparsed\t\t\tbool\n\t)\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.trace(p, from, to, Fail, \"no match\")\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.trace(p, from, to, Fail, \"illegal keyword\")\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.trace(p, from, to, Success)\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\tc.trace(p, c.offset, c.offset, Enter)\n\tif c.fromResults(p) {\n\t\treturn\n\t}\n\tif c.results.pending(c.offset, p.id) {\n\t\tc.trace(p, c.offset, c.offset, Fail, \"same position recursion\")\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 && c.failOffset > failOffset {\n\t\t\t\tfailOffset = c.failOffset\n\t\t\t\tfailingParser = c.failingParser\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.trace(p, from, to, Fail, \"illegal keyword\")\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.trace(p, from, to, Success)\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.trace(p, from, to, Fail, \"no match\")\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<<uint(m)) != 0\n}\n\ntype pool[T any] struct {\n\tcreate\tfunc() T\n\tvalues\t[]T\n}\n\nfunc newPool[T any](create func() T) *pool[T] {\n\treturn &pool[T]{create: create}\n}\nfunc (p *pool[T]) get() T {\n\tif len(p.values) == 0 {\n\t\treturn p.create()\n\t}\n\tlast := len(p.values) - 1\n\tv := p.values[last]\n\tp.values = p.values[:last]\n\treturn v\n}\nfunc (p *pool[T]) put(v T) {\n\tp.values = append(p.values, v)\n}\n\ntype arena struct {\n\tf\tbool\n\tp\t*pool[[]int]\n\tw\tint\n\tc\t[]int\n\ta\t[]int\n\tl\tint\n\to\tint\n\tm\tint\n\ts\tint\n\tt\tint\n}\n\nfunc newArena(w int, p *pool[[]int], f bool, size int) *arena {\n\treturn &arena{f: f, p: p, w: w, c: make([]int, 0, size), a: make([]int, 0, size*3)}\n}\nfunc (a *arena) findPosition(pages [][]int, p int) ([]int, int) {\n\tif a.f {\n\t\tif len(pages) == 0 {\n\t\t\treturn nil, -1\n\t\t}\n\t\ts := len(pages[0])\n\t\tif p >= s*len(pages) {\n\t\t\treturn nil, -1\n\t\t}\n\t\treturn pages[p/s], p % s\n\t}\n\tfor i := 0; i < len(pages); i++ {\n\t\tif p < len(pages[i]) {\n\t\t\treturn pages[i], p\n\t\t}\n\t\tp -= len(pages[i])\n\t}\n\treturn nil, -1\n}\nfunc matchValues(v []int, id, to int) bool {\n\treturn v[0] == id && v[1] == to\n}\nfunc (a *arena) cursor(index int) *int {\n\tif len(a.c) <= index {\n\t\treturn nil\n\t}\n\treturn &a.c[index]\n}\nfunc (a *arena) stepCursor(c *int) *int {\n\treturn &a.a[*c]\n}\nfunc (a *arena) recordAt(c int) []int {\n\treturn a.a[c-a.w : c+1]\n}\nfunc (a *arena) allocCursor(index int) {\n\tif len(a.c) > index {\n\t\treturn\n\t}\n\tif cap(a.c) > index {\n\t\tl := len(a.c)\n\t\ta.c = a.c[:index+1]\n\t\tfor i := l; i < len(a.c); i++ {\n\t\t\ta.c[i] = -1\n\t\t}\n\t\treturn\n\t}\n\tc := make([]int, index+1+index/4)\n\tcopy(c, a.c)\n\tfor i := len(a.c); i < len(c); i++ {\n\t\tc[i] = -1\n\t}\n\ta.c = c\n}\nfunc (a *arena) allocArena() {\n}\nfunc (a *arena) append(c, id, to int) int {\n\ta.a = append(a.a, id, to, c)\n\treturn len(a.a) - 1\n}\nfunc (a *arena) clearCursor(c *int, id, to int) {\n\tfor c != nil && *c > 0 {\n\t\tr := a.recordAt(*c)\n\t\tif matchValues(r[:len(r)-1], id, to) {\n\t\t\t*c, r[a.w] = r[a.w], 0\n\t\t\tcontinue\n\t\t}\n\t\tc = a.stepCursor(c)\n\t}\n}\nfunc (a *arena) lastActivePosition(p []int) int {\n\treturn 0\n}\nfunc (a *arena) trim() {\n\treturn\n}\nfunc (a *arena) len() int {\n\treturn a.l\n}\nfunc (a *arena) has(index, id, to int) bool {\n\tfor c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {\n\t\tr := a.recordAt(*c)\n\t\tif matchValues(r[:len(r)-1], id, to) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\nfunc (a *arena) hasID(index, id int) bool {\n\tfor c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {\n\t\tr := a.recordAt(*c)\n\t\tif r[0] == id {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\nfunc (a *arena) get(index, id, to int) [][]int {\n\tvar values [][]int\n\tfor c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {\n\t\tr := a.recordAt(*c)\n\t\tv := r[:len(r)-1]\n\t\tif matchValues(v, id, to) {\n\t\t\tvalues = append(values, v)\n\t\t}\n\t}\n\treturn values\n}\nfunc (a *arena) getLargest(index int, id int) int {\n\tl := -1\n\tfor c := a.cursor(index); c != nil && *c > 0; c = a.stepCursor(c) {\n\t\tr := a.recordAt(*c)\n\t\tif r[0] == id && r[1] > l {\n\t\t\tl = r[1]\n\t\t}\n\t}\n\treturn l\n}\nfunc (a *arena) set(index, id, to int) {\n\tif a.has(index, id, to) {\n\t\treturn\n\t}\n\ta.allocCursor(index)\n\tc := a.cursor(index)\n\tif c == nil {\n\t\treturn\n\t}\n\ta.allocArena()\n\t*c = a.append(*c, id, to)\n}\nfunc (a *arena) del(index, id, to int) {\n\tc := a.cursor(index)\n\ta.clearCursor(c, id, to)\n\ta.trim()\n}\nfunc (a *arena) prune(from, to int) {\n\treturn\n}\n\ntype results struct {\n\tnoMatch\t\t[]*idSet\n\tmatch\t\t*arena\n\tisPending\t[][]int\n}\n\nfunc newResults(size int) *results {\n\tp := newPool(func() []int {\n\t\treturn make([]int, 1<<9)\n\t})\n\treturn &results{match: newArena(2, p, true, size)}\n}\nfunc ensureOffsetInts(ints [][]int, offset int) [][]int {\n\tif len(ints) > 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.set(offset, id, to)\n}\nfunc (r *results) setNoMatch(offset, id int) {\n\tif r.match.hasID(offset, id) {\n\t\treturn\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\treturn r.match.has(offset, id, to)\n}\nfunc (r *results) longestMatch(offset, id int) (int, bool) {\n\tto := r.match.getLargest(offset, id)\n\treturn to, to >= 0\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\tr.match.del(offset, id, to)\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\tlevel\t\tint\n\ttr\t\t[]TraceEntry\n\tmaxTraceLength\tint\n}\n\nfunc newContext(r []rune, keywords []parser, maxTraceLength int) *context {\n\treturn &context{tokens: r, readOffset: len(r), eof: true, keywords: keywords, results: newResults(len(r)), offsetLimit: -1, failOffset: -1, maxTraceLength: maxTraceLength}\n}\nfunc (c *context) read() bool {\n\treturn false\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\tif offset < 0 {\n\t\treturn 0, 0\n\t}\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, unexpectedInput bool, root int) 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\tueLine, ueCol := -1, -1\n\tif unexpectedInput {\n\t\tto, _, _ := c.results.longestResult(0, root)\n\t\tueLine, ueCol = findLine(c.tokens, to)\n\t}\n\tfor i := range c.tr {\n\t\tc.tr[i].FromLine, c.tr[i].FromCol = findLine(c.tokens, c.tr[i].From)\n\t\tc.tr[i].ToLine, c.tr[i].ToCol = findLine(c.tokens, c.tr[i].To)\n\t}\n\treturn &parseError{inputContent: c.tokens, Offset: c.failOffset, Line: line, Column: col, Definition: definition, Trace: c.tr, UnexpectedInputLine: ueLine, UnexpectedInputCol: ueCol}\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, found && match && to < c.readOffset, root.nodeID())\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, false, root.nodeID())\n}\nfunc (c *context) trace(p parser, from, to int, event TraceEvent, reason ...string) {\n\tif c.maxTraceLength <= 0 {\n\t\treturn\n\t}\n\tif p.commitType()&userDefined == 0 || p.commitType()&failPass != 0 {\n\t\treturn\n\t}\n\tif len(c.tr) == c.maxTraceLength {\n\t\tc.tr = c.tr[1:]\n\t}\n\tswitch event {\n\tcase Success, Fail:\n\t\tc.level--\n\t}\n\tc.tr = append(c.tr, TraceEntry{Level: c.level, Parser: p.nodeName(), From: from, To: to, Event: event, Reason: strings.Join(reason, \"; \")})\n\tswitch event {\n\tcase Enter:\n\t\tc.level++\n\t}\n}\n\ntype node struct {\n\tName\tstring\n\tNodes\t[]node\n\tFrom\tint\n\tTo\tint\n\ttokens\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\tNoFailPass\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 formatOptions struct {\n\tmode\t\tformatFlags\n\ttargetWidth\tint\n}\ntype TraceEvent int\n\nconst (\n\tEnter\tTraceEvent\t= iota\n\tSuccess\n\tFail\n)\n\ntype TraceEntry struct {\n\tLevel\t\tint\n\tParser\t\tstring\n\tFrom\t\tint\n\tTo\t\tint\n\tFromLine\tint\n\tFromCol\t\tint\n\tToLine\t\tint\n\tToCol\t\tint\n\tEvent\t\tTraceEvent\n\tReason\t\tstring\n}\ntype parseError struct {\n\tinputContent\t\t[]rune\n\tInput\t\t\tstring\n\tOffset\t\t\tint\n\tLine\t\t\tint\n\tColumn\t\t\tint\n\tDefinition\t\tstring\n\tTrace\t\t\t[]TraceEntry\n\tUnexpectedInputLine\tint\n\tUnexpectedInputCol\tint\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) InputContent(from, to int) []rune {\n\tif to < 0 {\n\t\tto = len(pe.inputContent)\n\t}\n\tif to <= from {\n\t\treturn nil\n\t}\n\tc := make([]rune, to-from)\n\tcopy(c, pe.inputContent[from:])\n\treturn c\n}\nfunc (pe *parseError) Error() string {\n\tif pe.UnexpectedInputLine >= 0 && pe.UnexpectedInputCol >= 0 {\n\t\treturn fmt.Sprintf(\"%s:%d:%d:parse failed, unexpected input at %d:%d\", pe.Input, pe.UnexpectedInputLine+1, pe.UnexpectedInputCol+1, pe.UnexpectedInputLine+1, pe.UnexpectedInputCol+1)\n\t}\n\treturn fmt.Sprintf(\"%s:%d:%d:parse failed, parsing: %s, at %d:%d\", pe.Input, pe.Line+1, pe.Column+1, pe.Definition, pe.Line+1, pe.Column+1)\n}\nfunc parseInput(r io.Reader, p parser, b builder, kw []parser, maxTraceLength int) (node, error) {\n\tbb, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn node{}, err\n\t}\n\tc := newContext([]rune(string(bb)), kw, maxTraceLength)\n\tp.parse(c)\n\tif c.readErr != nil {\n\t\treturn node{}, 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 = \"<input>\"\n\t\t}\n\t\treturn node{}, err\n\t}\n\tc.offset = 0\n\tc.results.resetPending()\n\tn, _ := b.build(c)\n\treturn n[0], nil\n}\n"
|