parse list

yeah i can't figure out how to write the parse tests
master
Jordan Orelli 10 years ago
parent c9872dbe53
commit 11e332968f

@ -27,6 +27,12 @@ func (t tokenType) String() string {
return "t_equals" return "t_equals"
case t_comment: case t_comment:
return "t_comment" return "t_comment"
case t_list_start:
return "t_list_start"
case t_list_end:
return "t_list_end"
case t_list_separator:
return "t_list_separator"
default: default:
panic(fmt.Sprintf("unknown token type: %v", t)) panic(fmt.Sprintf("unknown token type: %v", t))
} }
@ -40,6 +46,9 @@ const (
t_type // a type t_type // a type
t_equals // equals sign t_equals // equals sign
t_comment // a comment t_comment // a comment
t_list_start // [
t_list_end // ]
t_list_separator // ,
) )
type stateFn func(*lexer) (stateFn, error) type stateFn func(*lexer) (stateFn, error)
@ -140,6 +149,18 @@ func lexRoot(l *lexer) (stateFn, error) {
return lexStringLiteral(r), nil return lexStringLiteral(r), nil
case r == '#': case r == '#':
return lexComment, nil return lexComment, nil
case r == '[':
l.keep(r)
l.emit(t_list_start)
return lexRoot, nil
case r == ']':
l.keep(r)
l.emit(t_list_end)
return lexRoot, nil
case r == ',':
l.keep(r)
l.emit(t_list_separator)
return lexRoot, nil
case unicode.IsSpace(r): case unicode.IsSpace(r):
return lexRoot, nil return lexRoot, nil
case unicode.IsLower(r): case unicode.IsLower(r):

@ -35,6 +35,8 @@ var primitivesTests = []struct {
# comment line one # comment line one
# comment line two # comment line two
`, []token{{t_comment, " comment line one"}, {t_comment, " comment line two"}}}, `, []token{{t_comment, " comment line one"}, {t_comment, " comment line two"}}},
{`[]`, []token{{t_list_start, "["}, {t_list_end, "]"}}},
{`["item"]`, []token{{t_list_start, "["}, {t_string, "item"}, {t_list_end, "]"}}},
} }
func TestLexPrimities(t *testing.T) { func TestLexPrimities(t *testing.T) {

@ -67,7 +67,7 @@ func (n *rootNode) String() string {
for _, child := range n.children { for _, child := range n.children {
fmt.Fprintf(&buf, "%s, ", child) fmt.Fprintf(&buf, "%s, ", child)
} }
if len(n.children) > 0 { if buf.Len() > 1 {
buf.Truncate(buf.Len() - 2) buf.Truncate(buf.Len() - 2)
} }
buf.WriteString("}") buf.WriteString("}")
@ -109,20 +109,51 @@ func (n *assignmentNode) parse(p *parser) error {
return fmt.Errorf("parse error: unexpected %v token after name, expected =", t.t) return fmt.Errorf("parse error: unexpected %v token after name, expected =", t.t)
} }
t = p.next() v, err := p.parseValue()
switch t.t { if err != nil {
case t_error: return err
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)
} }
n.value = v
return nil
} }
func (n *assignmentNode) String() string { func (n *assignmentNode) String() string {
return fmt.Sprintf("{assign: name=%s, val=%s}", n.name, n.value) return fmt.Sprintf("{assign: name=%s, val=%s}", n.name, n.value)
} }
type list struct {
head *listElem
tail *listElem
}
func (l list) String() string {
var buf bytes.Buffer
buf.WriteString("[")
for e := l.head; e != nil; e = e.next {
fmt.Fprintf(&buf, "%v, ", e.value)
}
if buf.Len() > 1 {
buf.Truncate(buf.Len() - 2)
}
buf.WriteString("]")
return buf.String()
}
func (l *list) append(v interface{}) {
e := listElem{value: v}
if l.head == nil {
l.head = &e
}
if l.tail != nil {
l.tail.next = &e
e.prev = l.tail
}
l.tail = &e
}
type listElem struct {
value interface{}
prev *listElem
next *listElem
}

@ -1,6 +1,7 @@
package main package main
import ( import (
"fmt"
"io" "io"
) )
@ -40,3 +41,57 @@ func (p *parser) next() token {
} }
return <-p.input return <-p.input
} }
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)
}
// 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_list_start:
l := new(list)
SIN:
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(v)
}
switch t := p.next(); t.t {
case t_list_separator:
goto SIN
case t_list_end:
return l, nil
default:
return nil, fmt.Errorf("parse error: unexpected %v token while scanning for list", t.t)
}
default:
return nil, fmt.Errorf("parse error: unexpected %v token while looking for value", t.t)
}
}
}

@ -53,6 +53,12 @@ var parseTests = []parseTest{
`, `,
root: &rootNode{}, root: &rootNode{},
}, },
{
source: `
heroes = ["lina", "cm"]
`,
root: &rootNode{},
},
} }
type parseTest struct { type parseTest struct {

Loading…
Cancel
Save