rt_func_test.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package interpreter
  11. import (
  12. "testing"
  13. "devt.de/krotik/common/stringutil"
  14. "devt.de/krotik/ecal/scope"
  15. )
  16. func TestFunctions(t *testing.T) {
  17. vs := scope.NewScope(scope.GlobalScope)
  18. res, err := UnitTestEvalAndAST(`
  19. foo := [ [ func (a, b, c=1) {
  20. return a + b + c
  21. }
  22. ]]
  23. result1 := foo[0][0](3, 2)
  24. `, vs, `
  25. statements
  26. :=
  27. identifier: foo
  28. list
  29. list
  30. function
  31. params
  32. identifier: a
  33. identifier: b
  34. preset
  35. identifier: c
  36. number: 1
  37. statements
  38. return
  39. plus
  40. plus
  41. identifier: a
  42. identifier: b
  43. identifier: c
  44. :=
  45. identifier: result1
  46. identifier: foo
  47. compaccess
  48. number: 0
  49. compaccess
  50. number: 0
  51. funccall
  52. number: 3
  53. number: 2
  54. `[1:])
  55. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  56. foo ([]interface {}) : [["ecal.function: (Line 2, Pos 12)"]]
  57. result1 (float64) : 6
  58. }` {
  59. t.Error("Unexpected result: ", vsRes, res, err)
  60. return
  61. }
  62. vs = scope.NewScope(scope.GlobalScope)
  63. res, err = UnitTestEval(`
  64. b := "a"
  65. foo := [{
  66. b : func (a, b, c=1) {
  67. return [1,[a + b + c]]
  68. }
  69. }]
  70. result1 := foo[0].a(3, 2)[1][0]
  71. `, vs)
  72. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  73. b (string) : a
  74. foo ([]interface {}) : [{"a":"ecal.function: (Line 4, Pos 7)"}]
  75. result1 (float64) : 6
  76. }` {
  77. t.Error("Unexpected result: ", vsRes, res, err)
  78. return
  79. }
  80. vs = scope.NewScope(scope.GlobalScope)
  81. res, err = UnitTestEval(`
  82. b := "a"
  83. foo := {
  84. b : [func (a, b, c=1) {
  85. return { "x" : { "y" : [a + b + c] }}
  86. }]
  87. }
  88. result1 := foo.a[0](3, 2).x.y[0]
  89. `, vs)
  90. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  91. b (string) : a
  92. foo (map[interface {}]interface {}) : {"a":["ecal.function: (Line 4, Pos 8)"]}
  93. result1 (float64) : 6
  94. }` {
  95. t.Error("Unexpected result: ", vsRes, res, err)
  96. return
  97. }
  98. vs = scope.NewScope(scope.GlobalScope)
  99. res, err = UnitTestEvalAndAST(`
  100. foo := {
  101. "a" : {
  102. "b" : func myfunc(a, b, c=1) {
  103. d := a + b + c
  104. return d
  105. }
  106. }
  107. }
  108. result1 := foo.a.b(3, 2)
  109. result2 := myfunc(3, 3)
  110. `, vs, `
  111. statements
  112. :=
  113. identifier: foo
  114. map
  115. kvp
  116. string: 'a'
  117. map
  118. kvp
  119. string: 'b'
  120. function
  121. identifier: myfunc
  122. params
  123. identifier: a
  124. identifier: b
  125. preset
  126. identifier: c
  127. number: 1
  128. statements
  129. :=
  130. identifier: d
  131. plus
  132. plus
  133. identifier: a
  134. identifier: b
  135. identifier: c
  136. return
  137. identifier: d
  138. :=
  139. identifier: result1
  140. identifier: foo
  141. identifier: a
  142. identifier: b
  143. funccall
  144. number: 3
  145. number: 2
  146. :=
  147. identifier: result2
  148. identifier: myfunc
  149. funccall
  150. number: 3
  151. number: 3
  152. `[1:])
  153. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  154. foo (map[interface {}]interface {}) : {"a":{"b":"ecal.function: myfunc (Line 4, Pos 8)"}}
  155. myfunc (*interpreter.function) : ecal.function: myfunc (Line 4, Pos 8)
  156. result1 (float64) : 6
  157. result2 (float64) : 7
  158. }` {
  159. t.Error("Unexpected result: ", vsRes, res, err)
  160. return
  161. }
  162. }
  163. func TestEmptyReturn(t *testing.T) {
  164. vs := scope.NewScope(scope.GlobalScope)
  165. res, err := UnitTestEvalAndAST(`
  166. func myfunc() {
  167. return
  168. return 1
  169. }
  170. result := myfunc()
  171. `, vs, `
  172. statements
  173. function
  174. identifier: myfunc
  175. params
  176. statements
  177. return
  178. return
  179. number: 1
  180. :=
  181. identifier: result
  182. identifier: myfunc
  183. funccall
  184. `[1:])
  185. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  186. myfunc (*interpreter.function) : ecal.function: myfunc (Line 2, Pos 1)
  187. result (<nil>) : null
  188. }` {
  189. t.Error("Unexpected result: ", vsRes, res, err)
  190. return
  191. }
  192. }
  193. func TestFunctionScoping(t *testing.T) {
  194. vs := scope.NewScope(scope.GlobalScope)
  195. res, err := UnitTestEval(`
  196. c := 1
  197. foo := func (a, b=1) {
  198. return a + b + c
  199. }
  200. result1 := foo(3, 2)
  201. `, vs)
  202. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  203. c (float64) : 1
  204. foo (*interpreter.function) : ecal.function: (Line 3, Pos 8)
  205. result1 (float64) : 6
  206. }` {
  207. t.Error("Unexpected result: ", vsRes, res, err)
  208. return
  209. }
  210. vs = scope.NewScope(scope.GlobalScope)
  211. res, err = UnitTestEval(`
  212. func fib(n) {
  213. if (n <= 1) {
  214. return n
  215. }
  216. return fib(n-1) + fib(n-2)
  217. }
  218. result1 := fib(12)
  219. `, vs)
  220. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  221. fib (*interpreter.function) : ecal.function: fib (Line 2, Pos 1)
  222. result1 (float64) : 144
  223. }` {
  224. t.Error("Unexpected result: ", vsRes, res, err)
  225. return
  226. }
  227. }
  228. func TestObjectInstantiation(t *testing.T) {
  229. vs := scope.NewScope(scope.GlobalScope)
  230. res, err := UnitTestEvalAndAST(`
  231. Super := {
  232. "name" : "base"
  233. "init" : func() {
  234. this.name := "baseclass"
  235. }
  236. }
  237. Bar := {
  238. "super" : [ Super ]
  239. "test" : ""
  240. "init" : func(test) {
  241. this.test := test
  242. x := super[0]()
  243. }
  244. }
  245. Bar2 := {
  246. "getTest" : func() {
  247. return this.test
  248. }
  249. }
  250. Foo := {
  251. "super" : [ Bar, Bar2 ]
  252. # Object ID
  253. #
  254. "id" : 0
  255. "idx" : 0
  256. # Constructor
  257. #
  258. "init" : func(id, test) {
  259. this.id := id
  260. x := super[0](test)
  261. }
  262. # Return the object ID
  263. #
  264. "getId" : func() {
  265. return this.idx
  266. }
  267. # Set the object ID
  268. #
  269. "setId" : func(id) {
  270. this.idx := id
  271. }
  272. }
  273. result1 := new(Foo, 123, "tester")
  274. result1.setId(500)
  275. result2 := result1.getId() + result1.id
  276. `, vs, "")
  277. if err == nil {
  278. v, _, _ := vs.GetValue("result1")
  279. if res := stringutil.ConvertToPrettyString(v); res != `{
  280. "getId": "ecal.function: (Line 45, Pos 42)",
  281. "getTest": "ecal.function: (Line 22, Pos 15)",
  282. "id": 123,
  283. "idx": 500,
  284. "init": "ecal.function: (Line 38, Pos 32)",
  285. "name": "baseclass",
  286. "setId": "ecal.function: (Line 51, Pos 39)",
  287. "super": [
  288. {
  289. "init": "ecal.function: (Line 15, Pos 12)",
  290. "super": [
  291. {
  292. "init": "ecal.function: (Line 5, Pos 12)",
  293. "name": "base"
  294. }
  295. ],
  296. "test": ""
  297. },
  298. {
  299. "getTest": "ecal.function: (Line 22, Pos 15)"
  300. }
  301. ],
  302. "test": "tester"
  303. }` {
  304. t.Error("Unexpected result: ", res)
  305. return
  306. }
  307. }
  308. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  309. Bar (map[interface {}]interface {}) : {"init":"ecal.function: (Line 15, Pos 12)","super":[{"init":"ecal.function: (Line 5, Pos 12)","name":"base"}],"test":""}
  310. Bar2 (map[interface {}]interface {}) : {"getTest":"ecal.function: (Line 22, Pos 15)"}
  311. Foo (map[interface {}]interface {}) : {"getId":"ecal.function: (Line 45, Pos 42)","id":0,"idx":0,"init":"ecal.function: (Line 38, Pos 32)","setId":"ecal.function: (Line 51, Pos 39)","super":[{"init":"ecal.function: (Line 15, Pos 12)","super":[{"init":"ecal.function: (Line 5, Pos 12)","name":"base"}],"test":""},{"getTest":"ecal.function: (Line 22, Pos 15)"}]}
  312. Super (map[interface {}]interface {}) : {"init":"ecal.function: (Line 5, Pos 12)","name":"base"}
  313. result1 (map[interface {}]interface {}) : {"getId":"ecal.function: (Line 45, Pos 42)","getTest":"ecal.function: (Line 22, Pos 15)","id":123,"idx":500,"init":"ecal.function: (Line 38, Pos 32)","name":"baseclass","setId":"ecal.function: (Line 51, Pos 39)","super":[{"init":"ecal.function: (Line 15, Pos 12)","super":[{"init":"ecal.function: (Line 5, Pos 12)","name":"base"}],"test":""},{"getTest":"ecal.function: (Line 22, Pos 15)"}],"test":"tester"}
  314. result2 (float64) : 623
  315. }` {
  316. t.Error("Unexpected result: ", vsRes, res, err)
  317. return
  318. }
  319. _, err = UnitTestEval(`
  320. Bar := {
  321. "super" : "hans"
  322. }
  323. result1 := new(Bar)
  324. `, vs)
  325. if err == nil || err.Error() != "ECAL error in ECALTestRuntime (ECALEvalTest): Runtime error (Property _super must be a list of super classes) (Line:8 Pos:12)" {
  326. t.Error("Unexpected result:", err)
  327. return
  328. }
  329. }