diff --git a/parse/parse.go b/parse/parse.go index 9269954..ad00eab 100644 --- a/parse/parse.go +++ b/parse/parse.go @@ -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 import ( + "bytes" "io" "fmt" "strconv" @@ -60,6 +64,7 @@ type Parser struct { l *lex.Lexer } +// Returns a NewParser, using the lex package as the tokenizer func NewParser(r io.Reader) *Parser { p := Parser{ l: lex.NewLexer(r), @@ -67,6 +72,9 @@ func NewParser(r io.Reader) *Parser { 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) { tok := p.l.Next() return p.parseToken(tok) @@ -139,3 +147,10 @@ func (p *Parser) readUntil(closer string) ([]types.Elem, error) { 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() +} diff --git a/parse/parse_test.go b/parse/parse_test.go index 51cdc24..0a4f851 100644 --- a/parse/parse_test.go +++ b/parse/parse_test.go @@ -9,19 +9,51 @@ import ( "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{ - "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": { types.GoType{":foo"}, types.GoType{4}, @@ -32,23 +64,6 @@ func TestParseBareString(t *T) { types.GoType{":foo"}, 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 {