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 {
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)
}

View File

@ -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

View File

@ -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
View File

@ -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
}

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 {
@ -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":

View File

@ -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
}

View File

@ -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)

View File

@ -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