misc fixes
Some checks failed
Build / build (push) Successful in 10m45s
Publish Image / publish (push) Failing after 42s
Test / build (push) Successful in 11m9s

This commit is contained in:
2024-04-01 17:44:15 -04:00
parent 99f7553d67
commit fe33fda0ab
8 changed files with 91 additions and 10 deletions

9
bench.sh Normal file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
currentBranch="$(git branch --show-current)"
hyperfine \
-w 5 \
-p "make build" \
-n "$currentBranch" \
'./monkey examples/fib.monkey'

View File

@@ -15,4 +15,10 @@ fib := fn(n) {
return a return a
} }
print(fib(35)) N := 35
if (len(args()) > 0) {
N = int(args()[0])
}
print(fib(N))

View File

@@ -8,4 +8,10 @@ fib := fn(n, a, b) {
return fib(n - 1, b, a + b) return fib(n - 1, b, a + b)
} }
print(fib(35, 0, 1)) N := 35
if (len(args()) > 0) {
N = int(args()[0])
}
print(fib(N, 0, 1))

View File

@@ -18,3 +18,17 @@ func (e BinaryOpError) Error() string {
func NewBinaryOpError(left, right Object, op string) BinaryOpError { func NewBinaryOpError(left, right Object, op string) BinaryOpError {
return BinaryOpError{left, right, op} return BinaryOpError{left, right, op}
} }
// DivisionByZeroError is an error returned when dividing by zero
type DivisionByZeroError struct {
left Object
}
func (e DivisionByZeroError) Error() string {
return fmt.Sprintf("cannot divide %s by zero", e.left)
}
// NewDivisionByZeroError returns a new DivisionByZeroError
func NewDivisionByZeroError(left Object) DivisionByZeroError {
return DivisionByZeroError{left}
}

View File

@@ -65,6 +65,9 @@ func (i Integer) Mul(other Object) (Object, error) {
func (i Integer) Div(other Object) (Object, error) { func (i Integer) Div(other Object) (Object, error) {
switch obj := other.(type) { switch obj := other.(type) {
case Integer: case Integer:
if obj.Value == 0 {
return nil, NewDivisionByZeroError(i)
}
return Integer{i.Value / obj.Value}, nil return Integer{i.Value / obj.Value}, nil
default: default:
return nil, NewBinaryOpError(i, other, "/") return nil, NewBinaryOpError(i, other, "/")

View File

@@ -130,11 +130,19 @@ func (vm *VM) currentFrame() *Frame {
} }
func (vm *VM) pushFrame(f Frame) { func (vm *VM) pushFrame(f Frame) {
if vm.fp >= MaxFrames {
panic("frame overflow")
}
vm.frames[vm.fp] = f vm.frames[vm.fp] = f
vm.fp++ vm.fp++
} }
func (vm *VM) popFrame() Frame { func (vm *VM) popFrame() Frame {
if vm.fp == 0 {
panic("fame underflow")
}
vm.fp-- vm.fp--
return vm.frames[vm.fp] return vm.frames[vm.fp]
} }
@@ -201,6 +209,10 @@ func (vm *VM) push(o object.Object) error {
} }
func (vm *VM) pop() object.Object { func (vm *VM) pop() object.Object {
if vm.sp == 0 {
panic("stack underflow")
}
o := vm.stack[vm.sp-1] o := vm.stack[vm.sp-1]
vm.sp-- vm.sp--
return o return o
@@ -768,20 +780,22 @@ func (vm *VM) Run() (err error) {
if vm.Debug { if vm.Debug {
start := time.Now() start := time.Now()
defer func() { defer func() {
end := time.Now().Sub(start)
total := 0 total := 0
opcodes := make([]code.Opcode, 0, len(opcodeFreqs)) opcodes := make([]code.Opcode, 0, len(opcodeFreqs))
for opcode := range opcodeFreqs { for opcode, count := range opcodeFreqs {
opcodes = append(opcodes, opcode) opcodes = append(opcodes, opcode)
total += count
} }
sort.SliceStable(opcodes, func(i, j int) bool { sort.SliceStable(opcodes, func(i, j int) bool {
return opcodeFreqs[opcodes[i]] > opcodeFreqs[opcodes[j]] return opcodeFreqs[opcodes[i]] > opcodeFreqs[opcodes[j]]
}) })
log.Printf("%d instructions executed in %s", total, time.Now().Sub(start)) log.Printf("%d instructions executed in %s %d/µs", total, end, total/int(end.Microseconds()))
log.Print("Top 10 instructions:") log.Print("Top Instructions:")
for _, opcode := range opcodes[:10] { for _, opcode := range opcodes[:min(len(opcodes), 10)] {
log.Printf("%10d %s", opcodeFreqs[opcode], opcode) log.Printf("%10d %s", opcodeFreqs[opcode], opcode)
} }
}() }()

View File

@@ -81,12 +81,15 @@ func ExecFileVM(f string, args []string, debug, trace bool) (err error) {
} else { } else {
bytecode, err = compile(f, debug) bytecode, err = compile(f, debug)
} }
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return return
} }
if debug {
log.Printf("Bytecode:\n%s\n", bytecode)
}
mvm := vm.New(f, bytecode) mvm := vm.New(f, bytecode)
mvm.Debug = debug mvm.Debug = debug
mvm.Trace = trace mvm.Trace = trace

32
repl.go
View File

@@ -30,13 +30,20 @@ func VmREPL(args []string, debug, trace bool) error {
fmt.Println(err) fmt.Println(err)
return fmt.Errorf("error opening terminal: %w", err) return fmt.Errorf("error opening terminal: %w", err)
} }
defer term.Restore(0, initState) defer func() {
if err := recover(); err != nil {
log.Printf("recovered from panic: %s", err)
}
term.Restore(0, initState)
}()
atexit.Register(func() { atexit.Register(func() {
term.Restore(0, initState) term.Restore(0, initState)
}) })
t := term.NewTerminal(os.Stdin, ">>> ") t := term.NewTerminal(os.Stdin, ">>> ")
t.AutoCompleteCallback = autoComplete t.AutoCompleteCallback = autoComplete
object.Args = args
object.Stdout = t object.Stdout = t
object.ExitFunction = atexit.Exit object.ExitFunction = atexit.Exit
@@ -71,6 +78,10 @@ func VmREPL(args []string, debug, trace bool) error {
continue continue
} }
if debug {
log.Printf("Bytecode:\n%s\n", c.Bytecode())
}
mvm := vm.NewWithState("<stdin>", c.Bytecode(), state) mvm := vm.NewWithState("<stdin>", c.Bytecode(), state)
mvm.Debug = debug mvm.Debug = debug
mvm.Trace = trace mvm.Trace = trace
@@ -80,7 +91,7 @@ func VmREPL(args []string, debug, trace bool) error {
continue continue
} }
if val := mvm.LastPoppedStackElem(); val.Type() != object.NullType { if val := mvm.LastPoppedStackElem(); val != nil && val.Type() != object.NullType {
fmt.Fprintln(t, val.Inspect()) fmt.Fprintln(t, val.Inspect())
} }
} }
@@ -137,7 +148,18 @@ func SimpleVmREPL(args []string, debug, trace bool) {
reader = bufio.NewReader(os.Stdin) reader = bufio.NewReader(os.Stdin)
) )
defer func() {
if err := recover(); err != nil {
log.Printf("recovered from panic: %s", err)
}
}()
t := term.NewTerminal(os.Stdin, ">>> ")
t.AutoCompleteCallback = autoComplete
object.Args = args object.Args = args
object.Stdout = t
object.ExitFunction = atexit.Exit
PrintVersionInfo(os.Stdout) PrintVersionInfo(os.Stdout)
for { for {
@@ -171,6 +193,10 @@ func SimpleVmREPL(args []string, debug, trace bool) {
continue continue
} }
if debug {
log.Printf("Bytecode:\n%s\n", c.Bytecode())
}
mvm := vm.NewWithState("<stdin>", c.Bytecode(), state) mvm := vm.NewWithState("<stdin>", c.Bytecode(), state)
mvm.Debug = debug mvm.Debug = debug
mvm.Trace = trace mvm.Trace = trace
@@ -180,7 +206,7 @@ func SimpleVmREPL(args []string, debug, trace bool) {
continue continue
} }
if val := mvm.LastPoppedStackElem(); val.Type() != object.NullType { if val := mvm.LastPoppedStackElem(); val != nil && val.Type() != object.NullType {
fmt.Println(val.Inspect()) fmt.Println(val.Inspect())
} }
} }