evaluator_test.go 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package evaluator
  2. import (
  3. "github/runnignwater/monkey/lexer"
  4. "github/runnignwater/monkey/object"
  5. "github/runnignwater/monkey/parser"
  6. "testing"
  7. )
  8. func TestEvalIntegerExpression(t *testing.T) {
  9. tests := []struct {
  10. input string
  11. expected int64
  12. }{
  13. {"5", 5},
  14. {"10", 10},
  15. {"-5", -5},
  16. {"-10", -10},
  17. {"5+5+5+5-10", 10},
  18. {"2*2*2*2*2", 32},
  19. {"-50+100+-50", 0},
  20. }
  21. for _, tt := range tests {
  22. evaluated := testEval(tt.input)
  23. testIntegerObject(t, evaluated, tt.expected)
  24. }
  25. }
  26. func TestEvalBooleanExpression(t *testing.T) {
  27. tests := []struct {
  28. input string
  29. expected bool
  30. }{
  31. {"true", true},
  32. {"false", false},
  33. {"1 < 2", true},
  34. {"1 > 2", false},
  35. {"1 == 1", true},
  36. {"1 != 1", false},
  37. {"1 == 2", false},
  38. {"1 != 2", true},
  39. {"true == true", true},
  40. {"false == false", true},
  41. {"(1 < 2) == true", true},
  42. }
  43. for _, tt := range tests {
  44. evaluated := testEval(tt.input)
  45. testBooleanObject(t, evaluated, tt.expected)
  46. }
  47. }
  48. func TestBangOperator(t *testing.T) {
  49. tests := []struct {
  50. input string
  51. expected bool
  52. }{
  53. {"!true", false},
  54. {"!false", true},
  55. {"!5", false},
  56. {"!!true", true},
  57. {"!!false", false},
  58. {"!!5", true},
  59. }
  60. for _, tt := range tests {
  61. evaluated := testEval(tt.input)
  62. testBooleanObject(t, evaluated, tt.expected)
  63. }
  64. }
  65. func TestIfElseExpression(t *testing.T) {
  66. tests := []struct {
  67. input string
  68. expected interface{}
  69. }{
  70. {"if (true) {10}", 10},
  71. {"if(false) {10}", nil},
  72. {"if (1) {10}", 10},
  73. {"if(1<2){10}", 10},
  74. {"if(1>2){10}", nil},
  75. {"if(1<2){10} else {20}", 10},
  76. {"if(1>2){10} else {20}", 20},
  77. }
  78. for _, tt := range tests {
  79. evaluated := testEval(tt.input)
  80. integer, ok := tt.expected.(int)
  81. if ok {
  82. testIntegerObject(t, evaluated, int64(integer))
  83. } else {
  84. testNullObject(t, evaluated)
  85. }
  86. }
  87. }
  88. func TestReturnStatements(t *testing.T) {
  89. tests := []struct {
  90. input string
  91. expected int64
  92. }{
  93. {"return 10;", 10},
  94. {"return 10;9", 10},
  95. {"return 2*5;9;", 10},
  96. {"9;return 3 *5; 9;", 15},
  97. {
  98. `if ( 10 > 1) {
  99. if( 10 > 1) {
  100. return 10;
  101. }
  102. return 1;
  103. }
  104. `,
  105. 10,
  106. },
  107. }
  108. for _, tt := range tests {
  109. evaluated := testEval(tt.input)
  110. testIntegerObject(t, evaluated, tt.expected)
  111. }
  112. }
  113. func TestErrorHandling(t *testing.T) {
  114. tests := []struct {
  115. input string
  116. expectedMsg string
  117. }{
  118. {
  119. "5 + true",
  120. "type mismatch: INTEGER + BOOLEAN",
  121. },
  122. {
  123. "5 + true; 5;",
  124. "type mismatch: INTEGER + BOOLEAN",
  125. },
  126. {
  127. "-true",
  128. "unknown operator: -BOOLEAN",
  129. },
  130. {
  131. "true + false",
  132. "unknown operator: BOOLEAN + BOOLEAN",
  133. },
  134. {
  135. "5;true + false;5",
  136. "unknown operator: BOOLEAN + BOOLEAN",
  137. },
  138. {
  139. "if ( 10 > 1) { true + false; }",
  140. "unknown operator: BOOLEAN + BOOLEAN",
  141. },
  142. {
  143. `
  144. if (10 > 1) {
  145. if (10 > 1) {
  146. return true + false;
  147. }
  148. return 1;
  149. }
  150. `,
  151. "unknown operator: BOOLEAN + BOOLEAN",
  152. },
  153. {
  154. "foobar",
  155. "identifier not found: foobar",
  156. },
  157. {
  158. `"Hello" - "World"`,
  159. "unknown operator: STRING - STRING",
  160. },
  161. }
  162. for _, tt := range tests {
  163. evaluated := testEval(tt.input)
  164. errObj, ok := evaluated.(*object.Error)
  165. if !ok {
  166. t.Errorf("no error object returned. got=%T (%+v)", evaluated, evaluated)
  167. continue
  168. }
  169. if errObj.Msg != tt.expectedMsg {
  170. t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedMsg, errObj.Msg)
  171. }
  172. }
  173. }
  174. func TestLetStatement(t *testing.T) {
  175. tests := []struct {
  176. input string
  177. expected int64
  178. }{
  179. {"let a = 5;a;", 5},
  180. {"let a = 5 * 5;a;", 25},
  181. {"let a = 5;let b = a;b;", 5},
  182. {"let a = 5; let b = a;let c = a + b + 5;c;", 15},
  183. }
  184. for _, tt := range tests {
  185. testIntegerObject(t, testEval(tt.input), tt.expected)
  186. }
  187. }
  188. func TestFunctionObject(t *testing.T) {
  189. input := "fn(x) {x + 2;};"
  190. evaluated := testEval(input)
  191. fn, ok := evaluated.(*object.Function)
  192. if !ok {
  193. t.Fatalf("object is not Function. got=%T (%+v)", evaluated, evaluated)
  194. }
  195. if len(fn.Parameters) != 1 {
  196. t.Fatalf("function has wrong parameters. Parameters=%+v", fn.Parameters)
  197. }
  198. if fn.Parameters[0].String() != "x" {
  199. t.Fatalf("parameter is not 'x'. got=%q", fn.Parameters[0])
  200. }
  201. expectedBody := "(x + 2)"
  202. if fn.Body.String() != expectedBody {
  203. t.Fatalf("body is not %q. got=%q", expectedBody, fn.Body.String())
  204. }
  205. }
  206. func TestFunctionApplication(t *testing.T) {
  207. tests := []struct {
  208. input string
  209. expected int64
  210. }{
  211. {"let identity = fn(x) {x;};identity(5);", 5},
  212. {"let identify = fn(x){return x;};identify(5);", 5},
  213. {"let double = fn(x) { x * 2; };double(5);", 10},
  214. {"let add = fn(x,y){x+y;};add(5,5);", 10},
  215. {"let add = fn(x,y){x+y;};add(5+5,add(5,5));", 20},
  216. {"fn(x){x;}(5)", 5},
  217. }
  218. for _, tt := range tests {
  219. testIntegerObject(t, testEval(tt.input), tt.expected)
  220. }
  221. }
  222. // --------------------------------------------------------------------------------------------------------------------
  223. func testNullObject(t *testing.T, obj object.Object) bool {
  224. if obj != NULL {
  225. t.Errorf("object is not NULL. got=%T (%+v)", obj, obj)
  226. return false
  227. }
  228. return true
  229. }
  230. func testIntegerObject(t *testing.T, obj object.Object, expected int64) bool {
  231. result, ok := obj.(*object.Integer)
  232. if !ok {
  233. t.Errorf("object is not Integer. got=%T (%+v)", obj, obj)
  234. return false
  235. }
  236. if result.Value != expected {
  237. t.Errorf("object has wrong value. got=%d, want=%d", result.Value, expected)
  238. return false
  239. }
  240. return true
  241. }
  242. func testBooleanObject(t *testing.T, obj object.Object, expected bool) bool {
  243. result, ok := obj.(*object.Boolean)
  244. if !ok {
  245. t.Errorf("object is not Boolean. got=%T (%+v)", obj, obj)
  246. return false
  247. }
  248. if result.Value != expected {
  249. t.Errorf("object has wrong value. got=%t, want=%t", result.Value, expected)
  250. return false
  251. }
  252. return true
  253. }
  254. func testEval(input string) object.Object {
  255. l := lexer.New(input)
  256. p := parser.New(l)
  257. program := p.ParseProgram()
  258. env := object.NewEnvironment()
  259. return Eval(program, env)
  260. }
  261. func TestClosures(t *testing.T) {
  262. input := `
  263. let newAdder = fn(x) {
  264. fn (y) { x + y };
  265. };
  266. let addTwo = newAdder(2); addTwo(2);
  267. `
  268. testIntegerObject(t, testEval(input), 4)
  269. }
  270. func TestStringLiteral(t *testing.T) {
  271. input := `"Hello World!"`
  272. evaluated := testEval(input)
  273. str, ok := evaluated.(*object.String)
  274. if !ok {
  275. t.Fatalf("object is not String. got=%T (%+v)", evaluated, evaluated)
  276. }
  277. if str.Value != "Hello World!" {
  278. t.Errorf("String has wrong value. got=%q", str.Value)
  279. }
  280. }
  281. func TestStringConcatenation(t *testing.T) {
  282. input := `"Hello" + " " + "World!"`
  283. evaluated := testEval(input)
  284. str, ok := evaluated.(*object.String)
  285. if !ok {
  286. t.Fatalf("object is not String. got=%T (%+v)", evaluated, evaluated)
  287. }
  288. if str.Value != "Hello World!" {
  289. t.Errorf("String has wrong value. got=%q", str.Value)
  290. }
  291. }
  292. // ------------------------------------------------------------------------Built-in Function
  293. func TestBuiltinFunctions(t *testing.T) {
  294. tests := []struct {
  295. input string
  296. expected interface{}
  297. }{
  298. {`len("")`, 0},
  299. {`len("four")`, 4},
  300. {`len("hello world")`, 11},
  301. {`len(1)`, "argument to `len` not supported, got INTEGER"},
  302. {`len("one", "two")`, "wrong number of arguments. got=2, want=1"},
  303. }
  304. for _, tt := range tests {
  305. evaluated := testEval(tt.input)
  306. switch expected := tt.expected.(type) {
  307. case int:
  308. testIntegerObject(t, evaluated, int64(expected))
  309. case string:
  310. errObj, ok := evaluated.(*object.Error)
  311. if !ok {
  312. t.Errorf("object is not Error. got=%T (%+v)", evaluated, evaluated)
  313. }
  314. if errObj.Msg != expected {
  315. t.Errorf("wrong error message. expected=%q, got=%q", expected, errObj.Msg)
  316. }
  317. }
  318. }
  319. }