From ca4eed10b831c2da85373ad1aff76a4a2b7ad2a1 Mon Sep 17 00:00:00 2001 From: Chuck Smith Date: Mon, 18 Mar 2024 19:46:54 -0400 Subject: [PATCH] More tests --- compiler/compiler.go | 2 +- evaluator/evaluator_test.go | 1 - examples/{ fibi.monkey => fibi.monkey} | 0 object/builtins.go | 11 ++++ testdata/arrays.monkey | 2 + testdata/assign.monkey | 3 + testdata/builtins.monkey | 13 ++++ testdata/closures.monkey | 2 + testdata/expressions.monkey | 2 + testdata/functions.monkey | 2 + testdata/hashes.monkey | 2 + testdata/if.monkey | 5 ++ testdata/let.monkey | 3 + testdata/strings.monkey | 2 + vm/vm.go | 7 ++ vm/vm_test.go | 91 +++++++++++++++++++------- 16 files changed, 124 insertions(+), 24 deletions(-) rename examples/{ fibi.monkey => fibi.monkey} (100%) create mode 100644 testdata/arrays.monkey create mode 100644 testdata/assign.monkey create mode 100644 testdata/builtins.monkey create mode 100644 testdata/closures.monkey create mode 100644 testdata/expressions.monkey create mode 100644 testdata/functions.monkey create mode 100644 testdata/hashes.monkey create mode 100644 testdata/if.monkey create mode 100644 testdata/let.monkey create mode 100644 testdata/strings.monkey diff --git a/compiler/compiler.go b/compiler/compiler.go index 2c0774d..7709fd6 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -68,7 +68,7 @@ func NewWithState(s *SymbolTable, constants []object.Object) *Compiler { func (c *Compiler) Compile(node ast.Node) error { if c.Debug { log.Printf( - "%s Compiling %T: %s\n", + "%sCompiling %T: %s\n", strings.Repeat(" ", c.l), node, node.String(), ) } diff --git a/evaluator/evaluator_test.go b/evaluator/evaluator_test.go index 7afd780..c09187f 100644 --- a/evaluator/evaluator_test.go +++ b/evaluator/evaluator_test.go @@ -479,7 +479,6 @@ func TestArrayIndexExpressions(t *testing.T) { } for _, tt := range tests { - t.Log(tt.input) evaluated := testEval(tt.input) integer, ok := tt.expected.(int) diff --git a/examples/ fibi.monkey b/examples/fibi.monkey similarity index 100% rename from examples/ fibi.monkey rename to examples/fibi.monkey diff --git a/object/builtins.go b/object/builtins.go index 28224b7..9d09751 100644 --- a/object/builtins.go +++ b/object/builtins.go @@ -9,6 +9,7 @@ import ( "unicode/utf8" ) +// Builtins ... var Builtins = map[string]*Builtin{ "len": {Name: "len", Fn: Len}, "input": {Name: "input", Fn: Input}, @@ -21,6 +22,7 @@ var Builtins = map[string]*Builtin{ "exit": {Name: "exit", Fn: Exit}, } +// BuiltinsIndex ... var BuiltinsIndex []*Builtin func init() { @@ -39,6 +41,7 @@ func newError(format string, a ...interface{}) *Error { return &Error{Message: fmt.Sprintf(format, a...)} } +// Len ... func Len(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", @@ -56,6 +59,7 @@ func Len(args ...Object) Object { } } +// Input ... func Input(args ...Object) Object { if len(args) > 0 { obj, ok := args[0].(*String) @@ -77,6 +81,7 @@ func Input(args ...Object) Object { return &String{Value: string(line)} } +// Print ... func Print(args ...Object) Object { for _, arg := range args { fmt.Println(arg.Inspect()) @@ -85,6 +90,7 @@ func Print(args ...Object) Object { return nil } +// First ... func First(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", @@ -103,6 +109,7 @@ func First(args ...Object) Object { return nil } +// Last ... func Last(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", @@ -122,6 +129,7 @@ func Last(args ...Object) Object { return nil } +// Rest ... func Rest(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", @@ -143,6 +151,7 @@ func Rest(args ...Object) Object { return nil } +// Push ... func Push(args ...Object) Object { if len(args) != 2 { return newError("wrong number of arguments. got=%d, want=2", @@ -167,6 +176,7 @@ func Push(args ...Object) Object { return &Array{Elements: newElements} } +// Pop ... func Pop(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", @@ -190,6 +200,7 @@ func Pop(args ...Object) Object { return element } +// Exit ... func Exit(args ...Object) Object { if len(args) == 1 { if args[0].Type() != INTEGER_OBJ { diff --git a/testdata/arrays.monkey b/testdata/arrays.monkey new file mode 100644 index 0000000..5e54d70 --- /dev/null +++ b/testdata/arrays.monkey @@ -0,0 +1,2 @@ +let xs = [1, 2, 3] +xs[0] + xs[1] + xs[2] \ No newline at end of file diff --git a/testdata/assign.monkey b/testdata/assign.monkey new file mode 100644 index 0000000..8e13df9 --- /dev/null +++ b/testdata/assign.monkey @@ -0,0 +1,3 @@ +let x = 1 +x = 2 +x = x + 1 \ No newline at end of file diff --git a/testdata/builtins.monkey b/testdata/builtins.monkey new file mode 100644 index 0000000..97c1ae8 --- /dev/null +++ b/testdata/builtins.monkey @@ -0,0 +1,13 @@ +let xs = [1, 2, 3] +len(xs) + +first(xs) +rest(xs) +last(xs) +push(xs, 5) +pop(xs) + +len("foo") + +let x = input() +print(x) \ No newline at end of file diff --git a/testdata/closures.monkey b/testdata/closures.monkey new file mode 100644 index 0000000..0be84a7 --- /dev/null +++ b/testdata/closures.monkey @@ -0,0 +1,2 @@ +let f = fn(x) { fn() { x + 1 } } +f(2) \ No newline at end of file diff --git a/testdata/expressions.monkey b/testdata/expressions.monkey new file mode 100644 index 0000000..d36849f --- /dev/null +++ b/testdata/expressions.monkey @@ -0,0 +1,2 @@ +1 + 2; +(1 + 2) * 3; \ No newline at end of file diff --git a/testdata/functions.monkey b/testdata/functions.monkey new file mode 100644 index 0000000..3caa4a5 --- /dev/null +++ b/testdata/functions.monkey @@ -0,0 +1,2 @@ +let f = fn(x, y) { x * y }; +f(2, 4) \ No newline at end of file diff --git a/testdata/hashes.monkey b/testdata/hashes.monkey new file mode 100644 index 0000000..4aad8db --- /dev/null +++ b/testdata/hashes.monkey @@ -0,0 +1,2 @@ +let d = {"a": 1, "b": 2} +d["a"] + d["b"] \ No newline at end of file diff --git a/testdata/if.monkey b/testdata/if.monkey new file mode 100644 index 0000000..ed7e345 --- /dev/null +++ b/testdata/if.monkey @@ -0,0 +1,5 @@ +let x = 1 +if (x == 1) { + x = 2 + x +} \ No newline at end of file diff --git a/testdata/let.monkey b/testdata/let.monkey new file mode 100644 index 0000000..d44cd88 --- /dev/null +++ b/testdata/let.monkey @@ -0,0 +1,3 @@ +let x = 1 +let y = 2 +let z = x \ No newline at end of file diff --git a/testdata/strings.monkey b/testdata/strings.monkey new file mode 100644 index 0000000..f8ae683 --- /dev/null +++ b/testdata/strings.monkey @@ -0,0 +1,2 @@ +let s = "hello" +s + " " + "world" \ No newline at end of file diff --git a/vm/vm.go b/vm/vm.go index c139179..b89f595 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -316,6 +316,13 @@ func (vm *VM) Run() error { } } + + if vm.Debug { + log.Printf( + "%-25s [ip=%02d fp=%02d, sp=%02d]", + "", ip, vm.framesIndex-1, vm.sp, + ) + } } return nil diff --git a/vm/vm_test.go b/vm/vm_test.go index 5fd0471..c858cd4 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -8,7 +8,9 @@ import ( "monkey/object" "monkey/parser" "os" + "path" "path/filepath" + "strings" "testing" ) @@ -831,6 +833,47 @@ func TestAssignmentStatements(t *testing.T) { runVmTests(t, tests) } +func TestIntegration(t *testing.T) { + matches, err := filepath.Glob("../testdata/*.monkey") + if err != nil { + t.Error(err) + } + + for _, match := range matches { + basename := path.Base(match) + name := strings.TrimSuffix(basename, filepath.Ext(basename)) + + t.Run(name, func(t *testing.T) { + b, err := os.ReadFile(match) + if err != nil { + t.Error(err) + } + + input := string(b) + program := parse(input) + + c := compiler.New() + err = c.Compile(program) + if err != nil { + t.Log(input) + t.Fatalf("compiler error: %s", err) + } + + vm := New(c.Bytecode()) + + err = vm.Run() + if err != nil { + t.Log(input) + t.Fatalf("vm error: %s", err) + } + if vm.sp != 0 { + t.Log(input) + t.Fatal("vm stack pointer non-zero") + } + }) + } +} + func TestExamples(t *testing.T) { matches, err := filepath.Glob("../examples/*.monkey") if err != nil { @@ -838,32 +881,36 @@ func TestExamples(t *testing.T) { } for _, match := range matches { - b, err := os.ReadFile(match) - if err != nil { - t.Error(err) - } + basename := path.Base(match) + name := strings.TrimSuffix(basename, filepath.Ext(basename)) - input := string(b) - program := parse(input) + t.Run(name, func(t *testing.T) { + b, err := os.ReadFile(match) + if err != nil { + t.Error(err) + } - c := compiler.New() - err = c.Compile(program) - if err != nil { - t.Log(input) - t.Fatalf("compiler error: %s", err) - } + input := string(b) + program := parse(input) - vm := New(c.Bytecode()) + c := compiler.New() + err = c.Compile(program) + if err != nil { + t.Log(input) + t.Fatalf("compiler error: %s", err) + } - err = vm.Run() - if err != nil { - t.Log(input) - t.Fatalf("vm error: %s", err) - } + vm := New(c.Bytecode()) - if vm.sp != 0 { - t.Log(input) - t.Fatal("vm stack pointer non-zero") - } + err = vm.Run() + if err != nil { + t.Log(input) + t.Fatalf("vm error: %s", err) + } + if vm.sp != 0 { + t.Log(input) + t.Fatal("vm stack pointer non-zero") + } + }) } }