treerack/syntax.go
2017-06-26 02:20:23 +02:00

166 lines
3.3 KiB
Go

package parse
import (
"bufio"
"errors"
"fmt"
"io"
)
type CommitType int
const (
None CommitType = 0
Alias CommitType = 1 << iota
Documentation
Root
)
type SequenceItem struct {
Name string
Min, Max int // 0,0 considered as 1,1, x,0 considered as x,-1
}
type Syntax struct {
trace Trace
registry *registry
initialized bool
initFailed bool
rootSet bool
root definition
parser parser
}
var (
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")
ErrNotImplemented = errors.New("not implemented")
)
func duplicateDefinition(name string) error {
return fmt.Errorf("duplicate definition: %s", name)
}
func NewSyntax() *Syntax {
return NewSyntaxTrace(nil)
}
func NewSyntaxTrace(t Trace) *Syntax {
if t == nil {
t = NopTrace{}
}
return &Syntax{
trace: t,
registry: newRegistry(),
}
}
func (s *Syntax) register(d definition) error {
if s.initialized {
return ErrSyntaxInitialized
}
if d.commitType()&Root != 0 {
s.root = d
s.rootSet = true
} else if !s.rootSet {
s.root = 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) Class(name string, ct CommitType, not bool, chars []rune, ranges [][]rune) error {
return s.register(newChar(name, ct, not, chars, ranges))
}
func childName(name string, childIndex int) string {
return fmt.Sprintf("%s:%d", name, childIndex)
}
func (s *Syntax) CharSequence(name string, ct CommitType, chars []rune) error {
var refs []string
for i, ci := range chars {
ref := childName(name, i)
refs = append(refs, ref)
if err := s.register(newChar(ref, Alias, false, []rune{ci}, nil)); err != nil {
return err
}
}
return s.Sequence(name, ct, namesToSequenceItems(refs)...)
}
func (s *Syntax) Sequence(name string, ct CommitType, items ...SequenceItem) error {
return s.register(newSequence(name, ct, items))
}
func (s *Syntax) Choice(name string, ct CommitType, elements ...string) error {
return s.register(newChoice(name, ct, elements))
}
func (s *Syntax) Read(r io.Reader) error {
if s.initialized {
return ErrSyntaxInitialized
}
return ErrNotImplemented
}
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
}
var err error
s.parser, err = s.root.parser(s.registry, nil)
if err != nil {
s.initFailed = true
return err
}
s.initialized = true
return nil
}
func (s *Syntax) Generate(w io.Writer) error {
if err := s.Init(); err != nil {
return err
}
return ErrNotImplemented
}
func (s *Syntax) Parse(r io.Reader) (*Node, error) {
if err := s.Init(); err != nil {
return nil, err
}
c := newContext(bufio.NewReader(r))
return parse(s.trace, s.parser, c)
}