vm_test.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package vm
  2. import (
  3. "fmt"
  4. "github/runnignwater/monkey/ast"
  5. "github/runnignwater/monkey/compiler"
  6. "github/runnignwater/monkey/lexer"
  7. "github/runnignwater/monkey/object"
  8. "github/runnignwater/monkey/parser"
  9. "testing"
  10. )
  11. type vmTestCase struct {
  12. input string
  13. expected interface{}
  14. }
  15. func TestIntegerArithmetic(t *testing.T) {
  16. tests := []vmTestCase{
  17. {"1", 1},
  18. {"2", 2},
  19. {"1 + 2", 3},
  20. {"1 - 2", -1},
  21. {"1 * 2", 2},
  22. {"4 / 2", 2},
  23. {"50 / 2 * 2 + 10 - 5", 55},
  24. {"5 * (2 + 10)", 60},
  25. {"5 + 5 + 5 + 5 - 10", 10},
  26. {"2 * 2 * 2 * 2 * 2", 32},
  27. {"5 * 2 + 10", 20},
  28. {"5 + 2 * 10", 25},
  29. {"5 * (2 + 10)", 60},
  30. {"-5", -5},
  31. {"-10", -10},
  32. {"-50 + 100 + -50", 0},
  33. {"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50},
  34. {"if ((if(false) {10})){10} else {20}", 20},
  35. }
  36. runVmTests(t, tests)
  37. }
  38. func TestBooleanExpression(t *testing.T) {
  39. tests := []vmTestCase{
  40. {"true", true},
  41. {"false", false},
  42. {"1 < 2", true},
  43. {"1 > 2", false},
  44. {"1 < 1", false},
  45. {"1 > 1", false},
  46. {"1 == 1", true},
  47. {"1 != 1", false},
  48. {"true == true", true},
  49. {"false == false", true},
  50. {"true == false", false},
  51. {"false != true", true},
  52. {"(1 < 2) == true", true},
  53. {"(1 < 2) == false", false},
  54. {"!true", false},
  55. {"!false", true},
  56. {"!5", false},
  57. {"!!true", true},
  58. {"!!false", false},
  59. {"!!5", true},
  60. {"if (true) { 10 };", 10},
  61. {"if (true) { 10 } else { 20 };", 10},
  62. {"if (false) { 10 } else { 20 };", 20},
  63. {"if (1) {10}", 10},
  64. {"if (1 < 2) {10}", 10},
  65. {"if (1 < 2) {10} else {20}", 10},
  66. {"if (1 > 2) {10} else {20}", 20},
  67. {"if (false) {10;}", Null},
  68. {"if (1 > 2) {10;}", Null},
  69. {"!(if(false) {5;})", true},
  70. }
  71. runVmTests(t, tests)
  72. }
  73. func TestGlobalLetStatement(t *testing.T) {
  74. tests := []vmTestCase{
  75. {"let one = 1; one", 1},
  76. {"let one = 1; let two = 2; one + two", 3},
  77. {"let one = 1; let two = one + one; one + two", 3},
  78. }
  79. runVmTests(t, tests)
  80. }
  81. func TestStringExpression(t *testing.T) {
  82. tests := []vmTestCase{
  83. {`"monkey"`, "monkey"},
  84. {`"mon" + "key"`, "monkey"},
  85. {`"mon" + "key" + "banana"`, "monkeybanana"},
  86. }
  87. runVmTests(t, tests)
  88. }
  89. func runVmTests(t *testing.T, tests []vmTestCase) {
  90. t.Helper()
  91. for _, tt := range tests {
  92. program := parse(tt.input)
  93. comp := compiler.New()
  94. err := comp.Compile(program)
  95. if err != nil {
  96. t.Fatalf("compler error: %s", err)
  97. }
  98. vm := New(comp.ByteCode())
  99. err = vm.Run()
  100. if err != nil {
  101. t.Fatalf("vm error: %s", err)
  102. }
  103. stackElem := vm.LastPopStackElem()
  104. testExpectedObject(t, tt.expected, stackElem)
  105. }
  106. }
  107. func parse(input string) *ast.Program {
  108. l := lexer.New(input)
  109. p := parser.New(l)
  110. return p.ParseProgram()
  111. }
  112. func testExpectedObject(
  113. t *testing.T,
  114. expected interface{},
  115. actual object.Object,
  116. ) {
  117. t.Helper()
  118. switch expected := expected.(type) {
  119. case int:
  120. err := testIntegerObject(int64(expected), actual)
  121. if err != nil {
  122. t.Errorf("testIntegerObject failed: %s", err)
  123. }
  124. case bool:
  125. err := testBooleanObject(expected, actual)
  126. if err != nil {
  127. t.Errorf("testBooleanObject failed: %s", err)
  128. }
  129. case string:
  130. err := testStringObject(expected, actual)
  131. if err != nil {
  132. t.Errorf("testStringObject failed: %s", err)
  133. }
  134. }
  135. }
  136. func testStringObject(expected string, actual object.Object) error {
  137. result, ok := actual.(*object.String)
  138. if !ok {
  139. return fmt.Errorf("object is not String. got=%T (%+v)", actual, actual)
  140. }
  141. if result.Value != expected {
  142. return fmt.Errorf("object has wrong value. got=%q, want=%q", result.Value, expected)
  143. }
  144. return nil
  145. }
  146. func testIntegerObject(expected int64, actual object.Object) error {
  147. result, ok := actual.(*object.Integer)
  148. if !ok {
  149. return fmt.Errorf("object is not Integer. got=%T (%+v)", actual, actual)
  150. }
  151. if result.Value != expected {
  152. return fmt.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
  153. }
  154. return nil
  155. }
  156. func testBooleanObject(expected bool, actual object.Object) error {
  157. result, ok := actual.(*object.Boolean)
  158. if !ok {
  159. return fmt.Errorf("object is not Boolean. got=%T (%+v)", actual, actual)
  160. }
  161. if result.Value != expected {
  162. return fmt.Errorf("object has wrong value. got=%t, want=%t", result.Value, expected)
  163. }
  164. return nil
  165. }