Compare commits

..

10 Commits

Author SHA1 Message Date
Arpad Ryszka
a8bec182b1 add go modules 2025-08-19 00:56:08 +02:00
Arpad Ryszka
a96580b2fd fix: all keywords need to be generated 2019-02-02 21:27:01 +01:00
Arpad Ryszka
7b2eaa5c7a add keyword commit type 2019-02-02 18:07:10 +01:00
Arpad Ryszka
19050f317b fix: use sequences from previous matches when failing and available 2019-01-27 19:06:44 +01:00
Arpad Ryszka
03acd8dea4 fix generated builder: builders didn't have the generalizations registered 2019-01-27 18:29:30 +01:00
Arpad Ryszka
505061f31a fix Makefile: no bash expansion 2019-01-27 16:08:39 +01:00
Arpad Ryszka
146315f495 fix formatting 2018-10-21 19:49:48 +02:00
Arpad Ryszka
3327e758c5 drop unused code 2018-10-11 23:48:58 +02:00
Arpad Ryszka
a7dc82ff12 fix test syntax 2018-10-11 23:48:00 +02:00
Arpad Ryszka
a31134291d test for bug in mml syntax: a.b[c] 2018-10-11 23:36:17 +02:00
30 changed files with 1216 additions and 1097 deletions

View File

@ -35,15 +35,15 @@ head: $(SOURCES) fmt
generate: $(SOURCES) $(PARSERS) fmt head install generate: $(SOURCES) $(PARSERS) fmt head install
treerack generate -export -package-name self < syntax.treerack > self/self.go.next treerack generate -export -package-name self < syntax.treerack > self/self.go.next
@mv self/self.go{.next,} @mv self/self.go.next self/self.go
@gofmt -s -w self/self.go @gofmt -s -w self/self.go
regenerate: $(SOURCES) $(PARSERS) fmt head install regenerate: $(SOURCES) $(PARSERS) fmt head install
treerack generate -export -package-name self < syntax.treerack > self/self.go.next treerack generate -export -package-name self < syntax.treerack > self/self.go.next
@mv self/self.go{.next,} @mv self/self.go.next self/self.go
go install ./cmd/treerack go install ./cmd/treerack
treerack generate -export -package-name self < syntax.treerack > self/self.go.next treerack generate -export -package-name self < syntax.treerack > self/self.go.next
@mv self/self.go{.next,} @mv self/self.go.next self/self.go
@gofmt -s -w self/self.go @gofmt -s -w self/self.go
check-generate: $(SOURCES) $(PARSERS) check-generate: $(SOURCES) $(PARSERS)
@ -68,7 +68,7 @@ check-generate: $(SOURCES) $(PARSERS)
@echo checking self @echo checking self
@mv self/self.go self/self.go.backup @mv self/self.go self/self.go.backup
@treerack generate -export -package-name self < syntax.treerack > self/self.go.next @treerack generate -export -package-name self < syntax.treerack > self/self.go.next
@mv self/self.go{.next,} @mv self/self.go.next self/self.go
@gofmt -s -w self/self.go @gofmt -s -w self/self.go
@if ! diff self/self.go self/self.go.backup > /dev/null; then \ @if ! diff self/self.go self/self.go.backup > /dev/null; then \
mv self/self.go.backup self/self.go; \ mv self/self.go.backup self/self.go; \

View File

@ -8,6 +8,6 @@
### Examples ### Examples
- JSON: https://github.com/aryszka/treerack/blob/master/examples/json.treerack - JSON: https://code.squareroundforest.org/arpio/treerack/blob/master/examples/json.treerack
- Scheme: https://github.com/aryszka/treerack/blob/master/examples/scheme.treerack - Scheme: https://code.squareroundforest.org/arpio/treerack/blob/master/examples/scheme.treerack
- Treerack (itself): https://github.com/aryszka/treerack/blob/master/syntax.treerack - Treerack (itself): https://code.squareroundforest.org/arpio/treerack/blob/master/syntax.treerack

View File

