2017-07-15 21:49:08 +02:00
|
|
|
package treerack
|
2017-06-25 17:51:08 +02:00
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2017-11-26 01:49:22 +01:00
|
|
|
const (
|
|
|
|
charClassEscape = '\\'
|
|
|
|
charClassBanned = "\\[]^-\b\f\n\r\t\v"
|
|
|
|
)
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
type charParser struct {
|
2018-01-04 18:36:59 +01:00
|
|
|
name string
|
|
|
|
id int
|
|
|
|
not bool
|
|
|
|
chars []rune
|
|
|
|
ranges [][]rune
|
|
|
|
}
|
|
|
|
|
|
|
|
type charBuilder struct {
|
|
|
|
name string
|
|
|
|
id int
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func newChar(
|
|
|
|
name string,
|
2017-06-25 23:38:32 +02:00
|
|
|
not bool,
|
2017-06-25 17:51:08 +02:00
|
|
|
chars []rune,
|
|
|
|
ranges [][]rune,
|
|
|
|
) *charParser {
|
|
|
|
return &charParser{
|
|
|
|
name: name,
|
|
|
|
not: not,
|
|
|
|
chars: chars,
|
|
|
|
ranges: ranges,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-01 02:43:46 +01:00
|
|
|
func (p *charParser) nodeName() string { return p.name }
|
2017-11-05 03:28:36 +01:00
|
|
|
func (p *charParser) setName(n string) { p.name = n }
|
2017-11-01 02:43:46 +01:00
|
|
|
func (p *charParser) nodeID() int { return p.id }
|
|
|
|
func (p *charParser) setID(id int) { p.id = id }
|
|
|
|
func (p *charParser) commitType() CommitType { return Alias }
|
|
|
|
func (p *charParser) setCommitType(ct CommitType) {}
|
2017-11-04 22:49:42 +01:00
|
|
|
func (p *charParser) preinit() {}
|
2017-11-01 02:43:46 +01:00
|
|
|
func (p *charParser) validate(*registry) error { return nil }
|
|
|
|
func (p *charParser) init(*registry) {}
|
2017-11-05 03:28:36 +01:00
|
|
|
func (p *charParser) addGeneralization(int) {}
|
|
|
|
func (p *charParser) parser() parser { return p }
|
2018-01-04 18:36:59 +01:00
|
|
|
|
|
|
|
func (p *charParser) builder() builder {
|
|
|
|
return &charBuilder{
|
|
|
|
id: p.id,
|
|
|
|
name: p.name,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *charParser) isSingleChar() bool {
|
|
|
|
return !p.not && len(p.chars) == 1 && len(p.ranges) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *charParser) format(_ *registry, f formatFlags) string {
|
|
|
|
if p.not && len(p.chars) == 0 && len(p.ranges) == 0 {
|
|
|
|
return "."
|
|
|
|
}
|
|
|
|
|
|
|
|
esc := func(c ...rune) []rune {
|
|
|
|
return escape(charClassEscape, []rune(charClassBanned), c)
|
|
|
|
}
|
|
|
|
|
|
|
|
var s []rune
|
|
|
|
s = append(s, '[')
|
|
|
|
|
|
|
|
if p.not {
|
|
|
|
s = append(s, '^')
|
|
|
|
}
|
|
|
|
|
|
|
|
s = append(s, esc(p.chars...)...)
|
|
|
|
|
|
|
|
for i := range p.ranges {
|
|
|
|
s = append(s, esc(p.ranges[i][0])...)
|
|
|
|
s = append(s, '-')
|
|
|
|
s = append(s, esc(p.ranges[i][1])...)
|
|
|
|
}
|
|
|
|
|
|
|
|
s = append(s, ']')
|
|
|
|
return string(s)
|
|
|
|
}
|
2017-06-25 17:51:08 +02:00
|
|
|
|
2017-12-31 16:14:56 +01:00
|
|
|
func matchChar(chars []rune, ranges [][]rune, not bool, char rune) bool {
|
2017-10-31 21:53:09 +01:00
|
|
|
for _, ci := range chars {
|
|
|
|
if ci == char {
|
|
|
|
return !not
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
for _, ri := range ranges {
|
|
|
|
if char >= ri[0] && char <= ri[1] {
|
|
|
|
return !not
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
return not
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *charParser) match(t rune) bool {
|
2017-12-31 16:14:56 +01:00
|
|
|
return matchChar(p.chars, p.ranges, p.not, t)
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-10-31 21:09:30 +01:00
|
|
|
func (p *charParser) parse(c *context) {
|
2017-07-17 04:23:29 +02:00
|
|
|
if tok, ok := c.token(); !ok || !p.match(tok) {
|
2017-11-28 20:52:02 +01:00
|
|
|
if c.offset > c.failOffset {
|
|
|
|
c.failOffset = c.offset
|
|
|
|
c.failingParser = nil
|
|
|
|
}
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
c.fail(c.offset)
|
|
|
|
return
|
|
|
|
}
|
2017-07-17 04:23:29 +02:00
|
|
|
|
2017-11-01 00:19:29 +01:00
|
|
|
c.success(c.offset + 1)
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
2017-07-29 16:25:17 +02:00
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
func (p *charParser) generate(w io.Writer, done map[string]bool) error {
|
|
|
|
if done[p.name] {
|
|
|
|
return nil
|
|
|
|
}
|
2017-12-31 18:03:12 +01:00
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
done[p.name] = true
|
2017-12-31 18:03:12 +01:00
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
var err error
|
|
|
|
fprintf := func(f string, args ...interface{}) {
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2017-12-31 18:03:12 +01:00
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
_, err = fmt.Fprintf(w, f, args...)
|
2017-12-31 18:03:12 +01:00
|
|
|
}
|
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
fprintf("var p%d = charParser{", p.id)
|
|
|
|
fprintf("id: %d, not: %t,", p.id, p.not)
|
2017-12-31 18:03:12 +01:00
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
fprintf("chars: []rune{")
|
|
|
|
for i := range p.chars {
|
|
|
|
fprintf("%d,", p.chars[i])
|
2017-12-31 18:03:12 +01:00
|
|
|
}
|
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
fprintf("},")
|
2017-12-31 18:03:12 +01:00
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
fprintf("ranges: [][]rune{")
|
2017-12-31 18:03:12 +01:00
|
|
|
for i := range p.ranges {
|
2018-01-04 18:36:59 +01:00
|
|
|
fprintf("{%d, %d},", p.ranges[i][0], p.ranges[i][1])
|
2017-12-31 18:03:12 +01:00
|
|
|
}
|
|
|
|
|
2018-01-04 18:36:59 +01:00
|
|
|
fprintf("}};")
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *charBuilder) nodeName() string { return b.name }
|
|
|
|
func (b *charBuilder) nodeID() int { return b.id }
|
|
|
|
|
|
|
|
func (b *charBuilder) build(c *context) ([]*Node, bool) {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b *charBuilder) generate(w io.Writer, done map[string]bool) error {
|
|
|
|
if done[b.name] {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
done[b.name] = true
|
|
|
|
_, err := fmt.Fprintf(w, "var b%d = charBuilder{};", b.id)
|
|
|
|
return err
|
2017-12-31 18:03:12 +01:00
|
|
|
}
|