conditions.lisp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. (import test ())
  2. (import tests/compiler/codegen/codegen-helpers ())
  3. (describe "The codegen"
  4. (will "simplify elseif branches"
  5. (affirm-codegen
  6. '((cond
  7. [foo 0]
  8. [bar 1]))
  9. "if foo then
  10. return 0
  11. elseif bar then
  12. return 1
  13. else
  14. _error(\"unmatched item\")
  15. end")
  16. (affirm-codegen
  17. '((cond
  18. [foo 0]
  19. [bar 1]
  20. [true true]))
  21. "if foo then
  22. return 0
  23. elseif bar then
  24. return 1
  25. else
  26. return true
  27. end")
  28. (affirm-codegen
  29. '((cond
  30. [foo 0]
  31. [true true]
  32. [bar 1]))
  33. "if foo then
  34. return 0
  35. else
  36. return true
  37. end")
  38. (affirm-codegen
  39. '((cond
  40. [true true]
  41. [foo 0]
  42. [foo 1]))
  43. "do
  44. return true
  45. end"))
  46. (will "handle nested conds"
  47. (affirm-codegen
  48. '((cond
  49. [(cond
  50. [foo 0]
  51. [bar false]) 1]
  52. [true 2]))
  53. "local temp
  54. if foo then
  55. temp = 0
  56. elseif bar then
  57. temp = false
  58. else
  59. _error(\"unmatched item\")
  60. end
  61. if temp then
  62. return 1
  63. else
  64. return 2
  65. end")
  66. (affirm-codegen
  67. '((cond
  68. [(cond
  69. [foo 0]
  70. [bar 10]) 1]
  71. [(cond
  72. [foo 0]
  73. [bar 10]) 2]
  74. [(cond
  75. [foo 0]
  76. [bar 10]) 3]
  77. [true 1]))
  78. "local temp
  79. if foo then
  80. temp = 0
  81. elseif bar then
  82. temp = 10
  83. else
  84. _error(\"unmatched item\")
  85. end
  86. if temp then
  87. return 1
  88. else
  89. local temp
  90. if foo then
  91. temp = 0
  92. elseif bar then
  93. temp = 10
  94. else
  95. _error(\"unmatched item\")
  96. end
  97. if temp then
  98. return 2
  99. else
  100. local temp
  101. if foo then
  102. temp = 0
  103. elseif bar then
  104. temp = 10
  105. else
  106. _error(\"unmatched item\")
  107. end
  108. if temp then
  109. return 3
  110. else
  111. return 1
  112. end
  113. end
  114. end"))
  115. (will "handle deeply nested conds"
  116. (affirm-codegen
  117. '((cond
  118. [(cond
  119. [(cond
  120. [(cond [foo 0]) 1]) 2]) 3]))
  121. "local temp
  122. local temp1
  123. local temp2
  124. if foo then
  125. temp2 = 0
  126. else
  127. _error(\"unmatched item\")
  128. end
  129. if temp2 then
  130. temp1 = 1
  131. else
  132. _error(\"unmatched item\")
  133. end
  134. if temp1 then
  135. temp = 2
  136. else
  137. _error(\"unmatched item\")
  138. end
  139. if temp then
  140. return 3
  141. else
  142. _error(\"unmatched item\")
  143. end"))
  144. (section "will emit and expressions"
  145. (it "which are simple"
  146. (affirm-codegen
  147. '((cond
  148. [foo bar]
  149. [true foo]))
  150. "return foo and bar")
  151. (affirm-codegen
  152. '((cond
  153. [foo bar]
  154. [true false]))
  155. "if foo then
  156. return bar
  157. else
  158. return false
  159. end")
  160. (affirm-codegen
  161. '((cond
  162. [(cond
  163. [foo bar]
  164. [true false]) 1]
  165. [true 2]))
  166. "if foo and bar then
  167. return 1
  168. else
  169. return 2
  170. end"))
  171. (it "which are nested"
  172. (affirm-codegen
  173. '((cond
  174. [foo (cond
  175. [bar 2]
  176. [true bar])]
  177. [true foo]))
  178. "return foo and (bar and 2)"))
  179. (it "with a directly called lambda"
  180. (affirm-codegen
  181. '(((lambda (x)
  182. (cond
  183. [x bar]
  184. [true x]))
  185. foo))
  186. "return foo and bar")
  187. (affirm-codegen
  188. '(((lambda (x)
  189. (cond
  190. [x (bar x)]
  191. [true x]))
  192. foo))
  193. "local x = foo
  194. return x and bar(x)"))
  195. (pending "with nested directly called lambdas"
  196. (affirm-codegen
  197. '((cond
  198. [(cond
  199. [foo
  200. (cond
  201. [bar ((lambda (x)
  202. (cond
  203. [x (baz x)]
  204. [true x])) bar)]
  205. [true false])]
  206. [true false])
  207. 1]
  208. [true 2]))
  209. "local temp
  210. if foo and bar then
  211. local x = bar
  212. temp = x and baz(x)
  213. else
  214. temp = false
  215. end
  216. if temp then
  217. return 1
  218. else
  219. return 2
  220. end")))
  221. (section "will emit or expressions"
  222. (it "which are simple"
  223. (affirm-codegen
  224. '((cond
  225. [foo foo]
  226. [true bar]))
  227. "return foo or bar")
  228. (affirm-codegen
  229. '((cond
  230. [foo true]
  231. [true bar]))
  232. "if foo then
  233. return true
  234. else
  235. return bar
  236. end")
  237. (affirm-codegen
  238. '((cond
  239. [(cond
  240. [foo true]
  241. [true bar]) 1]
  242. [true 2]))
  243. "if foo or bar then
  244. return 1
  245. else
  246. return 2
  247. end"))
  248. (it "which are nested"
  249. (affirm-codegen
  250. '((cond
  251. [foo foo]
  252. [true (cond
  253. [bar bar]
  254. [true 2])]))
  255. "return foo or (bar or 2)"))
  256. (it "which are sequential"
  257. (affirm-codegen
  258. '((cond
  259. [foo foo]
  260. [bar bar]
  261. [true 2]))
  262. "return foo or bar or 2"))
  263. (it "with a directly called lambda"
  264. (affirm-codegen
  265. '(((lambda (x)
  266. (cond
  267. [x x]
  268. [true bar]))
  269. foo))
  270. "return foo or bar")
  271. (affirm-codegen
  272. '(((lambda (x)
  273. (cond
  274. [x x]
  275. [true (bar x)]))
  276. foo))
  277. "local x = foo
  278. return x or bar(x)"))
  279. (section "will handle a trailing `and`"
  280. (it "in the simple case"
  281. (affirm-codegen
  282. '((cond
  283. [foo foo]
  284. [bar bar]
  285. [baz qux]
  286. [true baz]))
  287. "return foo or bar or baz and qux"))
  288. (it "with a directly called lambda"
  289. (affirm-codegen
  290. '(((lambda (x)
  291. (cond
  292. [x x]
  293. [bar (foo 3)]
  294. [true bar])) (foo 2)))
  295. "return foo(2) or bar and foo(3)"))
  296. (it "inside a condition"
  297. (affirm-codegen
  298. '((cond
  299. [(cond
  300. [foo foo]
  301. [bar baz]
  302. [true bar]) 1]
  303. [true 2]))
  304. "if foo or bar and baz then
  305. return 1
  306. else
  307. return 2
  308. end")))
  309. (section "will handle a trailing `or not`"
  310. (it "in the simple case"
  311. '((cond
  312. [foo foo]
  313. [bar bar]
  314. [baz false]
  315. [true true]))
  316. "return foo or bar or not baz")
  317. (it "with a directly called lambda"
  318. '(((lambda (x)
  319. (cond
  320. [x x]
  321. [bar false]
  322. [true true])) (foo 2)))
  323. "return foo(2) or not bar")
  324. (it "inside a condition"
  325. (affirm-codegen
  326. '((cond
  327. [(cond
  328. [foo foo]
  329. [bar false]
  330. [true true]) 1]
  331. [true 2]))
  332. "if foo or not bar then
  333. return 1
  334. else
  335. return 2
  336. end"))))
  337. (will "emit not expressions"
  338. (affirm-codegen
  339. '((cond
  340. [foo false]
  341. [true true]))
  342. "return not foo"))
  343. (will "invert if statements"
  344. (affirm-codegen
  345. '((cond
  346. [foo]
  347. [true (bar)])
  348. nil)
  349. "if not foo then
  350. bar()
  351. end
  352. return nil")
  353. (affirm-codegen
  354. '((cond
  355. [foo]
  356. [true (bar)]))
  357. "if foo then
  358. return nil
  359. else
  360. return bar()
  361. end"))
  362. (will "emit if statements in bindings"
  363. (affirm-codegen
  364. '(((lambda (x) (+ x 1))
  365. (cond
  366. [foo 1]
  367. [true 2])))
  368. "local x
  369. if foo then
  370. x = 1
  371. else
  372. x = 2
  373. end
  374. return x + 1")
  375. (affirm-codegen
  376. '(((lambda (x) (+ x 1))
  377. ((lambda (y)
  378. (cond
  379. [y 1]
  380. [true 2]))
  381. 3)))
  382. "local x
  383. local y = 3
  384. if y then
  385. x = 1
  386. else
  387. x = 2
  388. end
  389. return x + 1")))