vm_test.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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 TestArrayLiterals(t *testing.T) {
  90. tests := []vmTestCase{
  91. {"[]", []int{}},
  92. {"[1, 2, 3]", []int{1, 2, 3}},
  93. {"[1+2,3*4,5+6]", []int{3, 12, 11}},
  94. }
  95. runVmTests(t, tests)
  96. }
  97. func TestHashLiterals(t *testing.T) {
  98. test := []vmTestCase{
  99. {"{}", map[object.HashKey]int64{}},
  100. {"{1:2, 2:3}", map[object.HashKey]int64{
  101. (&object.Integer{Value: 1}).HashKey(): 2,
  102. (&object.Integer{Value: 2}).HashKey(): 3,
  103. }},
  104. {"{1+1:2*2, 3+3:4*4}", map[object.HashKey]int64{
  105. (&object.Integer{Value: 2}).HashKey(): 4,
  106. (&object.Integer{Value: 6}).HashKey(): 16,
  107. }},
  108. }
  109. runVmTests(t, test)
  110. }
  111. func TestIndexExpressions(t *testing.T) {
  112. tests := []vmTestCase{
  113. {"[1,2,3][1]", 2},
  114. {"[1,2,3][0+2]", 3},
  115. {"[[1,1,1]][0][0]", 1},
  116. {"[][0]", Null},
  117. {"[1,2,3][99]", Null},
  118. {"[1][-1]", Null},
  119. {"{1:1, 2:2}[1]", 1},
  120. {"{1:1, 2:2}[2]", 2},
  121. {"{1:1}[0]", Null},
  122. {"{}[0]", Null},
  123. }
  124. runVmTests(t, tests)
  125. }
  126. func TestCallingFunctionsWithoutArguments(t *testing.T) {
  127. tests := []vmTestCase{
  128. {
  129. input: `
  130. let fivePlusTen = fn () { 5 + 10; };
  131. fivePlusTen();
  132. `,
  133. expected: 15,
  134. },
  135. {
  136. input: `
  137. let earlyExit = fn () {return 99; 100;};
  138. earlyExit();
  139. `,
  140. expected: 99,
  141. },
  142. }
  143. runVmTests(t, tests)
  144. }
  145. func TestFunctionWithoutReturnValue(t *testing.T) {
  146. tests := []vmTestCase{
  147. {
  148. input: `let noReturn = fn() {};noReturn()`,
  149. expected: Null,
  150. },
  151. {
  152. input: `let noReturn = fn() {};let noReturnTwo=fn(){noReturn();};noReturn(); noReturnTwo();`,
  153. expected: Null,
  154. },
  155. }
  156. runVmTests(t, tests)
  157. }
  158. func TestFirstClassFunctions(t *testing.T) {
  159. tests := []vmTestCase{
  160. {
  161. input: `
  162. let returnsOne = fn() { 1; };
  163. let returnsOneReturner = fn() { returnsOne; };
  164. returnsOneReturner()();
  165. `,
  166. expected: 1,
  167. },
  168. }
  169. runVmTests(t, tests)
  170. }
  171. func TestCallingFunctionsWithBindings(t *testing.T) {
  172. tests := []vmTestCase{
  173. {
  174. input: `let one = fn () {let one = 1; one;}; one();`,
  175. expected: 1,
  176. },
  177. {
  178. input: `
  179. let oneAndTwo = fn() { let one = 1; let two = 2; one + two;};
  180. oneAndTwo();
  181. `,
  182. expected: 3,
  183. },
  184. {
  185. input: `
  186. let oneAndTwo = fn() {let one = 1; let two = 2; one + two;};
  187. let threeAndFour = fn () {let three = 3; let four = 4; three + four; };
  188. oneAndTwo() + threeAndFour();
  189. `,
  190. expected: 10,
  191. },
  192. {
  193. input: `
  194. let firstFoobar = fn() { let foobar = 50; foobar; };
  195. let secondFoobar = fn() { let foobar = 100; foobar; };
  196. firstFoobar() + secondFoobar();
  197. `,
  198. expected: 150,
  199. },
  200. {
  201. input: `
  202. let globalSeed = 50;
  203. let minusOne = fn () { let num = 1; globalSeed - num; };
  204. let minusTwo = fn () { let num = 2; globalSeed - num; };
  205. minusOne() + minusTwo();
  206. `,
  207. expected: 97,
  208. },
  209. }
  210. runVmTests(t, tests)
  211. }
  212. func runVmTests(t *testing.T, tests []vmTestCase) {
  213. t.Helper()
  214. for _, tt := range tests {
  215. program := parse(tt.input)
  216. comp := compiler.New()
  217. err := comp.Compile(program)
  218. if err != nil {
  219. t.Fatalf("compler error: %s", err)
  220. }
  221. vm := New(comp.ByteCode())
  222. err = vm.Run()
  223. if err != nil {
  224. t.Fatalf("vm error: %s", err)
  225. }
  226. stackElem := vm.LastPopStackElem()
  227. testExpectedObject(t, tt.expected, stackElem)
  228. }
  229. }
  230. func parse(input string) *ast.Program {
  231. l := lexer.New(input)
  232. p := parser.New(l)
  233. return p.ParseProgram()
  234. }
  235. func testExpectedObject(
  236. t *testing.T,
  237. expected interface{},
  238. actual object.Object,
  239. ) {
  240. t.Helper()
  241. switch expected := expected.(type) {
  242. case int:
  243. err := testIntegerObject(int64(expected), actual)
  244. if err != nil {
  245. t.Errorf("testIntegerObject failed: %s", err)
  246. }
  247. case bool:
  248. err := testBooleanObject(expected, actual)
  249. if err != nil {
  250. t.Errorf("testBooleanObject failed: %s", err)
  251. }
  252. case string:
  253. err := testStringObject(expected, actual)
  254. if err != nil {
  255. t.Errorf("testStringObject failed: %s", err)
  256. }
  257. case []int:
  258. array, ok := actual.(*object.Array)
  259. if !ok {
  260. t.Errorf("object not Array: %T (%+v)", actual, actual)
  261. return
  262. }
  263. if len(array.Elements) != len(expected) {
  264. t.Errorf("wrong num of elements. want=%d, got=%d", len(expected), len(array.Elements))
  265. return
  266. }
  267. for i, expectedElem := range expected {
  268. err := testIntegerObject(int64(expectedElem), array.Elements[i])
  269. if err != nil {
  270. t.Errorf("testIntegerObject failed: %s", err)
  271. }
  272. }
  273. case map[object.HashKey]int64:
  274. hash, ok := actual.(*object.Hash)
  275. if !ok {
  276. t.Errorf("object is not Hash. got=%T (%+v)", actual, actual)
  277. return
  278. }
  279. if len(hash.Pairs) != len(expected) {
  280. t.Errorf("hash has wrong number of Pairs. want=%d, got=%d", len(expected), len(hash.Pairs))
  281. return
  282. }
  283. for expectedKey, expectedValue := range expected {
  284. pair, ok := hash.Pairs[expectedKey]
  285. if !ok {
  286. t.Errorf("no pair for given key in Pairs")
  287. }
  288. err := testIntegerObject(expectedValue, pair.Value)
  289. if err != nil {
  290. t.Errorf("testIntegerObject failed: %s", err)
  291. }
  292. }
  293. }
  294. }
  295. func testStringObject(expected string, actual object.Object) error {
  296. result, ok := actual.(*object.String)
  297. if !ok {
  298. return fmt.Errorf("object is not String. got=%T (%+v)", actual, actual)
  299. }
  300. if result.Value != expected {
  301. return fmt.Errorf("object has wrong value. got=%q, want=%q", result.Value, expected)
  302. }
  303. return nil
  304. }
  305. func testIntegerObject(expected int64, actual object.Object) error {
  306. result, ok := actual.(*object.Integer)
  307. if !ok {
  308. return fmt.Errorf("object is not Integer. got=%T (%+v)", actual, actual)
  309. }
  310. if result.Value != expected {
  311. return fmt.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
  312. }
  313. return nil
  314. }
  315. func testBooleanObject(expected bool, actual object.Object) error {
  316. result, ok := actual.(*object.Boolean)
  317. if !ok {
  318. return fmt.Errorf("object is not Boolean. got=%T (%+v)", actual, actual)
  319. }
  320. if result.Value != expected {
  321. return fmt.Errorf("object has wrong value. got=%t, want=%t", result.Value, expected)
  322. }
  323. return nil
  324. }