misc fixes
This commit is contained in:
9
bench.sh
Normal file
9
bench.sh
Normal 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'
|
||||||
@@ -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))
|
||||||
@@ -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))
|
||||||
@@ -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}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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, "/")
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|||||||
@@ -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
32
repl.go
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user