evaluator_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. package evaluator
  2. import (
  3. "github/runnignwater/monkey/lexer"
  4. "github/runnignwater/monkey/object"
  5. "github/runnignwater/monkey/parser"
  6. "log"
  7. "testing"
  8. )
  9. func TestEvalIntegerExpression(t *testing.T) {
  10. tests := []struct {
  11. input string
  12. expected int64
  13. }{
  14. {"5", 5},
  15. {"10", 10},
  16. {"-5", -5},
  17. {"-10", -10},
  18. {"5+5+5+5-10", 10},
  19. {"2*2*2*2*2", 32},
  20. {"-50+100+-50", 0},
  21. }
  22. for _, tt := range tests {
  23. evaluated := testEval(tt.input)
  24. testIntegerObject(t, evaluated, tt.expected)
  25. }
  26. }
  27. func TestEvalBooleanExpression(t *testing.T) {
  28. tests := []struct {
  29. input string
  30. expected bool
  31. }{
  32. {"true", true},
  33. {"false", false},
  34. {"1 < 2", true},
  35. {"1 > 2", false},
  36. {"1 == 1", true},
  37. {"1 != 1", false},
  38. {"1 == 2", false},
  39. {"1 != 2", true},
  40. {"true == true", true},
  41. {"false == false", true},
  42. {"(1 < 2) == true", true},
  43. }
  44. for _, tt := range tests {
  45. evaluated := testEval(tt.input)
  46. testBooleanObject(t, evaluated, tt.expected)
  47. }
  48. }
  49. func TestBangOperator(t *testing.T) {
  50. tests := []struct {
  51. input string
  52. expected bool
  53. }{
  54. {"!true", false},
  55. {"!false", true},
  56. {"!5", false},
  57. {"!!true", true},
  58. {"!!false", false},
  59. {"!!5", true},
  60. }
  61. for _, tt := range tests {
  62. evaluated := testEval(tt.input)
  63. testBooleanObject(t, evaluated, tt.expected)
  64. }
  65. }
  66. func TestIfElseExpression(t *testing.T) {
  67. tests := []struct {
  68. input string
  69. expected interface{}
  70. }{
  71. {"if (true) {10}", 10},
  72. {"if(false) {10}", nil},
  73. {"if (1) {10}", 10},
  74. {"if(1<2){10}", 10},
  75. {"if(1>2){10}", nil},
  76. {"if(1<2){10} else {20}", 10},
  77. {"if(1>2){10} else {20}", 20},
  78. }
  79. for _, tt := range tests {
  80. evaluated := testEval(tt.input)
  81. integer, ok := tt.expected.(int)
  82. if ok {
  83. testIntegerObject(t, evaluated, int64(integer))
  84. } else {
  85. testNullObject(t, evaluated)
  86. }
  87. }
  88. }
  89. func TestReturnStatements(t *testing.T) {
  90. tests := []struct {
  91. input string
  92. expected int64
  93. }{
  94. {"return 10;", 10},
  95. {"return 10;9", 10},
  96. {"return 2*5;9;", 10},
  97. {"9;return 3 *5; 9;", 15},
  98. {
  99. `if ( 10 > 1) {
  100. if( 10 > 1) {
  101. return 10;
  102. }
  103. return 1;
  104. }
  105. `,
  106. 10,
  107. },
  108. }
  109. for _, tt := range tests {
  110. evaluated := testEval(tt.input)
  111. testIntegerObject(t, evaluated, tt.expected)
  112. }
  113. }
  114. func TestErrorHandling(t *testing.T) {
  115. tests := []struct {
  116. input string
  117. expectedMsg string
  118. }{
  119. {
  120. "5 + true",
  121. "type mismatch: INTEGER + BOOLEAN",
  122. },
  123. {
  124. "5 + true; 5;",
  125. "type mismatch: INTEGER + BOOLEAN",
  126. },
  127. {
  128. "-true",
  129. "unknown operator: -BOOLEAN",
  130. },
  131. {
  132. "true + false",
  133. "unknown operator: BOOLEAN + BOOLEAN",
  134. },
  135. {
  136. "5;true + false;5",
  137. "unknown operator: BOOLEAN + BOOLEAN",
  138. },
  139. {
  140. "if ( 10 > 1) { true + false; }",
  141. "unknown operator: BOOLEAN + BOOLEAN",
  142. },
  143. {
  144. `
  145. if (10 > 1) {
  146. if (10 > 1) {
  147. return true + false;
  148. }
  149. return 1;
  150. }
  151. `,
  152. "unknown operator: BOOLEAN + BOOLEAN",
  153. },
  154. {
  155. "foobar",
  156. "identifier not found: foobar",
  157. },
  158. {
  159. `"Hello" - "World"`,
  160. "unknown operator: STRING - STRING",
  161. },
  162. {
  163. `{"name": "Monkey"}[fn(x){x}]`,
  164. "unusable as hash key: FUNCTION",
  165. },
  166. }
  167. for _, tt := range tests {
  168. evaluated := testEval(tt.input)
  169. errObj, ok := evaluated.(*object.Error)
  170. if !ok {
  171. t.Errorf("no error object returned. got=%T (%+v)", evaluated, evaluated)
  172. continue
  173. }
  174. if errObj.Msg != tt.expectedMsg {
  175. t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedMsg, errObj.Msg)
  176. }
  177. }
  178. }
  179. func TestLetStatement(t *testing.T) {
  180. tests := []struct {
  181. input string
  182. expected int64
  183. }{
  184. {"let a = 5;a;", 5},
  185. {"let a = 5 * 5;a;", 25},
  186. {"let a = 5;let b = a;b;", 5},
  187. {"let a = 5; let b = a;let c = a + b + 5;c;", 15},
  188. }
  189. for _, tt := range tests {
  190. testIntegerObject(t, testEval(tt.input), tt.expected)
  191. }
  192. }
  193. func TestFunctionObject(t *testing.T) {
  194. input := "fn(x) {x + 2;};"
  195. evaluated := testEval(input)
  196. fn, ok := evaluated.(*object.Function)
  197. if !ok {
  198. t.Fatalf("object is not Function. got=%T (%+v)", evaluated, evaluated)
  199. }
  200. if len(fn.Parameters) != 1 {
  201. t.Fatalf("function has wrong parameters. Parameters=%+v", fn.Parameters)
  202. }
  203. if fn.Parameters[0].String() != "x" {
  204. t.Fatalf("parameter is not 'x'. got=%q", fn.Parameters[0])
  205. }
  206. expectedBody := "(x + 2)"
  207. if fn.Body.String() != expectedBody {
  208. t.Fatalf("body is not %q. got=%q", expectedBody, fn.Body.String())
  209. }
  210. }
  211. func TestFunctionApplication(t *testing.T) {
  212. tests := []struct {
  213. input string
  214. expected int64
  215. }{
  216. {"let identity = fn(x) {x;};identity(5);", 5},
  217. {"let identify = fn(x){return x;};identify(5);", 5},
  218. {"let double = fn(x) { x * 2; };double(5);", 10},
  219. {"let add = fn(x,y){x+y;};add(5,5);", 10},
  220. {"let add = fn(x,y){x+y;};add(5+5,add(5,5));", 20},
  221. {"fn(x){x;}(5)", 5},
  222. }
  223. for _, tt := range tests {
  224. testIntegerObject(t, testEval(tt.input), tt.expected)
  225. }
  226. }
  227. // --------------------------------------------------------------------------------------------------------------------
  228. func testNullObject(t *testing.T, obj object.Object) bool {
  229. if obj != NULL {
  230. t.Errorf("object is not NULL. got=%T (%+v)", obj, obj)
  231. return false
  232. }
  233. return true
  234. }
  235. func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
  236. result, ok := obj.(*object.Integer)
  237. if !ok {
  238. t.Errorf("object is not Integer. got=%T (%+v)", obj, obj)
  239. return false
  240. }
  241. if result.Value != expected {
  242. t.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
  243. return false
  244. }
  245. return true
  246. }
  247. func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
  248. result, ok := obj.(*object.Boolean)
  249. if !ok {
  250. t.Errorf("object is not Boolean. got=%T (%+v)", obj, obj)
  251. return false
  252. }
  253. if result.Value != expected {
  254. t.Errorf("object has wrong value. got=%t, want=%t", result.Value, expected)
  255. return false
  256. }
  257. return true
  258. }
  259. func testEval(input string) object.Object {
  260. l := lexer.New(input)
  261. p := parser.New(l)
  262. program := p.ParseProgram()
  263. env := object.NewEnvironment()
  264. return Eval(program, env)
  265. }
  266. func TestClosures(t *testing.T) {
  267. input := `
  268. let newAdder = fn(x) {
  269. fn (y) { x + y };
  270. };
  271. let addTwo = newAdder(2); addTwo(2);
  272. `
  273. testIntegerObject(t, testEval(input), 4)
  274. }
  275. func TestStringLiteral(t *testing.T) {
  276. input := `"Hello World!"`
  277. evaluated := testEval(input)
  278. str, ok := evaluated.(*object.String)
  279. if !ok {
  280. t.Fatalf("object is not String. got=%T (%+v)", evaluated, evaluated)
  281. }
  282. if str.Value != "Hello World!" {
  283. t.Errorf("String has wrong value. got=%q", str.Value)
  284. }
  285. }
  286. func TestStringConcatenation(t *testing.T) {
  287. input := `"Hello" + " " + "World!"`
  288. evaluated := testEval(input)
  289. str, ok := evaluated.(*object.String)
  290. if !ok {
  291. t.Fatalf("object is not String. got=%T (%+v)", evaluated, evaluated)
  292. }
  293. if str.Value != "Hello World!" {
  294. t.Errorf("String has wrong value. got=%q", str.Value)
  295. }
  296. }
  297. // ------------------------------------------------------------------------Built-in Function
  298. func TestBuiltinFunctions(t *testing.T) {
  299. tests := []struct {
  300. input string
  301. expected interface{}
  302. }{
  303. {`len("")`, 0},
  304. {`len("four")`, 4},
  305. {`len("hello world")`, 11},
  306. {`len(1)`, "argument to `len` not supported, got INTEGER"},
  307. {`len("one", "two")`, "wrong number of arguments. got=2, want=1"},
  308. }
  309. for _, tt := range tests {
  310. evaluated := testEval(tt.input)
  311. switch expected := tt.expected.(type) {
  312. case int:
  313. testIntegerObject(t, evaluated, int64(expected))
  314. case string:
  315. errObj, ok := evaluated.(*object.Error)
  316. if !ok {
  317. t.Errorf("object is not Error. got=%T (%+v)", evaluated, evaluated)
  318. }
  319. if errObj.Msg != expected {
  320. t.Errorf("wrong error message. expected=%q, got=%q", expected, errObj.Msg)
  321. }
  322. }
  323. }
  324. }
  325. func TestArrayLiterals(t *testing.T) {
  326. input := "[1, 2 * 2, 3 + 5]"
  327. evaluated := testEval(input)
  328. result, ok := evaluated.(*object.Array)
  329. if !ok {
  330. t.Fatalf("object is not Array. got=%T (%+v)", evaluated, evaluated)
  331. }
  332. if len(result.Elements) != 3 {
  333. log.Fatalf("array has wrong num of elements. got=%d",
  334. len(result.Elements))
  335. }
  336. testIntegerObject(t, result.Elements[0], 1)
  337. testIntegerObject(t, result.Elements[1], 4)
  338. testIntegerObject(t, result.Elements[2], 8)
  339. }
  340. func TestArrayIndexExpression(t *testing.T) {
  341. tests := []struct {
  342. input string
  343. expected interface{}
  344. }{
  345. {
  346. "[1, 2, 3][0]",
  347. 1,
  348. },
  349. {
  350. "[1, 2, 3][1]",
  351. 2,
  352. },
  353. {
  354. "[1, 2, 3][2]",
  355. 3,
  356. },
  357. {
  358. "let i = 0; [1][i];",
  359. 1,
  360. },
  361. {
  362. "[1, 2, 3][1 + 1]",
  363. 3,
  364. },
  365. {
  366. "let myArray = [1, 2, 3];myArray[2]",
  367. 3,
  368. },
  369. {
  370. "let myArray = [1, 2, 3];myArray[0]+myArray[1]+myArray[2]",
  371. 6,
  372. },
  373. {
  374. "let myArray = [1, 2, 3]; let i = myArray[0];myArray[i];",
  375. 2,
  376. },
  377. {
  378. "[1, 2, 3][3]",
  379. nil,
  380. },
  381. {
  382. "[1, 2, 3][-1]",
  383. nil,
  384. },
  385. }
  386. for _, tt := range tests {
  387. evaluated := testEval(tt.input)
  388. integer, ok := tt.expected.(int)
  389. if ok {
  390. testIntegerObject(t, evaluated, int64(integer))
  391. } else {
  392. testNullObject(t, evaluated)
  393. }
  394. }
  395. }
  396. func TestHashLiterals(t *testing.T) {
  397. input := `let two = "two";
  398. {
  399. "one" : 10 -9,
  400. "two" : 1 + 1,
  401. "thr"+"ee" : 6 / 2,
  402. 4 : 4,
  403. true: 5,
  404. false :6
  405. }
  406. `
  407. evaluated := testEval(input)
  408. result, ok := evaluated.(*object.Hash)
  409. if !ok {
  410. t.Fatalf("Eval didn't return Hash. got=%T (%+v)", evaluated, evaluated)
  411. }
  412. expected := map[object.HashKey]int64{
  413. (&object.String{Value: "one"}).HashKey(): 1,
  414. (&object.String{Value: "two"}).HashKey(): 2,
  415. (&object.String{Value: "three"}).HashKey(): 3,
  416. (&object.Integer{Value: 4}).HashKey(): 4,
  417. TRUE.HashKey(): 5,
  418. FALSE.HashKey(): 6,
  419. }
  420. if len(result.Pairs) != len(expected) {
  421. t.Fatalf("Hash has wrong num of pairs. got=%d", len(result.Pairs))
  422. }
  423. for expectedKey, expectedValue := range expected {
  424. pair, ok := result.Pairs[expectedKey]
  425. if !ok {
  426. t.Errorf("no pair for given key in Pairs")
  427. }
  428. testIntegerObject(t, pair.Value, expectedValue)
  429. }
  430. }
  431. func TestHashIndexExpression(t *testing.T) {
  432. tests := []struct {
  433. input string
  434. expected interface{}
  435. }{
  436. {
  437. `{"foo":5}["foo"]`,
  438. 5,
  439. },
  440. {
  441. `{"foo":5}["bar"]`,
  442. nil,
  443. },
  444. {
  445. `let key = "foo"; {"foo":5}[key]`,
  446. 5,
  447. },
  448. {
  449. `{}["foo"]`,
  450. nil,
  451. },
  452. {
  453. `{5:5}[5]`,
  454. 5,
  455. },
  456. {
  457. `{true: 5}[true]`,
  458. 5,
  459. },
  460. {`{false:5}[false]`,
  461. 5,
  462. },
  463. }
  464. for _, tt := range tests {
  465. evaluated := testEval(tt.input)
  466. integer, ok := tt.expected.(int)
  467. if ok {
  468. testIntegerObject(t, evaluated, int64(integer))
  469. } else {
  470. testNullObject(t, evaluated)
  471. }
  472. }
  473. }