Compiler-Tests.st 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. Smalltalk createPackage: 'Compiler-Tests'!
  2. TestCase subclass: #ASTMethodRunningTest
  3. slots: {#receiver}
  4. package: 'Compiler-Tests'!
  5. !ASTMethodRunningTest methodsFor: 'accessing'!
  6. receiver
  7. ^ receiver
  8. ! !
  9. !ASTMethodRunningTest methodsFor: 'initialization'!
  10. setUp
  11. receiver := DoIt new
  12. ! !
  13. !ASTMethodRunningTest methodsFor: 'testing'!
  14. should: aString class: aClass receiver: anObject return: aResult
  15. receiver := anObject.
  16. self while: aString inClass: aClass should: [ :runBlock |
  17. self assert: runBlock value equals: aResult ]
  18. !
  19. should: aString receiver: anObject raise: anErrorClass
  20. receiver := anObject.
  21. self while: aString should: [ :runBlock |
  22. self should: runBlock raise: anErrorClass ]
  23. !
  24. should: aString receiver: anObject return: aResult
  25. receiver := anObject.
  26. self should: aString return: aResult
  27. !
  28. should: aString return: anObject
  29. self while: aString should: [ :runBlock |
  30. self assert: runBlock value equals: anObject ]
  31. ! !
  32. ASTMethodRunningTest subclass: #AbstractCompilerTest
  33. slots: {}
  34. package: 'Compiler-Tests'!
  35. !AbstractCompilerTest methodsFor: 'tests'!
  36. testAfterInliningNonLocalBlockReturnIndexSend
  37. self should: 'foo [ ^ true ifTrue: [ self class ] ] value. self class' return: DoIt.
  38. !
  39. testAfterInliningNonLocalBlockReturnSuperSend
  40. self should: 'foo [ ^ true ifTrue: [ super class ] ] value' return: DoIt.
  41. !
  42. testAssignment
  43. self should: 'foo | a | a := true ifTrue: [ 1 ]. ^ a' return: 1.
  44. self should: 'foo | a | a := false ifTrue: [ 1 ]. ^ a' return: nil.
  45. self should: 'foo | a | ^ a := true ifTrue: [ 1 ]' return: 1
  46. !
  47. testBackslashSelectors
  48. self should: '\ arg ^ 4' return: 4.
  49. self should: '\\ arg ^ 42' return: 42
  50. !
  51. testBlockReturn
  52. self should: 'foo ^ #(1 2 3) collect: [ :each | true ifTrue: [ each + 1 ] ]' return: #(2 3 4).
  53. self should: 'foo ^ #(1 2 3) collect: [ :each | false ifFalse: [ each + 1 ] ]' return: #(2 3 4).
  54. self should: 'foo ^ #(1 2 3) collect: [ :each | each odd ifTrue: [ each + 1 ] ifFalse: [ each - 1 ] ]' return: #(2 1 4).
  55. !
  56. testCascades
  57. self should: 'foo ^ Array new add: 3; add: 4; yourself' return: #(3 4)
  58. !
  59. testCascadesInDynamicArray
  60. self should: 'foo | x | x := 1. ^ {x. [x:=2] value; in: [x]}' return: #(1 2)
  61. !
  62. testCascadesInDynamicDictioary
  63. self should: 'foo | x | x := 1. ^ #{''one'' -> x. ''two'' -> ([x:=2] value; in: [x])}' return: #{'one' -> 1. 'two' -> 2}
  64. !
  65. testCascadesInSend
  66. self should: 'foo | x | x := 1. ^ Array with: x with: ([x:=2] value; in: [x])' return: #(1 2)
  67. !
  68. testCascadesWithInlining
  69. self should: 'foo ^ true class; ifTrue: [ 1 ] ifFalse: [ 2 ]' return: 1.
  70. self should: 'foo ^ false class; ifTrue: [ 1 ] ifFalse: [ 2 ]' return: 2
  71. !
  72. testDynamicArrayElementsOrdered
  73. self should: 'foo
  74. | x |
  75. x := 1.
  76. ^ { x. x := 2 }
  77. ' return: #(1 2).
  78. self should: 'foo
  79. | x |
  80. x := 1.
  81. ^ { x. true ifTrue: [ x := 2 ] }
  82. ' return: #(1 2).
  83. !
  84. testDynamicDictionaryElementsOrdered
  85. self should: 'foo
  86. | x |
  87. x := ''foo''.
  88. ^ #{ x->1. ''bar''->(true ifTrue: [ 2 ]) }
  89. ' return: #{'foo'->1. 'bar'->2}.
  90. !
  91. testDynamicDictionaryWithMoreArrows
  92. self should: 'foo ^ #{1->2->3}' return: (HashedCollection with: 1->2->3)
  93. !
  94. testGlobalVar
  95. self should: 'foo ^ eval class' return: BlockClosure.
  96. self should: 'foo ^ Math cos: 0' return: 1.
  97. self should: 'foo ^ NonExistingVar' return: nil
  98. !
  99. testInnerTemporalDependentElementsOrdered
  100. self should: 'foo
  101. | x |
  102. x := Array.
  103. ^ x with: ''foo''->x with: ''bar''->(x := 2)
  104. ' return: {'foo'->Array. 'bar'->2}.
  105. self should: 'foo
  106. | x |
  107. x := Array.
  108. ^ x with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])
  109. ' return: {'foo'->Array. 'bar'->2}.
  110. self should: 'foo
  111. | x |
  112. x := 1.
  113. ^ Array with: ''foo''->x with: ''bar''->(true ifTrue: [ x := 2 ])
  114. ' return: {'foo'->1. 'bar'->2}.
  115. self should: 'foo
  116. | x |
  117. x := 1.
  118. ^ { ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }
  119. ' return: {'foo'->1. 'bar'->2}.
  120. self should: 'foo
  121. | x |
  122. x := 1.
  123. ^ #{ ''foo''->x. ''bar''->(true ifTrue: [ x := 2 ]) }
  124. ' return: #{'foo'->1. 'bar'->2}.
  125. !
  126. testLexicalScope
  127. self should: 'foo | a | a := 1. [ a := 2 ] value. ^ a' return: 2
  128. !
  129. testLiterals
  130. self should: 'foo ^ 1' return: 1.
  131. self should: 'foo ^ ''hello''' return: 'hello'.
  132. self should: 'foo ^ #(1 2 3 4)' return: #(1 2 3 4).
  133. self should: 'foo ^ {1. [:x | x ] value: 2. 3. [4] value}' return: #(1 2 3 4).
  134. self should: 'foo ^ true' return: true.
  135. self should: 'foo ^ false' return: false.
  136. self should: 'foo ^ #{1->2. 3->4}' return: #{1->2. 3->4}.
  137. self should: 'foo ^ #hello' return: #hello.
  138. self should: 'foo ^ $h' return: 'h'.
  139. self should: 'foo ^ -123.456' return: -123.456.
  140. self should: 'foo ^ -2.5e4' return: -25000.
  141. !
  142. testLocalReturn
  143. self should: 'foo ^ 1' return: 1.
  144. self should: 'foo ^ 1 + 1' return: 2.
  145. self should: 'foo ' return: receiver.
  146. self should: 'foo self asString' return: receiver.
  147. self should: 'foo | a b | a := 1. b := 2. ^ a + b' return: 3
  148. !
  149. testMessageSends
  150. self should: 'foo ^ 1 asString' return: '1'.
  151. self should: 'foo ^ 1 + 1' return: 2.
  152. self should: 'foo ^ 1 + 2 * 3' return: 9.
  153. self should: 'foo ^ 1 to: 3' return: #(1 2 3).
  154. self should: 'foo ^ 1 to: 5 by: 2' return: #(1 3 5)
  155. !
  156. testMultipleSequences
  157. self should: 'foo | a b c | a := 2. b := 3. c := a + b. ^ c * 6' return: 30
  158. !
  159. testMutableLiterals
  160. "Mutable literals must be aliased in cascades.
  161. See https://lolg.it/amber/amber/issues/428"
  162. self
  163. should: 'foo ^ #( 1 2 ) at: 1 put: 3; yourself'
  164. return: #(3 2)
  165. !
  166. testNestedIfTrue
  167. self should: 'foo ^ true ifTrue: [ false ifFalse: [ 1 ] ]' return: 1.
  168. self should: 'foo ^ true ifTrue: [ false ifTrue: [ 1 ] ]' return: nil.
  169. self should: 'foo true ifTrue: [ false ifFalse: [ ^ 1 ] ]' return: 1.
  170. self should: 'foo true ifTrue: [ false ifTrue: [ ^ 1 ] ]' return: receiver.
  171. !
  172. testNestedSends
  173. self should: 'foo ^ (Point x: (Point x: 2 y: 3) y: 4) asString' return: (Point x: (2@3) y: 4) asString
  174. !
  175. testNilPerform
  176. self should: 'foo ^ nil perform: #yourself' return: nil
  177. !
  178. testNonLocalReturn
  179. self should: 'foo [ ^ 1 ] value' return: 1.
  180. self should: 'foo [ ^ 1 + 1 ] value' return: 2.
  181. self should: 'foo | a b | a := 1. b := 2. [ ^ a + b ] value. self halt' return: 3.
  182. self should: 'foo [ :x | ^ x + x ] value: 4. ^ 2' return: 8
  183. !
  184. testPascalCaseGlobal
  185. self should: 'foo ^Object' return: (Smalltalk globals at: 'Object').
  186. self should: 'foo ^NonExistent' return: nil
  187. !
  188. testPragmaJSStatement
  189. self should: 'foo < inlineJS: ''return 2+3'' >' return: 5
  190. !
  191. testReceiverEvaluatedOnceInSpecials
  192. self should: 'foo |x| x := 1. ^ {[ x := x+1 ] value ifNil: []. x}' return: {2. 2}.
  193. self should: 'foo |xs| xs := {nil. nil}. ^ {[ xs removeLast ] value ifNotNil: []. xs}' return: {nil. {nil}}.
  194. !
  195. testRegression1242
  196. self should: '
  197. foo
  198. |x|
  199. x := 2.
  200. x := nil ifNil: [].
  201. ^ x
  202. ' return: nil.
  203. self should: '
  204. foo
  205. |x|
  206. x := 2.
  207. x := 1 ifNotNil: [].
  208. ^ x
  209. ' return: nil.
  210. self should: '
  211. foo
  212. |x|
  213. x := 2.
  214. x := false ifFalse: [].
  215. ^ x
  216. ' return: nil.
  217. self should: '
  218. foo
  219. |x|
  220. x := 2.
  221. x := true ifTrue: [].
  222. ^ x
  223. ' return: nil.
  224. !
  225. testRegression1242ForReturn
  226. self should: 'foo [ ^ nil ifNil: [] ] value' return: nil.
  227. self should: 'foo [ ^ 1 ifNotNil: [] ] value' return: nil.
  228. self should: 'foo [ ^ false ifFalse: [] ] value' return: nil.
  229. self should: 'foo [ ^ true ifTrue: [] ] value' return: nil.
  230. !
  231. testRegression1244
  232. self should: 'foo [ ^ true ifTrue: [1] ifFalse: [2] ] value' return: 1
  233. !
  234. testRootSuperSend
  235. self
  236. should: 'foo ^ super class'
  237. receiver: ProtoObject new
  238. raise: MessageNotUnderstood
  239. !
  240. testSendReceiverAndArgumentsOrdered
  241. self should: 'foo
  242. | x |
  243. x := 1.
  244. ^ Array with: x with: (true ifTrue: [ x := 2 ])
  245. ' return: #(1 2).
  246. self should: 'foo
  247. | x |
  248. x := Array.
  249. ^ x with: x with: (true ifTrue: [ x := 2 ])
  250. ' return: {Array. 2}.
  251. !
  252. testSuperSend
  253. self
  254. should: 'foo ^ super isBoolean'
  255. receiver: true
  256. return: false
  257. !
  258. testSuperSend2
  259. self
  260. should: 'foo ^ super isNil'
  261. receiver: nil
  262. return: false
  263. !
  264. testSuperSend3
  265. self
  266. should: 'doo ^ super isNil'
  267. class: Object
  268. receiver: nil
  269. return: false
  270. !
  271. testSuperSend4
  272. self
  273. should: 'foo ^ super asJavaScriptObject'
  274. receiver: 'me'
  275. return: #('m' 'e')
  276. !
  277. testSuperSend5
  278. self
  279. should: 'foo [super addLast: 4] on: Error do: [ self add: 5 ]. ^ self'
  280. class: SequenceableCollection
  281. receiver: #(1 2 3)
  282. return: #(1 2 3 5)
  283. !
  284. testSuperSend6
  285. self
  286. should: 'foo ^ super ifTrue: [ true ] ifFalse: [ false ]'
  287. receiver: true
  288. raise: Error
  289. !
  290. testTempVariables
  291. self should: 'foo | a | ^ a' return: nil.
  292. self should: 'foo | AVariable | ^ AVariable' return: nil.
  293. self should: 'foo | a b c | ^ c' return: nil.
  294. self should: 'foo | a | [ | d | ^ d ] value' return: nil.
  295. self should: 'foo | a | a:= 1. ^ a' return: 1.
  296. self should: 'foo | AVariable | AVariable := 1. ^ AVariable' return: 1.
  297. !
  298. testThisContext
  299. self should: 'foo ^ [ thisContext ] value outerContext == thisContext' return: true
  300. !
  301. testUnknownPragma
  302. self should: 'foo < fooBar: ''return 2+3'' > | x | ^ x := 6' return: 6.
  303. self should: 'foo | x | < fooBar: ''return 2+3'' > ^ x := 6' return: 6
  304. !
  305. testifFalse
  306. self should: 'foo true ifFalse: [ ^ 1 ]' return: receiver.
  307. self should: 'foo false ifFalse: [ ^ 2 ]' return: 2.
  308. self should: 'foo ^ true ifFalse: [ 1 ]' return: nil.
  309. self should: 'foo ^ false ifFalse: [ 2 ]' return: 2.
  310. !
  311. testifFalseIfTrue
  312. self should: 'foo true ifFalse: [ ^ 1 ] ifTrue: [ ^ 2 ]' return: 2.
  313. self should: 'foo false ifFalse: [ ^ 2 ] ifTrue: [ ^1 ]' return: 2.
  314. self should: 'foo ^ true ifFalse: [ 1 ] ifTrue: [ 2 ]' return: 2.
  315. self should: 'foo ^ false ifFalse: [ 2 ] ifTrue: [ 1 ]' return: 2.
  316. !
  317. testifNil
  318. self should: 'foo ^ 1 ifNil: [ 2 ]' return: 1.
  319. self should: 'foo ^ nil ifNil: [ 2 ]' return: 2.
  320. self should: 'foo 1 ifNil: [ ^ 2 ]' return: receiver.
  321. self should: 'foo nil ifNil: [ ^ 2 ]' return: 2.
  322. !
  323. testifNilIfNotNil
  324. self should: 'foo ^ 1 ifNil: [ 2 ] ifNotNil: [ 3 ]' return: 3.
  325. self should: 'foo ^ nil ifNil: [ 2 ] ifNotNil: [ 3 ]' return: 2.
  326. self should: 'foo 1 ifNil: [ ^ 2 ] ifNotNil: [ ^3 ]' return: 3.
  327. self should: 'foo nil ifNil: [ ^ 2 ] ifNotNil: [ ^3 ]' return: 2.
  328. !
  329. testifNotNil
  330. self should: 'foo ^ 1 ifNotNil: [ 2 ]' return: 2.
  331. self should: 'foo ^ nil ifNotNil: [ 2 ]' return: nil.
  332. self should: 'foo 1 ifNotNil: [ ^ 2 ]' return: 2.
  333. self should: 'foo nil ifNotNil: [ ^ 2 ]' return: receiver.
  334. !
  335. testifNotNilWithArgument
  336. self should: 'foo ^ 1 ifNotNil: [ :val | val + 2 ]' return: 3.
  337. self should: 'foo ^ nil ifNotNil: [ :val | val + 2 ]' return: nil.
  338. self should: 'foo ^ 1 ifNil: [ 5 ] ifNotNil: [ :val | val + 2 ]' return: 3.
  339. self should: 'foo ^ nil ifNil: [ 5 ] ifNotNil: [ :val | val + 2 ]' return: 5.
  340. self should: 'foo ^ 1 ifNotNil: [ :val | val + 2 ] ifNil: [ 5 ]' return: 3.
  341. self should: 'foo ^ nil ifNotNil: [ :val | val + 2 ] ifNil: [ 5 ]' return: 5
  342. !
  343. testifTrue
  344. self should: 'foo false ifTrue: [ ^ 1 ]' return: receiver.
  345. self should: 'foo true ifTrue: [ ^ 2 ]' return: 2.
  346. self should: 'foo ^ false ifTrue: [ 1 ]' return: nil.
  347. self should: 'foo ^ true ifTrue: [ 2 ]' return: 2.
  348. !
  349. testifTrueIfFalse
  350. self should: 'foo false ifTrue: [ ^ 1 ] ifFalse: [ ^2 ]' return: 2.
  351. self should: 'foo true ifTrue: [ ^ 1 ] ifFalse: [ ^ 2 ]' return: 1.
  352. self should: 'foo ^ false ifTrue: [ 2 ] ifFalse: [ 1 ]' return: 1.
  353. self should: 'foo ^ true ifTrue: [ 2 ] ifFalse: [ 1 ]' return: 2.
  354. ! !
  355. !AbstractCompilerTest class methodsFor: 'testing'!
  356. isAbstract
  357. ^ self name = AbstractCompilerTest name
  358. ! !
  359. AbstractCompilerTest subclass: #ASTDebuggerTest
  360. slots: {}
  361. package: 'Compiler-Tests'!
  362. AbstractCompilerTest subclass: #ASTInterpreterTest
  363. slots: {}
  364. package: 'Compiler-Tests'!
  365. AbstractCompilerTest subclass: #CodeGeneratorTest
  366. slots: {}
  367. package: 'Compiler-Tests'!
  368. AbstractCompilerTest subclass: #InliningCodeGeneratorTest
  369. slots: {}
  370. package: 'Compiler-Tests'!
  371. TestCase subclass: #ASTPCNodeVisitorTest
  372. slots: {}
  373. package: 'Compiler-Tests'!
  374. !ASTPCNodeVisitorTest methodsFor: 'factory'!
  375. astPCNodeVisitor
  376. ^ ASTPCNodeVisitor new
  377. index: 0;
  378. yourself
  379. !
  380. astPCNodeVisitorForSelector: aString
  381. ^ ASTPCNodeVisitor new
  382. selector: aString;
  383. index: 0;
  384. yourself
  385. !
  386. newTeachableVisitor
  387. | result |
  388. result := Teachable new
  389. whenSend: #visit: evaluate: [ :one | one acceptDagVisitor: result ];
  390. acceptSend: #visitDagNode:.
  391. ^ result
  392. ! !
  393. !ASTPCNodeVisitorTest methodsFor: 'tests'!
  394. testJSStatementNode
  395. | ast result |
  396. ast := self parse: 'foo <inlineJS: ''consolee.log(1)''>' forClass: Object.
  397. result := self astPCNodeVisitor visit: ast; currentNode.
  398. self
  399. assert: ((self newTeachableVisitor whenSend: #visitJSStatementNode: return: 'JS'; yourself) visit: result)
  400. equals: 'JS'
  401. !
  402. testMessageSend
  403. | ast |
  404. ast := self parse: 'foo self asString yourself. ^ self asBoolean' forClass: Object.
  405. self assert: ((self astPCNodeVisitorForSelector: 'yourself')
  406. visit: ast;
  407. currentNode) selector equals: 'yourself'
  408. !
  409. testMessageSendWithBlocks
  410. | ast |
  411. ast := self parse: 'foo true ifTrue: [ [ self asString yourself ] value. ]. ^ self asBoolean' forClass: Object.
  412. self assert: ((self astPCNodeVisitorForSelector: 'yourself')
  413. visit: ast;
  414. currentNode) selector equals: 'yourself'
  415. !
  416. testMessageSendWithInlining
  417. | ast |
  418. ast := self parse: 'foo true ifTrue: [ self asString yourself ]. ^ self asBoolean' forClass: Object.
  419. self assert: ((self astPCNodeVisitorForSelector: 'yourself')
  420. visit: ast;
  421. currentNode) selector equals: 'yourself'.
  422. ast := self parse: 'foo true ifTrue: [ self asString yourself ]. ^ self asBoolean' forClass: Object.
  423. self assert: ((self astPCNodeVisitorForSelector: 'asBoolean')
  424. visit: ast;
  425. currentNode) selector equals: 'asBoolean'
  426. !
  427. testNoMessageSend
  428. | ast |
  429. ast := self parse: 'foo ^ self' forClass: Object.
  430. self assert: (self astPCNodeVisitor
  431. visit: ast;
  432. currentNode) isNil
  433. ! !
  434. TestCase subclass: #ASTPositionTest
  435. slots: {}
  436. package: 'Compiler-Tests'!
  437. !ASTPositionTest methodsFor: 'tests'!
  438. testNodeAtPosition
  439. | node |
  440. node := self parse: 'yourself
  441. ^ self' forClass: Object.
  442. self assert: (node navigationNodeAt: 2@4 ifAbsent: [ nil ]) source equals: 'self'.
  443. node := self parse: 'foo
  444. true ifTrue: [ 1 ]' forClass: Object.
  445. self assert: (node navigationNodeAt: 2@7 ifAbsent: [ nil ]) selector equals: 'ifTrue:'.
  446. node := self parse: 'foo
  447. self foo; bar; baz' forClass: Object.
  448. self assert: (node navigationNodeAt: 2@8 ifAbsent: [ nil ]) selector equals: 'foo'
  449. ! !
  450. TestCase subclass: #AbstractCodeGeneratorInstallTest
  451. slots: {#receiver}
  452. package: 'Compiler-Tests'!
  453. !AbstractCodeGeneratorInstallTest methodsFor: 'accessing'!
  454. receiver
  455. ^ receiver
  456. ! !
  457. !AbstractCodeGeneratorInstallTest methodsFor: 'testing'!
  458. shouldntInstall: aString andRaise: anErrorClass
  459. | method |
  460. [ self
  461. should: [ method := self install: aString forClass: receiver class ]
  462. raise: anErrorClass ]
  463. ensure: [ method ifNotNil: [ receiver class removeCompiledMethod: method ] ]
  464. ! !
  465. !AbstractCodeGeneratorInstallTest methodsFor: 'tests'!
  466. testInvalidAssignment
  467. self shouldntInstall: 'foo:a a:=1' andRaise: InvalidAssignmentError.
  468. self shouldntInstall: 'foo false:=1' andRaise: InvalidAssignmentError.
  469. self shouldntInstall: 'foo console:=1' andRaise: InvalidAssignmentError.
  470. self shouldntInstall: 'foo Number:=1' andRaise: InvalidAssignmentError
  471. !
  472. testMistypedPragmaJSStatement
  473. self shouldntInstall: 'foo < inlineJS: ''return ''foo'''' >' andRaise: ParseError
  474. !
  475. testNiladicJSOverride
  476. receiver := ObjectMock new.
  477. receiver foo: 4.
  478. self while: 'baz <jsOverride: #baz> ^ (foo := foo + 3)' should: [
  479. self assert: receiver baz equals: 7.
  480. self assert: (receiver basicPerform: #baz) equals: 10.
  481. self assert: receiver baz equals: 13.
  482. self assert: receiver foo equals: 13 ]
  483. !
  484. testNiladicJSOverrideDifferentNames
  485. receiver := ObjectMock new.
  486. receiver foo: 4.
  487. self while: 'quux <jsOverride: #mux> ^ (foo := foo + 3)' should: [
  488. self should: [ receiver mux ] raise: MessageNotUnderstood.
  489. self assert: (receiver basicPerform: #mux) equals: 7.
  490. self assert: receiver quux equals: 10.
  491. self should: [ receiver basicPerform: #quux ] raise: Error.
  492. self assert: receiver foo equals: 10 ]
  493. !
  494. testPragmaInBlock
  495. self shouldntInstall: 'foo ^ [ < fooBar > 4 ] value' andRaise: ParseError
  496. ! !
  497. !AbstractCodeGeneratorInstallTest class methodsFor: 'testing'!
  498. isAbstract
  499. ^ self name = AbstractCodeGeneratorInstallTest name
  500. ! !
  501. AbstractCodeGeneratorInstallTest subclass: #CodeGeneratorInstallTest
  502. slots: {}
  503. package: 'Compiler-Tests'!
  504. AbstractCodeGeneratorInstallTest subclass: #InliningCodeGeneratorInstallTest
  505. slots: {}
  506. package: 'Compiler-Tests'!
  507. TestCase subclass: #ScopeVarTest
  508. slots: {}
  509. package: 'Compiler-Tests'!
  510. !ScopeVarTest methodsFor: 'tests'!
  511. testClassRefVar
  512. | node binding |
  513. node := VariableNode new
  514. identifier: 'Object';
  515. yourself.
  516. SemanticAnalyzer new
  517. pushScope: MethodLexicalScope new;
  518. visit: node.
  519. binding := node binding.
  520. self deny: binding isAssignable.
  521. self deny: binding isIdempotent.
  522. self assert: (binding alias includesSubString: 'Object').
  523. self assert: (binding alias ~= 'Object')
  524. !
  525. testExternallyKnownVar
  526. | node binding |
  527. node := VariableNode new
  528. identifier: 'console';
  529. yourself.
  530. SemanticAnalyzer new
  531. pushScope: MethodLexicalScope new;
  532. visit: node.
  533. binding := node binding.
  534. self deny: binding isAssignable.
  535. self deny: binding isIdempotent.
  536. self assert: binding alias equals: 'console'
  537. !
  538. testExternallyUnknownVar
  539. | node |
  540. node := VariableNode new
  541. identifier: 'bzzz';
  542. yourself.
  543. self
  544. should: [
  545. SemanticAnalyzer new
  546. pushScope: MethodLexicalScope new;
  547. visit: node ]
  548. raise: UnknownVariableError
  549. !
  550. testInstanceVar
  551. | binding |
  552. binding := MethodLexicalScope new
  553. addIVar: 'bzzz';
  554. bindingFor: 'bzzz'.
  555. self assert: binding isAssignable.
  556. self deny: binding isIdempotent.
  557. self assert: (binding alias includesSubString: 'bzzz').
  558. self assert: (binding alias ~= 'bzzz')
  559. !
  560. testPseudoVar
  561. #('self' 'super' 'true' 'false' 'nil' 'thisContext') do: [ :each |
  562. | binding |
  563. binding := MethodLexicalScope new bindingFor: each.
  564. self deny: binding isAssignable.
  565. self assert: binding isIdempotent ]
  566. !
  567. testTempVar
  568. | binding |
  569. binding := MethodLexicalScope new
  570. addTemp: 'bzzz';
  571. bindingFor: 'bzzz'.
  572. self assert: binding isAssignable.
  573. self deny: binding isIdempotent.
  574. self assert: binding alias equals: 'bzzz'
  575. !
  576. testUnknownVar
  577. self assert: (MethodLexicalScope new bindingFor: 'bzzz') isNil
  578. ! !
  579. TestCase subclass: #SemanticAnalyzerTest
  580. slots: {#analyzer}
  581. package: 'Compiler-Tests'!
  582. !SemanticAnalyzerTest methodsFor: 'running'!
  583. setUp
  584. analyzer := SemanticAnalyzer on: Object
  585. ! !
  586. !SemanticAnalyzerTest methodsFor: 'tests'!
  587. testAssignment
  588. | src ast |
  589. src := 'foo self := 1'.
  590. ast := Smalltalk parse: src.
  591. self should: [analyzer visit: ast] raise: InvalidAssignmentError
  592. !
  593. testNonLocalReturn
  594. | src ast |
  595. src := 'foo | a | a + 1. ^ a'.
  596. ast := Smalltalk parse: src.
  597. analyzer visit: ast.
  598. self deny: ast scope hasNonLocalReturn
  599. !
  600. testNonLocalReturn2
  601. | src ast |
  602. src := 'foo | a | a + 1. [ [ ^ a] ]'.
  603. ast := Smalltalk parse: src.
  604. analyzer visit: ast.
  605. self assert: ast scope hasNonLocalReturn
  606. !
  607. testScope
  608. | src ast |
  609. src := 'foo | a | a + 1. [ | b | b := a ]'.
  610. ast := Smalltalk parse: src.
  611. analyzer visit: ast.
  612. self deny: ast sequenceNode dagChildren last scope == ast scope.
  613. !
  614. testScope2
  615. | src ast |
  616. src := 'foo | a | a + 1. [ [ | b | b := a ] ]'.
  617. ast := Smalltalk parse: src.
  618. analyzer visit: ast.
  619. self deny: ast sequenceNode dagChildren last sequenceNode dagChildren first scope == ast scope.
  620. !
  621. testScopeLevel
  622. | src ast |
  623. src := 'foo | a | a + 1. [ [ | b | b := a ] ]'.
  624. ast := Smalltalk parse: src.
  625. analyzer visit: ast.
  626. self assert: ast scope scopeLevel equals: 1.
  627. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first scope scopeLevel equals: 3
  628. !
  629. testUnknownVariables
  630. | src ast |
  631. src := 'foo | a | b + a'.
  632. ast := Smalltalk parse: src.
  633. self should: [ analyzer visit: ast ] raise: UnknownVariableError
  634. !
  635. testUnknownVariablesWithScope
  636. | src ast |
  637. src := 'foo | a b | [ c + 1. [ a + 1. d + 1 ]]'.
  638. ast := Smalltalk parse: src.
  639. self should: [ analyzer visit: ast ] raise: UnknownVariableError
  640. !
  641. testVariableShadowing
  642. | src ast |
  643. src := 'foo | a | a + 1'.
  644. ast := Smalltalk parse: src.
  645. analyzer visit: ast
  646. !
  647. testVariableShadowing2
  648. | src ast |
  649. src := 'foo | a | a + 1. [ | a | a := 2 ]'.
  650. ast := Smalltalk parse: src.
  651. self should: [analyzer visit: ast] raise: ShadowingVariableError
  652. !
  653. testVariableShadowing3
  654. | src ast |
  655. src := 'foo | a | a + 1. [ | b | b := 2 ]'.
  656. ast := Smalltalk parse: src.
  657. analyzer visit: ast
  658. !
  659. testVariableShadowing4
  660. | src ast |
  661. src := 'foo | a | a + 1. [ [ [ | b | b := 2 ] ] ]'.
  662. ast := Smalltalk parse: src.
  663. analyzer visit: ast
  664. !
  665. testVariableShadowing5
  666. | src ast |
  667. src := 'foo | a | a + 1. [ [ [ | a | a := 2 ] ] ]'.
  668. ast := Smalltalk parse: src.
  669. self should: [analyzer visit: ast] raise: ShadowingVariableError
  670. !
  671. testVariablesLookup
  672. | src ast |
  673. src := 'foo | a | a + 1. [ | b | b := a ]'.
  674. ast := Smalltalk parse: src.
  675. analyzer visit: ast.
  676. "Binding for `a` in the message send"
  677. self assert: ast sequenceNode dagChildren first receiver binding isAssignable.
  678. self assert: ast sequenceNode dagChildren first receiver binding alias equals: 'a'.
  679. self assert: ast sequenceNode dagChildren first receiver binding scope == ast scope.
  680. "Binding for `b`"
  681. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding isAssignable.
  682. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding alias equals: 'b'.
  683. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding scope == ast sequenceNode dagChildren last scope.
  684. ! !
  685. SemanticAnalyzerTest subclass: #AISemanticAnalyzerTest
  686. slots: {}
  687. package: 'Compiler-Tests'!
  688. !AISemanticAnalyzerTest methodsFor: 'running'!
  689. setUp
  690. analyzer := (AISemanticAnalyzer on: Object)
  691. context: (AIContext new
  692. defineLocal: 'local';
  693. localAt: 'local' put: 3;
  694. yourself);
  695. yourself
  696. ! !
  697. !AISemanticAnalyzerTest methodsFor: 'tests'!
  698. testContextVariables
  699. | src ast |
  700. src := 'foo | a | local + a'.
  701. ast := Smalltalk parse: src.
  702. self shouldnt: [ analyzer visit: ast ] raise: UnknownVariableError
  703. ! !
  704. Trait named: #TASTCompilingTest
  705. package: 'Compiler-Tests'!
  706. !TASTCompilingTest methodsFor: 'accessing'!
  707. codeGeneratorClass
  708. self subclassResponsibility
  709. ! !
  710. !TASTCompilingTest methodsFor: 'compiling'!
  711. install: aString forClass: aClass
  712. ^ self compiler
  713. install: aString
  714. forClass: aClass
  715. protocol: 'tests'
  716. ! !
  717. !TASTCompilingTest methodsFor: 'factory'!
  718. compiler
  719. ^ Compiler new
  720. codeGeneratorClass: self codeGeneratorClass;
  721. yourself
  722. ! !
  723. !TASTCompilingTest methodsFor: 'testing'!
  724. while: aString inClass: aClass should: aBlock
  725. | method |
  726. [
  727. method := self install: aString forClass: aClass.
  728. aBlock value: method ]
  729. ensure: [ method ifNotNil: [ aClass removeCompiledMethod: method ] ]
  730. !
  731. while: aString should: aBlock
  732. self while: aString inClass: self receiver class should: aBlock
  733. ! !
  734. Trait named: #TASTParsingTest
  735. package: 'Compiler-Tests'!
  736. !TASTParsingTest methodsFor: 'parsing'!
  737. parse: aString forClass: aClass
  738. ^ Compiler new
  739. ast: aString
  740. forClass: aClass
  741. protocol: 'test'
  742. ! !
  743. Trait named: #TCTDebugged
  744. package: 'Compiler-Tests'!
  745. !TCTDebugged methodsFor: 'private'!
  746. interpret: aString forClass: aClass receiver: anObject withArguments: aDictionary
  747. "The food is a methodNode. Interpret the sequenceNode only"
  748. | ctx |
  749. ctx := self prepareContextFor: aString class: aClass receiver: anObject withArguments: aDictionary.
  750. ^ (ASTDebugger context: ctx) proceed; result
  751. ! !
  752. Trait named: #TCTExecuted
  753. package: 'Compiler-Tests'!
  754. !TCTExecuted methodsFor: 'testing'!
  755. while: aString inClass: aClass should: aBlock
  756. super
  757. while: aString
  758. inClass: aClass
  759. should: [ :method | aBlock value: [
  760. self receiver perform: method selector ] ]
  761. ! !
  762. Trait named: #TCTInlined
  763. package: 'Compiler-Tests'!
  764. !TCTInlined methodsFor: 'accessing'!
  765. codeGeneratorClass
  766. ^ InliningCodeGenerator
  767. ! !
  768. Trait named: #TCTInterpreted
  769. package: 'Compiler-Tests'!
  770. !TCTInterpreted methodsFor: 'private'!
  771. interpret: aString forClass: aClass receiver: anObject withArguments: aDictionary
  772. "The food is a methodNode. Interpret the sequenceNode only"
  773. | ctx |
  774. ctx := self prepareContextFor: aString class: aClass receiver: anObject withArguments: aDictionary.
  775. ^ ctx interpreter proceed; result
  776. !
  777. prepareContextFor: aString class: aClass receiver: anObject withArguments: aDictionary
  778. "The food is a methodNode. Interpret the sequenceNode only"
  779. | ctx ast |
  780. ast := self parse: aString forClass: aClass.
  781. ctx := AIContext new
  782. receiver: anObject;
  783. selector: ast selector;
  784. interpreter: ASTInterpreter new;
  785. yourself.
  786. "Define locals for the context"
  787. ast sequenceNode ifNotNil: [ :sequence |
  788. sequence temps do: [ :each |
  789. ctx defineLocal: each ] ].
  790. aDictionary keysAndValuesDo: [ :key :value |
  791. ctx localAt: key put: value ].
  792. ctx interpreter
  793. context: ctx;
  794. node: ast;
  795. enterNode.
  796. ^ctx
  797. ! !
  798. !TCTInterpreted methodsFor: 'testing'!
  799. while: aString inClass: aClass should: aBlock
  800. super
  801. while: aString
  802. inClass: aClass
  803. should: [ aBlock value: [
  804. self
  805. interpret: aString
  806. forClass: aClass
  807. receiver: self receiver
  808. withArguments: #{} ] ]
  809. ! !
  810. Trait named: #TCTNonInlined
  811. package: 'Compiler-Tests'!
  812. !TCTNonInlined methodsFor: 'accessing'!
  813. codeGeneratorClass
  814. ^ CodeGenerator
  815. ! !
  816. TASTCompilingTest setTraitComposition: {TASTParsingTest} asTraitComposition!
  817. TCTDebugged setTraitComposition: {TCTInterpreted} asTraitComposition!
  818. ASTMethodRunningTest setTraitComposition: {TASTCompilingTest} asTraitComposition!
  819. ASTDebuggerTest setTraitComposition: {TCTNonInlined. TCTDebugged} asTraitComposition!
  820. ASTInterpreterTest setTraitComposition: {TCTNonInlined. TCTInterpreted} asTraitComposition!
  821. CodeGeneratorTest setTraitComposition: {TCTNonInlined. TCTExecuted} asTraitComposition!
  822. InliningCodeGeneratorTest setTraitComposition: {TCTInlined. TCTExecuted} asTraitComposition!
  823. ASTPCNodeVisitorTest setTraitComposition: {TASTParsingTest} asTraitComposition!
  824. ASTPositionTest setTraitComposition: {TASTParsingTest} asTraitComposition!
  825. AbstractCodeGeneratorInstallTest setTraitComposition: {TASTCompilingTest} asTraitComposition!
  826. CodeGeneratorInstallTest setTraitComposition: {TCTNonInlined} asTraitComposition!
  827. InliningCodeGeneratorInstallTest setTraitComposition: {TCTInlined} asTraitComposition!
  828. ! !