refactor how repl works
Some checks failed
Build / build (push) Failing after 5m26s
Publish Image / publish (push) Failing after 45s
Test / build (push) Failing after 5m54s

This commit is contained in:
Chuck Smith
2024-03-28 16:51:54 -04:00
parent fc6ceee02c
commit 244b71d245
32 changed files with 612 additions and 476 deletions

140
monkey.go Normal file
View File

@@ -0,0 +1,140 @@
package monkey
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"monkey/internal/ast"
"monkey/internal/compiler"
"monkey/internal/parser"
"monkey/internal/vm"
)
const MonkeyVersion = "v0.0.1"
var ErrParseError = errors.New("error: parse error")
func mustReadFile(fname string) []byte {
b, err := os.ReadFile(fname)
if err != nil {
panic(err)
}
return b
}
func writeFile(fname string, cont []byte) {
if err := os.WriteFile(fname, cont, 0644); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func decode(path string) (*compiler.Bytecode, error) {
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
return compiler.Decode(b), nil
}
func compile(path string) (bc *compiler.Bytecode, err error) {
input := string(mustReadFile(path))
res, errs := parser.Parse(path, input)
if len(errs) > 0 {
var buf strings.Builder
for _, e := range errs {
buf.WriteString(e)
buf.WriteByte('\n')
}
return nil, errors.New(buf.String())
}
c := compiler.New()
c.SetFileInfo(path, input)
if err = c.Compile(res); err != nil {
return
}
return c.Bytecode(), nil
}
func ExecFileVM(f string) (err error) {
var bytecode *compiler.Bytecode
if filepath.Ext(f) == ".monkeyc" {
bytecode, err = decode(f)
} else {
bytecode, err = compile(f)
}
if err != nil {
fmt.Println(err)
return
}
mvm := vm.New(f, bytecode)
if err = mvm.Run(); err != nil {
fmt.Println(err)
return
}
return
}
func CompileFiles(files []string) error {
for _, f := range files {
b := mustReadFile(f)
res, errs := parser.Parse(f, string(b))
if len(errs) != 0 {
for _, e := range errs {
fmt.Println(e)
}
return ErrParseError
}
c := compiler.New()
if err := c.Compile(res); err != nil {
fmt.Println(err)
continue
}
cnt, err := c.Bytecode().Encode()
if err != nil {
fmt.Println(err)
continue
}
ext := filepath.Ext(f)
writeFile(f[:len(f)-len(ext)]+".monkeyc", cnt)
}
return nil
}
func PrintVersionInfo(w io.Writer) {
fmt.Fprintf(w, "Monkey %s on %s\n", MonkeyVersion, strings.Title(runtime.GOOS))
}
func Parse(src string) (ast.Node, error) {
tree, errs := parser.Parse("<input>", src)
if len(errs) > 0 {
var buf strings.Builder
buf.WriteString("parser error:\n")
for _, e := range errs {
buf.WriteString(e)
buf.WriteByte('\n')
}
return nil, errors.New(buf.String())
}
return tree, nil
}