diff --git a/boot.go b/boot.go index 0f5c932..f454552 100644 --- a/boot.go +++ b/boot.go @@ -97,7 +97,7 @@ func parseClass(class []rune) (not bool, chars []rune, ranges [][]rune, err erro func defineBootAnything(s *Syntax, d []string) error { ct := stringToCommitType(d[2]) - return s.AnyChar(d[1], ct) + return s.anyChar(d[1], ct) } func defineBootClass(s *Syntax, d []string) error { @@ -109,7 +109,7 @@ func defineBootClass(s *Syntax, d []string) error { return err } - return s.Class(name, ct, not, chars, ranges) + return s.class(name, ct, not, chars, ranges) } func defineBootCharSequence(s *Syntax, d []string) error { @@ -121,7 +121,7 @@ func defineBootCharSequence(s *Syntax, d []string) error { return err } - return s.CharSequence(name, ct, chars) + return s.charSequence(name, ct, chars) } func splitQuantifiedSymbol(s string) (string, int, int) { @@ -159,14 +159,14 @@ func defineBootSequence(s *Syntax, defs []string) error { name := defs[1] ct := stringToCommitType(defs[2]) items := namesToSequenceItemsQuantify(defs[3:]) - return s.Sequence(name, ct, items...) + return s.sequence(name, ct, items...) } func defineBootChoice(s *Syntax, defs []string) error { name := defs[1] ct := stringToCommitType(defs[2]) items := defs[3:] - return s.Choice(name, ct, items...) + return s.choice(name, ct, items...) } func defineBoot(s *Syntax, defs []string) error { @@ -197,7 +197,7 @@ func defineAllBoot(s *Syntax, defs [][]string) error { } func createBoot() (*Syntax, error) { - s := NewSyntax() + s := &Syntax{} if err := defineAllBoot(s, bootSyntaxDefs); err != nil { return nil, err } @@ -211,7 +211,7 @@ func bootSyntax() (*Syntax, error) { return nil, err } - f, err := os.Open("treerack.treerack") + f, err := os.Open("syntax.treerack") if err != nil { return nil, err } @@ -223,6 +223,6 @@ func bootSyntax() (*Syntax, error) { return nil, err } - s := NewSyntax() + s := &Syntax{} return s, define(s, doc) } diff --git a/boot_test.go b/boot_test.go index eab4746..ad6523b 100644 --- a/boot_test.go +++ b/boot_test.go @@ -15,7 +15,7 @@ func parseWithSyntax(s *Syntax, f io.ReadSeeker) (*Node, error) { } func syntaxFromTree(n *Node) (*Syntax, error) { - s := NewSyntax() + s := &Syntax{} if err := define(s, n); err != nil { return nil, err } @@ -51,7 +51,7 @@ func TestBoot(t *testing.T) { return } - f, err := os.Open("treerack.treerack") + f, err := os.Open("syntax.treerack") if err != nil { t.Error(err) return diff --git a/bootsyntax.go b/bootsyntax.go index 0c3b25d..6668c11 100644 --- a/bootsyntax.go +++ b/bootsyntax.go @@ -135,7 +135,7 @@ var bootSyntaxDefs = [][]string{{ }, { "choice", "terminal", "alias", "any-char", "char-class", "char-sequence", }, { - "class", "symbol-char", "alias", "^\\\\ \\n\\t\\b\\f\\r\\v\\b/.\\[\\]\\\"{}\\^+*?|():=;", + "class", "symbol-char", "alias", symbolChars, }, { "sequence", "symbol-chars", "alias", "symbol-char:1:-1", }, { diff --git a/char.go b/char.go index 8e100cb..467a25c 100644 --- a/char.go +++ b/char.go @@ -56,20 +56,24 @@ func (p *charParser) builder() builder { return p } +func matchChars(chars []rune, ranges [][]rune, not bool, char rune) bool { + for _, ci := range chars { + if ci == char { + return !not + } + } + + for _, ri := range ranges { + if char >= ri[0] && char <= ri[1] { + return !not + } + } + + return not +} + func (p *charParser) match(t rune) bool { - for _, ci := range p.chars { - if ci == t { - return !p.not - } - } - - for _, ri := range p.ranges { - if t >= ri[0] && t <= ri[1] { - return !p.not - } - } - - return p.not + return matchChars(p.chars, p.ranges, p.not, t) } func (p *charParser) parse(c *context) { @@ -86,17 +90,4 @@ func (p *charParser) parse(c *context) { func (p *charParser) build(c *context) ([]*Node, bool) { panic("called char build") - // // TODO: how to remove this check - // t, ok := c.token() - // if !ok { - // panic("damaged parser context") - // } - - // if !p.match(t) { - // return nil, false - // } - - // // always alias - // c.offset++ - // return nil, true } diff --git a/define.go b/define.go index 4af7927..12bf599 100644 --- a/define.go +++ b/define.go @@ -95,7 +95,7 @@ func defineClass(s *Syntax, name string, ct CommitType, n []*Node) error { } } - return s.Class(name, ct, not, chars, ranges) + return s.class(name, ct, not, chars, ranges) } func defineCharSequence(s *Syntax, name string, ct CommitType, charNodes []*Node) error { @@ -104,7 +104,7 @@ func defineCharSequence(s *Syntax, name string, ct CommitType, charNodes []*Node chars = append(chars, nodeChar(ci)) } - return s.CharSequence(name, ct, chars) + return s.charSequence(name, ct, chars) } func getQuantity(n *Node) (min int, max int, err error) { @@ -148,7 +148,7 @@ func getQuantity(n *Node) (min int, max int, err error) { } func defineSymbol(s *Syntax, name string, ct CommitType, n *Node) error { - return s.Sequence(name, ct, SequenceItem{Name: n.Text()}) + return s.sequence(name, ct, SequenceItem{Name: n.Text()}) } func defineSequence(s *Syntax, name string, ct CommitType, n ...*Node) error { @@ -180,7 +180,7 @@ func defineSequence(s *Syntax, name string, ct CommitType, n ...*Node) error { items = append(items, item) } - return s.Sequence(name, ct, items...) + return s.sequence(name, ct, items...) } func defineChoice(s *Syntax, name string, ct CommitType, n ...*Node) error { @@ -190,14 +190,14 @@ func defineChoice(s *Syntax, name string, ct CommitType, n ...*Node) error { return err } - return s.Choice(name, ct, refs...) + return s.choice(name, ct, refs...) } func defineExpression(s *Syntax, name string, ct CommitType, expression *Node) error { var err error switch expression.Name { case "any-char": - err = s.AnyChar(name, ct) + err = s.anyChar(name, ct) case "char-class": err = defineClass(s, name, ct, expression.Nodes) case "char-sequence": diff --git a/open_test.go b/open_test.go index 960237d..b439c29 100644 --- a/open_test.go +++ b/open_test.go @@ -17,7 +17,7 @@ func openSyntaxReader(r io.Reader) (*Syntax, error) { return nil, err } - s := NewSyntax() + s := &Syntax{} if err := define(s, doc); err != nil { return nil, err } diff --git a/parse_test.go b/parse_test.go index af5ee88..43edb4c 100644 --- a/parse_test.go +++ b/parse_test.go @@ -573,7 +573,7 @@ func TestUndefined(t *testing.T) { t.Error(err) } - stest := NewSyntax() + stest := &Syntax{} err = define(stest, n) if err != nil { t.Error(err) diff --git a/syntax.go b/syntax.go index 31692b8..4921744 100644 --- a/syntax.go +++ b/syntax.go @@ -46,16 +46,36 @@ var ( ErrRootWhitespace = errors.New("root node cannot be a whitespace") ErrNotImplemented = errors.New("not implemented") ErrMultipleRoots = errors.New("multiple roots") + ErrInvalidSymbolName = errors.New("invalid symbol name") ) +const symbolChars = "^\\\\ \\n\\t\\b\\f\\r\\v/.\\[\\]\\\"{}\\^+*?|():=;" + +func parseSymbolChars(c []rune) []rune { + _, chars, _, err := parseClass(c) + if err != nil { + panic(err) + } + + return chars +} + +var symbolCharRunes = parseSymbolChars([]rune(symbolChars)) + func duplicateDefinition(name string) error { return fmt.Errorf("duplicate definition: %s", name) } -func NewSyntax() *Syntax { - return &Syntax{ - registry: newRegistry(), +func isValidSymbol(n string) bool { + runes := []rune(n) + for _, r := range runes { + if !matchChars(symbolCharRunes, nil, true, r) { + return false + } } + + return true + } func (s *Syntax) register(d definition) error { @@ -63,6 +83,10 @@ func (s *Syntax) register(d definition) error { return ErrSyntaxInitialized } + if s.registry == nil { + s.registry = newRegistry() + } + if d.commitType()&Root != 0 { if s.explicitRoot { return ErrMultipleRoots @@ -90,8 +114,16 @@ func (s *Syntax) register(d definition) error { return s.registry.setDefinition(d) } +func (s *Syntax) anyChar(name string, ct CommitType) error { + return s.class(name, ct, true, nil, nil) +} + func (s *Syntax) AnyChar(name string, ct CommitType) error { - return s.Class(name, ct, true, nil, nil) + if !isValidSymbol(name) { + return ErrInvalidSymbolName + } + + return s.anyChar(name, ct) } func childName(name string, childIndex int) string { @@ -107,16 +139,24 @@ func namesToSequenceItems(n []string) []SequenceItem { return si } -func (s *Syntax) Class(name string, ct CommitType, not bool, chars []rune, ranges [][]rune) error { +func (s *Syntax) class(name string, ct CommitType, not bool, chars []rune, ranges [][]rune) error { cname := childName(name, 0) if err := s.register(newChar(cname, not, chars, ranges)); err != nil { return err } - return s.Sequence(name, ct, SequenceItem{Name: cname}) + return s.sequence(name, ct, SequenceItem{Name: cname}) } -func (s *Syntax) CharSequence(name string, ct CommitType, chars []rune) error { +func (s *Syntax) Class(name string, ct CommitType, not bool, chars []rune, ranges [][]rune) error { + if !isValidSymbol(name) { + return ErrInvalidSymbolName + } + + return s.class(name, ct, not, chars, ranges) +} + +func (s *Syntax) charSequence(name string, ct CommitType, chars []rune) error { var refs []string for i, ci := range chars { ref := childName(name, i) @@ -126,17 +166,41 @@ func (s *Syntax) CharSequence(name string, ct CommitType, chars []rune) error { } } - return s.Sequence(name, ct|NoWhitespace, namesToSequenceItems(refs)...) + return s.sequence(name, ct|NoWhitespace, namesToSequenceItems(refs)...) } -func (s *Syntax) Sequence(name string, ct CommitType, items ...SequenceItem) error { +func (s *Syntax) CharSequence(name string, ct CommitType, chars []rune) error { + if !isValidSymbol(name) { + return ErrInvalidSymbolName + } + + return s.charSequence(name, ct, chars) +} + +func (s *Syntax) sequence(name string, ct CommitType, items ...SequenceItem) error { return s.register(newSequence(name, ct, items)) } -func (s *Syntax) Choice(name string, ct CommitType, elements ...string) error { +func (s *Syntax) Sequence(name string, ct CommitType, items ...SequenceItem) error { + if !isValidSymbol(name) { + return ErrInvalidSymbolName + } + + return s.sequence(name, ct, items...) +} + +func (s *Syntax) choice(name string, ct CommitType, elements ...string) error { return s.register(newChoice(name, ct, elements)) } +func (s *Syntax) Choice(name string, ct CommitType, elements ...string) error { + if !isValidSymbol(name) { + return ErrInvalidSymbolName + } + + return s.choice(name, ct, elements...) +} + func (s *Syntax) Read(r io.Reader) error { if s.initialized { return ErrSyntaxInitialized diff --git a/treerack.treerack b/syntax.treerack similarity index 100% rename from treerack.treerack rename to syntax.treerack