2017-07-15 21:49:08 +02:00
|
|
|
package treerack
|
2017-06-25 17:51:08 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
|
|
|
type CommitType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
None CommitType = 0
|
|
|
|
Alias CommitType = 1 << iota
|
2017-10-28 22:54:15 +02:00
|
|
|
Whitespace
|
|
|
|
NoWhitespace
|
2017-06-25 17:51:08 +02:00
|
|
|
Root
|
|
|
|
)
|
|
|
|
|
2017-11-04 22:49:42 +01:00
|
|
|
// if min=0&&max=0, it means min=1,max=1
|
|
|
|
// else if max<=0, it means no max
|
|
|
|
// else if min<=0, it means no min
|
2017-06-25 23:38:32 +02:00
|
|
|
type SequenceItem struct {
|
|
|
|
Name string
|
2017-11-04 22:49:42 +01:00
|
|
|
Min, Max int
|
2017-06-25 23:38:32 +02:00
|
|
|
}
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
type Syntax struct {
|
2017-07-15 21:49:08 +02:00
|
|
|
registry *registry
|
|
|
|
initialized bool
|
|
|
|
initFailed bool
|
|
|
|
explicitRoot bool
|
|
|
|
root definition
|
|
|
|
parser parser
|
2017-07-29 18:40:22 +02:00
|
|
|
builder builder
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-11-01 03:54:53 +01:00
|
|
|
type definition interface {
|
|
|
|
nodeName() string
|
2017-11-05 03:28:36 +01:00
|
|
|
setName(string)
|
2017-11-01 03:54:53 +01:00
|
|
|
nodeID() int
|
2017-11-05 03:28:36 +01:00
|
|
|
setID(int)
|
2017-11-01 03:54:53 +01:00
|
|
|
commitType() CommitType
|
|
|
|
setCommitType(CommitType)
|
2017-11-04 22:49:42 +01:00
|
|
|
preinit()
|
2017-11-01 03:54:53 +01:00
|
|
|
validate(*registry) error
|
|
|
|
init(*registry)
|
2017-11-02 22:19:03 +01:00
|
|
|
addGeneralization(int)
|
2017-11-01 03:54:53 +01:00
|
|
|
parser() parser
|
|
|
|
builder() builder
|
|
|
|
}
|
|
|
|
|
|
|
|
type parser interface {
|
|
|
|
nodeName() string
|
|
|
|
nodeID() int
|
|
|
|
parse(*context)
|
|
|
|
}
|
|
|
|
|
|
|
|
type builder interface {
|
|
|
|
nodeName() string
|
|
|
|
nodeID() int
|
|
|
|
build(*context) ([]*Node, bool)
|
|
|
|
}
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
var (
|
2017-07-15 19:04:04 +02:00
|
|
|
ErrSyntaxInitialized = errors.New("syntax initialized")
|
|
|
|
ErrInitFailed = errors.New("init failed")
|
|
|
|
ErrNoParsersDefined = errors.New("no parsers defined")
|
|
|
|
ErrInvalidInput = errors.New("invalid input")
|
|
|
|
ErrInvalidUnicodeCharacter = errors.New("invalid unicode character")
|
|
|
|
ErrInvalidEscapeCharacter = errors.New("invalid escape character")
|
|
|
|
ErrUnexpectedCharacter = errors.New("unexpected character")
|
|
|
|
ErrInvalidSyntax = errors.New("invalid syntax")
|
|
|
|
ErrRootAlias = errors.New("root node cannot be an alias")
|
2017-10-28 22:54:15 +02:00
|
|
|
ErrRootWhitespace = errors.New("root node cannot be a whitespace")
|
2017-07-15 19:04:04 +02:00
|
|
|
ErrNotImplemented = errors.New("not implemented")
|
2017-10-28 22:54:15 +02:00
|
|
|
ErrMultipleRoots = errors.New("multiple roots")
|
2017-10-31 21:53:09 +01:00
|
|
|
ErrInvalidSymbolName = errors.New("invalid symbol name")
|
2017-06-25 17:51:08 +02:00
|
|
|
)
|
|
|
|
|
2017-11-01 03:54:53 +01:00
|
|
|
func duplicateDefinition(name string) error {
|
|
|
|
return fmt.Errorf("duplicate definition: %s", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func parserNotFound(name string) error {
|
|
|
|
return fmt.Errorf("parser not found: %s", name)
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
const symbolChars = "^\\\\ \\n\\t\\b\\f\\r\\v/.\\[\\]\\\"{}\\^+*?|():=;"
|
|
|
|
|
|
|
|
func parseSymbolChars(c []rune) []rune {
|
2017-11-05 03:28:36 +01:00
|
|
|
_, chars, _, _ := parseClass(c)
|
2017-10-31 21:53:09 +01:00
|
|
|
return chars
|
|
|
|
}
|
|
|
|
|
|
|
|
var symbolCharRunes = parseSymbolChars([]rune(symbolChars))
|
|
|
|
|
|
|
|
func isValidSymbol(n string) bool {
|
|
|
|
runes := []rune(n)
|
|
|
|
for _, r := range runes {
|
|
|
|
if !matchChars(symbolCharRunes, nil, true, r) {
|
|
|
|
return false
|
|
|
|
}
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
2017-10-31 21:53:09 +01:00
|
|
|
|
|
|
|
return true
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-11-01 03:54:53 +01:00
|
|
|
func intsContain(is []int, i int) bool {
|
|
|
|
for _, ii := range is {
|
|
|
|
if ii == i {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-11-01 00:19:29 +01:00
|
|
|
func (s *Syntax) applyRoot(d definition) error {
|
|
|
|
explicitRoot := d.commitType()&Root != 0
|
|
|
|
if explicitRoot && s.explicitRoot {
|
|
|
|
return ErrMultipleRoots
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-11-01 00:19:29 +01:00
|
|
|
if s.root != nil && (explicitRoot || !s.explicitRoot) {
|
|
|
|
s.root.setCommitType(s.root.commitType() &^ Root)
|
2017-10-31 21:53:09 +01:00
|
|
|
}
|
|
|
|
|
2017-11-01 00:19:29 +01:00
|
|
|
if explicitRoot || !s.explicitRoot {
|
2017-06-25 17:51:08 +02:00
|
|
|
s.root = d
|
2017-10-28 22:54:15 +02:00
|
|
|
s.root.setCommitType(s.root.commitType() | Root)
|
2017-11-01 00:19:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if explicitRoot {
|
2017-07-15 21:49:08 +02:00
|
|
|
s.explicitRoot = true
|
2017-11-01 00:19:29 +01:00
|
|
|
}
|
2017-10-28 22:54:15 +02:00
|
|
|
|
2017-11-01 00:19:29 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Syntax) register(d definition) error {
|
|
|
|
if s.initialized {
|
|
|
|
return ErrSyntaxInitialized
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.registry == nil {
|
|
|
|
s.registry = newRegistry()
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-11-01 00:19:29 +01:00
|
|
|
if err := s.applyRoot(d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2017-10-28 22:54:15 +02:00
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
return s.registry.setDefinition(d)
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
func (s *Syntax) anyChar(name string, ct CommitType) error {
|
|
|
|
return s.class(name, ct, true, nil, nil)
|
|
|
|
}
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
func (s *Syntax) AnyChar(name string, ct CommitType) error {
|
2017-10-31 21:53:09 +01:00
|
|
|
if !isValidSymbol(name) {
|
|
|
|
return ErrInvalidSymbolName
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.anyChar(name, ct)
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func childName(name string, childIndex int) string {
|
|
|
|
return fmt.Sprintf("%s:%d", name, childIndex)
|
|
|
|
}
|
|
|
|
|
2017-10-29 16:46:17 +01:00
|
|
|
func namesToSequenceItems(n []string) []SequenceItem {
|
|
|
|
si := make([]SequenceItem, len(n))
|
|
|
|
for i := range n {
|
|
|
|
si[i] = SequenceItem{Name: n[i]}
|
|
|
|
}
|
|
|
|
|
|
|
|
return si
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
func (s *Syntax) class(name string, ct CommitType, not bool, chars []rune, ranges [][]rune) error {
|
2017-07-17 01:41:38 +02:00
|
|
|
cname := childName(name, 0)
|
2017-07-29 16:25:17 +02:00
|
|
|
if err := s.register(newChar(cname, not, chars, ranges)); err != nil {
|
2017-07-17 01:41:38 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
return s.sequence(name, ct, SequenceItem{Name: cname})
|
2017-07-17 01:41:38 +02:00
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
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 {
|
2017-06-25 17:51:08 +02:00
|
|
|
var refs []string
|
|
|
|
for i, ci := range chars {
|
|
|
|
ref := childName(name, i)
|
|
|
|
refs = append(refs, ref)
|
2017-07-29 16:25:17 +02:00
|
|
|
if err := s.register(newChar(ref, false, []rune{ci}, nil)); err != nil {
|
2017-06-25 17:51:08 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
return s.sequence(name, ct|NoWhitespace, namesToSequenceItems(refs)...)
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
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 {
|
2017-11-04 22:49:42 +01:00
|
|
|
citems := make([]SequenceItem, len(items))
|
|
|
|
copy(citems, items)
|
2017-06-25 17:51:08 +02:00
|
|
|
return s.register(newSequence(name, ct, items))
|
|
|
|
}
|
|
|
|
|
2017-10-31 21:53:09 +01:00
|
|
|
func (s *Syntax) Sequence(name string, ct CommitType, items ...SequenceItem) error {
|
|
|
|
if !isValidSymbol(name) {
|
|
|
|
return ErrInvalidSymbolName
|
|
|
|
}
|
|
|
|
|
|
|
|
return s.sequence(name, ct, items...)
|
|
|
|
}
|
|
|
|
|
2017-11-02 22:19:03 +01:00
|
|
|
func (s *Syntax) choice(name string, ct CommitType, options ...string) error {
|
|
|
|
return s.register(newChoice(name, ct, options))
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
2017-11-02 22:19:03 +01:00
|
|
|
func (s *Syntax) Choice(name string, ct CommitType, options ...string) error {
|
2017-10-31 21:53:09 +01:00
|
|
|
if !isValidSymbol(name) {
|
|
|
|
return ErrInvalidSymbolName
|
|
|
|
}
|
|
|
|
|
2017-11-02 22:19:03 +01:00
|
|
|
return s.choice(name, ct, options...)
|
2017-10-31 21:53:09 +01:00
|
|
|
}
|
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
func (s *Syntax) Read(r io.Reader) error {
|
|
|
|
if s.initialized {
|
|
|
|
return ErrSyntaxInitialized
|
|
|
|
}
|
|
|
|
|
2017-06-26 01:21:46 +02:00
|
|
|
return ErrNotImplemented
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Syntax) Init() error {
|
|
|
|
if s.initFailed {
|
|
|
|
return ErrInitFailed
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.initialized {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.root == nil {
|
|
|
|
return ErrNoParsersDefined
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.root.commitType()&Alias != 0 {
|
|
|
|
return ErrRootAlias
|
|
|
|
}
|
|
|
|
|
2017-10-28 22:54:15 +02:00
|
|
|
if s.root.commitType()&Whitespace != 0 {
|
|
|
|
return ErrRootWhitespace
|
|
|
|
}
|
|
|
|
|
2017-11-01 02:43:46 +01:00
|
|
|
defs := s.registry.getDefinitions()
|
2017-11-04 22:49:42 +01:00
|
|
|
for i := range defs {
|
|
|
|
defs[i].preinit()
|
|
|
|
}
|
2017-10-28 22:54:15 +02:00
|
|
|
|
2017-11-01 02:43:46 +01:00
|
|
|
if hasWhitespace(defs) {
|
|
|
|
defs, s.root = applyWhitespace(defs)
|
|
|
|
s.registry = newRegistry(defs...)
|
2017-08-06 20:43:52 +02:00
|
|
|
}
|
|
|
|
|
2017-11-01 02:43:46 +01:00
|
|
|
if err := s.root.validate(s.registry); err != nil {
|
2017-06-25 17:51:08 +02:00
|
|
|
s.initFailed = true
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-11-01 02:43:46 +01:00
|
|
|
s.root.init(s.registry)
|
2017-11-01 03:54:53 +01:00
|
|
|
s.parser = s.root.parser()
|
2017-07-29 18:40:22 +02:00
|
|
|
s.builder = s.root.builder()
|
2017-11-01 02:43:46 +01:00
|
|
|
|
2017-06-25 17:51:08 +02:00
|
|
|
s.initialized = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Syntax) Generate(w io.Writer) error {
|
|
|
|
if err := s.Init(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2017-06-26 01:21:46 +02:00
|
|
|
return ErrNotImplemented
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Syntax) Parse(r io.Reader) (*Node, error) {
|
|
|
|
if err := s.Init(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
c := newContext(bufio.NewReader(r))
|
2017-11-01 03:54:53 +01:00
|
|
|
s.parser.parse(c)
|
|
|
|
if c.readErr != nil {
|
|
|
|
return nil, c.readErr
|
|
|
|
}
|
|
|
|
|
2017-11-02 22:55:19 +01:00
|
|
|
if err := c.finalizeParse(s.parser.nodeID()); err != nil {
|
2017-07-29 18:40:22 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-11-01 03:54:53 +01:00
|
|
|
c.offset = 0
|
2017-11-06 11:41:00 +01:00
|
|
|
c.results.resetPending()
|
2017-11-04 22:08:15 +01:00
|
|
|
|
2017-11-05 03:28:36 +01:00
|
|
|
n, _ := s.builder.build(c)
|
2017-11-01 03:54:53 +01:00
|
|
|
return n[0], nil
|
2017-06-25 17:51:08 +02:00
|
|
|
}
|