add ParseString and refactor parse_test a bit

This commit is contained in:
Brian Picciano 2014-10-20 21:57:56 -04:00
parent 269d033fcb
commit b307273223
2 changed files with 59 additions and 29 deletions

View File

@ -1,6 +1,10 @@
// The parse package implements a syntax parser for the ginger syntax. It can
// read in any io.Reader and returns fully parsed Elem's from the types package
// that it finds.
package parse package parse
import ( import (
"bytes"
"io" "io"
"fmt" "fmt"
"strconv" "strconv"
@ -60,6 +64,7 @@ type Parser struct {
l *lex.Lexer l *lex.Lexer
} }
// Returns a NewParser, using the lex package as the tokenizer
func NewParser(r io.Reader) *Parser { func NewParser(r io.Reader) *Parser {
p := Parser{ p := Parser{
l: lex.NewLexer(r), l: lex.NewLexer(r),
@ -67,6 +72,9 @@ func NewParser(r io.Reader) *Parser {
return &p return &p
} }
// Reads a full element, and any sub-elements (if the top-level element is a
// data-structure) into an Elem and returns it. Returns any errors, including
// io.EOF, if it runs into them instead
func (p *Parser) ReadElem() (types.Elem, error) { func (p *Parser) ReadElem() (types.Elem, error) {
tok := p.l.Next() tok := p.l.Next()
return p.parseToken(tok) return p.parseToken(tok)
@ -139,3 +147,10 @@ func (p *Parser) readUntil(closer string) ([]types.Elem, error) {
return series, nil return series, nil
} }
} }
// Parses the first Elem it finds out of the given string and returns it
func ParseString(input string) (types.Elem, error) {
buf := bytes.NewBufferString(input)
p := NewParser(buf)
return p.ReadElem()
}

View File

@ -9,19 +9,51 @@ import (
"github.com/mediocregopher/ginger/types" "github.com/mediocregopher/ginger/types"
) )
func TestParseBareString(t *T) { func TestParse(t *T) {
m := map[string]types.Elem{
"1": types.GoType{int(1)},
"-1": types.GoType{int(-1)},
"+1": types.GoType{int(1)},
"1.5": types.GoType{float32(1.5)},
"-1.5": types.GoType{float32(-1.5)},
"+1.5": types.GoType{float32(1.5)},
"1.5e1": types.GoType{float32(15)},
"foo": types.GoType{":foo"},
"()": seq.NewList(),
"(foo)": seq.NewList(
types.GoType{":foo"},
),
"(foo (bar))": seq.NewList(
types.GoType{":foo"},
seq.NewList(types.GoType{":bar"}),
),
"{}": seq.NewHashMap(),
"{foo bar}": seq.NewHashMap(
seq.KeyVal(types.GoType{":foo"}, types.GoType{":bar"}),
),
}
for input, output := range m {
parsed, err := ParseString(input)
if err != nil {
t.Fatal(err)
}
if !output.Equal(parsed) {
t.Fatalf("input: %q %#v != %#v", input, output, parsed)
}
}
}
func TestParseMulti(t *T) {
m := map[string][]types.Elem{ m := map[string][]types.Elem{
"1": {types.GoType{int(1)}},
"-1": {types.GoType{int(-1)}},
"+1": {types.GoType{int(1)}},
"1.5": {types.GoType{float32(1.5)}},
"-1.5": {types.GoType{float32(-1.5)}},
"+1.5": {types.GoType{float32(1.5)}},
"1.5e1": {types.GoType{float32(15)}},
"foo": {types.GoType{":foo"}},
"foo 4 bar": { "foo 4 bar": {
types.GoType{":foo"}, types.GoType{":foo"},
types.GoType{4}, types.GoType{4},
@ -32,23 +64,6 @@ func TestParseBareString(t *T) {
types.GoType{":foo"}, types.GoType{":foo"},
types.GoType{"bar"}, types.GoType{"bar"},
}, },
"()": {seq.NewList()},
"(foo)": {seq.NewList(
types.GoType{":foo"},
)},
"(foo (bar))": {seq.NewList(
types.GoType{":foo"},
seq.NewList(types.GoType{":bar"}),
)},
"{}": {seq.NewHashMap()},
"{foo bar}": {seq.NewHashMap(
seq.KeyVal(types.GoType{":foo"}, types.GoType{":bar"}),
)},
} }
for input, output := range m { for input, output := range m {