Change assignment into expressions
This commit is contained in:
@@ -2,6 +2,7 @@ package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"monkey/ast"
|
||||
"monkey/code"
|
||||
"monkey/lexer"
|
||||
@@ -16,6 +17,12 @@ type compilerTestCase struct {
|
||||
expectedInstructions []code.Instructions
|
||||
}
|
||||
|
||||
type compilerTestCase2 struct {
|
||||
input string
|
||||
constants []interface{}
|
||||
instructions string
|
||||
}
|
||||
|
||||
func TestIntegerArithmetic(t *testing.T) {
|
||||
tests := []compilerTestCase{
|
||||
{
|
||||
@@ -264,34 +271,30 @@ func TestConditionals(t *testing.T) {
|
||||
// 0006
|
||||
code.Make(code.OpTrue),
|
||||
// 0007
|
||||
code.Make(code.OpJumpNotTruthy, 20),
|
||||
code.Make(code.OpJumpNotTruthy, 19),
|
||||
// 0010
|
||||
code.Make(code.OpConstant, 1),
|
||||
// 0013
|
||||
code.Make(code.OpAssignGlobal, 0),
|
||||
// 0016
|
||||
// 0018
|
||||
code.Make(code.OpJump, 20),
|
||||
// 0019
|
||||
code.Make(code.OpNull),
|
||||
// 0017
|
||||
code.Make(code.OpJump, 21),
|
||||
// 0020
|
||||
code.Make(code.OpNull),
|
||||
// 0021
|
||||
code.Make(code.OpPop),
|
||||
// 0022
|
||||
// 0021
|
||||
code.Make(code.OpFalse),
|
||||
// 0023
|
||||
code.Make(code.OpJumpNotTruthy, 36),
|
||||
// 0025
|
||||
// 0022
|
||||
code.Make(code.OpJumpNotTruthy, 34),
|
||||
// 0024
|
||||
code.Make(code.OpConstant, 2),
|
||||
// 0029
|
||||
// 0028
|
||||
code.Make(code.OpAssignGlobal, 0),
|
||||
// 0032
|
||||
code.Make(code.OpJump, 35),
|
||||
// 0035
|
||||
code.Make(code.OpNull),
|
||||
// 0033
|
||||
code.Make(code.OpJump, 37),
|
||||
// 0036
|
||||
code.Make(code.OpNull),
|
||||
// 0037
|
||||
code.Make(code.OpPop),
|
||||
},
|
||||
},
|
||||
@@ -475,7 +478,7 @@ func TestIndexExpressions(t *testing.T) {
|
||||
code.Make(code.OpConstant, 3),
|
||||
code.Make(code.OpConstant, 4),
|
||||
code.Make(code.OpAdd),
|
||||
code.Make(code.OpIndex),
|
||||
code.Make(code.OpGetItem),
|
||||
code.Make(code.OpPop),
|
||||
},
|
||||
},
|
||||
@@ -489,7 +492,7 @@ func TestIndexExpressions(t *testing.T) {
|
||||
code.Make(code.OpConstant, 2),
|
||||
code.Make(code.OpConstant, 3),
|
||||
code.Make(code.OpSub),
|
||||
code.Make(code.OpIndex),
|
||||
code.Make(code.OpGetItem),
|
||||
code.Make(code.OpPop),
|
||||
},
|
||||
},
|
||||
@@ -823,6 +826,21 @@ func TestFunctionCalls(t *testing.T) {
|
||||
runCompilerTests(t, tests)
|
||||
}
|
||||
|
||||
func TestAssignmentExpressions(t *testing.T) {
|
||||
tests := []compilerTestCase2{
|
||||
{
|
||||
input: `
|
||||
let x = 1
|
||||
x = 2
|
||||
`,
|
||||
constants: []interface{}{1, 2},
|
||||
instructions: "0000 OpConstant 0\n0003 OpSetGlobal 0\n0006 OpConstant 1\n0009 OpAssignGlobal 0\n0012 OpPop\n",
|
||||
},
|
||||
}
|
||||
|
||||
runCompilerTests2(t, tests)
|
||||
}
|
||||
|
||||
func TestAssignmentStatementScopes(t *testing.T) {
|
||||
tests := []compilerTestCase{
|
||||
{
|
||||
@@ -1085,14 +1103,16 @@ func TestIteration(t *testing.T) {
|
||||
// 0000
|
||||
code.Make(code.OpTrue),
|
||||
// 0001
|
||||
code.Make(code.OpJumpNotTruthy, 10),
|
||||
code.Make(code.OpJumpNotTruthy, 11),
|
||||
// 0004
|
||||
code.Make(code.OpConstant, 0),
|
||||
// 0007
|
||||
code.Make(code.OpPop),
|
||||
// 0008
|
||||
code.Make(code.OpJump, 0),
|
||||
// 0010
|
||||
code.Make(code.OpNoop),
|
||||
// 0011
|
||||
code.Make(code.OpNull),
|
||||
// 0012
|
||||
code.Make(code.OpPop),
|
||||
},
|
||||
},
|
||||
@@ -1127,6 +1147,25 @@ func runCompilerTests(t *testing.T, tests []compilerTestCase) {
|
||||
}
|
||||
}
|
||||
|
||||
func runCompilerTests2(t *testing.T, tests []compilerTestCase2) {
|
||||
t.Helper()
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
for _, tt := range tests {
|
||||
program := parse(tt.input)
|
||||
|
||||
compiler := New()
|
||||
err := compiler.Compile(program)
|
||||
assert.NoError(err)
|
||||
|
||||
bytecode := compiler.Bytecode()
|
||||
assert.Equal(tt.instructions, bytecode.Instructions.String())
|
||||
|
||||
testConstants2(t, tt.constants, bytecode.Constants)
|
||||
}
|
||||
}
|
||||
|
||||
func parse(input string) *ast.Program {
|
||||
l := lexer.New(input)
|
||||
p := parser.New(l)
|
||||
@@ -1193,6 +1232,28 @@ func testConstants(t *testing.T, expected []interface{}, actual []object.Object)
|
||||
return nil
|
||||
}
|
||||
|
||||
func testConstants2(t *testing.T, expected []interface{}, actual []object.Object) {
|
||||
assert := assert.New(t)
|
||||
|
||||
assert.Equal(len(expected), len(actual))
|
||||
|
||||
for i, constant := range expected {
|
||||
switch constant := constant.(type) {
|
||||
|
||||
case []code.Instructions:
|
||||
fn, ok := actual[i].(*object.CompiledFunction)
|
||||
assert.True(ok)
|
||||
assert.Equal(constant, fn.Instructions.String())
|
||||
|
||||
case string:
|
||||
assert.Equal(constant, actual[i].(*object.String).Value)
|
||||
|
||||
case int:
|
||||
assert.Equal(int64(constant), actual[i].(*object.Integer).Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testIntegerObject(expected int64, actual object.Object) interface{} {
|
||||
result, ok := actual.(*object.Integer)
|
||||
if !ok {
|
||||
|
||||
Reference in New Issue
Block a user