| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 |
- package vm
- import (
- "fmt"
- "github/runnignwater/monkey/ast"
- "github/runnignwater/monkey/compiler"
- "github/runnignwater/monkey/lexer"
- "github/runnignwater/monkey/object"
- "github/runnignwater/monkey/parser"
- "testing"
- )
- type vmTestCase struct {
- input string
- expected interface{}
- }
- func TestIntegerArithmetic(t *testing.T) {
- tests := []vmTestCase{
- {"1", 1},
- {"2", 2},
- {"1 + 2", 3},
- {"1 - 2", -1},
- {"1 * 2", 2},
- {"4 / 2", 2},
- {"50 / 2 * 2 + 10 - 5", 55},
- {"5 * (2 + 10)", 60},
- {"5 + 5 + 5 + 5 - 10", 10},
- {"2 * 2 * 2 * 2 * 2", 32},
- {"5 * 2 + 10", 20},
- {"5 + 2 * 10", 25},
- {"5 * (2 + 10)", 60},
- {"-5", -5},
- {"-10", -10},
- {"-50 + 100 + -50", 0},
- {"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
- }
- runVmTests(t, tests)
- }
- func TestBooleanExpression(t *testing.T) {
- tests := []vmTestCase{
- {"true", true},
- {"false", false},
- {"1 < 2", true},
- {"1 > 2", false},
- {"1 < 1", false},
- {"1 > 1", false},
- {"1 == 1", true},
- {"1 != 1", false},
- {"true == true", true},
- {"false == false", true},
- {"true == false", false},
- {"false != true", true},
- {"(1 < 2) == true", true},
- {"(1 < 2) == false", false},
- {"!true", false},
- {"!false", true},
- {"!5", false},
- {"!!true", true},
- {"!!false", false},
- {"!!5", true},
- }
- runVmTests(t, tests)
- }
- func runVmTests(t *testing.T, tests []vmTestCase) {
- t.Helper()
- for _, tt := range tests {
- program := parse(tt.input)
- comp := compiler.New()
- err := comp.Compile(program)
- if err != nil {
- t.Fatalf("compler error: %s", err)
- }
- vm := New(comp.ByteCode())
- err = vm.Run()
- if err != nil {
- t.Fatalf("vm error: %s", err)
- }
- stackElem := vm.LastPopStackElem()
- testExpectedObject(t, tt.expected, stackElem)
- }
- }
- func parse(input string) *ast.Program {
- l := lexer.New(input)
- p := parser.New(l)
- return p.ParseProgram()
- }
- func testExpectedObject(
- t *testing.T,
- expected interface{},
- actual object.Object,
- ) {
- t.Helper()
- switch expected := expected.(type) {
- case int:
- err := testIntegerObject(int64(expected), actual)
- if err != nil {
- t.Errorf("testIntegerObject failed: %s", err)
- }
- case bool:
- err := testBooleanObject(expected, actual)
- if err != nil {
- t.Errorf("testBooleanObject failed: %s", err)
- }
- }
- }
- func testIntegerObject(expected int64, actual object.Object) error {
- result, ok := actual.(*object.Integer)
- if !ok {
- return fmt.Errorf("object is not Integer. got=%T (%+v)", actual, actual)
- }
- if result.Value != expected {
- return fmt.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
- }
- return nil
- }
- func testBooleanObject(expected bool, actual object.Object) error {
- result, ok := actual.(*object.Boolean)
- if !ok {
- return fmt.Errorf("object is not Boolean. got=%T (%+v)", actual, actual)
- }
- if result.Value != expected {
- return fmt.Errorf("object has wrong value. got=%t, want=%t", result.Value, expected)
- }
- return nil
- }
|