Compiler-Tests.st 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129
  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. ASTMethodRunningTest subclass: #AbstractJavaScriptGatewayTest
  372. slots: {#theClass}
  373. package: 'Compiler-Tests'!
  374. !AbstractJavaScriptGatewayTest methodsFor: 'accessing'!
  375. theClass
  376. ^ theClass
  377. ! !
  378. !AbstractJavaScriptGatewayTest methodsFor: 'running'!
  379. jsConstructor
  380. <inlineJS: '
  381. var ctr = function () {};
  382. ctr.prototype.foo = function (a,b) {return a+","+b};
  383. return ctr;
  384. '>
  385. ! !
  386. !AbstractJavaScriptGatewayTest methodsFor: 'tests'!
  387. testNiladicSuper
  388. theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
  389. theClass beJavaScriptSubclassOf: self jsConstructor.
  390. self
  391. should: 'foo <jsOverride: #foo> ^ super foo'
  392. receiver: (ObjectMock2 new foo: 'should be shadowed'; yourself)
  393. return: 'undefined,undefined'
  394. !
  395. testNiladicSuperDifferentNames
  396. theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
  397. theClass beJavaScriptSubclassOf: self jsConstructor.
  398. receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
  399. self while: 'bar <jsOverride: #foo> ^ super bar' should: [
  400. self shouldnt: [ receiver bar ] raise: Error.
  401. self assert: receiver bar equals: 'undefined,undefined' ]
  402. !
  403. testNiladicSuperNested
  404. theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
  405. theClass beJavaScriptSubclassOf: self jsConstructor.
  406. self
  407. should: 'foo <jsOverride: #foo> ^ [ super foo ] value'
  408. receiver: (ObjectMock2 new foo: 'should be shadowed'; yourself)
  409. return: 'undefined,undefined'
  410. ! !
  411. !AbstractJavaScriptGatewayTest class methodsFor: 'testing'!
  412. isAbstract
  413. ^ self name = AbstractJavaScriptGatewayTest name
  414. ! !
  415. AbstractJavaScriptGatewayTest subclass: #InlinedJSGTest
  416. slots: {}
  417. package: 'Compiler-Tests'!
  418. AbstractJavaScriptGatewayTest subclass: #PlainJSGTest
  419. slots: {}
  420. package: 'Compiler-Tests'!
  421. TestCase subclass: #ASTPCNodeVisitorTest
  422. slots: {}
  423. package: 'Compiler-Tests'!
  424. !ASTPCNodeVisitorTest methodsFor: 'factory'!
  425. astPCNodeVisitor
  426. ^ ASTPCNodeVisitor new
  427. index: 0;
  428. yourself
  429. !
  430. astPCNodeVisitorForSelector: aString
  431. ^ ASTPCNodeVisitor new
  432. selector: aString;
  433. index: 0;
  434. yourself
  435. !
  436. newTeachableVisitor
  437. | result |
  438. result := Teachable new
  439. whenSend: #visit: evaluate: [ :one | one acceptDagVisitor: result ];
  440. acceptSend: #visitDagNode:.
  441. ^ result
  442. ! !
  443. !ASTPCNodeVisitorTest methodsFor: 'tests'!
  444. testJSStatementNode
  445. | ast result |
  446. ast := self parse: 'foo <inlineJS: ''consolee.log(1)''>' forClass: Object.
  447. result := self astPCNodeVisitor visit: ast; currentNode.
  448. self
  449. assert: ((self newTeachableVisitor whenSend: #visitJSStatementNode: return: 'JS'; yourself) visit: result)
  450. equals: 'JS'
  451. !
  452. testMessageSend
  453. | ast |
  454. ast := self parse: 'foo self asString yourself. ^ self asBoolean' forClass: Object.
  455. self assert: ((self astPCNodeVisitorForSelector: 'yourself')
  456. visit: ast;
  457. currentNode) selector equals: 'yourself'
  458. !
  459. testMessageSendWithBlocks
  460. | ast |
  461. ast := self parse: 'foo true ifTrue: [ [ self asString yourself ] value. ]. ^ self asBoolean' forClass: Object.
  462. self assert: ((self astPCNodeVisitorForSelector: 'yourself')
  463. visit: ast;
  464. currentNode) selector equals: 'yourself'
  465. !
  466. testMessageSendWithInlining
  467. | ast |
  468. ast := self parse: 'foo true ifTrue: [ self asString yourself ]. ^ self asBoolean' forClass: Object.
  469. self assert: ((self astPCNodeVisitorForSelector: 'yourself')
  470. visit: ast;
  471. currentNode) selector equals: 'yourself'.
  472. ast := self parse: 'foo true ifTrue: [ self asString yourself ]. ^ self asBoolean' forClass: Object.
  473. self assert: ((self astPCNodeVisitorForSelector: 'asBoolean')
  474. visit: ast;
  475. currentNode) selector equals: 'asBoolean'
  476. !
  477. testNoMessageSend
  478. | ast |
  479. ast := self parse: 'foo ^ self' forClass: Object.
  480. self assert: (self astPCNodeVisitor
  481. visit: ast;
  482. currentNode) isNil
  483. ! !
  484. TestCase subclass: #ASTPositionTest
  485. slots: {}
  486. package: 'Compiler-Tests'!
  487. !ASTPositionTest methodsFor: 'tests'!
  488. testNodeAtPosition
  489. | node |
  490. node := self parse: 'yourself
  491. ^ self' forClass: Object.
  492. self assert: (node navigationNodeAt: 2@4 ifAbsent: [ nil ]) source equals: 'self'.
  493. node := self parse: 'foo
  494. true ifTrue: [ 1 ]' forClass: Object.
  495. self assert: (node navigationNodeAt: 2@7 ifAbsent: [ nil ]) selector equals: 'ifTrue:'.
  496. node := self parse: 'foo
  497. self foo; bar; baz' forClass: Object.
  498. self assert: (node navigationNodeAt: 2@8 ifAbsent: [ nil ]) selector equals: 'foo'
  499. ! !
  500. TestCase subclass: #AbstractCodeGeneratorInstallTest
  501. slots: {#receiver}
  502. package: 'Compiler-Tests'!
  503. !AbstractCodeGeneratorInstallTest methodsFor: 'accessing'!
  504. receiver
  505. ^ receiver
  506. ! !
  507. !AbstractCodeGeneratorInstallTest methodsFor: 'testing'!
  508. shouldntInstall: aString andRaise: anErrorClass
  509. | method |
  510. [ self
  511. should: [ method := self install: aString forClass: receiver class ]
  512. raise: anErrorClass ]
  513. ensure: [ method ifNotNil: [ receiver class removeCompiledMethod: method ] ]
  514. ! !
  515. !AbstractCodeGeneratorInstallTest methodsFor: 'tests'!
  516. testInvalidAssignment
  517. self shouldntInstall: 'foo:a a:=1' andRaise: InvalidAssignmentError.
  518. self shouldntInstall: 'foo false:=1' andRaise: InvalidAssignmentError.
  519. self shouldntInstall: 'foo console:=1' andRaise: InvalidAssignmentError.
  520. self shouldntInstall: 'foo Number:=1' andRaise: InvalidAssignmentError
  521. !
  522. testMistypedPragmaJSStatement
  523. self shouldntInstall: 'foo < inlineJS: ''return ''foo'''' >' andRaise: ParseError
  524. !
  525. testNiladicJSOverride
  526. receiver := ObjectMock new.
  527. receiver foo: 4.
  528. self while: 'baz <jsOverride: #baz> ^ (foo := foo + 3)' should: [
  529. self assert: receiver baz equals: 7.
  530. self assert: (receiver basicPerform: #baz) equals: 10.
  531. self assert: receiver baz equals: 13.
  532. self assert: receiver foo equals: 13 ]
  533. !
  534. testNiladicJSOverrideDifferentNames
  535. receiver := ObjectMock new.
  536. receiver foo: 4.
  537. self while: 'quux <jsOverride: #mux> ^ (foo := foo + 3)' should: [
  538. self should: [ receiver mux ] raise: MessageNotUnderstood.
  539. self assert: (receiver basicPerform: #mux) equals: 7.
  540. self assert: receiver quux equals: 10.
  541. self should: [ receiver basicPerform: #quux ] raise: Error.
  542. self assert: receiver foo equals: 10 ]
  543. !
  544. testPragmaInBlock
  545. self shouldntInstall: 'foo ^ [ < fooBar > 4 ] value' andRaise: ParseError
  546. ! !
  547. !AbstractCodeGeneratorInstallTest class methodsFor: 'testing'!
  548. isAbstract
  549. ^ self name = AbstractCodeGeneratorInstallTest name
  550. ! !
  551. AbstractCodeGeneratorInstallTest subclass: #CodeGeneratorInstallTest
  552. slots: {}
  553. package: 'Compiler-Tests'!
  554. AbstractCodeGeneratorInstallTest subclass: #InliningCodeGeneratorInstallTest
  555. slots: {}
  556. package: 'Compiler-Tests'!
  557. TestCase subclass: #ScopeVarTest
  558. slots: {}
  559. package: 'Compiler-Tests'!
  560. !ScopeVarTest methodsFor: 'tests'!
  561. testClassRefVar
  562. | node binding |
  563. node := VariableNode new
  564. identifier: 'Object';
  565. yourself.
  566. SemanticAnalyzer new
  567. pushScope: MethodLexicalScope new;
  568. visit: node.
  569. binding := node binding.
  570. self deny: binding isAssignable.
  571. self deny: binding isIdempotent.
  572. self assert: (binding alias includesSubString: 'Object').
  573. self assert: (binding alias ~= 'Object')
  574. !
  575. testExternallyKnownVar
  576. | node binding |
  577. node := VariableNode new
  578. identifier: 'console';
  579. yourself.
  580. SemanticAnalyzer new
  581. pushScope: MethodLexicalScope new;
  582. visit: node.
  583. binding := node binding.
  584. self deny: binding isAssignable.
  585. self deny: binding isIdempotent.
  586. self assert: binding alias equals: 'console'
  587. !
  588. testExternallyUnknownVar
  589. | node |
  590. node := VariableNode new
  591. identifier: 'bzzz';
  592. yourself.
  593. self
  594. should: [
  595. SemanticAnalyzer new
  596. pushScope: MethodLexicalScope new;
  597. visit: node ]
  598. raise: UnknownVariableError
  599. !
  600. testInstanceVar
  601. | binding |
  602. binding := MethodLexicalScope new
  603. addIVar: 'bzzz';
  604. bindingFor: 'bzzz'.
  605. self assert: binding isAssignable.
  606. self deny: binding isIdempotent.
  607. self assert: (binding alias includesSubString: 'bzzz').
  608. self assert: (binding alias ~= 'bzzz')
  609. !
  610. testPseudoVar
  611. #('self' 'super' 'true' 'false' 'nil' 'thisContext') do: [ :each |
  612. | binding |
  613. binding := MethodLexicalScope new bindingFor: each.
  614. self deny: binding isAssignable.
  615. self assert: binding isIdempotent ]
  616. !
  617. testTempVar
  618. | binding |
  619. binding := MethodLexicalScope new
  620. addTemp: 'bzzz';
  621. bindingFor: 'bzzz'.
  622. self assert: binding isAssignable.
  623. self deny: binding isIdempotent.
  624. self assert: binding alias equals: 'bzzz'
  625. !
  626. testUnknownVar
  627. self assert: (MethodLexicalScope new bindingFor: 'bzzz') isNil
  628. ! !
  629. TestCase subclass: #SemanticAnalyzerTest
  630. slots: {#analyzer}
  631. package: 'Compiler-Tests'!
  632. !SemanticAnalyzerTest methodsFor: 'running'!
  633. setUp
  634. analyzer := SemanticAnalyzer on: Object
  635. ! !
  636. !SemanticAnalyzerTest methodsFor: 'tests'!
  637. testAssignment
  638. | src ast |
  639. src := 'foo self := 1'.
  640. ast := Smalltalk parse: src.
  641. self should: [analyzer visit: ast] raise: InvalidAssignmentError
  642. !
  643. testNonLocalReturn
  644. | src ast |
  645. src := 'foo | a | a + 1. ^ a'.
  646. ast := Smalltalk parse: src.
  647. analyzer visit: ast.
  648. self deny: ast scope hasNonLocalReturn
  649. !
  650. testNonLocalReturn2
  651. | src ast |
  652. src := 'foo | a | a + 1. [ [ ^ a] ]'.
  653. ast := Smalltalk parse: src.
  654. analyzer visit: ast.
  655. self assert: ast scope hasNonLocalReturn
  656. !
  657. testScope
  658. | src ast |
  659. src := 'foo | a | a + 1. [ | b | b := a ]'.
  660. ast := Smalltalk parse: src.
  661. analyzer visit: ast.
  662. self deny: ast sequenceNode dagChildren last scope == ast scope.
  663. !
  664. testScope2
  665. | src ast |
  666. src := 'foo | a | a + 1. [ [ | b | b := a ] ]'.
  667. ast := Smalltalk parse: src.
  668. analyzer visit: ast.
  669. self deny: ast sequenceNode dagChildren last sequenceNode dagChildren first scope == ast scope.
  670. !
  671. testScopeLevel
  672. | src ast |
  673. src := 'foo | a | a + 1. [ [ | b | b := a ] ]'.
  674. ast := Smalltalk parse: src.
  675. analyzer visit: ast.
  676. self assert: ast scope scopeLevel equals: 1.
  677. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first scope scopeLevel equals: 3
  678. !
  679. testUnknownVariables
  680. | src ast |
  681. src := 'foo | a | b + a'.
  682. ast := Smalltalk parse: src.
  683. self should: [ analyzer visit: ast ] raise: UnknownVariableError
  684. !
  685. testUnknownVariablesWithScope
  686. | src ast |
  687. src := 'foo | a b | [ c + 1. [ a + 1. d + 1 ]]'.
  688. ast := Smalltalk parse: src.
  689. self should: [ analyzer visit: ast ] raise: UnknownVariableError
  690. !
  691. testVariableShadowing
  692. | src ast |
  693. src := 'foo | a | a + 1'.
  694. ast := Smalltalk parse: src.
  695. analyzer visit: ast
  696. !
  697. testVariableShadowing2
  698. | src ast |
  699. src := 'foo | a | a + 1. [ | a | a := 2 ]'.
  700. ast := Smalltalk parse: src.
  701. self should: [analyzer visit: ast] raise: ShadowingVariableError
  702. !
  703. testVariableShadowing3
  704. | src ast |
  705. src := 'foo | a | a + 1. [ | b | b := 2 ]'.
  706. ast := Smalltalk parse: src.
  707. analyzer visit: ast
  708. !
  709. testVariableShadowing4
  710. | src ast |
  711. src := 'foo | a | a + 1. [ [ [ | b | b := 2 ] ] ]'.
  712. ast := Smalltalk parse: src.
  713. analyzer visit: ast
  714. !
  715. testVariableShadowing5
  716. | src ast |
  717. src := 'foo | a | a + 1. [ [ [ | a | a := 2 ] ] ]'.
  718. ast := Smalltalk parse: src.
  719. self should: [analyzer visit: ast] raise: ShadowingVariableError
  720. !
  721. testVariablesLookup
  722. | src ast |
  723. src := 'foo | a | a + 1. [ | b | b := a ]'.
  724. ast := Smalltalk parse: src.
  725. analyzer visit: ast.
  726. "Binding for `a` in the message send"
  727. self assert: ast sequenceNode dagChildren first receiver binding isAssignable.
  728. self assert: ast sequenceNode dagChildren first receiver binding alias equals: 'a'.
  729. self assert: ast sequenceNode dagChildren first receiver binding scope == ast scope.
  730. "Binding for `b`"
  731. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding isAssignable.
  732. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding alias equals: 'b'.
  733. self assert: ast sequenceNode dagChildren last sequenceNode dagChildren first left binding scope == ast sequenceNode dagChildren last scope.
  734. ! !
  735. SemanticAnalyzerTest subclass: #AISemanticAnalyzerTest
  736. slots: {}
  737. package: 'Compiler-Tests'!
  738. !AISemanticAnalyzerTest methodsFor: 'running'!
  739. setUp
  740. analyzer := (AISemanticAnalyzer on: Object)
  741. context: (AIContext new
  742. defineLocal: 'local';
  743. localAt: 'local' put: 3;
  744. yourself);
  745. yourself
  746. ! !
  747. !AISemanticAnalyzerTest methodsFor: 'tests'!
  748. testContextVariables
  749. | src ast |
  750. src := 'foo | a | local + a'.
  751. ast := Smalltalk parse: src.
  752. self shouldnt: [ analyzer visit: ast ] raise: UnknownVariableError
  753. ! !
  754. Trait named: #TASTCompilingTest
  755. package: 'Compiler-Tests'!
  756. !TASTCompilingTest methodsFor: 'accessing'!
  757. codeGeneratorClass
  758. self subclassResponsibility
  759. ! !
  760. !TASTCompilingTest methodsFor: 'compiling'!
  761. install: aString forClass: aClass
  762. ^ self compiler
  763. install: aString
  764. forClass: aClass
  765. protocol: 'tests'
  766. ! !
  767. !TASTCompilingTest methodsFor: 'factory'!
  768. compiler
  769. ^ Compiler new
  770. codeGeneratorClass: self codeGeneratorClass;
  771. yourself
  772. ! !
  773. !TASTCompilingTest methodsFor: 'testing'!
  774. while: aString inClass: aClass should: aBlock
  775. | method |
  776. [
  777. method := self install: aString forClass: aClass.
  778. aBlock value: method ]
  779. ensure: [ method ifNotNil: [ aClass removeCompiledMethod: method ] ]
  780. !
  781. while: aString should: aBlock
  782. self while: aString inClass: self receiver class should: aBlock
  783. ! !
  784. Trait named: #TASTParsingTest
  785. package: 'Compiler-Tests'!
  786. !TASTParsingTest methodsFor: 'parsing'!
  787. parse: aString forClass: aClass
  788. ^ Compiler new
  789. ast: aString
  790. forClass: aClass
  791. protocol: 'test'
  792. ! !
  793. Trait named: #TCTDebugged
  794. package: 'Compiler-Tests'!
  795. !TCTDebugged methodsFor: 'private'!
  796. interpret: aString forClass: aClass receiver: anObject withArguments: aDictionary
  797. "The food is a methodNode. Interpret the sequenceNode only"
  798. | ctx |
  799. ctx := self prepareContextFor: aString class: aClass receiver: anObject withArguments: aDictionary.
  800. ^ (ASTDebugger context: ctx) proceed; result
  801. ! !
  802. Trait named: #TCTExecuted
  803. package: 'Compiler-Tests'!
  804. !TCTExecuted methodsFor: 'testing'!
  805. while: aString inClass: aClass should: aBlock
  806. super
  807. while: aString
  808. inClass: aClass
  809. should: [ :method | aBlock value: [
  810. self receiver perform: method selector ] ]
  811. ! !
  812. Trait named: #TCTInlined
  813. package: 'Compiler-Tests'!
  814. !TCTInlined methodsFor: 'accessing'!
  815. codeGeneratorClass
  816. ^ InliningCodeGenerator
  817. ! !
  818. Trait named: #TCTInterpreted
  819. package: 'Compiler-Tests'!
  820. !TCTInterpreted methodsFor: 'private'!
  821. interpret: aString forClass: aClass receiver: anObject withArguments: aDictionary
  822. "The food is a methodNode. Interpret the sequenceNode only"
  823. | ctx |
  824. ctx := self prepareContextFor: aString class: aClass receiver: anObject withArguments: aDictionary.
  825. ^ ctx interpreter proceed; result
  826. !
  827. prepareContextFor: aString class: aClass receiver: anObject withArguments: aDictionary
  828. "The food is a methodNode. Interpret the sequenceNode only"
  829. | ctx ast |
  830. ast := self parse: aString forClass: aClass.
  831. ctx := AIContext new
  832. receiver: anObject;
  833. selector: ast selector;
  834. interpreter: ASTInterpreter new;
  835. yourself.
  836. "Define locals for the context"
  837. ast sequenceNode ifNotNil: [ :sequence |
  838. sequence temps do: [ :each |
  839. ctx defineLocal: each ] ].
  840. aDictionary keysAndValuesDo: [ :key :value |
  841. ctx localAt: key put: value ].
  842. ctx interpreter
  843. context: ctx;
  844. node: ast;
  845. enterNode.
  846. ^ctx
  847. ! !
  848. !TCTInterpreted methodsFor: 'testing'!
  849. while: aString inClass: aClass should: aBlock
  850. super
  851. while: aString
  852. inClass: aClass
  853. should: [ aBlock value: [
  854. self
  855. interpret: aString
  856. forClass: aClass
  857. receiver: self receiver
  858. withArguments: #{} ] ]
  859. ! !
  860. Trait named: #TCTNonInlined
  861. package: 'Compiler-Tests'!
  862. !TCTNonInlined methodsFor: 'accessing'!
  863. codeGeneratorClass
  864. ^ CodeGenerator
  865. ! !
  866. TASTCompilingTest setTraitComposition: {TASTParsingTest} asTraitComposition!
  867. TCTDebugged setTraitComposition: {TCTInterpreted} asTraitComposition!
  868. ASTMethodRunningTest setTraitComposition: {TASTCompilingTest} asTraitComposition!
  869. ASTDebuggerTest setTraitComposition: {TCTNonInlined. TCTDebugged} asTraitComposition!
  870. ASTInterpreterTest setTraitComposition: {TCTNonInlined. TCTInterpreted} asTraitComposition!
  871. CodeGeneratorTest setTraitComposition: {TCTNonInlined. TCTExecuted} asTraitComposition!
  872. InliningCodeGeneratorTest setTraitComposition: {TCTInlined. TCTExecuted} asTraitComposition!
  873. AbstractJavaScriptGatewayTest setTraitComposition: {TClassBuildingTest} asTraitComposition!
  874. InlinedJSGTest setTraitComposition: {TCTInlined. TCTExecuted} asTraitComposition!
  875. PlainJSGTest setTraitComposition: {TCTNonInlined. TCTExecuted} asTraitComposition!
  876. ASTPCNodeVisitorTest setTraitComposition: {TASTParsingTest} asTraitComposition!
  877. ASTPositionTest setTraitComposition: {TASTParsingTest} asTraitComposition!
  878. AbstractCodeGeneratorInstallTest setTraitComposition: {TASTCompilingTest} asTraitComposition!
  879. CodeGeneratorInstallTest setTraitComposition: {TCTNonInlined} asTraitComposition!
  880. InliningCodeGeneratorInstallTest setTraitComposition: {TCTInlined} asTraitComposition!
  881. ! !