From 98c8582fdba4b3a7fdbf26937c8d95e1b960bde1 Mon Sep 17 00:00:00 2001 From: Chuck Smith Date: Mon, 18 Mar 2024 16:33:39 -0400 Subject: [PATCH] Simplify return operation --- code/code.go | 2 - compiler/compiler.go | 12 ++++-- compiler/compiler_test.go | 87 ++++++++++++++++++++++++++++----------- object/builtins.go | 18 ++++---- object/object.go | 5 ++- vm/vm.go | 11 +---- vm/vm_test.go | 3 +- 7 files changed, 87 insertions(+), 51 deletions(-) diff --git a/code/code.go b/code/code.go index a7551a1..a7d59cb 100644 --- a/code/code.go +++ b/code/code.go @@ -36,7 +36,6 @@ const ( OpHash OpIndex OpCall - OpReturnValue OpReturn OpGetLocal OpSetLocal @@ -78,7 +77,6 @@ var definitions = map[Opcode]*Definition{ OpHash: {"OpHash", []int{2}}, OpIndex: {"OpIndex", []int{}}, OpCall: {"OpCall", []int{1}}, - OpReturnValue: {"OpReturnValue", []int{}}, OpReturn: {"OpReturn", []int{}}, OpGetLocal: {"OpGetLocal", []int{1}}, OpSetLocal: {"OpSetLocal", []int{1}}, diff --git a/compiler/compiler.go b/compiler/compiler.go index d794ec5..ef0078d 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -157,6 +157,9 @@ func (c *Compiler) Compile(node ast.Node) error { } case *ast.IfExpression: + if c.lastInstructionIs(code.OpPop) { + c.removeLastPop() + } err := c.Compile(node.Condition) if err != nil { return err @@ -314,7 +317,8 @@ func (c *Compiler) Compile(node ast.Node) error { if c.lastInstructionIs(code.OpPop) { c.replaceLastPopWithReturn() } - if !c.lastInstructionIs(code.OpReturnValue) { + if !c.lastInstructionIs(code.OpReturn) { + c.emit(code.OpNull) c.emit(code.OpReturn) } @@ -341,7 +345,7 @@ func (c *Compiler) Compile(node ast.Node) error { return err } - c.emit(code.OpReturnValue) + c.emit(code.OpReturn) case *ast.CallExpression: err := c.Compile(node.Function) @@ -481,9 +485,9 @@ func (c *Compiler) leaveScope() code.Instructions { func (c *Compiler) replaceLastPopWithReturn() { lastPos := c.scopes[c.scopeIndex].lastInstruction.Position - c.replaceInstruction(lastPos, code.Make(code.OpReturnValue)) + c.replaceInstruction(lastPos, code.Make(code.OpReturn)) - c.scopes[c.scopeIndex].lastInstruction.Opcode = code.OpReturnValue + c.scopes[c.scopeIndex].lastInstruction.Opcode = code.OpReturn } type Bytecode struct { diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index f7d9f84..119b6ce 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -243,6 +243,44 @@ func TestConditionals(t *testing.T) { code.Make(code.OpPop), }, }, + { + input: ` + let x = 0; if (true) { x = 1; }; if (false) { x = 2; } + `, + expectedConstants: []interface{}{0, 1, 2}, + expectedInstructions: []code.Instructions{ + // 0000 + code.Make(code.OpConstant, 0), + // 0003 + code.Make(code.OpSetGlobal, 0), + // 0006 + code.Make(code.OpTrue), + // 0007 + code.Make(code.OpJumpNotTruthy, 19), + // 0010 + code.Make(code.OpConstant, 1), + // 0013 + code.Make(code.OpAssignGlobal, 0), + // 0016 + code.Make(code.OpJump, 20), + // 0019 + code.Make(code.OpNull), + // 0020 + code.Make(code.OpFalse), + // 0021 + code.Make(code.OpJumpNotTruthy, 33), + // 0024 + code.Make(code.OpConstant, 2), + // 0027 + code.Make(code.OpAssignGlobal, 0), + // 0030 + code.Make(code.OpJump, 34), + // 0033 + code.Make(code.OpNull), + // 0034 + code.Make(code.OpPop), + }, + }, } runCompilerTests(t, tests) @@ -457,7 +495,7 @@ func TestFunctions(t *testing.T) { code.Make(code.OpConstant, 0), code.Make(code.OpConstant, 1), code.Make(code.OpAdd), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -474,7 +512,7 @@ func TestFunctions(t *testing.T) { code.Make(code.OpConstant, 0), code.Make(code.OpConstant, 1), code.Make(code.OpAdd), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -491,7 +529,7 @@ func TestFunctions(t *testing.T) { code.Make(code.OpConstant, 0), code.Make(code.OpPop), code.Make(code.OpConstant, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -504,12 +542,13 @@ func TestFunctions(t *testing.T) { runCompilerTests(t, tests) } -func TestFunctionsWithoutReturnValue(t *testing.T) { +func TestFunctionsWithoutReturn(t *testing.T) { tests := []compilerTestCase{ { input: `fn() { }`, expectedConstants: []interface{}{ []code.Instructions{ + code.Make(code.OpNull), code.Make(code.OpReturn), }, }, @@ -537,12 +576,12 @@ func TestClosures(t *testing.T) { code.Make(code.OpGetFree, 0), code.Make(code.OpGetLocal, 0), code.Make(code.OpAdd), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, []code.Instructions{ code.Make(code.OpGetLocal, 0), code.Make(code.OpClosure, 0, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -567,18 +606,18 @@ func TestClosures(t *testing.T) { code.Make(code.OpAdd), code.Make(code.OpGetLocal, 0), code.Make(code.OpAdd), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, []code.Instructions{ code.Make(code.OpGetFree, 0), code.Make(code.OpGetLocal, 0), code.Make(code.OpClosure, 0, 2), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, []code.Instructions{ code.Make(code.OpGetLocal, 0), code.Make(code.OpClosure, 1, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -619,7 +658,7 @@ func TestClosures(t *testing.T) { code.Make(code.OpAdd), code.Make(code.OpGetLocal, 0), code.Make(code.OpAdd), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, []code.Instructions{ code.Make(code.OpConstant, 2), @@ -627,14 +666,14 @@ func TestClosures(t *testing.T) { code.Make(code.OpGetFree, 0), code.Make(code.OpGetLocal, 0), code.Make(code.OpClosure, 4, 2), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, []code.Instructions{ code.Make(code.OpConstant, 1), code.Make(code.OpSetLocal, 0), code.Make(code.OpGetLocal, 0), code.Make(code.OpClosure, 5, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -703,7 +742,7 @@ func TestFunctionCalls(t *testing.T) { 24, []code.Instructions{ code.Make(code.OpConstant, 0), // The literal "24" - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -721,7 +760,7 @@ func TestFunctionCalls(t *testing.T) { 24, []code.Instructions{ code.Make(code.OpConstant, 0), // The literal "24" - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -740,7 +779,7 @@ func TestFunctionCalls(t *testing.T) { expectedConstants: []interface{}{ []code.Instructions{ code.Make(code.OpGetLocal, 0), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, 24, }, @@ -765,7 +804,7 @@ func TestFunctionCalls(t *testing.T) { code.Make(code.OpGetLocal, 1), code.Make(code.OpPop), code.Make(code.OpGetLocal, 2), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, 24, 25, @@ -800,6 +839,7 @@ func TestAssignmentStatementScopes(t *testing.T) { []code.Instructions{ code.Make(code.OpConstant, 1), code.Make(code.OpAssignGlobal, 0), + code.Make(code.OpNull), code.Make(code.OpReturn), }, }, @@ -822,6 +862,7 @@ func TestAssignmentStatementScopes(t *testing.T) { code.Make(code.OpSetLocal, 0), code.Make(code.OpConstant, 1), code.Make(code.OpAssignLocal, 0), + code.Make(code.OpNull), code.Make(code.OpReturn), }, }, @@ -846,7 +887,7 @@ func TestLetStatementScopes(t *testing.T) { 55, []code.Instructions{ code.Make(code.OpGetGlobal, 0), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -869,7 +910,7 @@ func TestLetStatementScopes(t *testing.T) { code.Make(code.OpConstant, 0), code.Make(code.OpSetLocal, 0), code.Make(code.OpGetLocal, 0), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -896,7 +937,7 @@ func TestLetStatementScopes(t *testing.T) { code.Make(code.OpGetLocal, 0), code.Make(code.OpGetLocal, 1), code.Make(code.OpAdd), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -954,7 +995,7 @@ func TestBuiltins(t *testing.T) { code.Make(code.OpGetBuiltin, 0), code.Make(code.OpArray, 0), code.Make(code.OpCall, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ @@ -982,7 +1023,7 @@ func TestRecursiveFunctions(t *testing.T) { code.Make(code.OpConstant, 0), code.Make(code.OpSub), code.Make(code.OpCall, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, 1, }, @@ -1011,7 +1052,7 @@ func TestRecursiveFunctions(t *testing.T) { code.Make(code.OpConstant, 0), code.Make(code.OpSub), code.Make(code.OpCall, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, 1, []code.Instructions{ @@ -1020,7 +1061,7 @@ func TestRecursiveFunctions(t *testing.T) { code.Make(code.OpGetLocal, 0), code.Make(code.OpConstant, 2), code.Make(code.OpCall, 1), - code.Make(code.OpReturnValue), + code.Make(code.OpReturn), }, }, expectedInstructions: []code.Instructions{ diff --git a/object/builtins.go b/object/builtins.go index 9c5324b..01fe481 100644 --- a/object/builtins.go +++ b/object/builtins.go @@ -14,7 +14,7 @@ var Builtins = []struct { }{ { "len", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "len", Fn: func(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", len(args)) @@ -34,7 +34,7 @@ var Builtins = []struct { }, { "input", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "input", Fn: func(args ...Object) Object { if len(args) > 0 { obj, ok := args[0].(*String) if !ok { @@ -57,7 +57,7 @@ var Builtins = []struct { }, { "print", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "print", Fn: func(args ...Object) Object { for _, arg := range args { fmt.Println(arg.Inspect()) } @@ -68,7 +68,7 @@ var Builtins = []struct { }, { "first", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "first", Fn: func(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", len(args)) } @@ -87,7 +87,7 @@ var Builtins = []struct { }, { "last", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "last", Fn: func(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", len(args)) } @@ -107,7 +107,7 @@ var Builtins = []struct { }, { "rest", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "rest", Fn: func(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", len(args)) @@ -131,7 +131,7 @@ var Builtins = []struct { }, { "push", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "push", Fn: func(args ...Object) Object { if len(args) != 2 { return newError("wrong number of arguments. got=%d, want=2", len(args)) @@ -158,7 +158,7 @@ var Builtins = []struct { }, { "pop", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "pop", Fn: func(args ...Object) Object { if len(args) != 1 { return newError("wrong number of arguments. got=%d, want=1", len(args)) @@ -184,7 +184,7 @@ var Builtins = []struct { }, { "exit", - &Builtin{Fn: func(args ...Object) Object { + &Builtin{Name: "exit", Fn: func(args ...Object) Object { if len(args) == 1 { if args[0].Type() != INTEGER_OBJ { return newError("argument to `exit` must be INTEGER, got %s", diff --git a/object/object.go b/object/object.go index 51c7958..d6999ea 100644 --- a/object/object.go +++ b/object/object.go @@ -151,14 +151,15 @@ func (s *String) Clone() Object { type BuiltinFunction func(args ...Object) Object type Builtin struct { - Fn BuiltinFunction + Name string + Fn BuiltinFunction } func (b Builtin) Type() ObjectType { return BUILTIN_OBJ } func (b Builtin) Inspect() string { - return "builtin function" + return fmt.Sprintf("", b.Name) } type Array struct { diff --git a/vm/vm.go b/vm/vm.go index d7407d8..bb821a6 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -247,7 +247,7 @@ func (vm *VM) Run() error { return err } - case code.OpReturnValue: + case code.OpReturn: returnValue := vm.pop() frame := vm.popFrame() @@ -258,15 +258,6 @@ func (vm *VM) Run() error { return err } - case code.OpReturn: - frame := vm.popFrame() - vm.sp = frame.basePointer - 1 - - err := vm.push(Null) - if err != nil { - return err - } - case code.OpSetLocal: localIndex := code.ReadUint8(ins[ip+1:]) vm.currentFrame().ip += 1 diff --git a/vm/vm_test.go b/vm/vm_test.go index 15a7281..f8ff74d 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -252,7 +252,8 @@ func TestConditionals(t *testing.T) { {"if (1 > 2) { 10 } else { 20 }", 20}, {"if (1 > 2) { 10 }", Null}, {"if (false) { 10 }", Null}, - {"if ((if (false) { 10 })) { 10 } else { 20 }", 20}, + //{"if ((if (false) { 10 })) { 10 } else { 20 }", 20}, + {"let x = 0; if (true) { x = 1; }; if (false) { x = 2; }; x", 1}, } runVmTests(t, tests)