cleanup boot

This commit is contained in:
Arpad Ryszka 2017-10-29 16:46:17 +01:00
parent 278a4952b9
commit f0288e26b4
3 changed files with 73 additions and 118 deletions

123
boot.go
View File

@ -32,12 +32,7 @@ func checkBootDefinitionLength(d []string) error {
} }
switch d[0] { switch d[0] {
case "chars", "class": case "chars", "class", "sequence", "choice":
if len(d) < 4 {
return errInvalidDefinition
}
case "sequence", "choice":
if len(d) < 4 { if len(d) < 4 {
return errInvalidDefinition return errInvalidDefinition
} }
@ -46,19 +41,19 @@ func checkBootDefinitionLength(d []string) error {
return nil return nil
} }
func parseClass(c []rune) (not bool, chars []rune, ranges [][]rune, err error) { func parseClass(class []rune) (not bool, chars []rune, ranges [][]rune, err error) {
if c[0] == '^' { if class[0] == '^' {
not = true not = true
c = c[1:] class = class[1:]
} }
for { for {
if len(c) == 0 { if len(class) == 0 {
return return
} }
var c0 rune var c0 rune
c0, c = c[0], c[1:] c0, class = class[0], class[1:]
switch c0 { switch c0 {
case '[', ']', '^', '-': case '[', ']', '^', '-':
err = errInvalidDefinition err = errInvalidDefinition
@ -66,28 +61,34 @@ func parseClass(c []rune) (not bool, chars []rune, ranges [][]rune, err error) {
} }
if c0 == '\\' { if c0 == '\\' {
if len(c) == 0 { if len(class) == 0 {
err = errInvalidDefinition err = errInvalidDefinition
return return
} }
c0, c = unescapeChar(c[0]), c[1:] c0, class = unescapeChar(class[0]), class[1:]
} }
if len(c) < 2 || c[0] != '-' { if len(class) < 2 || class[0] != '-' {
chars = append(chars, c0) chars = append(chars, c0)
continue continue
} }
var c1 rune var c1 rune
c1, c = c[1], c[2:] c1, class = class[1], class[2:]
switch c1 {
case '[', ']', '^', '-':
err = errInvalidDefinition
return
}
if c1 == '\\' { if c1 == '\\' {
if len(c) == 0 { if len(class) == 0 {
err = errInvalidDefinition err = errInvalidDefinition
return return
} }
c1, c = unescapeChar(c[0]), c[1:] c1, class = unescapeChar(class[0]), class[1:]
} }
ranges = append(ranges, []rune{c0, c1}) ranges = append(ranges, []rune{c0, c1})
@ -100,6 +101,7 @@ func defineBootAnything(s *Syntax, d []string) error {
} }
func defineBootClass(s *Syntax, d []string) error { func defineBootClass(s *Syntax, d []string) error {
name := d[1]
ct := stringToCommitType(d[2]) ct := stringToCommitType(d[2])
not, chars, ranges, err := parseClass([]rune(d[3])) not, chars, ranges, err := parseClass([]rune(d[3]))
@ -107,75 +109,78 @@ func defineBootClass(s *Syntax, d []string) error {
return err return err
} }
return s.Class(d[1], 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 {
name := d[1]
ct := stringToCommitType(d[2]) ct := stringToCommitType(d[2])
chars, err := unescape('\\', []rune{'"', '\\'}, []rune(d[3])) chars, err := unescapeCharSequence(d[3])
if err != nil { if err != nil {
return err return err
} }
return s.CharSequence(d[1], ct, chars) return s.CharSequence(name, ct, chars)
} }
func namesToSequenceItemsQuantify(n []string, quantify bool) []SequenceItem { func splitQuantifiedSymbol(s string) (string, int, int) {
ssplit := strings.Split(s, ":")
if len(ssplit) != 3 {
return s, 0, 0
}
name := ssplit[0]
min, err := strconv.Atoi(ssplit[1])
if err != nil {
panic(err)
}
max, err := strconv.Atoi(ssplit[2])
if err != nil {
panic(err)
}
return name, min, max
}
func namesToSequenceItemsQuantify(n []string) []SequenceItem {
si := make([]SequenceItem, len(n)) si := make([]SequenceItem, len(n))
for i, ni := range n { for i, ni := range n {
var min, max int name, min, max := splitQuantifiedSymbol(ni)
if quantify { si[i] = SequenceItem{Name: name, Min: min, Max: max}
nis := strings.Split(ni, ":")
if len(nis) == 3 {
ni = nis[0]
var err error
min, err = strconv.Atoi(nis[1])
if err != nil {
panic(err)
}
max, err = strconv.Atoi(nis[2])
if err != nil {
panic(err)
}
}
}
si[i] = SequenceItem{Name: ni, Min: min, Max: max}
} }
return si return si
} }
func namesToSequenceItems(n []string) []SequenceItem { func defineBootSequence(s *Syntax, defs []string) error {
return namesToSequenceItemsQuantify(n, false) name := defs[1]
ct := stringToCommitType(defs[2])
items := namesToSequenceItemsQuantify(defs[3:])
return s.Sequence(name, ct, items...)
} }
func defineBootSequence(s *Syntax, d []string) error { func defineBootChoice(s *Syntax, defs []string) error {
ct := stringToCommitType(d[2]) name := defs[1]
return s.Sequence(d[1], ct, namesToSequenceItemsQuantify(d[3:], true)...) ct := stringToCommitType(defs[2])
items := defs[3:]
return s.Choice(name, ct, items...)
} }
func defineBootChoice(s *Syntax, d []string) error { func defineBoot(s *Syntax, defs []string) error {
ct := stringToCommitType(d[2]) switch defs[0] {
return s.Choice(d[1], ct, d[3:]...)
}
func defineBoot(s *Syntax, d []string) error {
switch d[0] {
case "anything": case "anything":
return defineBootAnything(s, d) return defineBootAnything(s, defs)
case "class": case "class":
return defineBootClass(s, d) return defineBootClass(s, defs)
case "chars": case "chars":
return defineBootCharSequence(s, d) return defineBootCharSequence(s, defs)
case "sequence": case "sequence":
return defineBootSequence(s, d) return defineBootSequence(s, defs)
case "choice": case "choice":
return defineBootChoice(s, d) return defineBootChoice(s, defs)
default: default:
return errInvalidDefinition return errInvalidDefinition
} }

View File

@ -2,65 +2,6 @@ package treerack
import "strconv" import "strconv"
func runesContain(rs []rune, r rune) bool {
for _, ri := range rs {
if ri == r {
return true
}
}
return false
}
func unescapeChar(c rune) rune {
switch c {
case 'n':
return '\n'
case 't':
return '\t'
case 'b':
return '\b'
case 'f':
return '\f'
case 'r':
return '\r'
case 'v':
return '\v'
default:
return c
}
}
func unescape(escape rune, banned []rune, chars []rune) ([]rune, error) {
var (
unescaped []rune
escaped bool
)
for _, ci := range chars {
if escaped {
unescaped = append(unescaped, unescapeChar(ci))
escaped = false
continue
}
switch {
case ci == escape:
escaped = true
case runesContain(banned, ci):
return nil, ErrInvalidEscapeCharacter
default:
unescaped = append(unescaped, ci)
}
}
if escaped {
return nil, ErrInvalidEscapeCharacter
}
return unescaped, nil
}
func dropComments(n *Node) *Node { func dropComments(n *Node) *Node {
ncc := *n ncc := *n
nc := &ncc nc := &ncc

View File

@ -108,6 +108,15 @@ func childName(name string, childIndex int) string {
return fmt.Sprintf("%s:%d", name, childIndex) return fmt.Sprintf("%s:%d", name, childIndex)
} }
func namesToSequenceItems(n []string) []SequenceItem {
si := make([]SequenceItem, len(n))
for i := range n {
si[i] = SequenceItem{Name: n[i]}
}
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 {