@ -78,6 +78,19 @@ func (p *choiceParser) parse(c *context) {
} }
if match { 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 { if failOffset > to {
c.failOffset = failOffset c.failOffset = failOffset
c.failingParser = failingParser c.failingParser = failingParser

View File

@ -227,6 +227,15 @@ func (b *choiceBuilder) generate(w io.Writer, done map[string]bool) error {
fprintf("name: \"%s\",", b.name) fprintf("name: \"%s\",", b.name)
} }
if len(b.generalizations) > 0 {
fprintf("generalizations: []int{")
for i := range b.generalizations {
fprintf("%d,", b.generalizations[i])
}
fprintf("},")
}
fprintf("};") fprintf("};")
if len(b.options) > 0 { if len(b.options) > 0 {

View File

@ -5,7 +5,7 @@ import (
"unicode/utf8" "unicode/utf8"
) )
const summary = `treerack - parser generator - https://github.com/aryszka/treerack` const summary = `treerack - parser generator - https://code.squareroundforest.org/aryszka/treerack`
const commandsHelp = `Available commands: const commandsHelp = `Available commands:
check validates an arbitrary input against a syntax definition check validates an arbitrary input against a syntax definition
@ -18,7 +18,7 @@ See more details about a particular command by calling:
treerack <command> -help` treerack <command> -help`
const docRef = `See more documentation about the definition syntax and the parser output at const docRef = `See more documentation about the definition syntax and the parser output at
https://github.com/aryszka/treerack.` https://code.squareroundforest.org/arpio/treerack.`
const positionalSyntaxUsage = "The path to the syntax file is accepted as a positional argument." const positionalSyntaxUsage = "The path to the syntax file is accepted as a positional argument."

View File

@ -1,6 +1,6 @@
package main package main
import "github.com/aryszka/treerack" import "code.squareroundforest.org/arpio/treerack"
type generateOptions struct { type generateOptions struct {
command *commandOptions command *commandOptions

View File

@ -6,8 +6,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"os" "os"
"code.squareroundforest.org/arpio/treerack"
"github.com/aryszka/treerack"
"golang.org/x/crypto/ssh/terminal" "golang.org/x/crypto/ssh/terminal"
) )

View File

@ -2,8 +2,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"code.squareroundforest.org/arpio/treerack"
"github.com/aryszka/treerack"
) )
type showOptions struct { type showOptions struct {

View File

@ -8,9 +8,11 @@ import (
type context struct { type context struct {
reader io.RuneReader reader io.RuneReader
keywords []parser
offset int offset int
readOffset int readOffset int
consumed int consumed int
offsetLimit int
failOffset int failOffset int
failingParser parser failingParser parser
readErr error readErr error
@ -20,11 +22,13 @@ type context struct {
matchLast bool matchLast bool
} }
func newContext(r io.RuneReader) *context { func newContext(r io.RuneReader, keywords []parser) *context {
return &context{ return &context{
reader: r, reader: r,
results: &results{}, keywords: keywords,
failOffset: -1, results: &results{},
offsetLimit: -1,
failOffset: -1,
} }
} }
@ -58,6 +62,10 @@ func (c *context) read() bool {
} }
func (c *context) token() (rune, bool) { func (c *context) token() (rune, bool) {
if c.offset == c.offsetLimit {
return 0, false
}
if c.offset == c.readOffset { if c.offset == c.readOffset {
if !c.read() { if !c.read() {
return 0, false return 0, false
@ -82,6 +90,21 @@ func (c *context) fromResults(p parser) bool {
return true 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) { func (c *context) success(to int) {
c.offset = to c.offset = to
c.matchLast = true c.matchLast = true

View File

@ -20,6 +20,10 @@ func flagsToCommitType(n []*Node) CommitType {
ct |= Whitespace ct |= Whitespace
case "nows": case "nows":
ct |= NoWhitespace ct |= NoWhitespace
case "kw":
ct |= Keyword
case "nokw":
ct |= NoKeyword
case "failpass": case "failpass":
ct |= FailPass ct |= FailPass
case "root": case "root":

View File

@ -1,750 +0,0 @@
package treerack
import (
"bytes"
"errors"
"fmt"
"math/rand"
"strconv"
"strings"
"testing"
"github.com/zalando/skipper/eskip"
)
const (
maxID = 27
meanID = 9
setPathChance = 0.72
maxPathTags = 12
meanPathTags = 2
maxPathTag = 24
meanPathTag = 9
setHostChance = 0.5
maxHost = 48
meanHost = 24
setPathRegexpChance = 0.45
maxPathRegexp = 36
meanPathRegexp = 12
setMethodChance = 0.1
setHeadersChance = 0.3
maxHeadersLength = 6
meanHeadersLength = 1
maxHeaderKeyLength = 18
meanHeaderKeyLength = 12
maxHeaderValueLength = 48
meanHeaderValueLength = 6
setHeaderRegexpChance = 0.05
maxHeaderRegexpsLength = 3
meanHeaderRegexpsLength = 1
maxHeaderRegexpLength = 12
meanHeaderRegexpLength = 6
maxTermNameLength = 15
meanTermNameLength = 6
maxTermArgsLength = 6
meanTermArgsLength = 1
floatArgChance = 0.1
intArgChance = 0.3
maxTermStringLength = 24
meanTermStringLength = 6
maxPredicatesLength = 4
meanPredicatesLength = 1
maxFiltersLength = 18
meanFiltersLength = 3
loopBackendChance = 0.05
shuntBackendChance = 0.1
maxBackend = 48
meanBackend = 15
)
func takeChance(c float64) bool {
return rand.Float64() < c
}
func generateID() string {
return generateString(maxID, meanID)
}
func generatePath() string {
if !takeChance(setPathChance) {
return ""
}
l := randomLength(maxPathTags, meanPathTags)
p := append(make([]string, 0, l+1), "")
for i := 0; i < l; i++ {
p = append(p, generateString(maxPathTag, meanPathTag))
}
return strings.Join(p, "/")
}
func generateHostRegexps() []string {
if !takeChance(setHostChance) {
return nil
}
return []string{generateString(maxHost, meanHost)}
}
func generatePathRegexps() []string {
if !takeChance(setPathRegexpChance) {
return nil
}
return []string{generateString(maxPathRegexp, meanPathRegexp)}
}
func generateMethod() string {
if !takeChance(setMethodChance) {
return ""
}
methods := []string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"}
return methods[rand.Intn(len(methods))]
}
func generateHeaders() map[string]string {
if !takeChance(setHeadersChance) {
return nil
}
h := make(map[string]string)
for i := 0; i < randomLength(maxHeadersLength, meanHeadersLength); i++ {
h[generateString(maxHeaderKeyLength, meanHeaderKeyLength)] =
generateString(maxHeaderValueLength, meanHeaderValueLength)
}
return h
}
func generateHeaderRegexps() map[string][]string {
if !takeChance(setHeaderRegexpChance) {
return nil
}
h := make(map[string][]string)
for i := 0; i < randomLength(maxHeaderRegexpsLength, meanHeaderRegexpsLength); i++ {
k := generateString(maxHeaderKeyLength, meanHeaderKeyLength)
for i := 0; i < randomLength(maxHeaderRegexpLength, meanHeaderRegexpLength); i++ {
h[k] = append(h[k], generateString(maxHeaderValueLength, meanHeaderValueLength))
}
}
return h
}
func generateTerm() (string, []interface{}) {
n := generateString(maxTermNameLength, meanTermNameLength)
al := randomLength(maxTermArgsLength, meanTermArgsLength)
a := make([]interface{}, 0, al)
for i := 0; i < al; i++ {
at := rand.Float64()
switch {
case at < floatArgChance:
a = append(a, rand.NormFloat64())
case at < intArgChance:
a = append(a, rand.Int())
default:
a = append(a, generateString(maxTermStringLength, meanTermStringLength))
}
}
return n, a
}
func generatePredicates() []*eskip.Predicate {
l := randomLength(maxPredicatesLength, meanPredicatesLength)
p := make([]*eskip.Predicate, 0, l)
for i := 0; i < l; i++ {
pi := &eskip.Predicate{}
pi.Name, pi.Args = generateTerm()
p = append(p, pi)
}
return p
}
func generateFilters() []*eskip.Filter {
l := randomLength(maxFiltersLength, meanFiltersLength)
f := make([]*eskip.Filter, 0, l)
for i := 0; i < l; i++ {
fi := &eskip.Filter{}
fi.Name, fi.Args = generateTerm()
f = append(f, fi)
}
return f
}
func generateBackend() (eskip.BackendType, string) {
t := rand.Float64()
switch {
case t < loopBackendChance:
return eskip.LoopBackend, ""
case t < loopBackendChance+shuntBackendChance:
return eskip.ShuntBackend, ""
default:
return eskip.NetworkBackend, generateString(maxBackend, meanBackend)
}
}
func generateRoute() *eskip.Route {
r := &eskip.Route{}
r.Id = generateID()
r.Path = generatePath()
r.HostRegexps = generateHostRegexps()
r.PathRegexps = generatePathRegexps()
r.Method = generateMethod()
r.Headers = generateHeaders()
r.HeaderRegexps = generateHeaderRegexps()
r.Predicates = generatePredicates()
r.Filters = generateFilters()
r.BackendType, r.Backend = generateBackend()
return r
}
func generateEskip(l int) []*eskip.Route {
r := make([]*eskip.Route, 0, l)
for i := 0; i < l; i++ {
r = append(r, generateRoute())
}
return r
}
func parseEskipInt(s string) (int, error) {
i, err := strconv.ParseInt(s, 0, 64)
return int(i), err
}
func parseEskipFloat(s string) (float64, error) {
f, err := strconv.ParseFloat(s, 64)
return f, err
}
func unquote(s string, escapedChars string) (string, error) {
if len(s) < 2 {
return "", nil
}
b := make([]byte, 0, len(s)-2)
var escaped bool
for _, bi := range []byte(s[1 : len(s)-1]) {
if escaped {
switch bi {
case 'b':
bi = '\b'
case 'f':
bi = '\f'
case 'n':
bi = '\n'
case 'r':
bi = '\r'
case 't':
bi = '\t'
case 'v':
bi = '\v'
}
b = append(b, bi)
escaped = false
continue
}
for _, ec := range []byte(escapedChars) {
if ec == bi {
return "", errors.New("invalid quote")
}
}
if bi == '\\' {
escaped = true
continue
}
b = append(b, bi)
}
return string(b), nil
}
func unquoteString(s string) (string, error) {
return unquote(s, "\"")
}
func unquoteRegexp(s string) (string, error) {
return unquote(s, "/")
}
func nodeToArg(n *Node) (interface{}, error) {
switch n.Name {
case "int":
return parseEskipInt(n.Text())
case "float":
return parseEskipFloat(n.Text())
case "string":
return unquoteString(n.Text())
case "regexp":
return unquoteRegexp(n.Text())
default:
return nil, errors.New("invalid arg")
}
}
func nodeToTerm(n *Node) (string, []interface{}, error) {
if len(n.Nodes) < 1 || n.Nodes[0].Name != "symbol" {
return "", nil, errors.New("invalid term")
}
name := n.Nodes[0].Text()
var args []interface{}
for _, ni := range n.Nodes[1:] {
a, err := nodeToArg(ni)
if err != nil {
return "", nil, err
}
args = append(args, a)
}
return name, args, nil
}
func nodeToPredicate(r *eskip.Route, n *Node) error {
name, args, err := nodeToTerm(n)
if err != nil {
return err
}
switch name {
case "Path":
if len(args) != 1 {
return errors.New("invalid path predicate")
}
p, ok := args[0].(string)
if !ok {
return errors.New("invalid path predicate")
}
r.Path = p
case "Host":
if len(args) != 1 {
return errors.New("invalid host predicate")
}
h, ok := args[0].(string)
if !ok {
return errors.New("invalid host predicate")
}
r.HostRegexps = append(r.HostRegexps, h)
case "PathRegexp":
if len(args) != 1 {
return errors.New("invalid path regexp predicate")
}
p, ok := args[0].(string)
if !ok {
return errors.New("invalid path regexp predicate")
}
r.PathRegexps = append(r.PathRegexps, p)
case "Method":
if len(args) != 1 {
return errors.New("invalid method predicate")
}
m, ok := args[0].(string)
if !ok {
return errors.New("invalid method predicate")
}
r.Method = m
case "Header":
if len(args) != 2 {
return errors.New("invalid header predicate")
}
name, ok := args[0].(string)
if !ok {
return errors.New("invalid header predicate")
}
value, ok := args[1].(string)
if !ok {
return errors.New("invalid header predicate")
}
if r.Headers == nil {
r.Headers = make(map[string]string)
}
r.Headers[name] = value
case "HeaderRegexp":
if len(args) != 2 {
return errors.New("invalid header regexp predicate")
}
name, ok := args[0].(string)
if !ok {
return errors.New("invalid header regexp predicate")
}
value, ok := args[1].(string)
if !ok {
return errors.New("invalid header regexp predicate")
}
if r.HeaderRegexps == nil {
r.HeaderRegexps = make(map[string][]string)
}
r.HeaderRegexps[name] = append(r.HeaderRegexps[name], value)
default:
r.Predicates = append(r.Predicates, &eskip.Predicate{Name: name, Args: args})
}
return nil
}
func nodeToFilter(n *Node) (*eskip.Filter, error) {
name, args, err := nodeToTerm(n)
if err != nil {
return nil, err
}
return &eskip.Filter{Name: name, Args: args}, nil
}
func nodeToBackend(r *eskip.Route, n *Node) error {
switch n.Name {
case "string":
b, err := unquoteString(n.Text())
if err != nil {
return err
}
r.BackendType = eskip.NetworkBackend
r.Backend = b
case "shunt":
r.BackendType = eskip.ShuntBackend
case "loopback":
r.BackendType = eskip.LoopBackend
default:
return errors.New("invalid backend type")
}
return nil
}
func nodeToEskipDefinition(n *Node) (*eskip.Route, error) {
ns := n.Nodes
if len(ns) < 2 || len(ns[1].Nodes) == 0 {
return nil, fmt.Errorf("invalid definition length: %d", len(ns))
}
r := &eskip.Route{}
if ns[0].Name != "symbol" {
return nil, errors.New("invalid definition id")
}
r.Id, ns = ns[0].Text(), ns[1].Nodes
predicates:
for i, ni := range ns {
switch ni.Name {
case "predicate":
if err := nodeToPredicate(r, ni); err != nil {
return nil, err
}
case "filter", "string", "shunt", "loopback":
ns = ns[i:]
break predicates
default:
return nil, errors.New("invalid definition item among predicates")
}
}
filters:
for i, ni := range ns {
switch ni.Name {
case "filter":
f, err := nodeToFilter(ni)
if err != nil {
return nil, err
}
r.Filters = append(r.Filters, f)
case "string", "shunt", "loopback":
ns = ns[i:]
break filters
default:
return nil, errors.New("invalid definition item among filters")
}
}
if len(ns) != 1 {
return nil, fmt.Errorf("invalid definition backend, remaining definition length: %d, %s",
len(ns), n.Text())
}
if err := nodeToBackend(r, ns[0]); err != nil {
return nil, err
}
return r, nil
}
func eskipTreeToEskip(n []*Node) ([]*eskip.Route, error) {
r := make([]*eskip.Route, 0, len(n))
for _, ni := range n {
d, err := nodeToEskipDefinition(ni)
if err != nil {
return nil, err
}
r = append(r, d)
}
return r, nil
}
func checkTerm(t *testing.T, gotName, expectedName string, gotArgs, expectedArgs []interface{}) {
if gotName != expectedName {
t.Error("invalid term name")
return
}
if len(gotArgs) != len(expectedArgs) {
t.Error("invalid term args length in:", gotName, len(gotArgs), len(expectedArgs))
return
}
// legacy bug support, dropping numeric arguments:
for i, a := range gotArgs {
ea := expectedArgs[i]
switch a.(type) {
case int, float64:
switch ea.(type) {
case int, float64:
gotArgs = append(gotArgs[:i], gotArgs[i+1:]...)
expectedArgs = append(expectedArgs[:i], expectedArgs[i+1:]...)
default:
t.Error("invalid argument type at:", i)
}
}
}
for i, a := range gotArgs {
if a != expectedArgs[i] {
t.Error("invalid term arg")
return
}
}
}
func checkPredicates(t *testing.T, got, expected *eskip.Route) {
if got.Path != expected.Path {
t.Error("invalid path")
return
}
if len(got.HostRegexps) != len(expected.HostRegexps) {
t.Error("invalid host length")
return
}
for i, h := range got.HostRegexps {
if h != expected.HostRegexps[i] {
t.Error("invalid host")
return
}
}
if len(got.PathRegexps) != len(expected.PathRegexps) {
t.Error("invalid path regexp length", len(got.PathRegexps), len(expected.PathRegexps))
return
}
for i, h := range got.PathRegexps {
if h != expected.PathRegexps[i] {
t.Error("invalid path regexp")
return
}
}
if got.Method != expected.Method {
t.Error("invalid method")
return
}
if len(got.Headers) != len(expected.Headers) {
t.Error("invalid headers length")
return
}
for n, h := range got.Headers {
he, ok := expected.Headers[n]
if !ok {
t.Error("invalid header name")
return
}
if he != h {
t.Error("invalid header")
return
}
}
if len(got.HeaderRegexps) != len(expected.HeaderRegexps) {
t.Error("invalid header regexp length")
return
}
for n, h := range got.HeaderRegexps {
he, ok := expected.HeaderRegexps[n]
if !ok {
t.Error("invalid header regexp name")
return
}
if len(h) != len(he) {
t.Error("invalid header regexp item length")
return
}
for i, hi := range h {
if hi != he[i] {
t.Error("invalid header regexp")
return
}
}
}
if len(got.Predicates) != len(expected.Predicates) {
t.Error("invalid predicates length")
return
}
for i, p := range got.Predicates {
checkTerm(
t,
p.Name, expected.Predicates[i].Name,
p.Args, expected.Predicates[i].Args,
)
if t.Failed() {
t.Log(p.Name, expected.Predicates[i].Name)
t.Log(p.Args, expected.Predicates[i].Args)
return
}
}
}
func checkFilters(t *testing.T, got, expected []*eskip.Filter) {
if len(got) != len(expected) {
t.Error("invalid filters length")
return
}
for i, f := range got {
checkTerm(
t,
f.Name, expected[i].Name,
f.Args, expected[i].Args,
)
if t.Failed() {
return
}
}
}
func checkBackend(t *testing.T, got, expected *eskip.Route) {
if got.BackendType != expected.BackendType {
t.Error("invalid backend type")
return
}
if got.Backend != expected.Backend {
t.Error("invalid backend")
return
}
}
func checkRoute(t *testing.T, got, expected *eskip.Route) {
if got.Id != expected.Id {
t.Error("invalid route id")
return
}
checkPredicates(t, got, expected)
if t.Failed() {
return
}
checkFilters(t, got.Filters, expected.Filters)
if t.Failed() {
return
}
checkBackend(t, got, expected)
}
func checkEskip(t *testing.T, got, expected []*eskip.Route) {
if len(got) != len(expected) {
t.Error("invalid length", len(got), len(expected))
return
}
for i, ri := range got {
checkRoute(t, ri, expected[i])
if t.Failed() {
t.Log(ri.String())
t.Log(expected[i].String())
return
}
}
}
func TestEskip(t *testing.T) {
const count = 1 << 9
r := generateEskip(count)
e := eskip.Print(eskip.PrettyPrintInfo{Pretty: true}, r...)
b := bytes.NewBufferString(e)
s, err := openSyntaxFile("examples/eskip.treerack")
if err != nil {
t.Error(err)
return
}
n, err := s.Parse(b)
if err != nil {
t.Error(err)
return
}
rback, err := eskipTreeToEskip(n.Nodes)
if err != nil {
t.Error(err)
return
}
checkEskip(t, rback, r)
}

View File

@ -1,50 +0,0 @@
/*
Eskip routing configuration format for Skipper: https://github.com/zalando/skipper
*/
eskip:root = (expression | definitions)?;
space:ws = [ \n\b\f\r\t\v];
comment:ws = "//" [^\n]*;
decimal-digit:alias = [0-9];
octal-digit:alias = [0-7];
hexa-digit:alias = [0-9a-fA-F];
decimal:alias:nows = [1-9] decimal-digit*;
octal:alias:nows = "0" octal-digit*;
hexa:alias:nows = "0" [xX] hexa-digit+;
int = decimal | octal | hexa;
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
float:nows = decimal-digit+ "." decimal-digit* exponent?
| "." decimal-digit+ exponent?
| decimal-digit+ exponent;
number:alias:nows = "-"? (int | float);
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
regexp:nows = "/" ([^\\/] | "\\" .)* "/";
symbol:nows = [a-zA-Z_] [a-zA-z0-9_]*;
arg:alias = number | string | regexp;
args:alias = arg ("," arg)*;
term:alias = symbol "(" args? ")";
predicate = term;
predicates:alias = "*" | predicate ("&&" predicate)*;
filter = term;
filters:alias = filter ("->" filter)*;
address:alias = string;
shunt = "<shunt>";
loopback = "<loopback>";
backend:alias = address | shunt | loopback;
expression = predicates ("->" filters)? "->" backend;
id:alias = symbol;
definition = id ":" expression;
definitions:alias = ";"* definition (";"+ definition)* ";"*;

271
examples/mml-exp2.treerack Normal file
View File

@ -0,0 +1,271 @@
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
wsc:ws = comment;
nl:alias = "\n";
line-comment-content:nows = [^\n]*;
line-comment:alias:nows = "//" line-comment-content;
block-comment-content:nows = ([^*] | "*" [^/])*;
block-comment:alias:nows = "/*" block-comment-content "*/";
comment-part:alias = line-comment | block-comment;
comment:alias = comment-part (nl? comment-part)*;
decimal-digit:alias = [0-9];
octal-digit:alias = [0-7];
hexa-digit:alias = [0-9a-fA-F];
decimal:alias:nows = [1-9] decimal-digit*;
octal:alias:nows = "0" octal-digit*;
hexa:alias:nows = "0" [xX] hexa-digit+;
int = decimal | octal | hexa;
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
float:nows = decimal-digit+ "." decimal-digit* exponent?
| "." decimal-digit+ exponent?
| decimal-digit+ exponent;
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
true = "true";
false = "false";
bool:alias = true | false;
symbol:nows = [a-zA-Z_][a-zA-Z_0-9]*;
spread-expression = primary-expression "...";
list-sep:alias = (nl | ",")+;
list-item:alias = expression | spread-expression;
expression-list:alias = list-item (list-sep list-item)*;
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
list = list-fact;
mutable-list = "~" nl* list-fact;
expression-key = "[" nl* expression nl* "]";
entry = (symbol | string | expression-key) nl* ":" nl* expression;
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
struct = struct-fact;
mutable-struct = "~" nl* struct-fact;
parameter-list:alias = symbol (list-sep symbol)*;
collect-parameter = "..." nl* symbol;
return = "return" (nl* expression)?;
block = "{" sep? statement-list? sep? "}";
function-fact:alias = "(" list-sep?
(parameter-list
| parameter-list list-sep collect-parameter
| collect-parameter)?
list-sep? ")" nl*
(simple-statement | block);
function = "fn" nl* function-fact;
effect = "fn" nl* "~" nl* function-fact;
range-from = expression;
range-to = expression;
range:alias = range-from? nl* ":" nl* range-to?;
symbol-index = "." nl* symbol;
expression-index = "[" nl* expression nl* "]";
index:alias = symbol-index | expression-index;
index-list:alias = index (nl* index)?;
indexer = primary-expression nl* index-list;
function-application = primary-expression "(" list-sep? expression-list? list-sep? ")";
expression-group:alias = "(" nl* expression nl* ")";
primary-expression:alias = int
| float
| string
| bool
| receive
| symbol
| list
| mutable-list
| struct
| mutable-struct
| function
| effect
| indexer
| function-application
| expression-group;
binary-not = "^";
binary-and = "&";
binary-or = "|";
xor = "^";
and-not = "&^";
lshift = "<<";
rshift = ">>";
plus = "+";
minus = "-";
mul = "*";
div = "/";
mod = "%";
add = "+";
sub = "-";
logical-not = "!";
eq = "==";
not-eq = "!=";
less = "<";
less-or-eq = "<=";
greater = ">";
greater-or-eq = ">=";
logical-and = "&&";
logical-or = "||";
chain:alias = "->";
unary-operator:alias = plus | minus | binary-not | logical-not;
unary-expression = unary-operator primary-expression;
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
binary-op1:alias = binary-or | xor | add | sub;
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
binary-op3:alias = logical-and;
binary-op4:alias = logical-or;
operand0:alias = primary-expression | unary-expression;
operand1:alias = operand0 | binary0;
operand2:alias = operand1 | binary1;
operand3:alias = operand2 | binary2;
operand4:alias = operand3 | binary3;
operand5:alias = operand4 | binary4;
binary0 = operand0 (nl* binary-op0 nl* operand0)+;
binary1 = operand1 (nl* binary-op1 nl* operand1)+;
binary2 = operand2 (nl* binary-op2 nl* operand2)+;
binary3 = operand3 (nl* binary-op3 nl* operand3)+;
binary4 = operand4 (nl* binary-op4 nl* operand4)+;
binary-expression:alias = binary0
| binary1
| binary2
| binary3
| binary4;
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
chainingOperand:alias = primary-expression
| unary-expression
| binary-expression
| ternary-expression;
chaining = chainingOperand (nl* chain nl* chainingOperand)+;
expression:alias = primary-expression
| unary-expression
| binary-expression
| ternary-expression
| chaining;
if = "if" nl* expression nl* block
(nl* "else" nl* "if" nl* expression nl* block)*
(nl* "else" nl* block)?;
// TODO: empty switch not parsed
default = "default" nl* ":";
default-line:alias = default ";"* statement?;
case = "case" nl* expression nl* ":";
case-line:alias = case ";"* statement?;
switch = "switch" nl* expression? nl* "{" sep?
((case-line | default-line) (sep (case-line | default-line | statement))*)?
sep? "}";
send = "send" nl* primary-expression nl* primary-expression;
receive = "receive" nl* primary-expression;
receive-definition = symbol nl* receive;
communication:alias = send | receive | receive-definition;
select-case = "case" nl* communication nl* ":";
select-case-line:alias = select-case ";"* statement?;
select = "select" nl* "{" sep?
((select-case-line | default-line)
(sep (select-case-line | default-line | statement))*)?
sep? "}";
go = "go" nl* function-application;
defer = "defer" nl* function-application;
range-over-expression = symbol nl* "in" nl* (expression | range) | range;
loop-expression:alias = expression | range-over-expression;
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
// TODO: set(a b)
assign-capture:alias = primary-expression (nl* "=")? nl* expression;
assign-capture-list:alias = assign-capture (list-sep assign-capture)*;
assign-set:alias = "set" nl* assign-capture;
assign-eq:alias = primary-expression nl* "=" nl* expression;
assign-group:alias = "set" nl* "(" (list-sep assign-capture-list)? list-sep? ")";
assignment = assign-set | assign-eq | assign-group;
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
value-capture = value-capture-fact;
mutable-capture = "~" nl* value-capture-fact;
value-definition = "let" nl* (value-capture | mutable-capture);
mixed-capture-list:alias = (value-capture | mutable-capture) (list-sep (value-capture | mutable-capture))*;
value-capture-list:alias = value-capture (list-sep value-capture)*;
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
function-definition-fact:alias = symbol nl* function-fact;
function-capture = function-definition-fact;
effect-capture = "~" nl* function-definition-fact;
function-definition = "fn" nl* (function-capture | effect-capture);
function-capture-list:alias = function-capture (list-sep function-capture)*;
mixed-function-capture-list:alias = (function-capture | effect-capture)
(list-sep (function-capture | effect-capture))*;
function-definition-group = "fn" nl* "(" list-sep?
mixed-function-capture-list?
list-sep? ")";
effect-definition-group = "fn" nl* "~" nl* "(" list-sep?
function-capture-list?
list-sep? ")";
definition:alias = value-definition
| value-definition-group
| mutable-definition-group
| function-definition
| function-definition-group
| effect-definition-group;
// TODO:
// - use effect
// - rename to 'use'
use-inline = ".";
use-fact = string
| (symbol | use-inline) (nl* "=")? nl* string;
use-fact-list:alias = use-fact (list-sep use-fact)*;
use-statement:alias = "use" nl* use-fact;
use-statement-group:alias = "use" nl* "(" list-sep?
use-fact-list?
list-sep? ")";
use = use-statement | use-statement-group;
export = "export" nl* definition;
simple-statement:alias = send
| go
| defer
| assignment
| simple-statement-group
| expression;
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
statement:alias = return
| if
| switch
| select
| loop
| definition
| use
| export
| statement-group
| simple-statement;
statement-group:alias = "(" nl* statement nl* ")";
sep:alias = (";" | nl)+;
statement-list:alias = statement (sep statement)*;
shebang-command = [^\n]*;
shebang = "#!" shebang-command "\n";
mml:root = shebang? sep? statement-list? sep?;

271
examples/mml-exp3.treerack Normal file
View File

@ -0,0 +1,271 @@
ws:ws = " " | "\b" | "\f" | "\r" | "\t" | "\v";
wsc:ws = comment;
nl:alias = "\n";
wsep:alias = ws | nl;
line-comment-content:nows = [^\n]*;
line-comment:alias:nows = "//" line-comment-content;
block-comment-content:nows = ([^*] | "*" [^/])*;
block-comment:alias:nows = "/*" block-comment-content "*/";
comment-part:alias = line-comment | block-comment;
comment:alias = comment-part (nl? comment-part)*;
decimal-digit:alias = [0-9];
octal-digit:alias = [0-7];
hexa-digit:alias = [0-9a-fA-F];
decimal:alias:nows = [1-9] decimal-digit*;
octal:alias:nows = "0" octal-digit*;
hexa:alias:nows = "0" [xX] hexa-digit+;
int = decimal | octal | hexa;
exponent:alias:nows = [eE] [+\-]? decimal-digit+;
float:nows = decimal-digit+ "." decimal-digit* exponent?
| "." decimal-digit+ exponent?
| decimal-digit+ exponent;
string:nows = "\"" ([^\\"] | "\\" .)* "\"";
true = "true";
false = "false";
bool:alias = true | false;
symbol:nows = [a-zA-Z_][a-zA-Z_0-9]*;
spread-expression = primary-expression "...";
list-sep:alias = (nl | ",")+;
list-item:alias = expression | spread-expression;
expression-list:alias = list-item (list-sep list-item)*;
list-fact:alias = "[" list-sep? expression-list? list-sep? "]";
list = list-fact;
mutable-list = "~" nl* list-fact;
expression-key = "[" nl* expression nl* "]";
entry = (symbol | string | expression-key) nl* ":" nl* expression;
entry-list:alias = (entry | spread-expression) (list-sep (entry | spread-expression))*;
struct-fact:alias = "{" list-sep? entry-list? list-sep? "}";
struct = struct-fact;
mutable-struct = "~" nl* struct-fact;
parameter-list:alias = symbol (list-sep symbol)*;
collect-parameter = "..." nl* symbol;
return = "return" | "return" nl* expression;
block = "{" sep? statement-list? sep? "}";
function-fact:alias = "(" list-sep?
(parameter-list
| parameter-list list-sep collect-parameter
| collect-parameter)?
list-sep? ")" nl*
(expression | simple-statement | block);
function = "fn" nl* function-fact;
effect = "fn" nl* "~" nl* function-fact;
range-from = expression;
range-to = expression;
range:alias = range-from? nl* ":" nl* range-to?;
symbol-index = "." nl* symbol;
expression-index = "[" nl* expression nl* "]";
range-index = "[" nl* range nl* "]";
index:alias = symbol-index | expression-index | range-index;
index-list:alias = index (nl* index)?;
indexer = primary-expression nl* index-list;
application = primary-expression "(" list-sep? expression-list? list-sep? ")";
expression-group:alias = "(" nl* expression nl* ")";
primary-expression:alias = int
| float
| string
| bool
| symbol
| list
| mutable-list
| struct
| mutable-struct
| function
| effect
| indexer
| application
| receive
| expression-group;
binary-not = "^";
binary-and = "&";
binary-or = "|";
xor = "^";
and-not = "&^";
lshift = "<<";
rshift = ">>";
plus = "+";
minus = "-";
mul = "*";
div = "/";
mod = "%";
add = "+";
sub = "-";
logical-not = "!";
eq = "==";
not-eq = "!=";
less = "<";
less-or-eq = "<=";
greater = ">";
greater-or-eq = ">=";
logical-and = "&&";
logical-or = "||";
chain:alias = "->";
unary-operator:alias = plus | minus | binary-not | logical-not;
unary-expression = unary-operator primary-expression;
binary-op0:alias = binary-and | and-not | lshift | rshift | mul | div | mod;
binary-op1:alias = binary-or | xor | add | sub;
binary-op2:alias = eq | not-eq | less | less-or-eq | greater | greater-or-eq;
binary-op3:alias = logical-and;
binary-op4:alias = logical-or;
operand0:alias = primary-expression | unary-expression;
operand1:alias = operand0 | binary0;
operand2:alias = operand1 | binary1;
operand3:alias = operand2 | binary2;
operand4:alias = operand3 | binary3;
operand5:alias = operand4 | binary4;
binary0 = operand0 (nl* binary-op0 nl* operand0)+;
binary1 = operand1 (nl* binary-op1 nl* operand1)+;
binary2 = operand2 (nl* binary-op2 nl* operand2)+;
binary3 = operand3 (nl* binary-op3 nl* operand3)+;
binary4 = operand4 (nl* binary-op4 nl* operand4)+;
binary-expression:alias = binary0
| binary1
| binary2
| binary3
| binary4;
ternary-expression = expression nl* "?" nl* expression nl* ":" nl* expression;
chainingOperand:alias = primary-expression
| unary-expression
| binary-expression
| ternary-expression;
chaining = chainingOperand (nl* chain nl* chainingOperand)+;
expression:alias = primary-expression
| unary-expression
| binary-expression
| ternary-expression
| chaining;
if = "if" nl* expression nl* block
(nl* "else" nl* "if" nl* expression nl* block)*
(nl* "else" nl* block)?;
// TODO: empty switch not parsed
default = "default" nl* ":";
default-line:alias = default ";"* statement?;
case = "case" nl* expression nl* ":";
case-line:alias = case ";"* statement?;
switch = "switch" nl* expression? nl* "{" sep?
((case-line | default-line) (sep (case-line | default-line | statement))*)?
sep? "}";
send = "send" nl* primary-expression nl* primary-expression;
receive = "receive" nl* primary-expression;
receive-definition = symbol nl* receive;
communication:alias = send | receive | receive-definition;
select-case = "case" nl* communication nl* ":";
select-case-line:alias = select-case ";"* statement?;
select = "select" nl* "{" sep?
((select-case-line | default-line)
(sep (select-case-line | default-line | statement))*)?
sep? "}";
go = "go" nl* application;
defer = "defer" nl* application;
break = "break";
continue = "continue";
loop-control:alias = break | continue;
range-over = symbol nl* "in" nl* (expression | range) | range;
loop-expression:alias = expression | range-over;
loop = "for" ((nl* loop-expression)? nl* block | nl* block);
assignment = (symbol | indexer) nl* "=" nl* expression;
value-capture-fact:alias = symbol (nl* "=")? nl* expression;
value-capture = value-capture-fact;
mutable-capture = "~" nl* value-capture-fact;
value-definition = "let" nl* (value-capture | mutable-capture);
mixed-capture-list:alias = (value-capture | mutable-capture) (list-sep (value-capture | mutable-capture))*;
value-capture-list:alias = value-capture (list-sep value-capture)*;
value-definition-group = "let" nl* "(" list-sep? mixed-capture-list? list-sep? ")";
mutable-definition-group = "let" nl* "~" nl* "(" list-sep? value-capture-list? list-sep? ")";
function-definition-fact:alias = symbol nl* function-fact;
function-capture = function-definition-fact;
effect-capture = "~" nl* function-definition-fact;
function-definition = "fn" nl* (function-capture | effect-capture);
function-capture-list:alias = function-capture (list-sep function-capture)*;
mixed-function-capture-list:alias = (function-capture | effect-capture)
(list-sep (function-capture | effect-capture))*;
function-definition-group = "fn" nl* "(" list-sep?
mixed-function-capture-list?
list-sep? ")";
effect-definition-group = "fn" nl* "~" nl* "(" list-sep?
function-capture-list?
list-sep? ")";
definition:alias = value-definition
| value-definition-group
| mutable-definition-group
| function-definition
| function-definition-group
| effect-definition-group;
// TODO:
// - use effect
use-inline = ".";
use-fact = string
| (symbol | use-inline) (nl* "=")? nl* string;
use-fact-list:alias = use-fact (list-sep use-fact)*;
use-statement:alias = "use" nl* use-fact;
use-statement-group:alias = "use" nl* "(" list-sep?
use-fact-list?
list-sep? ")";
use = use-statement | use-statement-group;
export = "export" nl* definition;
simple-statement:alias = send
| go
| defer
| assignment
| simple-statement-group;
simple-statement-group:alias = "(" nl* simple-statement nl* ")";
statement:alias = simple-statement
| return
| if
| switch
| select
| loop
| loop-control
| definition
| use
| export
| application // TODO: sendSomething() and sendSomething
| chaining
| statement-group;
statement-group:alias = "(" nl* statement nl* ")";
sep:alias = (";" | nl)+;
statement-list:alias = statement (sep statement)*;
shebang-command = [^\n]*;
shebang = "#!" shebang-command "\n";
mml:root = shebang? sep? statement-list? sep?;

View File

@ -4,12 +4,12 @@ package treerack
// only to the source code generated with treerack. // only to the source code generated with treerack.
const gendoc = ` const gendoc = `
/* /*
This file was generated with treerack (https://github.com/aryszka/treerack). This file was generated with treerack (https://code.squareroundforest.org/arpio/treerack).
The contents of this file fall under different licenses. The contents of this file fall under different licenses.
The code between the "// head" and "// eo head" lines falls under the same The code between the "// head" and "// eo head" lines falls under the same
license as the source code of treerack (https://github.com/aryszka/treerack), license as the source code of treerack (https://code.squareroundforest.org/arpio/treerack),
unless explicitly stated otherwise, if treerack's license allows changing the unless explicitly stated otherwise, if treerack's license allows changing the
license of this source code. license of this source code.

10
go.mod Normal file
View File

@ -0,0 +1,10 @@
module code.squareroundforest.org/arpio/treerack
go 1.24.6
require golang.org/x/crypto v0.41.0
require (
golang.org/x/sys v0.35.0 // indirect
golang.org/x/term v0.34.0 // indirect
)

6
go.sum Normal file
View File

@ -0,0 +1,6 @@
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=

File diff suppressed because one or more lines are too long

23
keyword_test.go Normal file
View File

@ -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",
},
}})
}

59
mmlexp2_test.go Normal file
View File

@ -0,0 +1,59 @@
package treerack
import (
"testing"
)
func TestMMLExp2(t *testing.T) {
s, err := openSyntaxFile("examples/mml-exp2.treerack")
if err != nil {
t.Error(err)
return
}
t.Run("indexer", func(t *testing.T) {
runTestsSyntax(t, s, []testItem{{
title: "mixed indexer",
text: "a.b[c]",
ignorePosition: true,
nodes: []*Node{{
Name: "indexer",
Nodes: []*Node{{
Name: "symbol",
}, {
Name: "symbol-index",
Nodes: []*Node{{
Name: "symbol",
}},
}, {
Name: "expression-index",
Nodes: []*Node{{
Name: "symbol",
}},
}},
}},
}})
runTestsSyntax(t, s, []testItem{{
title: "mixed indexer inverted",
text: "a[b].c",
ignorePosition: true,
nodes: []*Node{{
Name: "indexer",
Nodes: []*Node{{
Name: "symbol",
}, {
Name: "expression-index",
Nodes: []*Node{{
Name: "symbol",
}},
}, {
Name: "symbol-index",
Nodes: []*Node{{
Name: "symbol",
}},
}},
}},
}})
})
}

45
mmlexp3_test.go Normal file
View File

@ -0,0 +1,45 @@
package treerack
import (
"testing"
)
func TestMMLExp3(t *testing.T) {
s, err := openSyntaxFile("examples/mml-exp3.treerack")
if err != nil {
t.Error(err)
return
}
t.Run("indexer", func(t *testing.T) {
runTestsSyntax(t, s, []testItem{{
title: "assignment",
text: "fn f() a.b = c",
ignorePosition: true,
nodes: []*Node{{
Name: "function-definition",
Nodes: []*Node{{
Name: "function-capture",
Nodes: []*Node{{
Name: "symbol",
}, {
Name: "assignment",
Nodes: []*Node{{
Name: "indexer",
Nodes: []*Node{{
Name: "symbol",
}, {
Name: "symbol-index",
Nodes: []*Node{{
Name: "symbol",
}},
}},
}, {
Name: "symbol",
}},
}},
}},
}},
}})
})
}

View File

@ -1,6 +1,6 @@
package treerack package treerack
import "github.com/aryszka/treerack/self" import "code.squareroundforest.org/arpio/treerack/self"
func mapNodes(m func(n *Node) *Node, n []*Node) []*Node { func mapNodes(m func(n *Node) *Node, n []*Node) []*Node {
var nn []*Node var nn []*Node

View File

@ -742,7 +742,7 @@ func TestCharBuildNoop(t *testing.T) {
c := newChar("foo", false, nil, nil) c := newChar("foo", false, nil, nil)
c.init(newRegistry()) c.init(newRegistry())
b := c.builder() 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 { if n, ok := b.build(ctx); len(n) != 0 || ok {
t.Error("char build not noop") t.Error("char build not noop")
} }

View File

@ -1,10 +1,10 @@
/* /*
This file was generated with treerack (https://github.com/aryszka/treerack). This file was generated with treerack (https://code.squareroundforest.org/arpio/treerack).
The contents of this file fall under different licenses. The contents of this file fall under different licenses.
The code between the "// head" and "// eo head" lines falls under the same The code between the "// head" and "// eo head" lines falls under the same
license as the source code of treerack (https://github.com/aryszka/treerack), license as the source code of treerack (https://code.squareroundforest.org/arpio/treerack),
unless explicitly stated otherwise, if treerack's license allows changing the unless explicitly stated otherwise, if treerack's license allows changing the
license of this source code. license of this source code.
@ -137,6 +137,17 @@ func (p *sequenceParser) parse(c *context) {
currentCount = 0 currentCount = 0
continue continue
} }
c.offset = from
if c.fromResults(p) {
if to > c.failOffset {
c.failOffset = -1
c.failingParser = nil
}
if !p.allChars {
c.results.unmarkPending(from, p.id)
}
return
}
if c.failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 && p.commit&FailPass == 0 { if c.failingParser == nil && p.commit&userDefined != 0 && p.commit&Whitespace == 0 && p.commit&FailPass == 0 {
c.failingParser = p c.failingParser = p
} }
@ -156,6 +167,16 @@ func (p *sequenceParser) parse(c *context) {
currentCount = 0 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 { for _, g := range p.generalizations {
if c.results.pending(from, g) { if c.results.pending(from, g) {
c.results.setMatch(from, g, to) c.results.setMatch(from, g, to)
@ -317,6 +338,14 @@ func (p *choiceParser) parse(c *context) {
} }
} }
if match { 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 { if failOffset > to {
c.failOffset = failOffset c.failOffset = failOffset
c.failingParser = failingParser c.failingParser = failingParser
@ -566,9 +595,11 @@ func (r *results) unmarkPending(offset, id int) {
type context struct { type context struct {
reader io.RuneReader reader io.RuneReader
keywords []parser
offset int offset int
readOffset int readOffset int
consumed int consumed int
offsetLimit int
failOffset int failOffset int
failingParser parser failingParser parser
readErr error readErr error
@ -578,8 +609,8 @@ type context struct {
matchLast bool matchLast bool
} }
func newContext(r io.RuneReader) *context { func newContext(r io.RuneReader, keywords []parser) *context {
return &context{reader: r, results: &results{}, failOffset: -1} return &context{reader: r, keywords: keywords, results: &results{}, offsetLimit: -1, failOffset: -1}
} }
func (c *context) read() bool { func (c *context) read() bool {
if c.eof || c.readErr != nil { if c.eof || c.readErr != nil {
@ -606,6 +637,9 @@ func (c *context) read() bool {
return true return true
} }
func (c *context) token() (rune, bool) { func (c *context) token() (rune, bool) {
if c.offset == c.offsetLimit {
return 0, false
}
if c.offset == c.readOffset { if c.offset == c.readOffset {
if !c.read() { if !c.read() {
return 0, false return 0, false
@ -625,6 +659,21 @@ func (c *context) fromResults(p parser) bool {
} }
return true 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) { func (c *context) success(to int) {
c.offset = to c.offset = to
c.matchLast = true c.matchLast = true
@ -702,6 +751,8 @@ const (
Alias CommitType = 1 << iota Alias CommitType = 1 << iota
Whitespace Whitespace
NoWhitespace NoWhitespace
Keyword
NoKeyword
FailPass FailPass
Root Root
userDefined userDefined
@ -739,8 +790,8 @@ var ErrInvalidUnicodeCharacter = errors.New("invalid unicode character")
func (pe *ParseError) Error() string { 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) 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) { func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) {
c := newContext(bufio.NewReader(r)) c := newContext(bufio.NewReader(r), kw)
p.parse(c) p.parse(c)
if c.readErr != nil { if c.readErr != nil {
return nil, c.readErr return nil, c.readErr
@ -758,35 +809,36 @@ func parseInput(r io.Reader, p parser, b builder) (*Node, error) {
} }
func Parse(r io.Reader) (*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 p196 = sequenceParser{id: 196, commit: 128, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}}
var p185 = choiceParser{id: 185, commit: 70, name: "wsc", generalizations: []int{186}} var p194 = choiceParser{id: 194, commit: 2}
var p15 = choiceParser{id: 15, commit: 66, name: "wschar", generalizations: []int{185, 186}} var p193 = choiceParser{id: 193, commit: 262, name: "wsc", generalizations: []int{194}}
var p2 = sequenceParser{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 185, 186}} 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}} var p1 = charParser{id: 1, chars: []rune{32}}
p2.items = []parser{&p1} 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}} var p3 = charParser{id: 3, chars: []rune{9}}
p4.items = []parser{&p3} 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}} var p5 = charParser{id: 5, chars: []rune{10}}
p6.items = []parser{&p5} 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}} var p7 = charParser{id: 7, chars: []rune{8}}
p8.items = []parser{&p7} 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}} var p9 = charParser{id: 9, chars: []rune{12}}
p10.items = []parser{&p9} 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}} var p11 = charParser{id: 11, chars: []rune{13}}
p12.items = []parser{&p11} 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}} var p13 = charParser{id: 13, chars: []rune{11}}
p14.items = []parser{&p13} p14.items = []parser{&p13}
p15.options = []parser{&p2, &p4, &p6, &p8, &p10, &p12, &p14} 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 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: 74, name: "comment-segment"} var p37 = choiceParser{id: 37, commit: 266, 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 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 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 p31 = charParser{id: 31, chars: []rune{47}}
var p32 = charParser{id: 32, chars: []rune{47}} var p32 = charParser{id: 32, chars: []rune{47}}
@ -795,7 +847,7 @@ func Parse(r io.Reader) (*Node, error) {
var p34 = charParser{id: 34, not: true, chars: []rune{10}} var p34 = charParser{id: 34, not: true, chars: []rune{10}}
p35.items = []parser{&p34} p35.items = []parser{&p34}
p36.items = []parser{&p33, &p35} 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 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 p16 = charParser{id: 16, chars: []rune{47}}
var p17 = charParser{id: 17, chars: []rune{42}} var p17 = charParser{id: 17, chars: []rune{42}}
@ -820,7 +872,7 @@ func Parse(r io.Reader) (*Node, error) {
p30.items = []parser{&p18, &p26, &p29} p30.items = []parser{&p18, &p26, &p29}
p37.options = []parser{&p36, &p30} 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 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 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}} var p38 = charParser{id: 38, chars: []rune{32}}
p39.items = []parser{&p38} p39.items = []parser{&p38}
@ -845,82 +897,92 @@ func Parse(r io.Reader) (*Node, error) {
p52.items = []parser{&p51} p52.items = []parser{&p51}
p53.items = []parser{&p50, &p52, &p50, &p37} p53.items = []parser{&p50, &p52, &p50, &p37}
p54.items = []parser{&p37, &p53} p54.items = []parser{&p37, &p53}
p185.options = []parser{&p15, &p54} p193.options = []parser{&p15, &p54}
p186.options = []parser{&p185} p194.options = []parser{&p193}
var p187 = sequenceParser{id: 187, commit: 66, name: "syntax:wsroot", ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} var p195 = sequenceParser{id: 195, commit: 258, 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 p190 = sequenceParser{id: 190, commit: 2, ranges: [][]int{{1, 1}, {0, -1}}}
var p178 = sequenceParser{id: 178, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p186 = sequenceParser{id: 186, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p177 = charParser{id: 177, chars: []rune{59}} var p185 = charParser{id: 185, chars: []rune{59}}
p178.items = []parser{&p177} p186.items = []parser{&p185}
var p181 = sequenceParser{id: 181, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var p189 = sequenceParser{id: 189, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
p181.items = []parser{&p186, &p178} p189.items = []parser{&p194, &p186}
p182.items = []parser{&p178, &p181} p190.items = []parser{&p186, &p189}
var p176 = sequenceParser{id: 176, commit: 66, name: "definitions", ranges: [][]int{{1, 1}, {0, 1}}} var p184 = sequenceParser{id: 184, commit: 258, 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 p177 = sequenceParser{id: 177, commit: 256, 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 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: 72, name: "symbol", ranges: [][]int{{1, -1}, {1, -1}}, generalizations: []int{133, 123, 127}} 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 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}} 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} p91.items = []parser{&p90}
p92.items = []parser{&p91} p92.items = []parser{&p91}
var p165 = sequenceParser{id: 165, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var p173 = sequenceParser{id: 173, 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 p172 = sequenceParser{id: 172, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p163 = charParser{id: 163, chars: []rune{58}} var p171 = charParser{id: 171, chars: []rune{58}}
p164.items = []parser{&p163} p172.items = []parser{&p171}
var p162 = choiceParser{id: 162, commit: 66, name: "flag"} var p170 = choiceParser{id: 170, commit: 258, 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 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 p134 = charParser{id: 134, chars: []rune{97}}
var p135 = charParser{id: 135, chars: []rune{108}} var p135 = charParser{id: 135, chars: []rune{108}}
var p136 = charParser{id: 136, chars: []rune{105}} var p136 = charParser{id: 136, chars: []rune{105}}
var p137 = charParser{id: 137, chars: []rune{97}} var p137 = charParser{id: 137, chars: []rune{97}}
var p138 = charParser{id: 138, chars: []rune{115}} var p138 = charParser{id: 138, chars: []rune{115}}
p139.items = []parser{&p134, &p135, &p136, &p137, &p138} 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 p140 = charParser{id: 140, chars: []rune{119}}
var p141 = charParser{id: 141, chars: []rune{115}} var p141 = charParser{id: 141, chars: []rune{115}}
p142.items = []parser{&p140, &p141} 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 p143 = charParser{id: 143, chars: []rune{110}}
var p144 = charParser{id: 144, chars: []rune{111}} var p144 = charParser{id: 144, chars: []rune{111}}
var p145 = charParser{id: 145, chars: []rune{119}} var p145 = charParser{id: 145, chars: []rune{119}}
var p146 = charParser{id: 146, chars: []rune{115}} var p146 = charParser{id: 146, chars: []rune{115}}
p147.items = []parser{&p143, &p144, &p145, &p146} 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 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{102}} var p148 = charParser{id: 148, chars: []rune{107}}
var p149 = charParser{id: 149, chars: []rune{97}} var p149 = charParser{id: 149, chars: []rune{119}}
var p150 = charParser{id: 150, chars: []rune{105}} p150.items = []parser{&p148, &p149}
var p151 = charParser{id: 151, chars: []rune{108}} 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 p152 = charParser{id: 152, chars: []rune{112}} var p151 = charParser{id: 151, chars: []rune{110}}
var p153 = charParser{id: 153, chars: []rune{97}} var p152 = charParser{id: 152, chars: []rune{111}}
var p154 = charParser{id: 154, chars: []rune{115}} var p153 = charParser{id: 153, chars: []rune{107}}
var p155 = charParser{id: 155, chars: []rune{115}} var p154 = charParser{id: 154, chars: []rune{119}}
p156.items = []parser{&p148, &p149, &p150, &p151, &p152, &p153, &p154, &p155} p155.items = []parser{&p151, &p152, &p153, &p154}
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 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 p157 = charParser{id: 157, chars: []rune{114}} var p156 = charParser{id: 156, chars: []rune{102}}
var p158 = charParser{id: 158, chars: []rune{111}} var p157 = charParser{id: 157, chars: []rune{97}}
var p159 = charParser{id: 159, chars: []rune{111}} var p158 = charParser{id: 158, chars: []rune{105}}
var p160 = charParser{id: 160, chars: []rune{116}} var p159 = charParser{id: 159, chars: []rune{108}}
p161.items = []parser{&p157, &p158, &p159, &p160} var p160 = charParser{id: 160, chars: []rune{112}}
p162.options = []parser{&p139, &p142, &p147, &p156, &p161} var p161 = charParser{id: 161, chars: []rune{97}}
p165.items = []parser{&p164, &p162} var p162 = charParser{id: 162, chars: []rune{115}}
p166.items = []parser{&p92, &p165} var p163 = charParser{id: 163, chars: []rune{115}}
var p168 = sequenceParser{id: 168, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} p164.items = []parser{&p156, &p157, &p158, &p159, &p160, &p161, &p162, &p163}
var p167 = charParser{id: 167, chars: []rune{61}} 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}}
p168.items = []parser{&p167} var p165 = charParser{id: 165, chars: []rune{114}}
var p133 = choiceParser{id: 133, commit: 66, name: "expression"} var p166 = charParser{id: 166, chars: []rune{111}}
var p89 = choiceParser{id: 89, commit: 66, name: "terminal", generalizations: []int{133, 123, 127}} var p167 = charParser{id: 167, chars: []rune{111}}
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 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}} var p55 = charParser{id: 55, chars: []rune{46}}
p56.items = []parser{&p55} 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 p71 = sequenceParser{id: 71, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p70 = charParser{id: 70, chars: []rune{91}} var p70 = charParser{id: 70, chars: []rune{91}}
p71.items = []parser{&p70} 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}} var p57 = charParser{id: 57, chars: []rune{94}}
p58.items = []parser{&p57} p58.items = []parser{&p57}
var p72 = choiceParser{id: 72, commit: 10} 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 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}} var p59 = charParser{id: 59, not: true, chars: []rune{92, 91, 93, 94, 45}}
p60.items = []parser{&p59} p60.items = []parser{&p59}
@ -933,7 +995,7 @@ func Parse(r io.Reader) (*Node, error) {
p64.items = []parser{&p63} p64.items = []parser{&p63}
p65.items = []parser{&p62, &p64} p65.items = []parser{&p62, &p64}
p66.options = []parser{&p60, &p65} 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 p68 = sequenceParser{id: 68, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p67 = charParser{id: 67, chars: []rune{45}} var p67 = charParser{id: 67, chars: []rune{45}}
p68.items = []parser{&p67} p68.items = []parser{&p67}
@ -943,11 +1005,11 @@ func Parse(r io.Reader) (*Node, error) {
var p73 = charParser{id: 73, chars: []rune{93}} var p73 = charParser{id: 73, chars: []rune{93}}
p74.items = []parser{&p73} p74.items = []parser{&p73}
p75.items = []parser{&p71, &p58, &p72, &p74} 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 p85 = sequenceParser{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p84 = charParser{id: 84, chars: []rune{34}} var p84 = charParser{id: 84, chars: []rune{34}}
p85.items = []parser{&p84} 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 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}} var p76 = charParser{id: 76, not: true, chars: []rune{92, 34}}
p77.items = []parser{&p76} p77.items = []parser{&p76}
@ -965,25 +1027,25 @@ func Parse(r io.Reader) (*Node, error) {
p87.items = []parser{&p86} p87.items = []parser{&p86}
p88.items = []parser{&p85, &p83, &p87} p88.items = []parser{&p85, &p83, &p87}
p89.options = []parser{&p56, &p75, &p88} 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 p94 = sequenceParser{id: 94, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p93 = charParser{id: 93, chars: []rune{40}} var p93 = charParser{id: 93, chars: []rune{40}}
p94.items = []parser{&p93} p94.items = []parser{&p93}
var p96 = sequenceParser{id: 96, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p96 = sequenceParser{id: 96, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p95 = charParser{id: 95, chars: []rune{41}} var p95 = charParser{id: 95, chars: []rune{41}}
p96.items = []parser{&p95} p96.items = []parser{&p95}
p97.items = []parser{&p94, &p186, &p133, &p186, &p96} p97.items = []parser{&p94, &p194, &p133, &p194, &p96}
var p126 = sequenceParser{id: 126, commit: 64, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}, generalizations: []int{133, 127}} 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: 72, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} 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} var p123 = choiceParser{id: 123, commit: 10}
p123.options = []parser{&p89, &p92, &p97} p123.options = []parser{&p89, &p92, &p97}
var p122 = choiceParser{id: 122, commit: 66, name: "quantity"} var p122 = choiceParser{id: 122, commit: 258, 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 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 p103 = sequenceParser{id: 103, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p102 = charParser{id: 102, chars: []rune{123}} var p102 = charParser{id: 102, chars: []rune{123}}
p103.items = []parser{&p102} p103.items = []parser{&p102}
var p101 = sequenceParser{id: 101, commit: 64, name: "count", ranges: [][]int{{1, 1}}} var p101 = sequenceParser{id: 101, commit: 256, name: "count", ranges: [][]int{{1, 1}}}
var p100 = sequenceParser{id: 100, commit: 74, name: "number", ranges: [][]int{{1, -1}, {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 p99 = sequenceParser{id: 99, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p98 = charParser{id: 98, ranges: [][]rune{{48, 57}}} var p98 = charParser{id: 98, ranges: [][]rune{{48, 57}}}
p99.items = []parser{&p98} p99.items = []parser{&p98}
@ -992,99 +1054,99 @@ func Parse(r io.Reader) (*Node, error) {
var p105 = sequenceParser{id: 105, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p105 = sequenceParser{id: 105, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p104 = charParser{id: 104, chars: []rune{125}} var p104 = charParser{id: 104, chars: []rune{125}}
p105.items = []parser{&p104} p105.items = []parser{&p104}
p106.items = []parser{&p103, &p186, &p101, &p186, &p105} p106.items = []parser{&p103, &p194, &p101, &p194, &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}} 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 p110 = sequenceParser{id: 110, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p109 = charParser{id: 109, chars: []rune{123}} var p109 = charParser{id: 109, chars: []rune{123}}
p110.items = []parser{&p109} 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} p107.items = []parser{&p100}
var p112 = sequenceParser{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p112 = sequenceParser{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p111 = charParser{id: 111, chars: []rune{44}} var p111 = charParser{id: 111, chars: []rune{44}}
p112.items = []parser{&p111} 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} p108.items = []parser{&p100}
var p114 = sequenceParser{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var p114 = sequenceParser{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p113 = charParser{id: 113, chars: []rune{125}} var p113 = charParser{id: 113, chars: []rune{125}}
p114.items = []parser{&p113} p114.items = []parser{&p113}
p115.items = []parser{&p110, &p186, &p107, &p186, &p112, &p186, &p108, &p186, &p114} p115.items = []parser{&p110, &p194, &p107, &p194, &p112, &p194, &p108, &p194, &p114}
var p117 = sequenceParser{id: 117, commit: 72, name: "one-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{122}} 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}} var p116 = charParser{id: 116, chars: []rune{43}}
p117.items = []parser{&p116} 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}} var p118 = charParser{id: 118, chars: []rune{42}}
p119.items = []parser{&p118} 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}} var p120 = charParser{id: 120, chars: []rune{63}}
p121.items = []parser{&p120} p121.items = []parser{&p120}
p122.options = []parser{&p106, &p115, &p117, &p119, &p121} p122.options = []parser{&p106, &p115, &p117, &p119, &p121}
p124.items = []parser{&p123, &p122} p124.items = []parser{&p123, &p122}
var p125 = sequenceParser{id: 125, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} 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} 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 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: 66, name: "option"} var p127 = choiceParser{id: 127, commit: 258, name: "option"}
p127.options = []parser{&p89, &p92, &p97, &p126} p127.options = []parser{&p89, &p92, &p97, &p126}
var p130 = sequenceParser{id: 130, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}} 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 p129 = sequenceParser{id: 129, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p128 = charParser{id: 128, chars: []rune{124}} var p128 = charParser{id: 128, chars: []rune{124}}
p129.items = []parser{&p128} 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}}} var p131 = sequenceParser{id: 131, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
p131.items = []parser{&p186, &p130} p131.items = []parser{&p194, &p130}
p132.items = []parser{&p127, &p186, &p130, &p131} p132.items = []parser{&p127, &p194, &p130, &p131}
p133.options = []parser{&p89, &p92, &p97, &p126, &p132} p133.options = []parser{&p89, &p92, &p97, &p126, &p132}
p169.items = []parser{&p166, &p186, &p168, &p186, &p133} p177.items = []parser{&p174, &p194, &p176, &p194, &p133}
var p175 = sequenceParser{id: 175, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} var p183 = sequenceParser{id: 183, 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 p181 = sequenceParser{id: 181, 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 p179 = sequenceParser{id: 179, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p170 = charParser{id: 170, chars: []rune{59}} var p178 = charParser{id: 178, chars: []rune{59}}
p171.items = []parser{&p170} p179.items = []parser{&p178}
var p172 = sequenceParser{id: 172, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var p180 = sequenceParser{id: 180, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
p172.items = []parser{&p186, &p171} p180.items = []parser{&p194, &p179}
p173.items = []parser{&p171, &p172, &p186, &p169} p181.items = []parser{&p179, &p180, &p194, &p177}
var p174 = sequenceParser{id: 174, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var p182 = sequenceParser{id: 182, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
p174.items = []parser{&p186, &p173} p182.items = []parser{&p194, &p181}
p175.items = []parser{&p186, &p173, &p174} p183.items = []parser{&p194, &p181, &p182}
p176.items = []parser{&p169, &p175} p184.items = []parser{&p177, &p183}
var p184 = sequenceParser{id: 184, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} var p192 = sequenceParser{id: 192, 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 p188 = sequenceParser{id: 188, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var p179 = charParser{id: 179, chars: []rune{59}} var p187 = charParser{id: 187, chars: []rune{59}}
p180.items = []parser{&p179} p188.items = []parser{&p187}
var p183 = sequenceParser{id: 183, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var p191 = sequenceParser{id: 191, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
p183.items = []parser{&p186, &p180} p191.items = []parser{&p194, &p188}
p184.items = []parser{&p186, &p180, &p183} p192.items = []parser{&p194, &p188, &p191}
p187.items = []parser{&p182, &p186, &p176, &p184} p195.items = []parser{&p190, &p194, &p184, &p192}
p188.items = []parser{&p186, &p187, &p186} p196.items = []parser{&p194, &p195, &p194}
var b188 = sequenceBuilder{id: 188, commit: 32, name: "syntax", ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} var b196 = sequenceBuilder{id: 196, commit: 128, name: "syntax", ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}}
var b186 = choiceBuilder{id: 186, commit: 2} var b194 = choiceBuilder{id: 194, commit: 2}
var b185 = choiceBuilder{id: 185, commit: 70} var b193 = choiceBuilder{id: 193, commit: 262, generalizations: []int{194}}
var b15 = choiceBuilder{id: 15, commit: 66} 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}}} var b2 = sequenceBuilder{id: 2, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}}
var b1 = charBuilder{} var b1 = charBuilder{}
b2.items = []builder{&b1} b2.items = []builder{&b1}
var b4 = sequenceBuilder{id: 4, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b4 = sequenceBuilder{id: 4, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}}
var b3 = charBuilder{} var b3 = charBuilder{}
b4.items = []builder{&b3} b4.items = []builder{&b3}
var b6 = sequenceBuilder{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b6 = sequenceBuilder{id: 6, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}}
var b5 = charBuilder{} var b5 = charBuilder{}
b6.items = []builder{&b5} b6.items = []builder{&b5}
var b8 = sequenceBuilder{id: 8, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b8 = sequenceBuilder{id: 8, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}}
var b7 = charBuilder{} var b7 = charBuilder{}
b8.items = []builder{&b7} b8.items = []builder{&b7}
var b10 = sequenceBuilder{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b10 = sequenceBuilder{id: 10, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}}
var b9 = charBuilder{} var b9 = charBuilder{}
b10.items = []builder{&b9} b10.items = []builder{&b9}
var b12 = sequenceBuilder{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b12 = sequenceBuilder{id: 12, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}}
var b11 = charBuilder{} var b11 = charBuilder{}
b12.items = []builder{&b11} b12.items = []builder{&b11}
var b14 = sequenceBuilder{id: 14, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b14 = sequenceBuilder{id: 14, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{15, 193, 194}}
var b13 = charBuilder{} var b13 = charBuilder{}
b14.items = []builder{&b13} b14.items = []builder{&b13}
b15.options = []builder{&b2, &b4, &b6, &b8, &b10, &b12, &b14} 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}}} 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: 74} var b37 = choiceBuilder{id: 37, commit: 266}
var b36 = sequenceBuilder{id: 36, commit: 74, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} 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 b33 = sequenceBuilder{id: 33, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}}
var b31 = charBuilder{} var b31 = charBuilder{}
var b32 = charBuilder{} var b32 = charBuilder{}
@ -1093,13 +1155,13 @@ func Parse(r io.Reader) (*Node, error) {
var b34 = charBuilder{} var b34 = charBuilder{}
b35.items = []builder{&b34} b35.items = []builder{&b34}
b36.items = []builder{&b33, &b35} 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}}} 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 b18 = sequenceBuilder{id: 18, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}}
var b16 = charBuilder{} var b16 = charBuilder{}
var b17 = charBuilder{} var b17 = charBuilder{}
b18.items = []builder{&b16, &b17} b18.items = []builder{&b16, &b17}
var b26 = choiceBuilder{id: 26, commit: 10} var b26 = choiceBuilder{id: 26, commit: 10}
var b23 = sequenceBuilder{id: 23, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var b23 = sequenceBuilder{id: 23, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{26}}
var b20 = sequenceBuilder{id: 20, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b20 = sequenceBuilder{id: 20, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b19 = charBuilder{} var b19 = charBuilder{}
b20.items = []builder{&b19} b20.items = []builder{&b19}
@ -1107,7 +1169,7 @@ func Parse(r io.Reader) (*Node, error) {
var b21 = charBuilder{} var b21 = charBuilder{}
b22.items = []builder{&b21} b22.items = []builder{&b21}
b23.items = []builder{&b20, &b22} b23.items = []builder{&b20, &b22}
var b25 = sequenceBuilder{id: 25, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b25 = sequenceBuilder{id: 25, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{26}}
var b24 = charBuilder{} var b24 = charBuilder{}
b25.items = []builder{&b24} b25.items = []builder{&b24}
b26.options = []builder{&b23, &b25} b26.options = []builder{&b23, &b25}
@ -1118,23 +1180,23 @@ func Parse(r io.Reader) (*Node, error) {
b30.items = []builder{&b18, &b26, &b29} b30.items = []builder{&b18, &b26, &b29}
b37.options = []builder{&b36, &b30} 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 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}}} var b39 = sequenceBuilder{id: 39, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}}
var b38 = charBuilder{} var b38 = charBuilder{}
b39.items = []builder{&b38} b39.items = []builder{&b38}
var b41 = sequenceBuilder{id: 41, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b41 = sequenceBuilder{id: 41, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}}
var b40 = charBuilder{} var b40 = charBuilder{}
b41.items = []builder{&b40} b41.items = []builder{&b40}
var b43 = sequenceBuilder{id: 43, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b43 = sequenceBuilder{id: 43, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}}
var b42 = charBuilder{} var b42 = charBuilder{}
b43.items = []builder{&b42} b43.items = []builder{&b42}
var b45 = sequenceBuilder{id: 45, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b45 = sequenceBuilder{id: 45, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}}
var b44 = charBuilder{} var b44 = charBuilder{}
b45.items = []builder{&b44} b45.items = []builder{&b44}
var b47 = sequenceBuilder{id: 47, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b47 = sequenceBuilder{id: 47, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}}
var b46 = charBuilder{} var b46 = charBuilder{}
b47.items = []builder{&b46} b47.items = []builder{&b46}
var b49 = sequenceBuilder{id: 49, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b49 = sequenceBuilder{id: 49, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{50}}
var b48 = charBuilder{} var b48 = charBuilder{}
b49.items = []builder{&b48} b49.items = []builder{&b48}
b50.options = []builder{&b39, &b41, &b43, &b45, &b47, &b49} b50.options = []builder{&b39, &b41, &b43, &b45, &b47, &b49}
@ -1143,86 +1205,96 @@ func Parse(r io.Reader) (*Node, error) {
b52.items = []builder{&b51} b52.items = []builder{&b51}
b53.items = []builder{&b50, &b52, &b50, &b37} b53.items = []builder{&b50, &b52, &b50, &b37}
b54.items = []builder{&b37, &b53} b54.items = []builder{&b37, &b53}
b185.options = []builder{&b15, &b54} b193.options = []builder{&b15, &b54}
b186.options = []builder{&b185} b194.options = []builder{&b193}
var b187 = sequenceBuilder{id: 187, commit: 66, ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}} var b195 = sequenceBuilder{id: 195, commit: 258, ranges: [][]int{{0, 1}, {0, -1}, {0, 1}, {0, 1}}}
var b182 = sequenceBuilder{id: 182, commit: 2, ranges: [][]int{{1, 1}, {0, -1}}} var b190 = sequenceBuilder{id: 190, commit: 2, ranges: [][]int{{1, 1}, {0, -1}}}
var b178 = sequenceBuilder{id: 178, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b186 = sequenceBuilder{id: 186, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b177 = charBuilder{} var b185 = charBuilder{}
b178.items = []builder{&b177} b186.items = []builder{&b185}
var b181 = sequenceBuilder{id: 181, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var b189 = sequenceBuilder{id: 189, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
b181.items = []builder{&b186, &b178} b189.items = []builder{&b194, &b186}
b182.items = []builder{&b178, &b181} b190.items = []builder{&b186, &b189}
var b176 = sequenceBuilder{id: 176, commit: 66, ranges: [][]int{{1, 1}, {0, 1}}} var b184 = sequenceBuilder{id: 184, commit: 258, 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 b177 = sequenceBuilder{id: 177, commit: 256, 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 b174 = sequenceBuilder{id: 174, commit: 266, 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}}} 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 b91 = sequenceBuilder{id: 91, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b90 = charBuilder{} var b90 = charBuilder{}
b91.items = []builder{&b90} b91.items = []builder{&b90}
b92.items = []builder{&b91} b92.items = []builder{&b91}
var b165 = sequenceBuilder{id: 165, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var b173 = sequenceBuilder{id: 173, 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 b172 = sequenceBuilder{id: 172, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b163 = charBuilder{} var b171 = charBuilder{}
b164.items = []builder{&b163} b172.items = []builder{&b171}
var b162 = choiceBuilder{id: 162, commit: 66} var b170 = choiceBuilder{id: 170, commit: 258}
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}}} 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 b134 = charBuilder{}
var b135 = charBuilder{} var b135 = charBuilder{}
var b136 = charBuilder{} var b136 = charBuilder{}
var b137 = charBuilder{} var b137 = charBuilder{}
var b138 = charBuilder{} var b138 = charBuilder{}
b139.items = []builder{&b134, &b135, &b136, &b137, &b138} 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}}} 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 b140 = charBuilder{}
var b141 = charBuilder{} var b141 = charBuilder{}
b142.items = []builder{&b140, &b141} 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}}} 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 b143 = charBuilder{}
var b144 = charBuilder{} var b144 = charBuilder{}
var b145 = charBuilder{} var b145 = charBuilder{}
var b146 = charBuilder{} var b146 = charBuilder{}
b147.items = []builder{&b143, &b144, &b145, &b146} 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}}} 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 b148 = charBuilder{}
var b149 = 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 b151 = charBuilder{}
var b152 = charBuilder{} var b152 = charBuilder{}
var b153 = charBuilder{} var b153 = charBuilder{}
var b154 = charBuilder{} var b154 = charBuilder{}
var b155 = charBuilder{} b155.items = []builder{&b151, &b152, &b153, &b154}
b156.items = []builder{&b148, &b149, &b150, &b151, &b152, &b153, &b154, &b155} 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 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}}} var b156 = charBuilder{}
var b157 = charBuilder{} var b157 = charBuilder{}
var b158 = charBuilder{} var b158 = charBuilder{}
var b159 = charBuilder{} var b159 = charBuilder{}
var b160 = charBuilder{} var b160 = charBuilder{}
b161.items = []builder{&b157, &b158, &b159, &b160} var b161 = charBuilder{}
b162.options = []builder{&b139, &b142, &b147, &b156, &b161} var b162 = charBuilder{}
b165.items = []builder{&b164, &b162} var b163 = charBuilder{}
b166.items = []builder{&b92, &b165} b164.items = []builder{&b156, &b157, &b158, &b159, &b160, &b161, &b162, &b163}
var b168 = sequenceBuilder{id: 168, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} 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{} var b167 = charBuilder{}
b168.items = []builder{&b167} var b168 = charBuilder{}
var b133 = choiceBuilder{id: 133, commit: 66} b169.items = []builder{&b165, &b166, &b167, &b168}
var b89 = choiceBuilder{id: 89, commit: 66} b170.options = []builder{&b139, &b142, &b147, &b150, &b155, &b164, &b169}
var b56 = sequenceBuilder{id: 56, commit: 72, name: "any-char", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} 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{} var b55 = charBuilder{}
b56.items = []builder{&b55} 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}}} 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 b71 = sequenceBuilder{id: 71, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b70 = charBuilder{} var b70 = charBuilder{}
b71.items = []builder{&b70} 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{} var b57 = charBuilder{}
b58.items = []builder{&b57} b58.items = []builder{&b57}
var b72 = choiceBuilder{id: 72, commit: 10} var b72 = choiceBuilder{id: 72, commit: 10}
var b66 = choiceBuilder{id: 66, commit: 72, name: "class-char"} 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}}} var b60 = sequenceBuilder{id: 60, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{66, 72}}
var b59 = charBuilder{} var b59 = charBuilder{}
b60.items = []builder{&b59} b60.items = []builder{&b59}
var b65 = sequenceBuilder{id: 65, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var b65 = sequenceBuilder{id: 65, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{66, 72}}
var b62 = sequenceBuilder{id: 62, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b62 = sequenceBuilder{id: 62, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b61 = charBuilder{} var b61 = charBuilder{}
b62.items = []builder{&b61} b62.items = []builder{&b61}
@ -1231,7 +1303,7 @@ func Parse(r io.Reader) (*Node, error) {
b64.items = []builder{&b63} b64.items = []builder{&b63}
b65.items = []builder{&b62, &b64} b65.items = []builder{&b62, &b64}
b66.options = []builder{&b60, &b65} 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}}} 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 b68 = sequenceBuilder{id: 68, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b67 = charBuilder{} var b67 = charBuilder{}
b68.items = []builder{&b67} b68.items = []builder{&b67}
@ -1241,15 +1313,15 @@ func Parse(r io.Reader) (*Node, error) {
var b73 = charBuilder{} var b73 = charBuilder{}
b74.items = []builder{&b73} b74.items = []builder{&b73}
b75.items = []builder{&b71, &b58, &b72, &b74} 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}}} 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 b85 = sequenceBuilder{id: 85, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b84 = charBuilder{} var b84 = charBuilder{}
b85.items = []builder{&b84} 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}}} var b77 = sequenceBuilder{id: 77, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}, generalizations: []int{83}}
var b76 = charBuilder{} var b76 = charBuilder{}
b77.items = []builder{&b76} b77.items = []builder{&b76}
var b82 = sequenceBuilder{id: 82, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}} var b82 = sequenceBuilder{id: 82, commit: 10, ranges: [][]int{{1, 1}, {1, 1}, {1, 1}, {1, 1}}, generalizations: []int{83}}
var b79 = sequenceBuilder{id: 79, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b79 = sequenceBuilder{id: 79, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b78 = charBuilder{} var b78 = charBuilder{}
b79.items = []builder{&b78} b79.items = []builder{&b78}
@ -1263,25 +1335,25 @@ func Parse(r io.Reader) (*Node, error) {
b87.items = []builder{&b86} b87.items = []builder{&b86}
b88.items = []builder{&b85, &b83, &b87} b88.items = []builder{&b85, &b83, &b87}
b89.options = []builder{&b56, &b75, &b88} 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}}} 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 b94 = sequenceBuilder{id: 94, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b93 = charBuilder{} var b93 = charBuilder{}
b94.items = []builder{&b93} b94.items = []builder{&b93}
var b96 = sequenceBuilder{id: 96, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b96 = sequenceBuilder{id: 96, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b95 = charBuilder{} var b95 = charBuilder{}
b96.items = []builder{&b95} b96.items = []builder{&b95}
b97.items = []builder{&b94, &b186, &b133, &b186, &b96} b97.items = []builder{&b94, &b194, &b133, &b194, &b96}
var b126 = sequenceBuilder{id: 126, commit: 64, name: "sequence", ranges: [][]int{{1, 1}, {0, -1}}} 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: 72, name: "item", ranges: [][]int{{1, 1}, {0, 1}, {1, 1}, {0, 1}}} 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} var b123 = choiceBuilder{id: 123, commit: 10}
b123.options = []builder{&b89, &b92, &b97} b123.options = []builder{&b89, &b92, &b97}
var b122 = choiceBuilder{id: 122, commit: 66} var b122 = choiceBuilder{id: 122, commit: 258}
var b106 = sequenceBuilder{id: 106, commit: 64, name: "count-quantifier", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}, {1, 1}}} 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 b103 = sequenceBuilder{id: 103, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b102 = charBuilder{} var b102 = charBuilder{}
b103.items = []builder{&b102} b103.items = []builder{&b102}
var b101 = sequenceBuilder{id: 101, commit: 64, name: "count", ranges: [][]int{{1, 1}}} var b101 = sequenceBuilder{id: 101, commit: 256, name: "count", ranges: [][]int{{1, 1}}}
var b100 = sequenceBuilder{id: 100, commit: 74, ranges: [][]int{{1, -1}, {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 b99 = sequenceBuilder{id: 99, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b98 = charBuilder{} var b98 = charBuilder{}
b99.items = []builder{&b98} b99.items = []builder{&b98}
@ -1290,70 +1362,72 @@ func Parse(r io.Reader) (*Node, error) {
var b105 = sequenceBuilder{id: 105, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b105 = sequenceBuilder{id: 105, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b104 = charBuilder{} var b104 = charBuilder{}
b105.items = []builder{&b104} b105.items = []builder{&b104}
b106.items = []builder{&b103, &b186, &b101, &b186, &b105} b106.items = []builder{&b103, &b194, &b101, &b194, &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}}} 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 b110 = sequenceBuilder{id: 110, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b109 = charBuilder{} var b109 = charBuilder{}
b110.items = []builder{&b109} 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} b107.items = []builder{&b100}
var b112 = sequenceBuilder{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b112 = sequenceBuilder{id: 112, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b111 = charBuilder{} var b111 = charBuilder{}
b112.items = []builder{&b111} 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} b108.items = []builder{&b100}
var b114 = sequenceBuilder{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} var b114 = sequenceBuilder{id: 114, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b113 = charBuilder{} var b113 = charBuilder{}
b114.items = []builder{&b113} b114.items = []builder{&b113}
b115.items = []builder{&b110, &b186, &b107, &b186, &b112, &b186, &b108, &b186, &b114} b115.items = []builder{&b110, &b194, &b107, &b194, &b112, &b194, &b108, &b194, &b114}
var b117 = sequenceBuilder{id: 117, commit: 72, name: "one-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} 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{} var b116 = charBuilder{}
b117.items = []builder{&b116} b117.items = []builder{&b116}
var b119 = sequenceBuilder{id: 119, commit: 72, name: "zero-or-more", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} 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{} var b118 = charBuilder{}
b119.items = []builder{&b118} b119.items = []builder{&b118}
var b121 = sequenceBuilder{id: 121, commit: 72, name: "zero-or-one", allChars: true, ranges: [][]int{{1, 1}, {1, 1}}} 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{} var b120 = charBuilder{}
b121.items = []builder{&b120} b121.items = []builder{&b120}
b122.options = []builder{&b106, &b115, &b117, &b119, &b121} b122.options = []builder{&b106, &b115, &b117, &b119, &b121}
b124.items = []builder{&b123, &b122} b124.items = []builder{&b123, &b122}
var b125 = sequenceBuilder{id: 125, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} 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} b126.items = []builder{&b124, &b125}
var b132 = sequenceBuilder{id: 132, commit: 64, name: "choice", ranges: [][]int{{1, 1}, {0, -1}, {1, 1}, {0, -1}}} 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: 66} var b127 = choiceBuilder{id: 127, commit: 258}
b127.options = []builder{&b89, &b92, &b97, &b126} b127.options = []builder{&b89, &b92, &b97, &b126}
var b130 = sequenceBuilder{id: 130, commit: 2, ranges: [][]int{{1, 1}, {0, -1}, {1, 1}}} 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 b129 = sequenceBuilder{id: 129, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b128 = charBuilder{} var b128 = charBuilder{}
b129.items = []builder{&b128} 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}}} var b131 = sequenceBuilder{id: 131, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
b131.items = []builder{&b186, &b130} b131.items = []builder{&b194, &b130}
b132.items = []builder{&b127, &b186, &b130, &b131} b132.items = []builder{&b127, &b194, &b130, &b131}
b133.options = []builder{&b89, &b92, &b97, &b126, &b132} b133.options = []builder{&b89, &b92, &b97, &b126, &b132}
b169.items = []builder{&b166, &b186, &b168, &b186, &b133} b177.items = []builder{&b174, &b194, &b176, &b194, &b133}
var b175 = sequenceBuilder{id: 175, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} var b183 = sequenceBuilder{id: 183, 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 b181 = sequenceBuilder{id: 181, 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 b179 = sequenceBuilder{id: 179, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b170 = charBuilder{} var b178 = charBuilder{}
b171.items = []builder{&b170} b179.items = []builder{&b178}
var b172 = sequenceBuilder{id: 172, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var b180 = sequenceBuilder{id: 180, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
b172.items = []builder{&b186, &b171} b180.items = []builder{&b194, &b179}
b173.items = []builder{&b171, &b172, &b186, &b169} b181.items = []builder{&b179, &b180, &b194, &b177}
var b174 = sequenceBuilder{id: 174, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var b182 = sequenceBuilder{id: 182, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
b174.items = []builder{&b186, &b173} b182.items = []builder{&b194, &b181}
b175.items = []builder{&b186, &b173, &b174} b183.items = []builder{&b194, &b181, &b182}
b176.items = []builder{&b169, &b175} b184.items = []builder{&b177, &b183}
var b184 = sequenceBuilder{id: 184, commit: 2, ranges: [][]int{{0, -1}, {1, 1}, {0, -1}}} var b192 = sequenceBuilder{id: 192, 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 b188 = sequenceBuilder{id: 188, commit: 10, allChars: true, ranges: [][]int{{1, 1}, {1, 1}}}
var b179 = charBuilder{} var b187 = charBuilder{}
b180.items = []builder{&b179} b188.items = []builder{&b187}
var b183 = sequenceBuilder{id: 183, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}} var b191 = sequenceBuilder{id: 191, commit: 2, ranges: [][]int{{0, -1}, {1, 1}}}
b183.items = []builder{&b186, &b180} b191.items = []builder{&b194, &b188}
b184.items = []builder{&b186, &b180, &b183} b192.items = []builder{&b194, &b188, &b191}
b187.items = []builder{&b182, &b186, &b176, &b184} b195.items = []builder{&b190, &b194, &b184, &b192}
b188.items = []builder{&b186, &b187, &b186} b196.items = []builder{&b194, &b195, &b194}
return parseInput(r, &p188, &b188) var keywords = []parser{}
return parseInput(r, &p196, &b196, keywords)
} }

View File

@ -52,6 +52,20 @@ func (p *sequenceParser) parse(c *context) {
continue continue
} }
c.offset = from
if c.fromResults(p) {
if to > c.failOffset {
c.failOffset = -1
c.failingParser = nil
}
if !p.allChars {
c.results.unmarkPending(from, p.id)
}
return
}
if c.failingParser == nil && if c.failingParser == nil &&
p.commit&userDefined != 0 && p.commit&userDefined != 0 &&
p.commit&Whitespace == 0 && p.commit&Whitespace == 0 &&
@ -80,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 { for _, g := range p.generalizations {
if c.results.pending(from, g) { if c.results.pending(from, g) {
c.results.setMatch(from, g, to) c.results.setMatch(from, g, to)

View File

@ -394,6 +394,15 @@ func (b *sequenceBuilder) generate(w io.Writer, done map[string]bool) error {
fprintf("},") fprintf("},")
} }
if len(b.generalizations) > 0 {
fprintf("generalizations: []int{")
for i := range b.generalizations {
fprintf("%d,", b.generalizations[i])
}
fprintf("},")
}
fprintf("};") fprintf("};")
if len(b.items) > 0 { if len(b.items) > 0 {

130
syntax.go
View File

@ -4,8 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"code.squareroundforest.org/arpio/treerack/self"
"github.com/aryszka/treerack/self"
) )
// if min=0&&max=0, it means min=1,max=1 // if min=0&&max=0, it means min=1,max=1
@ -21,9 +20,8 @@ type Syntax struct {
initialized bool initialized bool
initFailed bool initFailed bool
explicitRoot bool explicitRoot bool
keywords []definition
root definition root definition
parser parser
builder builder
} }
type GeneratorOptions struct { type GeneratorOptions struct {
@ -57,13 +55,33 @@ var (
ErrInitFailed = errors.New("init failed") ErrInitFailed = errors.New("init failed")
ErrNoParsersDefined = errors.New("no parsers defined") ErrNoParsersDefined = errors.New("no parsers defined")
ErrInvalidEscapeCharacter = errors.New("invalid escape character") 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") ErrMultipleRoots = errors.New("multiple roots")
ErrInvalidSymbolName = errors.New("invalid symbol name") 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 { func duplicateDefinition(name string) error {
return fmt.Errorf("duplicate definition: %s", name) return fmt.Errorf("duplicate definition: %s", name)
} }
@ -100,6 +118,36 @@ func intsContain(is []int, i int) bool {
return false 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 { func (s *Syntax) applyRoot(d definition) error {
explicitRoot := d.commitType()&Root != 0 explicitRoot := d.commitType()&Root != 0
if explicitRoot && s.explicitRoot { if explicitRoot && s.explicitRoot {
@ -131,10 +179,18 @@ func (s *Syntax) register(d definition) error {
s.registry = newRegistry() s.registry = newRegistry()
} }
if err := s.checkCommitType(d); err != nil {
return err
}
if err := s.applyRoot(d); err != nil { if err := s.applyRoot(d); err != nil {
return err return err
} }
if d.commitType()&Keyword != 0 {
s.keywords = append(s.keywords, d)
}
return s.registry.setDefinition(d) return s.registry.setDefinition(d)
} }
@ -252,20 +308,12 @@ func (s *Syntax) Init() error {
return ErrNoParsersDefined return ErrNoParsersDefined
} }
if s.root.commitType()&Alias != 0 { if err := s.checkCommitType(s.root); err != nil {
return ErrRootAlias return err
}
if s.root.commitType()&Whitespace != 0 {
return ErrRootWhitespace
}
if s.root.commitType()&FailPass != 0 {
return ErrRootFailPass
} }
defs := s.registry.definitions defs := s.registry.definitions
for i := range s.registry.definitions { for i := range defs {
defs[i].preinit() defs[i].preinit()
} }
@ -274,19 +322,36 @@ func (s *Syntax) Init() error {
s.registry = newRegistry(defs...) 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 { if err := s.root.validate(s.registry); err != nil {
s.initFailed = true s.initFailed = true
return err return err
} }
s.root.init(s.registry) for i := range s.keywords {
s.parser = s.root.parser() s.keywords[i].init(s.registry)
s.builder = s.root.builder() }
s.root.init(s.registry)
s.initialized = true s.initialized = true
return nil 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) Generate(o GeneratorOptions, w io.Writer) error { func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error {
if err := s.Init(); err != nil { if err := s.Init(); err != nil {
return err return err
@ -339,18 +404,33 @@ func (s *Syntax) Generate(o GeneratorOptions, w io.Writer) error {
fprintln() fprintln()
done := make(map[string]bool) done := make(map[string]bool)
if err := s.parser.(generator).generate(w, done); err != nil { for _, p := range s.keywordParsers() {
if err := p.(generator).generate(w, done); err != nil {
return err
}
}
fprintln()
if err := s.root.parser().(generator).generate(w, done); err != nil {
return err return err
} }
done = make(map[string]bool) 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 return err
} }
fprintln() fprintln()
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() fprintln()
fprint(`}`) fprint(`}`)
fprintln() fprintln()
@ -363,5 +443,5 @@ func (s *Syntax) Parse(r io.Reader) (*Node, error) {
return nil, err return nil, err
} }
return parseInput(r, s.parser, s.builder) return parseInput(r, s.root.parser(), s.root.builder(), s.keywordParsers())
} }

View File

@ -59,9 +59,11 @@ expression:alias = terminal
alias = "alias"; alias = "alias";
ws = "ws"; ws = "ws";
nows = "nows"; nows = "nows";
kw = "kw";
nokw = "nokw";
failpass = "failpass"; failpass = "failpass";
root = "root"; 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-name:alias:nows = symbol (":" flag)*;
definition = definition-name "=" expression; definition = definition-name "=" expression;

View File

@ -137,24 +137,14 @@ func TestInit(t *testing.T) {
t.Run("root is an alias", func(t *testing.T) { t.Run("root is an alias", func(t *testing.T) {
s := &Syntax{} s := &Syntax{}
if err := s.AnyChar("a", Root|Alias); err != nil { if err := s.AnyChar("a", Root|Alias); err == nil {
t.Error(err)
return
}
if err := s.Init(); err == nil {
t.Error("failed to fail") t.Error("failed to fail")
} }
}) })
t.Run("root is whitespace", func(t *testing.T) { t.Run("root is whitespace", func(t *testing.T) {
s := &Syntax{} s := &Syntax{}
if err := s.AnyChar("a", Root|Whitespace); err != nil { if err := s.AnyChar("a", Root|Whitespace); err == nil {
t.Error(err)
return
}
if err := s.Init(); err == nil {
t.Error("failed to fail") t.Error("failed to fail")
} }
}) })

View File

@ -14,6 +14,8 @@ const (
Alias CommitType = 1 << iota Alias CommitType = 1 << iota
Whitespace Whitespace
NoWhitespace NoWhitespace
Keyword
NoKeyword
FailPass FailPass
Root Root
@ -80,8 +82,8 @@ func (pe *ParseError) Error() string {
) )
} }
func parseInput(r io.Reader, p parser, b builder) (*Node, error) { func parseInput(r io.Reader, p parser, b builder, kw []parser) (*Node, error) {
c := newContext(bufio.NewReader(r)) c := newContext(bufio.NewReader(r), kw)
p.parse(c) p.parse(c)
if c.readErr != nil { if c.readErr != nil {
return nil, c.readErr return nil, c.readErr