func WhatisCommand(args []string) { line := repl.CmdLine[len(args[0]):len(repl.CmdLine)] ctx := &eval.Ctx{line} if expr, err := parser.ParseExpr(line); err != nil { if pair := eval.FormatErrorPos(line, err.Error()); len(pair) == 2 { repl.Msg(pair[0]) repl.Msg(pair[1]) } repl.Errmsg("parse error: %s\n", err) } else { cexpr, errs := eval.CheckExpr(ctx, expr, repl.Env) if len(errs) != 0 { for _, cerr := range errs { repl.Msg("%v", cerr) } } else { repl.Section(cexpr.String()) if cexpr.IsConst() { repl.Msg("constant:\t%s", cexpr.Const()) } knownTypes := cexpr.KnownType() if len(knownTypes) == 1 { repl.Msg("type:\t%s", knownTypes[0]) } else { for i, v := range knownTypes { repl.Msg("type[%d]:\t%s", i, v) } } } } }
// ExpectResult check the evaluation of a string with an expected result. // More importantly though, does the steps to evaluate a string: // 1. Parse expression using parser.ParseExpr (go/parser) // 2. Type check expression using evalCheckExpr (0xfaded/eval) // 3. run eval.EvalExpr (0xfaded/eval) func ExampleFullApi() { expr := `fmt.Sprintf("%s %d", constant1, add(var1, 1) + 1)` env := makeEnv() // Create evaluation environment if e, err := parser.ParseExpr(expr); err != nil { fmt.Printf("Failed to parse expression '%s' (%v)\n", expr, err) } else if cexpr, errs := eval.CheckExpr(e, env); len(errs) != 0 { fmt.Printf("Error checking expression '%s' (%v)\n", expr, errs) } else if results, err := eval.EvalExpr(cexpr, env); err != nil { fmt.Printf("Panic evaluating expression '%s' (%v)\n", expr, err) } else { fmt.Printf("Expression '%s' yielded '%+v'\n", expr, results[0].Interface()) } }
func expectResult(expr string, env eval.Env, expected interface{}) { if e, err := parser.ParseExpr(expr); err != nil { fmt.Printf("Failed to parse expression '%s' (%v)\n", expr, err) return } else if cexpr, errs := eval.CheckExpr(e, env); len(errs) != 0 { fmt.Printf("Error checking expression '%s' (%v)\n", expr, errs) } else if results, err := eval.EvalExpr(cexpr, env); err != nil { fmt.Printf("Error evaluating expression '%s' (%v)\n", expr, err) return } else { fmt.Printf("Expression '%s' yielded '%+v', expected '%+v'\n", expr, results[0].Interface(), expected) } }
// ExpectResult check the evaluation of a string with an expected result. // More importantly though, does the steps to evaluate a string: // 0. Create an evaluation enviroment // 1. Parse expression using parser.ParseExpr (go/parser) // 2. Type check expression using evalCheckExpr (0xfaded/eval) // 3. run eval.EvalExpr (0xfaded/eval) func ExpectResult(expr string, expected interface{}) { env := makeEnv() // Create evaluation environment ctx := &eval.Ctx{expr} if e, err := parser.ParseExpr(expr); err != nil { fmt.Printf("Failed to parse expression '%s' (%v)\n", expr, err) return } else if cexpr, errs := eval.CheckExpr(ctx, e, env); len(errs) != 0 { fmt.Printf("Error checking expression '%s' (%v)\n", expr, errs) } else if results, _, err := eval.EvalExpr(ctx, cexpr, env); err != nil { fmt.Printf("Error evaluating expression '%s' (%v)\n", expr, err) return } else { fmt.Printf("Expression '%s' yielded '%+v', expected '%+v'\n", expr, (*results)[0].Interface(), expected) } }
// REPL is the a read, eval, and print loop. func REPL(env *eval.SimpleEnv) { var err error // A place to store result values of expressions entered // interactively results := make([]interface{}, 0, 10) env.Vars["results"] = reflect.ValueOf(&results) exprs := 0 in := bufio.NewReader(os.Stdin) line, err := readline("go> ", in) for line != "quit" { if err != nil { if err == io.EOF { break } panic(err) } if expr, err := parser.ParseExpr(line); err != nil { if pair := eval.FormatErrorPos(line, err.Error()); len(pair) == 2 { fmt.Println(pair[0]) fmt.Println(pair[1]) } fmt.Printf("parse error: %s\n", err) } else if cexpr, errs := eval.CheckExpr(expr, env); len(errs) != 0 { for _, cerr := range errs { fmt.Printf("check error: %v\n", cerr) } } else if vals, err := eval.EvalExpr(cexpr, env); err != nil { fmt.Printf("panic: %s\n", err) } else if len(vals) == 0 { fmt.Printf("Kind=Slice\nvoid\n") } else if len(vals) == 1 { value := (vals)[0] if value.IsValid() { kind := value.Kind().String() typ := value.Type().String() if typ != kind { fmt.Printf("Kind = %v\n", kind) fmt.Printf("Type = %v\n", typ) } else { fmt.Printf("Kind = Type = %v\n", kind) } fmt.Printf("results[%d] = %s\n", exprs, eval.Inspect(value)) exprs += 1 results = append(results, (vals)[0].Interface()) } else { fmt.Printf("%s\n", value) } } else { fmt.Printf("Kind = Multi-Value\n") size := len(vals) for i, v := range vals { fmt.Printf("%s", eval.Inspect(v)) if i < size-1 { fmt.Printf(", ") } } fmt.Printf("\n") exprs += 1 results = append(results, vals) } line, err = readline("go> ", in) } }
func Repl(env *eval.SimpleEnv, history []string) { deleteMe := true if history == nil { introText() deleteMe = false } else { for _, h := range history { readline.AddHistory(h) } } // As a party piece. add the package contents as a map to the env. We can get away with this // because eval checks for packages before vars for EACH scope. Therefore, if a local variable // masks a pkg, it will still be found first. In other words, I'm cheating here, it's a hack. for name, pkg := range env.Pkgs { e := pkg.(*eval.SimpleEnv) // Don't overwrite existing vars if _, ok := e.Vars[name]; ok { continue } m := map[string]reflect.Type{} for n, v := range e.Vars { m[n] = v.Elem().Type() } for n, c := range e.Consts { m[n] = c.Type() } for n, f := range e.Funcs { m[n] = f.Type() } for n, t := range e.Types { m[n] = t } env.Vars[name] = reflect.ValueOf(&m) } complete := func(test string, start, end int) []string { return []string{""} } readline.SetAttemptedCompletionFunction(complete) prompt := "go> " line := "" for line != "quit" { result := readline.ReadLine(&prompt) if result == nil { fmt.Printf("\n") break } line := *result history = append(history, line) readline.AddHistory(line) if err := handleImport(env, line, history, deleteMe); err != nil { fmt.Println(err) // TODO[crc] move into generalised error position formatting code when written } else if stmt, err := eval.ParseStmt(line); err != nil { if pair := eval.FormatErrorPos(line, err.Error()); len(pair) == 2 { fmt.Println(pair[0]) fmt.Println(pair[1]) } fmt.Printf("%s\n", err) } else if expr, ok := stmt.(*ast.ExprStmt); ok { if cexpr, errs := eval.CheckExpr(expr.X, env); errs != nil { for _, cerr := range errs { fmt.Printf("%v\n", cerr) } } else if vals, err := eval.EvalExpr(cexpr, env); err != nil { fmt.Printf("panic: %s\n", err) } else if len(vals) == 0 { fmt.Printf("Kind=Slice\nvoid\n") } else { // Success if len(vals) == 1 { value := (vals)[0] if value.IsValid() { kind := value.Kind().String() typ := value.Type().String() if typ != kind { fmt.Printf("Kind = %v\n", kind) fmt.Printf("Type = %v\n", typ) } else { fmt.Printf("Kind = Type = %v\n", kind) } fmt.Printf("it = %s\n", eval.Inspect(value)) it := reflect.New(vals[0].Type()) it.Elem().Set(vals[0]) env.Vars["it"] = it } else { fmt.Printf("%s\n", value) } } else if len(vals) > 1 { fmt.Printf("Kind = Multi-Value\nit = ") size := len(vals) it := make([]interface{}, len(vals)) for i, v := range vals { fmt.Printf("%s", eval.Inspect(v)) if i < size-1 { fmt.Printf(", ") } it[i] = vals[i].Interface() } fmt.Printf("\n") env.Vars["it"] = reflect.ValueOf(&it) } } } else { if cstmt, errs := eval.CheckStmt(stmt, env); len(errs) != 0 { for _, cerr := range errs { fmt.Printf("%v\n", cerr) } } else if err = eval.InterpStmt(cstmt, env); err != nil { fmt.Printf("panic: %s\n", err) } } } }
// REPL is the read, eval, and print loop. func REPL(env *eval.Env, readLineFn ReadLineFnType, inspectFn InspectFnType) { var err error // A place to store result values of expressions entered // interactively results := make([]interface{}, 0, 10) env.Vars["results"] = reflect.ValueOf(&results) Env = env exprs := 0 line, err := readLineFn("gofish> ", true) for true { if err != nil { if err == io.EOF { break } panic(err) } if wasProcessed(line) { if LeaveREPL { break } line, err = readLineFn("gofish> ", true) continue } ctx := &eval.Ctx{line} if expr, err := parser.ParseExpr(line); err != nil { if pair := eval.FormatErrorPos(line, err.Error()); len(pair) == 2 { Msg(pair[0]) Msg(pair[1]) } Errmsg("parse error: %s", err) } else if cexpr, errs := eval.CheckExpr(ctx, expr, env); len(errs) != 0 { for _, cerr := range errs { Errmsg("%v", cerr) } } else if vals, _, err := eval.EvalExpr(ctx, cexpr, env); err != nil { Errmsg("eval error: %s", err) } else if vals == nil { Msg("Kind=nil\nnil") } else if len(*vals) == 0 { Msg("Kind=Slice\nvoid") } else if len(*vals) == 1 { value := (*vals)[0] if value.IsValid() { kind := value.Kind().String() typ := value.Type().String() if typ != kind { Msg("Kind = %v", kind) Msg("Type = %v", typ) } else { Msg("Kind = Type = %v", kind) } Msg("results[%d] = %s", exprs, inspectFn(value)) exprs += 1 results = append(results, (*vals)[0].Interface()) } else { Msg("%s", value) } } else { Msg("Kind = Multi-Value") size := len(*vals) for i, v := range *vals { fmt.Printf("%s", inspectFn(v)) if i < size-1 { fmt.Printf(", ") } } Msg("") exprs += 1 results = append(results, (*vals)) } line, err = readLineFn("gofish> ", true) } }