package repl import ( "bufio" "fmt" "github/runnignwater/monkey/compiler" "github/runnignwater/monkey/lexer" "github/runnignwater/monkey/object" "github/runnignwater/monkey/parser" "github/runnignwater/monkey/vm" "io" "log" ) /** * @Author: simon * @Author: ynwdlxm@163.com * @Date: 2022/10/2 下午5:41 * @Desc: REPL that tokenizes Monkey source code and prints the tokens */ const PROMPT = ">>> " func Start(in io.Reader, out io.Writer) { scanner := bufio.NewScanner(in) // env := object.NewEnvironment() var constants []object.Object globals := make([]object.Object, vm.GlobalSize) symbolTable := compiler.NewSymbolTable() for { fmt.Printf(PROMPT) scan := scanner.Scan() if !scan { return } line := scanner.Text() l := lexer.New(line) p := parser.New(l) program := p.ParseProgram() if len(p.Errors()) != 0 { printParserErrors(out, p.Errors()) continue } // evaluated := evaluator.Eval(program, env) // if evaluated != nil { // if _, err := io.WriteString(out, evaluated.Inspect()); err != nil { // panic(err) // } // if _, err := io.WriteString(out, "\n"); err != nil { // panic(err) // } // } comp := compiler.NewWithState(symbolTable, constants) err := comp.Compile(program) if err != nil { _, err := fmt.Fprintf(out, "Woops! Compilation failed:\n %s\n", err) if err != nil { return } continue } code := comp.ByteCode() constants = code.Constants machine := vm.NewWithGlobalsStore(code, globals) err = machine.Run() if err != nil { _, err := fmt.Fprintf(out, "Woops! Executing bytecode failed:\n %s\n", err) if err != nil { return } continue } lastPopped := machine.LastPopStackElem() _, err = io.WriteString(out, lastPopped.Inspect()) if err != nil { return } _, err = io.WriteString(out, "\n") if err != nil { return } } } func printParserErrors(out io.Writer, errors []string) { if _, err := io.WriteString(out, "Woops! we ran into some monkey business here!\n"); err != nil { log.Fatal(err) } if _, err := io.WriteString(out, " parser errors:\n"); err != nil { log.Fatal(err) } for _, msg := range errors { _, err := io.WriteString(out, "\t"+msg+"\n") if err != nil { return } } }