Extra Features
Some checks failed
Build / build (push) Failing after 1m40s
Test / build (push) Failing after 11m47s

This commit is contained in:
Chuck Smith
2024-03-14 21:25:47 -04:00
parent 36f04713bd
commit 997f0865f4
20 changed files with 757 additions and 128 deletions

131
main.go
View File

@@ -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()
}
}