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 {
|
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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
43
char.go
@ -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
|
|
||||||
}
|
}
|
||||||
|
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 {
|
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":
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
84
syntax.go
84
syntax.go
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user