You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
3.5 KiB
Go

package main
import (
"fmt"
"io"
"strconv"
)
const ()
func parse(r io.Reader) (node, error) {
p := &parser{
root: newRootNode(),
input: lex(r),
backup: make([]token, 0, 8),
}
if err := p.parse(); err != nil {
return nil, err
}
return p.root, nil
}
type parser struct {
root node
input chan token
backup []token
}
func (p *parser) parse() error {
if p.root == nil {
p.root = newRootNode()
}
return p.root.parse(p)
}
// returns the next token and advances the input stream
func (p *parser) next() token {
if len(p.backup) > 0 {
t := p.backup[len(p.backup)-1]
p.backup = p.backup[:len(p.backup)-1]
return t
}
SKIP_COMMENTS:
t, ok := <-p.input
if !ok {
return token{t_eof, "eof"}
}
if t.t == t_comment {
goto SKIP_COMMENTS
}
return t
}
func (p *parser) peek() token {
t := p.next()
p.unread(t)
return t
}
func (p *parser) unread(t token) {
if p.backup == nil {
p.backup = make([]token, 0, 8)
}
p.backup = append(p.backup, t)
}
func (p *parser) ensureNext(tt tokenType, context string) error {
if p.peek().t != tt {
return fmt.Errorf("unexpected %v in %s: expected %v", p.peek().t, context, tt)
}
return nil
}
// parse the next value. This is to be executed in a context where we know we
// want something that is a value to come next, such as after an equals sign.
func (p *parser) parseValue() (interface{}, error) {
for {
t := p.next()
switch t.t {
case t_error:
return nil, fmt.Errorf("parse error: saw lex error when looking for value: %v", t.s)
case t_eof:
return nil, fmt.Errorf("parse error: unexpected eof when looking for value")
case t_string:
return t.s, nil
case t_real_number, t_imaginary_number:
p.unread(t)
return p.number()
case t_list_start:
return p.parseList(make(list, 0, 4))
case t_object_start:
return p.parseObject(make(object))
default:
return nil, fmt.Errorf("parse error: unexpected %v token while looking for value", t.t)
}
}
}
func (p *parser) parseList(l list) (list, error) {
if p.peek().t == t_list_end {
p.next()
return l, nil
}
if v, err := p.parseValue(); err != nil {
return nil, err
} else {
l = append(l, v)
}
switch t := p.peek(); t.t {
case t_list_end:
p.next()
return l, nil
default:
return p.parseList(l)
}
}
func (p *parser) parseObject(obj object) (object, error) {
if p.peek().t == t_object_end {
p.next()
return obj, nil
}
if err := p.ensureNext(t_name, "looking for object field name in parseObject"); err != nil {
return nil, err
}
field_name := p.next().s
if err := p.ensureNext(t_object_separator, "looking for object separator in parseObject"); err != nil {
return nil, err
}
p.next()
if v, err := p.parseValue(); err != nil {
return nil, err
} else {
obj[field_name] = v
}
switch t := p.peek(); t.t {
case t_object_end:
p.next()
return obj, nil
default:
return p.parseObject(obj)
}
}
func (p *parser) number() (interface{}, error) {
t := p.next()
if t.t != t_real_number {
return nil, fmt.Errorf("unexpected %s token while parsing number", t.t)
}
if p.peek().t == t_imaginary_number {
var c complex128
s := t.s + p.next().s
if _, err := fmt.Sscan(s, &c); err != nil {
return nil, fmt.Errorf("ungood imaginary number format %s: %s", s, err)
}
return c, nil
}
i, err := strconv.ParseInt(t.s, 0, 64)
if err == nil {
return int(i), nil
}
f, err := strconv.ParseFloat(t.s, 64)
if err == nil {
return f, nil
}
return nil, fmt.Errorf("this token broke the number parser: %s", t)
}