Browse Source

Compiling Expression

runningwater 3 years ago
parent
commit
73f734b946
6 changed files with 25 additions and 3 deletions
  1. 2 0
      code/code.go
  2. 1 0
      compiler/compiler.go
  3. 13 0
      compiler/compiler_test.go
  4. 2 2
      repl/repl.go
  5. 6 0
      vm/vm.go
  6. 1 1
      vm/vm_test.go

+ 2 - 0
code/code.go

@@ -63,6 +63,7 @@ type Opcode byte
 const (
 	OpConstant Opcode = iota
 	OpAdd
+	OpPop
 )
 
 // Definition For debugging and testing purposes
@@ -80,6 +81,7 @@ type Definition struct {
 var definitions = map[Opcode]*Definition{
 	OpConstant: {"OpConstant", []int{2}},
 	OpAdd:      {"OpAdd", []int{}}, // doesn't have any operands
+	OpPop:      {"OpPop", []int{}},
 }
 
 func Lookup(op byte) (*Definition, error) {

+ 1 - 0
compiler/compiler.go

@@ -39,6 +39,7 @@ func (c *Compiler) Compile(node ast.Node) error {
 		if err != nil {
 			return err
 		}
+		c.emit(code.OpPop)
 
 	case *ast.InfixExpression:
 		err := c.Compile(node.Left)

+ 13 - 0
compiler/compiler_test.go

@@ -25,6 +25,17 @@ func TestIntegerArithmetic(t *testing.T) {
 				code.Make(code.OpConstant, 0),
 				code.Make(code.OpConstant, 1),
 				code.Make(code.OpAdd),
+				code.Make(code.OpPop),
+			},
+		},
+		{
+			input:             "1;2",
+			expectedConstants: []interface{}{1, 2},
+			expectedInstructions: []code.Instructions{
+				code.Make(code.OpConstant, 0),
+				code.Make(code.OpPop),
+				code.Make(code.OpConstant, 1),
+				code.Make(code.OpPop),
 			},
 		},
 	}
@@ -62,6 +73,8 @@ func testConstants(
 	expected []interface{},
 	actual []object.Object,
 ) error {
+	t.Helper()
+
 	if len(expected) != len(actual) {
 		return fmt.Errorf("wrong number of constants. got=%d, want=%d", len(actual), len(expected))
 	}

+ 2 - 2
repl/repl.go

@@ -70,8 +70,8 @@ func Start(in io.Reader, out io.Writer) {
 			continue
 		}
 
-		stackTop := machine.StackTop()
-		_, err = io.WriteString(out, stackTop.Inspect())
+		lastPopped := machine.LastPopStackElem()
+		_, err = io.WriteString(out, lastPopped.Inspect())
 		if err != nil {
 			return
 		}

+ 6 - 0
vm/vm.go

@@ -64,6 +64,8 @@ func (vm *VM) Run() error {
 			if err != nil {
 				return err
 			}
+		case code.OpPop:
+			vm.pop()
 		}
 	}
 
@@ -86,3 +88,7 @@ func (vm *VM) pop() object.Object {
 	vm.sp--
 	return o
 }
+
+func (vm *VM) LastPopStackElem() object.Object {
+	return vm.stack[vm.sp]
+}

+ 1 - 1
vm/vm_test.go

@@ -43,7 +43,7 @@ func runVmTests(t *testing.T, tests []vmTestCase) {
 			t.Fatalf("vm error: %s", err)
 		}
 
-		stackElem := vm.StackTop()
+		stackElem := vm.LastPopStackElem()
 
 		testExpectedObject(t, tt.expected, stackElem)
 	}