validate external symbol names
This commit is contained in:
parent
c895aed608
commit
65678eb8bc
16
boot.go
16
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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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",
|
||||
}, {
|
||||
|
43
char.go
43
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
|
||||
}
|
||||
|
12
define.go
12
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":
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
|
84
syntax.go
84
syntax.go
@ -46,23 +46,47 @@ 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 {
|
||||
if s.initialized {
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user