// 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 TestParseDash(t *testing.T) { r := strings.NewReader("(define a-b-c-efg x)") parser := New(lexer.New(r)) actual := []types.Expression{ types.Symbol("define"), types.Symbol("a-b-c-efg"), types.Symbol("x"), } 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 TestQuote(t *testing.T) { r := strings.NewReader("'hello") parser := New(lexer.New(r)) actual := types.Symbol("hello") 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 TestParseString(t *testing.T) { r := strings.NewReader("(print \"it's test\")") parser := New(lexer.New(r)) actual := []types.Expression{ types.Symbol("print"), "it's test", } 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 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 evalCond(exps []types.Expression, env *Env) (types.Expression, error) { for _, operand := range exps[1:] { tt, ok := operand.([]types.Expression) if !ok { return nil, errors.New("cond clause must have expression") } if tt[0] == types.Symbol("else") { return Eval(tt[1], env) } if bb, err := evalPredicate(tt[0], env); err != nil { return nil, err } else if bb { return Eval(tt[1], env) } } // unreachable return nil, nil }
// Eval is body of evaluator func Eval(exp types.Expression, env *Env) (types.Expression, error) { switch t := exp.(type) { case types.Boolean, types.Number, *types.Pair, string: return t, nil case types.Symbol: // it's variable or expression. get value from environment e, err := env.Get(t) if err != nil { return nil, err } return e, nil case []types.Expression: if len(t) == 0 { return &types.Pair{}, nil } switch t[0] { case types.Symbol("define"): return evalDefine(t, env) case types.Symbol("if"): if len(t) < 4 { return nil, errors.New("syntax error: if clause must be (if predicate consequent alternative) style") } return evalIf(t[1], t[2], t[3], env) case types.Symbol("cond"): if len(t) < 2 { return nil, errors.New("syntax error: cond clause must be (cond predicate consequent alternative) style") } return evalCond(t, env) case types.Symbol("lambda"): if len(t) < 3 { return nil, errors.New("lambda must have more than 3 words") } return Lambda{t[1], t[2], env}, nil case types.Symbol("begin"): return evalBegin(env, t[1:]...) case types.Symbol("load"): path, ok := t[1].(string) if !ok { return nil, errors.New("syntax error: args of load should be string") } return evalLoad(path, env) default: return evalApplication(env, t[0], t[1:]...) } default: // not found any known operands. failed. return nil, fmt.Errorf("unknown expression type -- %v", exp) } }
// EvalReader evaluate scheme program from io.Reader func EvalReader(r io.Reader, env *Env) (types.Expression, error) { l := lexer.New(r) p := parser.New(l) if _, err := env.Get("#current-load-path"); err != nil { env.Put("#current-load-path", "") } var exps types.Expression for { tokens, err := p.Parse() if err != nil { return nil, err } // TODO should handle unknown token. if tokens == types.Symbol("") { break } exps, err = Eval(tokens, env) if err != nil { return nil, err } } return exps, nil }
func TestParserRecursive(t *testing.T) { r := strings.NewReader("(define (square x) (* x x))") parser := New(lexer.New(r)) expected := []types.Expression{ types.Symbol("define"), []types.Expression{ types.Symbol("square"), types.Symbol("x"), }, []types.Expression{ types.Symbol("*"), types.Symbol("x"), types.Symbol("x"), }, } exps, err := parser.Parse() if err != nil { t.Fatalf("parser failed: %s", err) } if !reflect.DeepEqual(exps, expected) { 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) } }