parse ... differently
parent
d369388fa8
commit
c9872dbe53
@ -0,0 +1,128 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type nodeType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
n_error nodeType = iota
|
||||||
|
n_root
|
||||||
|
n_comment
|
||||||
|
n_assignment
|
||||||
|
)
|
||||||
|
|
||||||
|
type node interface {
|
||||||
|
Type() nodeType
|
||||||
|
parse(*parser) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type rootNode struct {
|
||||||
|
children []node
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRootNode() node {
|
||||||
|
return &rootNode{children: make([]node, 0, 8)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rootNode) Type() nodeType {
|
||||||
|
return n_root
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rootNode) parse(p *parser) error {
|
||||||
|
for {
|
||||||
|
t := p.next()
|
||||||
|
switch t.t {
|
||||||
|
case t_error:
|
||||||
|
return fmt.Errorf("parse error: saw lex error while parsing root node: %v", t.s)
|
||||||
|
case t_eof:
|
||||||
|
return nil
|
||||||
|
case t_comment:
|
||||||
|
shit := commentNode(t.s)
|
||||||
|
n.addChild(&shit)
|
||||||
|
case t_name:
|
||||||
|
nn := &assignmentNode{name: t.s}
|
||||||
|
if err := nn.parse(p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n.addChild(nn)
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("parse error: unexpected token type %v while parsing root node", t.t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rootNode) addChild(child node) {
|
||||||
|
if n.children == nil {
|
||||||
|
n.children = make([]node, 0, 8)
|
||||||
|
}
|
||||||
|
n.children = append(n.children, child)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *rootNode) String() string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.WriteString("{")
|
||||||
|
for _, child := range n.children {
|
||||||
|
fmt.Fprintf(&buf, "%s, ", child)
|
||||||
|
}
|
||||||
|
if len(n.children) > 0 {
|
||||||
|
buf.Truncate(buf.Len() - 2)
|
||||||
|
}
|
||||||
|
buf.WriteString("}")
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
type commentNode string
|
||||||
|
|
||||||
|
func (n commentNode) Type() nodeType {
|
||||||
|
return n_comment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n commentNode) parse(p *parser) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n commentNode) String() string {
|
||||||
|
return fmt.Sprintf("{comment: %s}", string(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
type assignmentNode struct {
|
||||||
|
name string
|
||||||
|
value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n assignmentNode) Type() nodeType {
|
||||||
|
return n_assignment
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *assignmentNode) parse(p *parser) error {
|
||||||
|
t := p.next()
|
||||||
|
switch t.t {
|
||||||
|
case t_error:
|
||||||
|
return fmt.Errorf("parse error: saw lex error while parsing assignment node: %v", t.s)
|
||||||
|
case t_eof:
|
||||||
|
return fmt.Errorf("parse error: unexpected eof in assignment node")
|
||||||
|
case t_equals:
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("parse error: unexpected %v token after name, expected =", t.t)
|
||||||
|
}
|
||||||
|
|
||||||
|
t = p.next()
|
||||||
|
switch t.t {
|
||||||
|
case t_error:
|
||||||
|
return fmt.Errorf("parse error: saw lex error while parsing assignment node: %v", t.s)
|
||||||
|
case t_eof:
|
||||||
|
return fmt.Errorf("parse error: unexpected eof in assignment node")
|
||||||
|
case t_string:
|
||||||
|
n.value = t.s
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("parse error: unexpected %v token after =, expected some kind of value", t.t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *assignmentNode) String() string {
|
||||||
|
return fmt.Sprintf("{assign: name=%s, val=%s}", n.name, n.value)
|
||||||
|
}
|
@ -1,134 +1,42 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const ()
|
||||||
e_no_error parseErrorType = iota
|
|
||||||
e_lex_error
|
|
||||||
e_unexpected_eof
|
|
||||||
e_unexpected_token
|
|
||||||
)
|
|
||||||
|
|
||||||
type parseErrorType int
|
|
||||||
|
|
||||||
type parseError struct {
|
|
||||||
t parseErrorType
|
|
||||||
m string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p parseError) Error() string {
|
|
||||||
return fmt.Sprintf("parse error: %s", p.m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseErrorf(t parseErrorType, tpl string, args ...interface{}) error {
|
|
||||||
return parseError{t: t, m: fmt.Sprintf(tpl, args...)}
|
|
||||||
}
|
|
||||||
|
|
||||||
type parseFn func(*parser) (parseFn, error)
|
func parse(r io.Reader) (node, error) {
|
||||||
|
p := &parser{
|
||||||
func parseRoot(p *parser) (parseFn, error) {
|
root: newRootNode(),
|
||||||
if err := p.next(); err != nil {
|
input: lex(r),
|
||||||
return nil, err
|
backup: make([]token, 0, 8),
|
||||||
}
|
|
||||||
switch p.cur.t {
|
|
||||||
case t_name:
|
|
||||||
return parseAfterName(p.cur.s), nil
|
|
||||||
default:
|
|
||||||
return nil, parseErrorf(e_unexpected_token, "unexpected %s token in parseRoot", p.cur.t)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseAfterName(name string) parseFn {
|
|
||||||
return func(p *parser) (parseFn, error) {
|
|
||||||
switch err := p.next(); err {
|
|
||||||
case io.EOF:
|
|
||||||
return nil, parseErrorf(e_unexpected_eof, "unexpected eof after name %s", name)
|
|
||||||
case nil:
|
|
||||||
default:
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch p.cur.t {
|
|
||||||
case t_equals:
|
|
||||||
return parseAssign(name), nil
|
|
||||||
default:
|
|
||||||
return nil, parseErrorf(e_unexpected_token, "unexpected %s token in parseAfterName", p.cur.t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
if err := p.parse(); err != nil {
|
||||||
|
return nil, err
|
||||||
func parseAssign(name string) parseFn {
|
|
||||||
return func(p *parser) (parseFn, error) {
|
|
||||||
switch err := p.next(); err {
|
|
||||||
case io.EOF:
|
|
||||||
return nil, parseErrorf(e_unexpected_eof, "unexpected eof when trying to parse value for name %s", name)
|
|
||||||
case nil:
|
|
||||||
default:
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch p.cur.t {
|
|
||||||
case t_string:
|
|
||||||
p.out.setUnique(name, p.cur.s)
|
|
||||||
return parseRoot, nil
|
|
||||||
default:
|
|
||||||
return nil, parseErrorf(e_unexpected_token, "unexpected %s token in parseAssign", p.cur.t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return p.root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type parser struct {
|
type parser struct {
|
||||||
in chan token
|
root node
|
||||||
cur token
|
input chan token
|
||||||
out *Config
|
backup []token
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) next() error {
|
func (p *parser) parse() error {
|
||||||
t, ok := <-p.in
|
if p.root == nil {
|
||||||
if !ok {
|
p.root = newRootNode()
|
||||||
return io.EOF
|
|
||||||
}
|
}
|
||||||
if t.t == t_error {
|
return p.root.parse(p)
|
||||||
return parseError{e_lex_error, t.s}
|
|
||||||
}
|
|
||||||
p.cur = t
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *parser) run() error {
|
// returns the next token and advances the input stream
|
||||||
fn := parseRoot
|
func (p *parser) next() token {
|
||||||
var err error
|
if len(p.backup) > 0 {
|
||||||
for {
|
t := p.backup[len(p.backup)-1]
|
||||||
fn, err = fn(p)
|
p.backup = p.backup[:len(p.backup)-1]
|
||||||
switch err {
|
return t
|
||||||
case io.EOF:
|
|
||||||
return nil
|
|
||||||
case nil:
|
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
return <-p.input
|
||||||
|
|
||||||
type assignment struct {
|
|
||||||
name string
|
|
||||||
value interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(in chan token) (*Config, error) {
|
|
||||||
p := &parser{
|
|
||||||
in: in,
|
|
||||||
out: new(Config),
|
|
||||||
}
|
|
||||||
if err := p.run(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return p.out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseString(in string) (*Config, error) {
|
|
||||||
return parse(lexString(in))
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue