rt_func_test.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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 TestFunctionScoping(t *testing.T) {
  164. vs := scope.NewScope(scope.GlobalScope)
  165. res, err := UnitTestEval(`
  166. c := 1
  167. foo := func (a, b=1) {
  168. return a + b + c
  169. }
  170. result1 := foo(3, 2)
  171. `, vs)
  172. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  173. c (float64) : 1
  174. foo (*interpreter.function) : ecal.function: (Line 3, Pos 8)
  175. result1 (float64) : 6
  176. }` {
  177. t.Error("Unexpected result: ", vsRes, res, err)
  178. return
  179. }
  180. vs = scope.NewScope(scope.GlobalScope)
  181. res, err = UnitTestEval(`
  182. func fib(n) {
  183. if (n <= 1) {
  184. return n
  185. }
  186. return fib(n-1) + fib(n-2)
  187. }
  188. result1 := fib(12)
  189. `, vs)
  190. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  191. fib (*interpreter.function) : ecal.function: fib (Line 2, Pos 1)
  192. result1 (float64) : 144
  193. }` {
  194. t.Error("Unexpected result: ", vsRes, res, err)
  195. return
  196. }
  197. }
  198. func TestObjectInstantiation(t *testing.T) {
  199. vs := scope.NewScope(scope.GlobalScope)
  200. res, err := UnitTestEvalAndAST(`
  201. Super := {
  202. "name" : "base"
  203. "init" : func() {
  204. this.name := "baseclass"
  205. }
  206. }
  207. Bar := {
  208. "super" : [ Super ]
  209. "test" : ""
  210. "init" : func(test) {
  211. this.test := test
  212. x := super[0]()
  213. }
  214. }
  215. Bar2 := {
  216. "getTest" : func() {
  217. return this.test
  218. }
  219. }
  220. Foo := {
  221. "super" : [ Bar, Bar2 ]
  222. # Object ID
  223. #
  224. "id" : 0
  225. "idx" : 0
  226. # Constructor
  227. #
  228. "init" : func(id, test) {
  229. this.id := id
  230. x := super[0](test)
  231. }
  232. # Return the object ID
  233. #
  234. "getId" : func() {
  235. return this.idx
  236. }
  237. # Set the object ID
  238. #
  239. "setId" : func(id) {
  240. this.idx := id
  241. }
  242. }
  243. result1 := new(Foo, 123, "tester")
  244. result1.setId(500)
  245. result2 := result1.getId() + result1.id
  246. `, vs, "")
  247. if err == nil {
  248. v, _, _ := vs.GetValue("result1")
  249. if res := stringutil.ConvertToPrettyString(v); res != `{
  250. "getId": "ecal.function: (Line 45, Pos 42)",
  251. "getTest": "ecal.function: (Line 22, Pos 15)",
  252. "id": 123,
  253. "idx": 500,
  254. "init": "ecal.function: (Line 38, Pos 32)",
  255. "name": "baseclass",
  256. "setId": "ecal.function: (Line 51, Pos 39)",
  257. "super": [
  258. {
  259. "init": "ecal.function: (Line 15, Pos 12)",
  260. "super": [
  261. {
  262. "init": "ecal.function: (Line 5, Pos 12)",
  263. "name": "base"
  264. }
  265. ],
  266. "test": ""
  267. },
  268. {
  269. "getTest": "ecal.function: (Line 22, Pos 15)"
  270. }
  271. ],
  272. "test": "tester"
  273. }` {
  274. t.Error("Unexpected result: ", res)
  275. return
  276. }
  277. }
  278. if vsRes := vs.String(); err != nil || res != nil || vsRes != `GlobalScope {
  279. Bar (map[interface {}]interface {}) : {"init":"ecal.function: (Line 15, Pos 12)","super":[{"init":"ecal.function: (Line 5, Pos 12)","name":"base"}],"test":""}
  280. Bar2 (map[interface {}]interface {}) : {"getTest":"ecal.function: (Line 22, Pos 15)"}
  281. 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)"}]}
  282. Super (map[interface {}]interface {}) : {"init":"ecal.function: (Line 5, Pos 12)","name":"base"}
  283. 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"}
  284. result2 (float64) : 623
  285. }` {
  286. t.Error("Unexpected result: ", vsRes, res, err)
  287. return
  288. }
  289. _, err = UnitTestEval(`
  290. Bar := {
  291. "super" : "hans"
  292. }
  293. result1 := new(Bar)
  294. `, vs)
  295. 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)" {
  296. t.Error("Unexpected result:", err)
  297. return
  298. }
  299. }