func (w *World) Compile(fset *token.FileSet, text string) (Code, os.Error) { stmts, err := parser.ParseStmtList(fset, "input", text) if err == nil { return w.CompileStmtList(fset, stmts) } // Otherwise try as DeclList. decls, err1 := parser.ParseDeclList(fset, "input", text) if err1 == nil { return w.CompileDeclList(fset, decls) } // Have to pick an error. // Parsing as statement list admits more forms, // its error is more likely to be useful. return nil, err }
func main() { fmt.Println("Welcome to the Go REPL!") fmt.Println("Enter '?' for a list of commands.") w := new(World) w.pkgs = new(vector.StringVector) w.defs = new(vector.StringVector) w.code = new(vector.Vector) buf := bufio.NewReader(os.Stdin) unstable := false for { if unstable { fmt.Print("! ") } fmt.Print(strings.Join(w.pkgs.Data(), " ") + "> ") read, err := buf.ReadString('\n') if err != nil { println() break } line := read[0 : len(read)-1] if len(line) == 0 { continue } w.exec = "" switch line[0] { case '?': fmt.Println("Commands:") fmt.Println("\t?\thelp") fmt.Println("\t+ (pkg)\timport package") fmt.Println("\t- (pkg)\tremove package") fmt.Println("\t-[dpc]\tpop last (declaration|package|code)") fmt.Println("\t~\treset") fmt.Println("\t: (...)\tadd persistent code") fmt.Println("\t!\tinspect source") case '+': w.pkgs.Push(line[2:]) unstable = true case '-': if len(line) > 1 && line[1] != ' ' { switch line[1] { case 'd': if w.defs.Len() > 0 { w.defs.Pop() } case 'p': if w.pkgs.Len() > 0 { w.pkgs.Pop() } case 'c': if w.code.Len() > 0 { w.code.Pop() } } } else { if len(line) > 2 && w.pkgs.Len() > 0 { for i, v := range w.pkgs.Data() { if v == line[2:] { w.pkgs.Delete(i) break } } } else { if w.code.Len() > 0 { w.code.Pop() } } } unstable = compile(w).Len() > 0 case '~': w.pkgs.Resize(0, 0) w.defs.Resize(0, 0) w.code.Resize(0, 0) unstable = false case '!': fmt.Println(w.source()) case ':': tree, err := parser.ParseStmtList("go-repl", line[2:], nil) if err != nil { fmt.Println("Parse error:", err) continue } w.code.Push(tree[0]) unstable = compile(w).Len() > 0 default: var tree interface{} tree, err := parser.ParseStmtList("go-repl", line[0:], nil) if err != nil { tree, err = parser.ParseDeclList("go-repl", line[0:], nil) if err != nil { fmt.Println("Parse error:", err) continue } } changed := false switch tree.(type) { case []ast.Stmt: for _, v := range tree.([]ast.Stmt) { str := new(bytes.Buffer) printer.Fprint(str, v) switch v.(type) { case *ast.AssignStmt: w.code.Push(v) changed = true default: w.exec = str.String() } } case []ast.Decl: for _, v := range tree.([]ast.Decl) { str := new(bytes.Buffer) printer.Fprint(str, v) w.defs.Push(str.String()) } changed = true } if err := compile(w); err.Len() > 0 { fmt.Println("Compile error:", err) if changed { unstable = true } } else if out, err := run(); err.Len() > 0 { fmt.Println("Runtime error:\n", err) if changed { unstable = true } } else { fmt.Print(out) } } } }
func main() { fmt.Println("Welcome to the Go REPL!") fmt.Println("Enter '?' for a list of commands.") w := new(World) w.pkgs = &[]string{} w.code = &[]interface{}{} w.defs = &[]string{} w.files = token.NewFileSet() buf := bufio.NewReader(os.Stdin) unstable := false for { if unstable { fmt.Print("! ") } fmt.Print(strings.Join(*w.pkgs, " ") + "> ") read, err := buf.ReadString('\n') if err != nil { println() break } line := read[0 : len(read)-1] if len(line) == 0 { continue } w.exec = "" switch line[0] { case '?': fmt.Println("Commands:") fmt.Println("\t?\thelp") fmt.Println("\t+ (pkg)\timport package") fmt.Println("\t- (pkg)\tremove package") fmt.Println("\t-[dpc]\tpop last (declaration|package|code)") fmt.Println("\t~\treset") fmt.Println("\t: (...)\tadd persistent code") fmt.Println("\t!\tinspect source") case '+': *w.pkgs = append(*w.pkgs, strings.Trim(line[1:], " ")) unstable = true case '-': if len(line) > 1 && line[1] != ' ' { switch line[1] { case 'd': if len(*w.defs) > 0 { *w.defs = (*w.defs)[:len(*w.defs)-1] } case 'p': if len(*w.pkgs) > 0 { *w.pkgs = (*w.pkgs)[:len(*w.pkgs)-1] } case 'c': if len(*w.code) > 0 { *w.code = (*w.code)[:len(*w.code)-1] } } } else { if len(line) > 2 && len(*w.pkgs) > 0 { for i, v := range *w.pkgs { if v == line[2:] { copy((*w.pkgs)[i:], (*w.pkgs)[i+1:]) *w.pkgs = (*w.pkgs)[:len(*w.pkgs)-1] break } } } else { if len(*w.code) > 0 { *w.code = (*w.code)[:len(*w.code)-1] } } } unstable = compile(w).Len() > 0 case '~': *w.pkgs = (*w.pkgs)[:0] *w.defs = (*w.pkgs)[:0] *w.code = (*w.code)[:0] unstable = false case '!': fmt.Println(w.source()) case ':': line = line + ";" tree, err := parser.ParseStmtList(w.files, "go-repl", strings.Trim(line[1:], " ")) if err != nil { fmt.Println("Parse error:", err) continue } *w.code = append(*w.code, tree[0]) unstable = compile(w).Len() > 0 default: line = line + ";" var tree interface{} tree, err := parser.ParseStmtList(w.files, "go-repl", line[0:]) if err != nil { tree, err = parser.ParseDeclList(w.files, "go-repl", line[0:]) if err != nil { fmt.Println("Parse error:", err) continue } } changed := false switch tree.(type) { case []ast.Stmt: for _, v := range tree.([]ast.Stmt) { str := new(bytes.Buffer) printer.Fprint(str, w.files, v) switch v.(type) { case *ast.AssignStmt: *w.code = append(*w.code, v) changed = true default: w.exec = str.String() } } case []ast.Decl: for _, v := range tree.([]ast.Decl) { str := new(bytes.Buffer) printer.Fprint(str, w.files, v) *w.defs = append(*w.defs, str.String()) } changed = true } if err := compile(w); err.Len() > 0 { fmt.Println("Compile error:", err) if changed { unstable = true } } else if out, err := run(); err.Len() > 0 { fmt.Println("Runtime error:\n", err) if changed { unstable = true } } else { fmt.Print(out) } } } }