Extra Features
This commit is contained in:
131
main.go
131
main.go
@@ -3,73 +3,90 @@ package main
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"monkey/compiler"
|
||||
"monkey/evaluator"
|
||||
"monkey/lexer"
|
||||
"monkey/object"
|
||||
"monkey/parser"
|
||||
"monkey/vm"
|
||||
"monkey/repl"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
)
|
||||
|
||||
var engine = flag.String("engine", "vm", "use 'vm' or 'eval'")
|
||||
var (
|
||||
engine string
|
||||
interactive bool
|
||||
compile bool
|
||||
version bool
|
||||
debug bool
|
||||
)
|
||||
|
||||
var input = `
|
||||
let fibonacci = fn(x) {
|
||||
if (x == 0) {
|
||||
0
|
||||
} else {
|
||||
if (x == 1) {
|
||||
return 1;
|
||||
} else {
|
||||
fibonacci(x - 1) + fibonacci(x - 2);
|
||||
}
|
||||
}
|
||||
};
|
||||
fibonacci(35);
|
||||
`
|
||||
func init() {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(flag.CommandLine.Output(), "Usage: %s [options] [<filename>]\n", path.Base(os.Args[0]))
|
||||
flag.PrintDefaults()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
flag.BoolVar(&version, "v", false, "display version information")
|
||||
flag.BoolVar(&debug, "d", false, "enable debug mode")
|
||||
flag.BoolVar(&compile, "c", false, "compile input to bytecode")
|
||||
|
||||
flag.BoolVar(&interactive, "i", false, "enable interactive mode")
|
||||
flag.StringVar(&engine, "e", "vm", "engine to use (eval or vm)")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
var duration time.Duration
|
||||
var result object.Object
|
||||
|
||||
l := lexer.New(input)
|
||||
p := parser.New(l)
|
||||
program := p.ParseProgram()
|
||||
|
||||
if *engine == "vm" {
|
||||
comp := compiler.New()
|
||||
err := comp.Compile(program)
|
||||
if err != nil {
|
||||
fmt.Printf("compiler error: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
machine := vm.New(comp.Bytecode())
|
||||
|
||||
start := time.Now()
|
||||
|
||||
err = machine.Run()
|
||||
if err != nil {
|
||||
fmt.Printf("vm error: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
duration = time.Since(start)
|
||||
result = machine.LastPoppedStackElem()
|
||||
} else {
|
||||
env := object.NewEnvironment()
|
||||
start := time.Now()
|
||||
result = evaluator.Eval(program, env)
|
||||
duration = time.Since(start)
|
||||
if version {
|
||||
fmt.Printf("%s %s", path.Base(os.Args[0]), FullVersion())
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
fmt.Printf(
|
||||
"engine=%s, result=%s, duration=%s\n",
|
||||
*engine,
|
||||
result.Inspect(),
|
||||
duration)
|
||||
user, err := user.Current()
|
||||
if err != nil {
|
||||
log.Fatalf("could not determine current user: %s", err)
|
||||
}
|
||||
|
||||
args := flag.Args()
|
||||
|
||||
if compile {
|
||||
if len(args) < 1 {
|
||||
log.Fatal("no source file given to compile")
|
||||
}
|
||||
f, err := os.Open(args[0])
|
||||
defer f.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
l := lexer.New(string(b))
|
||||
p := parser.New(l)
|
||||
|
||||
program := p.ParseProgram()
|
||||
if len(p.Errors()) != 0 {
|
||||
log.Fatal(p.Errors())
|
||||
}
|
||||
|
||||
c := compiler.New()
|
||||
err = c.Compile(program)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
code := c.Bytecode()
|
||||
fmt.Printf("%s\n", code.Instructions)
|
||||
} else {
|
||||
opts := &repl.Options{
|
||||
Debug: debug,
|
||||
Engine: engine,
|
||||
Interactive: interactive,
|
||||
}
|
||||
repl := repl.New(user.Username, args, opts)
|
||||
repl.Run()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user