validate external symbol names

This commit is contained in:
Arpad Ryszka 2017-10-31 21:53:09 +01:00
parent c895aed608
commit 65678eb8bc
9 changed files with 110 additions and 55 deletions

16
boot.go
View File

@ -97,7 +97,7 @@ func parseClass(class []rune) (not bool, chars []rune, ranges [][]rune, err erro
func defineBootAnything(s *Syntax, d []string) error { func defineBootAnything(s *Syntax, d []string) error {
ct := stringToCommitType(d[2]) ct := stringToCommitType(d[2])
return s.AnyChar(d[1], ct) return s.anyChar(d[1], ct)
} }
func defineBootClass(s *Syntax, d []string) error { func defineBootClass(s *Syntax, d []string) error {
@ -109,7 +109,7 @@ func defineBootClass(s *Syntax, d []string) error {
return err 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 { func defineBootCharSequence(s *Syntax, d []string) error {
@ -121,7 +121,7 @@ func defineBootCharSequence(s *Syntax, d []string) error {
return err return err
} }
return s.CharSequence(name, ct, chars) return s.charSequence(name, ct, chars)
} }
func splitQuantifiedSymbol(s string) (string, int, int) { func splitQuantifiedSymbol(s string) (string, int, int) {
@ -159,14 +159,14 @@ func defineBootSequence(s *Syntax, defs []string) error {
name := defs[1] name := defs[1]
ct := stringToCommitType(defs[2]) ct := stringToCommitType(defs[2])
items := namesToSequenceItemsQuantify(defs[3:]) items := namesToSequenceItemsQuantify(defs[3:])
return s.Sequence(name, ct, items...) return s.sequence(name, ct, items...)
} }
func defineBootChoice(s *Syntax, defs []string) error { func defineBootChoice(s *Syntax, defs []string) error {
name := defs[1] name := defs[1]
ct := stringToCommitType(defs[2]) ct := stringToCommitType(defs[2])
items := defs[3:] items := defs[3:]
return s.Choice(name, ct, items...) return s.choice(name, ct, items...)
} }
func defineBoot(s *Syntax, defs []string) error { func defineBoot(s *Syntax, defs []string) error {
@ -197,7 +197,7 @@ func defineAllBoot(s *Syntax, defs [][]string) error {
} }
func createBoot() (*Syntax, error) { func createBoot() (*Syntax, error) {
s := NewSyntax() s := &Syntax{}
if err := defineAllBoot(s, bootSyntaxDefs); err != nil { if err := defineAllBoot(s, bootSyntaxDefs); err != nil {
return nil, err return nil, err
} }
@ -211,7 +211,7 @@ func bootSyntax() (*Syntax, error) {
return nil, err return nil, err
} }
f, err := os.Open("treerack.treerack") f, err := os.Open("syntax.treerack")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -223,6 +223,6 @@ func bootSyntax() (*Syntax, error) {
return nil, err return nil, err
} }
s := NewSyntax() s := &Syntax{}
return s, define(s, doc) return s, define(s, doc)
} }

View File

@ -15,7 +15,7 @@ func parseWithSyntax(s *Syntax, f io.ReadSeeker) (*Node, error) {
} }
func syntaxFromTree(n *Node) (*Syntax, error) { func syntaxFromTree(n *Node) (*Syntax, error) {
s := NewSyntax() s := &Syntax{}
if err := define(s, n); err != nil { if err := define(s, n); err != nil {
return nil, err return nil, err
} }
@ -51,7 +51,7 @@ func TestBoot(t *testing.T) {
return return
} }
f, err := os.Open("treerack.treerack") f, err := os.Open("syntax.treerack")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return

View File

@ -135,7 +135,7 @@ var bootSyntaxDefs = [][]string{{
}, { }, {
"choice", "terminal", "alias", "any-char", "char-class", "char-sequence", "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", "sequence", "symbol-chars", "alias", "symbol-char:1:-1",
}, { }, {

43
char.go
View File

@ -56,20 +56,24 @@ func (p *charParser) builder() builder {
return p 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 { func (p *charParser) match(t rune) bool {
for _, ci := range p.chars { return matchChars(p.chars, p.ranges, p.not, t)
if ci == t {
return !p.not
}
}
for _, ri := range p.ranges {
if t >= ri[0] && t <= ri[1] {
return !p.not
}
}
return p.not
} }
func (p *charParser) parse(c *context) { func (p *charParser) parse(c *context) {
@ -86,17 +90,4 @@ func (p *charParser) parse(c *context) {
func (p *charParser) build(c *context) ([]*Node, bool) { func (p *charParser) build(c *context) ([]*Node, bool) {
panic("called char build") 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
} }

View File

@ -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 { 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)) 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) { 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 { 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 { 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) 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 { 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 err
} }
return s.Choice(name, ct, refs...) return s.choice(name, ct, refs...)
} }
func defineExpression(s *Syntax, name string, ct CommitType, expression *Node) error { func defineExpression(s *Syntax, name string, ct CommitType, expression *Node) error {
var err error var err error
switch expression.Name { switch expression.Name {
case "any-char": case "any-char":
err = s.AnyChar(name, ct) err = s.anyChar(name, ct)
case "char-class": case "char-class":
err = defineClass(s, name, ct, expression.Nodes) err = defineClass(s, name, ct, expression.Nodes)
case "char-sequence": case "char-sequence":

View File

@ -17,7 +17,7 @@ func openSyntaxReader(r io.Reader) (*Syntax, error) {
return nil, err return nil, err
} }
s := NewSyntax() s := &Syntax{}
if err := define(s, doc); err != nil { if err := define(s, doc); err != nil {
return nil, err return nil, err
} }

View File

@ -573,7 +573,7 @@ func TestUndefined(t *testing.T) {
t.Error(err) t.Error(err)
} }
stest := NewSyntax() stest := &Syntax{}
err = define(stest, n) err = define(stest, n)
if err != nil { if err != nil {
t.Error(err) t.Error(err)

View File

@ -46,16 +46,36 @@ var (
ErrRootWhitespace = errors.New("root node cannot be a whitespace") ErrRootWhitespace = errors.New("root node cannot be a whitespace")
ErrNotImplemented = errors.New("not implemented") ErrNotImplemented = errors.New("not implemented")
ErrMultipleRoots = errors.New("multiple roots") 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 { func duplicateDefinition(name string) error {
return fmt.Errorf("duplicate definition: %s", name) return fmt.Errorf("duplicate definition: %s", name)
} }
func NewSyntax() *Syntax { func isValidSymbol(n string) bool {
return &Syntax{ runes := []rune(n)
registry: newRegistry(), for _, r := range runes {
if !matchChars(symbolCharRunes, nil, true, r) {
return false
} }
}
return true
} }
func (s *Syntax) register(d definition) error { func (s *Syntax) register(d definition) error {
@ -63,6 +83,10 @@ func (s *Syntax) register(d definition) error {
return ErrSyntaxInitialized return ErrSyntaxInitialized
} }
if s.registry == nil {
s.registry = newRegistry()
}
if d.commitType()&Root != 0 { if d.commitType()&Root != 0 {
if s.explicitRoot { if s.explicitRoot {
return ErrMultipleRoots return ErrMultipleRoots
@ -90,8 +114,16 @@ func (s *Syntax) register(d definition) error {
return s.registry.setDefinition(d) 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 { 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 { func childName(name string, childIndex int) string {
@ -107,16 +139,24 @@ func namesToSequenceItems(n []string) []SequenceItem {
return si 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) cname := childName(name, 0)
if err := s.register(newChar(cname, not, chars, ranges)); err != nil { if err := s.register(newChar(cname, not, chars, ranges)); err != nil {
return err 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 var refs []string
for i, ci := range chars { for i, ci := range chars {
ref := childName(name, i) 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)) 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)) 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 { func (s *Syntax) Read(r io.Reader) error {
if s.initialized { if s.initialized {
return ErrSyntaxInitialized return ErrSyntaxInitialized