func TestQuoteList(t *testing.T) { r := strings.NewReader("'(1 2)") parser := New(lexer.New(r)) actual := types.NewList(types.Number(1), types.Number(2)) exps, err := parser.Parse() if err != nil { t.Fatalf("parser failed: %s", err) } if !reflect.DeepEqual(exps, actual) { t.Fatalf("expressions is not expected. %v", exps) } }
// Parse scans given tokens and return it into expression. func (p *Parser) Parse() (exps types.Expression, err error) { token, err := p.lex.Next() if err != nil { return nil, err } switch token { case "'": // if start with (, deal as list. // recursive scan until ")" // if start with "'(", it's list. if p.lex.Peek() == '(' { // this is (. skip it. if _, err := p.lex.Next(); err != nil { return nil, err } tokens, err := p.parseList() if err != nil { return nil, err } return types.NewList(tokens...), nil } // if not start with (, it's simply string (return string itself). t, err := p.lex.Next() if err != nil { return nil, err } return types.Symbol(t), nil case "(": // start S-Expression. Parse as list. return p.parseList() case ")": return nil, errors.New("unexpected ')'") case "#t": return types.Boolean(true), nil case "#f": return types.Boolean(false), nil default: // if token is string, get unquoted. // It's get test from \"test\". if p.lex.IsTokenString() { return strconv.Unquote(p.lex.TokenText()) } // try conversion to float. if failed, treated as symbol. if n, err := strconv.ParseFloat(token, 64); err == nil { return types.Number(n), nil } return types.Symbol(token), nil } }
func TestNewLine(t *testing.T) { r := strings.NewReader("(print 1)\n\n") parser := New(lexer.New(r)) actual := []types.Expression{ types.Symbol("print"), types.Number(1), } exps, err := parser.Parse() if err != nil { t.Fatalf("parser failed: %s", err) } if !reflect.DeepEqual(exps, actual) { t.Fatalf("expressions is not expected. %v", exps) } }
func TestParseLineDelimited(t *testing.T) { r := strings.NewReader(` (define (fib n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))))) `) parser := New(lexer.New(r)) actual := []types.Expression{ types.Symbol("define"), []types.Expression{ types.Symbol("fib"), types.Symbol("n"), }, []types.Expression{ types.Symbol("cond"), []types.Expression{ []types.Expression{ types.Symbol("="), types.Symbol("n"), types.Number(0), }, types.Number(0), }, []types.Expression{ []types.Expression{ types.Symbol("="), types.Symbol("n"), types.Number(1), }, types.Number(1), }, []types.Expression{ types.Symbol("else"), []types.Expression{ types.Symbol("+"), []types.Expression{ types.Symbol("fib"), []types.Expression{ types.Symbol("-"), types.Symbol("n"), types.Number(1), }, }, []types.Expression{ types.Symbol("fib"), []types.Expression{ types.Symbol("-"), types.Symbol("n"), types.Number(2), }, }, }, }, }, } exps, err := parser.Parse() if err != nil { t.Fatalf("parser failed: %s", err) } if !reflect.DeepEqual(exps, actual) { t.Fatalf("expressions is not expected. %#v", exps) } }