treerack/syntax.go

279 lines
5.9 KiB
Go
Raw Normal View History

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
Documentation
Root
)
2017-06-25 23:38:32 +02:00
type SequenceItem struct {
Name string
Min, Max int // 0,0 considered as 1,1, x,0 considered as x,-1
}
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
}
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-10-31 21:53:09 +01:00
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))
2017-06-25 17:51:08 +02:00
func duplicateDefinition(name string) error {
return fmt.Errorf("duplicate definition: %s", name)
}
2017-10-31 21:53:09 +01:00
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 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-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...)
}
func (s *Syntax) choice(name string, ct CommitType, elements ...string) error {
2017-06-25 17:51:08 +02:00
return s.register(newChoice(name, ct, elements))
}
2017-10-31 21:53:09 +01:00
func (s *Syntax) Choice(name string, ct CommitType, elements ...string) error {
if !isValidSymbol(name) {
return ErrInvalidSymbolName
}
return s.choice(name, ct, elements...)
}
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
}
2017-07-16 23:15:42 +02:00
// TODO: why normalization failed?
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-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)
s.parser = s.root.parser(s.registry)
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
}
2017-07-17 21:58:03 +02:00
// TODO: optimize top sequences to save memory, or just support streaming, or combine the two
2017-07-16 23:15:42 +02:00
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-10-31 21:09:30 +01:00
if err := parse(s.parser, c); err != nil {
2017-07-29 18:40:22 +02:00
return nil, err
}
return build(s.builder, c), nil
2017-06-25 17:51:08 +02:00
}