Compiler.st 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213
  1. Smalltalk current createPackage: 'Compiler' properties: #{}!
  2. Object subclass: #ChunkParser
  3. instanceVariableNames: 'stream'
  4. package: 'Compiler'!
  5. !ChunkParser methodsFor: 'accessing'!
  6. stream: aStream
  7. stream := aStream
  8. ! !
  9. !ChunkParser methodsFor: 'reading'!
  10. nextChunk
  11. "The chunk format (Smalltalk Interchange Format or Fileout format)
  12. is a trivial format but can be a bit tricky to understand:
  13. - Uses the exclamation mark as delimiter of chunks.
  14. - Inside a chunk a normal exclamation mark must be doubled.
  15. - A non empty chunk must be a valid Smalltalk expression.
  16. - A chunk on top level with a preceding empty chunk is an instruction chunk:
  17. - The object created by the expression then takes over reading chunks.
  18. This metod returns next chunk as a String (trimmed), empty String (all whitespace) or nil."
  19. | char result chunk |
  20. result := '' writeStream.
  21. [char := stream next.
  22. char notNil] whileTrue: [
  23. char = '!!' ifTrue: [
  24. stream peek = '!!'
  25. ifTrue: [stream next "skipping the escape double"]
  26. ifFalse: [^result contents trimBoth "chunk end marker found"]].
  27. result nextPut: char].
  28. ^nil "a chunk needs to end with !!"
  29. ! !
  30. !ChunkParser class methodsFor: 'not yet classified'!
  31. on: aStream
  32. ^self new stream: aStream
  33. ! !
  34. Object subclass: #Compiler
  35. instanceVariableNames: 'currentClass source unknownVariables codeGeneratorClass'
  36. package: 'Compiler'!
  37. !Compiler methodsFor: 'accessing'!
  38. codeGeneratorClass
  39. ^codeGeneratorClass ifNil: [FunCodeGenerator]
  40. !
  41. codeGeneratorClass: aClass
  42. codeGeneratorClass := aClass
  43. !
  44. currentClass
  45. ^currentClass
  46. !
  47. currentClass: aClass
  48. currentClass := aClass
  49. !
  50. source
  51. ^source ifNil: ['']
  52. !
  53. source: aString
  54. source := aString
  55. !
  56. unknownVariables
  57. ^unknownVariables
  58. !
  59. unknownVariables: aCollection
  60. unknownVariables := aCollection
  61. ! !
  62. !Compiler methodsFor: 'compiling'!
  63. compile: aString
  64. ^self compileNode: (self parse: aString)
  65. !
  66. compile: aString forClass: aClass
  67. self currentClass: aClass.
  68. self source: aString.
  69. ^self compile: aString
  70. !
  71. compileExpression: aString
  72. self currentClass: DoIt.
  73. self source: 'doIt ^[', aString, '] value'.
  74. ^self compileNode: (self parse: self source)
  75. !
  76. compileNode: aNode
  77. | generator result |
  78. generator := self codeGeneratorClass new.
  79. generator
  80. source: self source;
  81. currentClass: self currentClass.
  82. result := generator compileNode: aNode.
  83. self unknownVariables: generator unknownVariables.
  84. ^result
  85. !
  86. eval: aString
  87. <return eval(aString)>
  88. !
  89. evaluateExpression: aString
  90. "Unlike #eval: evaluate a Smalltalk expression and answer the returned object"
  91. | result |
  92. DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
  93. result := DoIt new doIt.
  94. DoIt removeCompiledMethod: (DoIt methodDictionary at: 'doIt').
  95. ^result
  96. !
  97. install: aString forClass: aBehavior category: anotherString
  98. | compiled |
  99. compiled := self eval: (self compile: aString forClass: aBehavior).
  100. compiled category: anotherString.
  101. aBehavior addCompiledMethod: compiled.
  102. ^compiled
  103. !
  104. parse: aString
  105. ^Smalltalk current parse: aString
  106. !
  107. parseExpression: aString
  108. ^self parse: 'doIt ^[', aString, '] value'
  109. !
  110. recompile: aClass
  111. aClass methodDictionary do: [:each |
  112. self install: each source forClass: aClass category: each category].
  113. self setupClass: aClass.
  114. aClass isMetaclass ifFalse: [self recompile: aClass class]
  115. !
  116. recompileAll
  117. Smalltalk current classes do: [:each |
  118. Transcript show: each; cr.
  119. [self recompile: each] valueWithTimeout: 100]
  120. !
  121. setupClass: aClass
  122. <smalltalk.init(aClass)>
  123. ! !
  124. !Compiler class methodsFor: 'compiling'!
  125. recompile: aClass
  126. self new recompile: aClass
  127. !
  128. recompileAll
  129. Smalltalk current classes do: [:each |
  130. self recompile: each]
  131. ! !
  132. Object subclass: #DoIt
  133. instanceVariableNames: ''
  134. package: 'Compiler'!
  135. Object subclass: #Exporter
  136. instanceVariableNames: ''
  137. package: 'Compiler'!
  138. !Exporter methodsFor: 'fileOut'!
  139. exportAll
  140. "Export all packages in the system."
  141. ^String streamContents: [:stream |
  142. Smalltalk current packages do: [:pkg |
  143. stream nextPutAll: (self exportPackage: pkg name)]]
  144. !
  145. exportClass: aClass
  146. "Export a single class. Subclasses override these methods."
  147. ^String streamContents: [:stream |
  148. self exportDefinitionOf: aClass on: stream.
  149. self exportMethodsOf: aClass on: stream.
  150. self exportMetaDefinitionOf: aClass on: stream.
  151. self exportMethodsOf: aClass class on: stream]
  152. !
  153. exportPackage: packageName
  154. "Export a given package by name."
  155. | package |
  156. ^String streamContents: [:stream |
  157. package := Smalltalk current packageAt: packageName.
  158. self exportPackageDefinitionOf: package on: stream.
  159. "Export classes in dependency order.
  160. Update (issue #171): Remove duplicates for export"
  161. package sortedClasses asSet do: [:each |
  162. stream nextPutAll: (self exportClass: each)].
  163. self exportPackageExtensionsOf: package on: stream]
  164. ! !
  165. !Exporter methodsFor: 'private'!
  166. classNameFor: aClass
  167. ^aClass isMetaclass
  168. ifTrue: [aClass instanceClass name, '.klass']
  169. ifFalse: [
  170. aClass isNil
  171. ifTrue: ['nil']
  172. ifFalse: [aClass name]]
  173. !
  174. exportDefinitionOf: aClass on: aStream
  175. aStream
  176. nextPutAll: 'smalltalk.addClass(';
  177. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  178. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  179. nextPutAll: ', ['.
  180. aClass instanceVariableNames
  181. do: [:each | aStream nextPutAll: '''', each, '''']
  182. separatedBy: [aStream nextPutAll: ', '].
  183. aStream
  184. nextPutAll: '], ''';
  185. nextPutAll: aClass category, '''';
  186. nextPutAll: ');'.
  187. aClass comment notEmpty ifTrue: [
  188. aStream
  189. lf;
  190. nextPutAll: 'smalltalk.';
  191. nextPutAll: (self classNameFor: aClass);
  192. nextPutAll: '.comment=';
  193. nextPutAll: aClass comment asJavascript].
  194. aStream lf
  195. !
  196. exportMetaDefinitionOf: aClass on: aStream
  197. aClass class instanceVariableNames isEmpty ifFalse: [
  198. aStream
  199. nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
  200. nextPutAll: '.iVarNames = ['.
  201. aClass class instanceVariableNames
  202. do: [:each | aStream nextPutAll: '''', each, '''']
  203. separatedBy: [aStream nextPutAll: ','].
  204. aStream nextPutAll: '];', String lf]
  205. !
  206. exportMethod: aMethod of: aClass on: aStream
  207. aStream
  208. nextPutAll: 'smalltalk.addMethod(';lf;
  209. nextPutAll: aMethod selector asSelector asJavascript, ',';lf;
  210. nextPutAll: 'smalltalk.method({';lf;
  211. nextPutAll: 'selector: ', aMethod selector asJavascript, ',';lf;
  212. nextPutAll: 'category: ''', aMethod category, ''',';lf;
  213. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  214. nextPutAll: 'args: ', aMethod arguments asJavascript, ','; lf;
  215. nextPutAll: 'source: ', aMethod source asJavascript, ',';lf;
  216. nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
  217. nextPutAll: 'referencedClasses: ', aMethod referencedClasses asJavascript.
  218. aStream
  219. lf;
  220. nextPutAll: '}),';lf;
  221. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  222. nextPutAll: ');';lf;lf
  223. !
  224. exportMethodsOf: aClass on: aStream
  225. "Issue #143: sort methods alphabetically"
  226. ((aClass methodDictionary values) sorted: [:a :b | a selector <= b selector]) do: [:each |
  227. (each category match: '^\*') ifFalse: [
  228. self exportMethod: each of: aClass on: aStream]].
  229. aStream lf
  230. !
  231. exportPackageDefinitionOf: package on: aStream
  232. aStream
  233. nextPutAll: 'smalltalk.addPackage(';
  234. nextPutAll: '''', package name, ''', ', package propertiesAsJSON , ');'.
  235. aStream lf
  236. !
  237. exportPackageExtensionsOf: package on: aStream
  238. "Issue #143: sort classes and methods alphabetically"
  239. | name |
  240. name := package name.
  241. (Package sortedClasses: Smalltalk current classes) do: [:each |
  242. {each. each class} do: [:aClass |
  243. ((aClass methodDictionary values) sorted: [:a :b | a selector <= b selector]) do: [:method |
  244. (method category match: '^\*', name) ifTrue: [
  245. self exportMethod: method of: aClass on: aStream ]]]]
  246. ! !
  247. Exporter subclass: #ChunkExporter
  248. instanceVariableNames: ''
  249. package: 'Compiler'!
  250. !ChunkExporter methodsFor: 'not yet classified'!
  251. chunkEscape: aString
  252. "Replace all occurrences of !! with !!!! and trim at both ends."
  253. ^(aString replace: '!!' with: '!!!!') trimBoth
  254. !
  255. classNameFor: aClass
  256. ^aClass isMetaclass
  257. ifTrue: [aClass instanceClass name, ' class']
  258. ifFalse: [
  259. aClass isNil
  260. ifTrue: ['nil']
  261. ifFalse: [aClass name]]
  262. !
  263. exportDefinitionOf: aClass on: aStream
  264. "Chunk format."
  265. aStream
  266. nextPutAll: (self classNameFor: aClass superclass);
  267. nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
  268. nextPutAll: ' instanceVariableNames: '''.
  269. aClass instanceVariableNames
  270. do: [:each | aStream nextPutAll: each]
  271. separatedBy: [aStream nextPutAll: ' '].
  272. aStream
  273. nextPutAll: ''''; lf;
  274. nextPutAll: ' package: ''', aClass category, '''!!'; lf.
  275. aClass comment notEmpty ifTrue: [
  276. aStream
  277. nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
  278. nextPutAll: (self chunkEscape: aClass comment), '!!';lf].
  279. aStream lf
  280. !
  281. exportMetaDefinitionOf: aClass on: aStream
  282. aClass class instanceVariableNames isEmpty ifFalse: [
  283. aStream
  284. nextPutAll: (self classNameFor: aClass class);
  285. nextPutAll: ' instanceVariableNames: '''.
  286. aClass class instanceVariableNames
  287. do: [:each | aStream nextPutAll: each]
  288. separatedBy: [aStream nextPutAll: ' '].
  289. aStream
  290. nextPutAll: '''!!'; lf; lf]
  291. !
  292. exportMethod: aMethod of: aClass on: aStream
  293. aStream
  294. lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;
  295. nextPutAll: '!!'
  296. !
  297. exportMethods: methods category: category of: aClass on: aStream
  298. "Issue #143: sort methods alphabetically"
  299. aStream
  300. nextPutAll: '!!', (self classNameFor: aClass);
  301. nextPutAll: ' methodsFor: ''', category, '''!!'.
  302. (methods sorted: [:a :b | a selector <= b selector]) do: [:each |
  303. self exportMethod: each of: aClass on: aStream].
  304. aStream nextPutAll: ' !!'; lf; lf
  305. !
  306. exportMethodsOf: aClass on: aStream
  307. "Issue #143: sort protocol alphabetically"
  308. | map |
  309. map := Dictionary new.
  310. aClass protocolsDo: [:category :methods |
  311. (category match: '^\*') ifFalse: [ map at: category put: methods ]].
  312. (map keys sorted: [:a :b | a <= b ]) do: [:category | | methods |
  313. methods := map at: category.
  314. self
  315. exportMethods: methods
  316. category: category
  317. of: aClass
  318. on: aStream ]
  319. !
  320. exportPackageDefinitionOf: package on: aStream
  321. "Chunk format."
  322. aStream
  323. nextPutAll: 'Smalltalk current createPackage: ''', package name,
  324. ''' properties: ', package properties storeString, '!!'; lf.
  325. !
  326. exportPackageExtensionsOf: package on: aStream
  327. "We need to override this one too since we need to group
  328. all methods in a given protocol under a leading methodsFor: chunk
  329. for that class."
  330. "Issue #143: sort protocol alphabetically"
  331. | name map |
  332. name := package name.
  333. (Package sortedClasses: Smalltalk current classes) do: [:each |
  334. {each. each class} do: [:aClass |
  335. map := Dictionary new.
  336. aClass protocolsDo: [:category :methods |
  337. (category match: '^\*', name) ifTrue: [ map at: category put: methods ]].
  338. (map keys sorted: [:a :b | a <= b ]) do: [:category | | methods |
  339. methods := map at: category.
  340. self exportMethods: methods category: category of: aClass on: aStream ]]]
  341. ! !
  342. Exporter subclass: #StrippedExporter
  343. instanceVariableNames: ''
  344. package: 'Compiler'!
  345. !StrippedExporter methodsFor: 'private'!
  346. exportDefinitionOf: aClass on: aStream
  347. aStream
  348. nextPutAll: 'smalltalk.addClass(';
  349. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  350. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  351. nextPutAll: ', ['.
  352. aClass instanceVariableNames
  353. do: [:each | aStream nextPutAll: '''', each, '''']
  354. separatedBy: [aStream nextPutAll: ', '].
  355. aStream
  356. nextPutAll: '], ''';
  357. nextPutAll: aClass category, '''';
  358. nextPutAll: ');'.
  359. aStream lf
  360. !
  361. exportMethod: aMethod of: aClass on: aStream
  362. aStream
  363. nextPutAll: 'smalltalk.addMethod(';lf;
  364. nextPutAll: aMethod selector asSelector asJavascript, ',';lf;
  365. nextPutAll: 'smalltalk.method({';lf;
  366. nextPutAll: 'selector: ', aMethod selector asJavascript, ',';lf;
  367. nextPutAll: 'fn: ', aMethod fn compiledSource;lf;
  368. nextPutAll: '}),';lf;
  369. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  370. nextPutAll: ');';lf;lf
  371. ! !
  372. Object subclass: #Importer
  373. instanceVariableNames: ''
  374. package: 'Compiler'!
  375. !Importer methodsFor: 'fileIn'!
  376. import: aStream
  377. | chunk result parser lastEmpty |
  378. parser := ChunkParser on: aStream.
  379. lastEmpty := false.
  380. [chunk := parser nextChunk.
  381. chunk isNil] whileFalse: [
  382. chunk isEmpty
  383. ifTrue: [lastEmpty := true]
  384. ifFalse: [
  385. result := Compiler new evaluateExpression: chunk.
  386. lastEmpty
  387. ifTrue: [
  388. lastEmpty := false.
  389. result scanFrom: parser]]]
  390. ! !
  391. Object subclass: #Node
  392. instanceVariableNames: 'nodes'
  393. package: 'Compiler'!
  394. !Node methodsFor: 'accessing'!
  395. addNode: aNode
  396. self nodes add: aNode
  397. !
  398. nodes
  399. ^nodes ifNil: [nodes := Array new]
  400. ! !
  401. !Node methodsFor: 'building'!
  402. nodes: aCollection
  403. nodes := aCollection
  404. ! !
  405. !Node methodsFor: 'testing'!
  406. isBlockNode
  407. ^false
  408. !
  409. isBlockSequenceNode
  410. ^false
  411. !
  412. isValueNode
  413. ^false
  414. ! !
  415. !Node methodsFor: 'visiting'!
  416. accept: aVisitor
  417. aVisitor visitNode: self
  418. ! !
  419. Node subclass: #AssignmentNode
  420. instanceVariableNames: 'left right'
  421. package: 'Compiler'!
  422. !AssignmentNode methodsFor: 'accessing'!
  423. left
  424. ^left
  425. !
  426. left: aNode
  427. left := aNode.
  428. left assigned: true
  429. !
  430. right
  431. ^right
  432. !
  433. right: aNode
  434. right := aNode
  435. ! !
  436. !AssignmentNode methodsFor: 'visiting'!
  437. accept: aVisitor
  438. aVisitor visitAssignmentNode: self
  439. ! !
  440. Node subclass: #BlockNode
  441. instanceVariableNames: 'parameters inlined'
  442. package: 'Compiler'!
  443. !BlockNode methodsFor: 'accessing'!
  444. inlined
  445. ^inlined ifNil: [false]
  446. !
  447. inlined: aBoolean
  448. inlined := aBoolean
  449. !
  450. parameters
  451. ^parameters ifNil: [parameters := Array new]
  452. !
  453. parameters: aCollection
  454. parameters := aCollection
  455. ! !
  456. !BlockNode methodsFor: 'testing'!
  457. isBlockNode
  458. ^true
  459. ! !
  460. !BlockNode methodsFor: 'visiting'!
  461. accept: aVisitor
  462. aVisitor visitBlockNode: self
  463. ! !
  464. Node subclass: #CascadeNode
  465. instanceVariableNames: 'receiver'
  466. package: 'Compiler'!
  467. !CascadeNode methodsFor: 'accessing'!
  468. receiver
  469. ^receiver
  470. !
  471. receiver: aNode
  472. receiver := aNode
  473. ! !
  474. !CascadeNode methodsFor: 'visiting'!
  475. accept: aVisitor
  476. aVisitor visitCascadeNode: self
  477. ! !
  478. Node subclass: #DynamicArrayNode
  479. instanceVariableNames: ''
  480. package: 'Compiler'!
  481. !DynamicArrayNode methodsFor: 'visiting'!
  482. accept: aVisitor
  483. aVisitor visitDynamicArrayNode: self
  484. ! !
  485. Node subclass: #DynamicDictionaryNode
  486. instanceVariableNames: ''
  487. package: 'Compiler'!
  488. !DynamicDictionaryNode methodsFor: 'visiting'!
  489. accept: aVisitor
  490. aVisitor visitDynamicDictionaryNode: self
  491. ! !
  492. Node subclass: #JSStatementNode
  493. instanceVariableNames: 'source'
  494. package: 'Compiler'!
  495. !JSStatementNode methodsFor: 'accessing'!
  496. source
  497. ^source ifNil: ['']
  498. !
  499. source: aString
  500. source := aString
  501. ! !
  502. !JSStatementNode methodsFor: 'visiting'!
  503. accept: aVisitor
  504. aVisitor visitJSStatementNode: self
  505. ! !
  506. Node subclass: #MethodNode
  507. instanceVariableNames: 'selector arguments source'
  508. package: 'Compiler'!
  509. !MethodNode methodsFor: 'accessing'!
  510. arguments
  511. ^arguments ifNil: [#()]
  512. !
  513. arguments: aCollection
  514. arguments := aCollection
  515. !
  516. selector
  517. ^selector
  518. !
  519. selector: aString
  520. selector := aString
  521. !
  522. source
  523. ^source
  524. !
  525. source: aString
  526. source := aString
  527. ! !
  528. !MethodNode methodsFor: 'visiting'!
  529. accept: aVisitor
  530. aVisitor visitMethodNode: self
  531. ! !
  532. Node subclass: #ReturnNode
  533. instanceVariableNames: ''
  534. package: 'Compiler'!
  535. !ReturnNode methodsFor: 'visiting'!
  536. accept: aVisitor
  537. aVisitor visitReturnNode: self
  538. ! !
  539. Node subclass: #SendNode
  540. instanceVariableNames: 'selector arguments receiver'
  541. package: 'Compiler'!
  542. !SendNode methodsFor: 'accessing'!
  543. arguments
  544. ^arguments ifNil: [arguments := #()]
  545. !
  546. arguments: aCollection
  547. arguments := aCollection
  548. !
  549. cascadeNodeWithMessages: aCollection
  550. | first |
  551. first := SendNode new
  552. selector: self selector;
  553. arguments: self arguments;
  554. yourself.
  555. ^CascadeNode new
  556. receiver: self receiver;
  557. nodes: (Array with: first), aCollection;
  558. yourself
  559. !
  560. receiver
  561. ^receiver
  562. !
  563. receiver: aNode
  564. receiver := aNode
  565. !
  566. selector
  567. ^selector
  568. !
  569. selector: aString
  570. selector := aString
  571. !
  572. valueForReceiver: anObject
  573. ^SendNode new
  574. receiver: (self receiver
  575. ifNil: [anObject]
  576. ifNotNil: [self receiver valueForReceiver: anObject]);
  577. selector: self selector;
  578. arguments: self arguments;
  579. yourself
  580. ! !
  581. !SendNode methodsFor: 'visiting'!
  582. accept: aVisitor
  583. aVisitor visitSendNode: self
  584. ! !
  585. Node subclass: #SequenceNode
  586. instanceVariableNames: 'temps'
  587. package: 'Compiler'!
  588. !SequenceNode methodsFor: 'accessing'!
  589. temps
  590. ^temps ifNil: [#()]
  591. !
  592. temps: aCollection
  593. temps := aCollection
  594. ! !
  595. !SequenceNode methodsFor: 'testing'!
  596. asBlockSequenceNode
  597. ^BlockSequenceNode new
  598. nodes: self nodes;
  599. temps: self temps;
  600. yourself
  601. ! !
  602. !SequenceNode methodsFor: 'visiting'!
  603. accept: aVisitor
  604. aVisitor visitSequenceNode: self
  605. ! !
  606. SequenceNode subclass: #BlockSequenceNode
  607. instanceVariableNames: ''
  608. package: 'Compiler'!
  609. !BlockSequenceNode methodsFor: 'testing'!
  610. isBlockSequenceNode
  611. ^true
  612. ! !
  613. !BlockSequenceNode methodsFor: 'visiting'!
  614. accept: aVisitor
  615. aVisitor visitBlockSequenceNode: self
  616. ! !
  617. Node subclass: #ValueNode
  618. instanceVariableNames: 'value'
  619. package: 'Compiler'!
  620. !ValueNode methodsFor: 'accessing'!
  621. value
  622. ^value
  623. !
  624. value: anObject
  625. value := anObject
  626. ! !
  627. !ValueNode methodsFor: 'testing'!
  628. isValueNode
  629. ^true
  630. ! !
  631. !ValueNode methodsFor: 'visiting'!
  632. accept: aVisitor
  633. aVisitor visitValueNode: self
  634. ! !
  635. ValueNode subclass: #VariableNode
  636. instanceVariableNames: 'assigned'
  637. package: 'Compiler'!
  638. !VariableNode methodsFor: 'accessing'!
  639. assigned
  640. ^assigned ifNil: [false]
  641. !
  642. assigned: aBoolean
  643. assigned := aBoolean
  644. ! !
  645. !VariableNode methodsFor: 'visiting'!
  646. accept: aVisitor
  647. aVisitor visitVariableNode: self
  648. ! !
  649. VariableNode subclass: #ClassReferenceNode
  650. instanceVariableNames: ''
  651. package: 'Compiler'!
  652. !ClassReferenceNode methodsFor: 'visiting'!
  653. accept: aVisitor
  654. aVisitor visitClassReferenceNode: self
  655. ! !
  656. Node subclass: #VerbatimNode
  657. instanceVariableNames: 'value'
  658. package: 'Compiler'!
  659. !VerbatimNode methodsFor: 'accessing'!
  660. value
  661. ^value
  662. !
  663. value: anObject
  664. value := anObject
  665. ! !
  666. !VerbatimNode methodsFor: 'visiting'!
  667. accept: aVisitor
  668. aVisitor visitVerbatimNode: self
  669. ! !
  670. Object subclass: #NodeVisitor
  671. instanceVariableNames: ''
  672. package: 'Compiler'!
  673. !NodeVisitor methodsFor: 'visiting'!
  674. visit: aNode
  675. aNode accept: self
  676. !
  677. visitAssignmentNode: aNode
  678. self visitNode: aNode
  679. !
  680. visitBlockNode: aNode
  681. self visitNode: aNode
  682. !
  683. visitBlockSequenceNode: aNode
  684. self visitNode: aNode
  685. !
  686. visitCascadeNode: aNode
  687. self visitNode: aNode
  688. !
  689. visitClassReferenceNode: aNode
  690. self visitNode: aNode
  691. !
  692. visitDynamicArrayNode: aNode
  693. self visitNode: aNode
  694. !
  695. visitDynamicDictionaryNode: aNode
  696. self visitNode: aNode
  697. !
  698. visitJSStatementNode: aNode
  699. self visitNode: aNode
  700. !
  701. visitMethodNode: aNode
  702. self visitNode: aNode
  703. !
  704. visitNode: aNode
  705. !
  706. visitReturnNode: aNode
  707. self visitNode: aNode
  708. !
  709. visitSendNode: aNode
  710. self visitNode: aNode
  711. !
  712. visitSequenceNode: aNode
  713. self visitNode: aNode
  714. !
  715. visitValueNode: aNode
  716. self visitNode: aNode
  717. !
  718. visitVariableNode: aNode
  719. self visitNode: aNode
  720. !
  721. visitVerbatimNode: aNode
  722. self visitNode: aNode
  723. ! !
  724. NodeVisitor subclass: #AbstractCodeGenerator
  725. instanceVariableNames: 'currentClass source'
  726. package: 'Compiler'!
  727. !AbstractCodeGenerator methodsFor: 'accessing'!
  728. classNameFor: aClass
  729. ^aClass isMetaclass
  730. ifTrue: [aClass instanceClass name, '.klass']
  731. ifFalse: [
  732. aClass isNil
  733. ifTrue: ['nil']
  734. ifFalse: [aClass name]]
  735. !
  736. currentClass
  737. ^currentClass
  738. !
  739. currentClass: aClass
  740. currentClass := aClass
  741. !
  742. pseudoVariables
  743. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  744. !
  745. safeVariableNameFor: aString
  746. ^(Smalltalk current reservedWords includes: aString)
  747. ifTrue: [aString, '_']
  748. ifFalse: [aString]
  749. !
  750. source
  751. ^source ifNil: ['']
  752. !
  753. source: aString
  754. source := aString
  755. ! !
  756. !AbstractCodeGenerator methodsFor: 'compiling'!
  757. compileNode: aNode
  758. self subclassResponsibility
  759. ! !
  760. AbstractCodeGenerator subclass: #FunCodeGenerator
  761. instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables'
  762. package: 'Compiler'!
  763. !FunCodeGenerator methodsFor: 'accessing'!
  764. argVariables
  765. ^argVariables copy
  766. !
  767. knownVariables
  768. ^self pseudoVariables
  769. addAll: self tempVariables;
  770. addAll: self argVariables;
  771. yourself
  772. !
  773. tempVariables
  774. ^tempVariables copy
  775. !
  776. unknownVariables
  777. ^unknownVariables copy
  778. ! !
  779. !FunCodeGenerator methodsFor: 'compiling'!
  780. compileNode: aNode
  781. stream := '' writeStream.
  782. self visit: aNode.
  783. ^stream contents
  784. ! !
  785. !FunCodeGenerator methodsFor: 'initialization'!
  786. initialize
  787. super initialize.
  788. stream := '' writeStream.
  789. unknownVariables := #().
  790. tempVariables := #().
  791. argVariables := #().
  792. messageSends := #().
  793. classReferenced := #()
  794. ! !
  795. !FunCodeGenerator methodsFor: 'optimizations'!
  796. checkClass: aClassName for: receiver
  797. stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
  798. !
  799. inline: aSelector receiver: receiver argumentNodes: aCollection
  800. | inlined |
  801. inlined := false.
  802. "-- Booleans --"
  803. (aSelector = 'ifFalse:') ifTrue: [
  804. aCollection first isBlockNode ifTrue: [
  805. self checkClass: 'Boolean' for: receiver.
  806. stream nextPutAll: '(!! $receiver ? '.
  807. self visit: aCollection first.
  808. stream nextPutAll: '() : nil)'.
  809. inlined := true]].
  810. (aSelector = 'ifTrue:') ifTrue: [
  811. aCollection first isBlockNode ifTrue: [
  812. self checkClass: 'Boolean' for: receiver.
  813. stream nextPutAll: '($receiver ? '.
  814. self visit: aCollection first.
  815. stream nextPutAll: '() : nil)'.
  816. inlined := true]].
  817. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  818. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  819. self checkClass: 'Boolean' for: receiver.
  820. stream nextPutAll: '($receiver ? '.
  821. self visit: aCollection first.
  822. stream nextPutAll: '() : '.
  823. self visit: aCollection second.
  824. stream nextPutAll: '())'.
  825. inlined := true]].
  826. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  827. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  828. self checkClass: 'Boolean' for: receiver.
  829. stream nextPutAll: '(!! $receiver ? '.
  830. self visit: aCollection first.
  831. stream nextPutAll: '() : '.
  832. self visit: aCollection second.
  833. stream nextPutAll: '())'.
  834. inlined := true]].
  835. "-- Numbers --"
  836. (aSelector = '<') ifTrue: [
  837. self checkClass: 'Number' for: receiver.
  838. stream nextPutAll: '$receiver <'.
  839. self visit: aCollection first.
  840. inlined := true].
  841. (aSelector = '<=') ifTrue: [
  842. self checkClass: 'Number' for: receiver.
  843. stream nextPutAll: '$receiver <='.
  844. self visit: aCollection first.
  845. inlined := true].
  846. (aSelector = '>') ifTrue: [
  847. self checkClass: 'Number' for: receiver.
  848. stream nextPutAll: '$receiver >'.
  849. self visit: aCollection first.
  850. inlined := true].
  851. (aSelector = '>=') ifTrue: [
  852. self checkClass: 'Number' for: receiver.
  853. stream nextPutAll: '$receiver >='.
  854. self visit: aCollection first.
  855. inlined := true].
  856. (aSelector = '+') ifTrue: [
  857. self checkClass: 'Number' for: receiver.
  858. stream nextPutAll: '$receiver +'.
  859. self visit: aCollection first.
  860. inlined := true].
  861. (aSelector = '-') ifTrue: [
  862. self checkClass: 'Number' for: receiver.
  863. stream nextPutAll: '$receiver -'.
  864. self visit: aCollection first.
  865. inlined := true].
  866. (aSelector = '*') ifTrue: [
  867. self checkClass: 'Number' for: receiver.
  868. stream nextPutAll: '$receiver *'.
  869. self visit: aCollection first.
  870. inlined := true].
  871. (aSelector = '/') ifTrue: [
  872. self checkClass: 'Number' for: receiver.
  873. stream nextPutAll: '$receiver /'.
  874. self visit: aCollection first.
  875. inlined := true].
  876. ^inlined
  877. !
  878. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  879. | inlined |
  880. inlined := false.
  881. "-- BlockClosures --"
  882. (aSelector = 'whileTrue:') ifTrue: [
  883. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  884. stream nextPutAll: '(function(){while('.
  885. self visit: anObject.
  886. stream nextPutAll: '()) {'.
  887. self visit: aCollection first.
  888. stream nextPutAll: '()}})()'.
  889. inlined := true]].
  890. (aSelector = 'whileFalse:') ifTrue: [
  891. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  892. stream nextPutAll: '(function(){while(!!'.
  893. self visit: anObject.
  894. stream nextPutAll: '()) {'.
  895. self visit: aCollection first.
  896. stream nextPutAll: '()}})()'.
  897. inlined := true]].
  898. (aSelector = 'whileTrue') ifTrue: [
  899. anObject isBlockNode ifTrue: [
  900. stream nextPutAll: '(function(){while('.
  901. self visit: anObject.
  902. stream nextPutAll: '()) {}})()'.
  903. inlined := true]].
  904. (aSelector = 'whileFalse') ifTrue: [
  905. anObject isBlockNode ifTrue: [
  906. stream nextPutAll: '(function(){while(!!'.
  907. self visit: anObject.
  908. stream nextPutAll: '()) {}})()'.
  909. inlined := true]].
  910. "-- Numbers --"
  911. (aSelector = '+') ifTrue: [
  912. (self isNode: anObject ofClass: Number) ifTrue: [
  913. self visit: anObject.
  914. stream nextPutAll: ' + '.
  915. self visit: aCollection first.
  916. inlined := true]].
  917. (aSelector = '-') ifTrue: [
  918. (self isNode: anObject ofClass: Number) ifTrue: [
  919. self visit: anObject.
  920. stream nextPutAll: ' - '.
  921. self visit: aCollection first.
  922. inlined := true]].
  923. (aSelector = '*') ifTrue: [
  924. (self isNode: anObject ofClass: Number) ifTrue: [
  925. self visit: anObject.
  926. stream nextPutAll: ' * '.
  927. self visit: aCollection first.
  928. inlined := true]].
  929. (aSelector = '/') ifTrue: [
  930. (self isNode: anObject ofClass: Number) ifTrue: [
  931. self visit: anObject.
  932. stream nextPutAll: ' / '.
  933. self visit: aCollection first.
  934. inlined := true]].
  935. (aSelector = '<') ifTrue: [
  936. (self isNode: anObject ofClass: Number) ifTrue: [
  937. self visit: anObject.
  938. stream nextPutAll: ' < '.
  939. self visit: aCollection first.
  940. inlined := true]].
  941. (aSelector = '<=') ifTrue: [
  942. (self isNode: anObject ofClass: Number) ifTrue: [
  943. self visit: anObject.
  944. stream nextPutAll: ' <= '.
  945. self visit: aCollection first.
  946. inlined := true]].
  947. (aSelector = '>') ifTrue: [
  948. (self isNode: anObject ofClass: Number) ifTrue: [
  949. self visit: anObject.
  950. stream nextPutAll: ' > '.
  951. self visit: aCollection first.
  952. inlined := true]].
  953. (aSelector = '>=') ifTrue: [
  954. (self isNode: anObject ofClass: Number) ifTrue: [
  955. self visit: anObject.
  956. stream nextPutAll: ' >= '.
  957. self visit: aCollection first.
  958. inlined := true]].
  959. "-- UndefinedObject --"
  960. (aSelector = 'ifNil:') ifTrue: [
  961. aCollection first isBlockNode ifTrue: [
  962. stream nextPutAll: '(($receiver = '.
  963. self visit: anObject.
  964. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  965. self visit: aCollection first.
  966. stream nextPutAll: '() : $receiver'.
  967. inlined := true]].
  968. (aSelector = 'ifNotNil:') ifTrue: [
  969. aCollection first isBlockNode ifTrue: [
  970. stream nextPutAll: '(($receiver = '.
  971. self visit: anObject.
  972. stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
  973. self visit: aCollection first.
  974. stream nextPutAll: '() : nil'.
  975. inlined := true]].
  976. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  977. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  978. stream nextPutAll: '(($receiver = '.
  979. self visit: anObject.
  980. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  981. self visit: aCollection first.
  982. stream nextPutAll: '() : '.
  983. self visit: aCollection second.
  984. stream nextPutAll: '()'.
  985. inlined := true]].
  986. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  987. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  988. stream nextPutAll: '(($receiver = '.
  989. self visit: anObject.
  990. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  991. self visit: aCollection second.
  992. stream nextPutAll: '() : '.
  993. self visit: aCollection first.
  994. stream nextPutAll: '()'.
  995. inlined := true]].
  996. ^inlined
  997. !
  998. isNode: aNode ofClass: aClass
  999. ^aNode isValueNode and: [
  1000. aNode value class = aClass or: [
  1001. aNode value = 'self' and: [self currentClass = aClass]]]
  1002. ! !
  1003. !FunCodeGenerator methodsFor: 'testing'!
  1004. performOptimizations
  1005. ^self class performOptimizations
  1006. ! !
  1007. !FunCodeGenerator methodsFor: 'visiting'!
  1008. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  1009. ^String streamContents: [:str || tmp |
  1010. tmp := stream.
  1011. str nextPutAll: 'smalltalk.send('.
  1012. str nextPutAll: aReceiver.
  1013. str nextPutAll: ', "', aSelector asSelector, '", ['.
  1014. stream := str.
  1015. aCollection
  1016. do: [:each | self visit: each]
  1017. separatedBy: [stream nextPutAll: ', '].
  1018. stream := tmp.
  1019. str nextPutAll: ']'.
  1020. aBoolean ifTrue: [
  1021. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass), '.superclass || nil'].
  1022. str nextPutAll: ')']
  1023. !
  1024. visit: aNode
  1025. aNode accept: self
  1026. !
  1027. visitAssignmentNode: aNode
  1028. stream nextPutAll: '('.
  1029. self visit: aNode left.
  1030. stream nextPutAll: '='.
  1031. self visit: aNode right.
  1032. stream nextPutAll: ')'
  1033. !
  1034. visitBlockNode: aNode
  1035. stream nextPutAll: '(function('.
  1036. aNode parameters
  1037. do: [:each |
  1038. tempVariables add: each.
  1039. stream nextPutAll: each]
  1040. separatedBy: [stream nextPutAll: ', '].
  1041. stream nextPutAll: '){'.
  1042. aNode nodes do: [:each | self visit: each].
  1043. stream nextPutAll: '})'
  1044. !
  1045. visitBlockSequenceNode: aNode
  1046. | index |
  1047. nestedBlocks := nestedBlocks + 1.
  1048. aNode nodes isEmpty
  1049. ifTrue: [
  1050. stream nextPutAll: 'return nil;']
  1051. ifFalse: [
  1052. aNode temps do: [:each | | temp |
  1053. temp := self safeVariableNameFor: each.
  1054. tempVariables add: temp.
  1055. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  1056. index := 0.
  1057. aNode nodes do: [:each |
  1058. index := index + 1.
  1059. index = aNode nodes size ifTrue: [
  1060. stream nextPutAll: 'return '].
  1061. self visit: each.
  1062. stream nextPutAll: ';']].
  1063. nestedBlocks := nestedBlocks - 1
  1064. !
  1065. visitCascadeNode: aNode
  1066. | index |
  1067. index := 0.
  1068. (tempVariables includes: '$rec') ifFalse: [
  1069. tempVariables add: '$rec'].
  1070. stream nextPutAll: '(function($rec){'.
  1071. aNode nodes do: [:each |
  1072. index := index + 1.
  1073. index = aNode nodes size ifTrue: [
  1074. stream nextPutAll: 'return '].
  1075. each receiver: (VariableNode new value: '$rec').
  1076. self visit: each.
  1077. stream nextPutAll: ';'].
  1078. stream nextPutAll: '})('.
  1079. self visit: aNode receiver.
  1080. stream nextPutAll: ')'
  1081. !
  1082. visitClassReferenceNode: aNode
  1083. (referencedClasses includes: aNode value) ifFalse: [
  1084. referencedClasses add: aNode value].
  1085. stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
  1086. !
  1087. visitDynamicArrayNode: aNode
  1088. stream nextPutAll: '['.
  1089. aNode nodes
  1090. do: [:each | self visit: each]
  1091. separatedBy: [stream nextPutAll: ','].
  1092. stream nextPutAll: ']'
  1093. !
  1094. visitDynamicDictionaryNode: aNode
  1095. stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.
  1096. aNode nodes
  1097. do: [:each | self visit: each]
  1098. separatedBy: [stream nextPutAll: ','].
  1099. stream nextPutAll: '])'
  1100. !
  1101. visitFailure: aFailure
  1102. self error: aFailure asString
  1103. !
  1104. visitJSStatementNode: aNode
  1105. stream nextPutAll: aNode source
  1106. !
  1107. visitMethodNode: aNode
  1108. | str currentSelector |
  1109. currentSelector := aNode selector asSelector.
  1110. nestedBlocks := 0.
  1111. earlyReturn := false.
  1112. messageSends := #().
  1113. referencedClasses := #().
  1114. unknownVariables := #().
  1115. tempVariables := #().
  1116. argVariables := #().
  1117. stream
  1118. nextPutAll: 'smalltalk.method({'; lf;
  1119. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  1120. stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
  1121. stream nextPutAll: 'fn: function('.
  1122. aNode arguments
  1123. do: [:each |
  1124. argVariables add: each.
  1125. stream nextPutAll: each]
  1126. separatedBy: [stream nextPutAll: ', '].
  1127. stream
  1128. nextPutAll: '){'; lf;
  1129. nextPutAll: 'var self=this;'; lf.
  1130. str := stream.
  1131. stream := '' writeStream.
  1132. aNode nodes do: [:each |
  1133. self visit: each].
  1134. earlyReturn ifTrue: [
  1135. str nextPutAll: 'var $early={};'; lf; nextPutAll: 'try{'].
  1136. str nextPutAll: stream contents.
  1137. stream := str.
  1138. stream
  1139. lf;
  1140. nextPutAll: 'return self;'.
  1141. earlyReturn ifTrue: [
  1142. stream lf; nextPutAll: '} catch(e) {if(e===$early)return e[0]; throw e}'].
  1143. stream nextPutAll: '}'.
  1144. stream
  1145. nextPutAll: ',', String lf, 'messageSends: ';
  1146. nextPutAll: messageSends asJavascript, ','; lf;
  1147. nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
  1148. nextPutAll: 'referencedClasses: ['.
  1149. referencedClasses
  1150. do: [:each | stream nextPutAll: each printString]
  1151. separatedBy: [stream nextPutAll: ','].
  1152. stream nextPutAll: ']'.
  1153. stream nextPutAll: '})'
  1154. !
  1155. visitReturnNode: aNode
  1156. nestedBlocks > 0 ifTrue: [
  1157. earlyReturn := true].
  1158. nestedBlocks > 0
  1159. ifTrue: [
  1160. stream
  1161. nextPutAll: '(function(){throw $early=[']
  1162. ifFalse: [stream nextPutAll: 'return '].
  1163. aNode nodes do: [:each |
  1164. self visit: each].
  1165. nestedBlocks > 0 ifTrue: [
  1166. stream nextPutAll: ']})()']
  1167. !
  1168. visitSendNode: aNode
  1169. | str receiver superSend inlined |
  1170. str := stream.
  1171. (messageSends includes: aNode selector) ifFalse: [
  1172. messageSends add: aNode selector].
  1173. stream := '' writeStream.
  1174. self visit: aNode receiver.
  1175. superSend := stream contents = 'super'.
  1176. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  1177. stream := str.
  1178. self performOptimizations
  1179. ifTrue: [
  1180. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
  1181. (self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
  1182. ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
  1183. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
  1184. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
  1185. !
  1186. visitSequenceNode: aNode
  1187. aNode temps do: [:each || temp |
  1188. temp := self safeVariableNameFor: each.
  1189. tempVariables add: temp.
  1190. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  1191. aNode nodes do: [:each |
  1192. self visit: each.
  1193. stream nextPutAll: ';']
  1194. separatedBy: [stream lf]
  1195. !
  1196. visitValueNode: aNode
  1197. stream nextPutAll: aNode value asJavascript
  1198. !
  1199. visitVariableNode: aNode
  1200. | varName |
  1201. (self currentClass allInstanceVariableNames includes: aNode value)
  1202. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  1203. ifFalse: [
  1204. varName := self safeVariableNameFor: aNode value.
  1205. (self knownVariables includes: varName)
  1206. ifFalse: [
  1207. unknownVariables add: aNode value.
  1208. aNode assigned
  1209. ifTrue: [stream nextPutAll: varName]
  1210. ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
  1211. ifTrue: [
  1212. aNode value = 'thisContext'
  1213. ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
  1214. ifFalse: [stream nextPutAll: varName]]]
  1215. ! !
  1216. FunCodeGenerator class instanceVariableNames: 'performOptimizations'!
  1217. !FunCodeGenerator class methodsFor: 'accessing'!
  1218. performOptimizations
  1219. ^performOptimizations ifNil: [true]
  1220. !
  1221. performOptimizations: aBoolean
  1222. performOptimizations := aBoolean
  1223. ! !
  1224. AbstractCodeGenerator subclass: #ImpCodeGenerator
  1225. instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables mutables target lazyVars realVarNames'
  1226. package: 'Compiler'!
  1227. !ImpCodeGenerator methodsFor: 'accessing'!
  1228. argVariables
  1229. ^argVariables copy
  1230. !
  1231. knownVariables
  1232. ^self pseudoVariables
  1233. addAll: self tempVariables;
  1234. addAll: self argVariables;
  1235. yourself
  1236. !
  1237. tempVariables
  1238. ^tempVariables copy
  1239. !
  1240. unknownVariables
  1241. ^unknownVariables copy
  1242. ! !
  1243. !ImpCodeGenerator methodsFor: 'compilation DSL'!
  1244. aboutToModifyState
  1245. | list old |
  1246. list := mutables.
  1247. mutables := Set new.
  1248. old := self switchTarget: nil.
  1249. list do: [ :each | | value |
  1250. self switchTarget: each.
  1251. self realAssign: (lazyVars at: each)
  1252. ].
  1253. self switchTarget: old
  1254. !
  1255. ifValueWanted: aBlock
  1256. target ifNotNil: aBlock
  1257. !
  1258. isolated: node
  1259. ^ self visit: node targetBeing: self nextLazyvarName
  1260. !
  1261. isolatedUse: node
  1262. | old |
  1263. old := self switchTarget: self nextLazyvarName.
  1264. self visit: node.
  1265. ^self useValueNamed: (self switchTarget: old)
  1266. !
  1267. lazyAssign: aString dependsOnState: aBoolean
  1268. (lazyVars includesKey: target)
  1269. ifTrue: [ lazyVars at: target put: aString. aBoolean ifTrue: [ mutables add: target ] ]
  1270. ifFalse: [ self realAssign: aString ]
  1271. !
  1272. lazyAssignExpression: aString
  1273. self lazyAssign: aString dependsOnState: true
  1274. !
  1275. lazyAssignValue: aString
  1276. self lazyAssign: aString dependsOnState: false
  1277. !
  1278. makeTargetRealVariable
  1279. (lazyVars includesKey: target) ifTrue: [
  1280. lazyVars removeKey: target.
  1281. lazyVars at: 'assigned ',target put: nil. "<-- only to retain size, it is used in nextLazyvarName"
  1282. realVarNames add: target ].
  1283. !
  1284. nextLazyvarName
  1285. | name |
  1286. name := '$', lazyVars size asString.
  1287. lazyVars at: name put: name.
  1288. ^name
  1289. !
  1290. nilIfValueWanted
  1291. target ifNotNil: [ self lazyAssignValue: 'nil' ]
  1292. !
  1293. realAssign: aString
  1294. | closer |
  1295. aString ifNotEmpty: [
  1296. self aboutToModifyState.
  1297. closer := ''.
  1298. self ifValueWanted: [ stream nextPutAll:
  1299. (target = '^' ifTrue: ['return '] ifFalse: [
  1300. target = '!!' ifTrue: [ closer := ']'. 'throw $early=['] ifFalse: [
  1301. target, '=']]) ].
  1302. self makeTargetRealVariable.
  1303. stream nextPutAll: aString, closer, ';', self mylf ]
  1304. !
  1305. switchTarget: aString
  1306. | old |
  1307. old := target.
  1308. target := aString.
  1309. ^old
  1310. !
  1311. useValueNamed: key
  1312. | val |
  1313. (realVarNames includes: key) ifTrue: [ ^key ].
  1314. mutables remove: key.
  1315. ^lazyVars at: key
  1316. !
  1317. visit: aNode targetBeing: aString
  1318. | old |
  1319. old := self switchTarget: aString.
  1320. self visit: aNode.
  1321. ^ self switchTarget: old.
  1322. ! !
  1323. !ImpCodeGenerator methodsFor: 'compiling'!
  1324. compileNode: aNode
  1325. stream := '' writeStream.
  1326. self visit: aNode.
  1327. ^stream contents
  1328. ! !
  1329. !ImpCodeGenerator methodsFor: 'initialization'!
  1330. initialize
  1331. super initialize.
  1332. stream := '' writeStream.
  1333. unknownVariables := #().
  1334. tempVariables := #().
  1335. argVariables := #().
  1336. messageSends := #().
  1337. classReferenced := #().
  1338. mutables := Set new.
  1339. realVarNames := Set new.
  1340. lazyVars := HashedCollection new.
  1341. target := nil
  1342. ! !
  1343. !ImpCodeGenerator methodsFor: 'optimizations'!
  1344. checkClass: aClassName for: receiver
  1345. self prvCheckClass: aClassName for: receiver.
  1346. stream nextPutAll: '{'
  1347. !
  1348. checkClass: aClassName for: receiver includeIf: aBoolean
  1349. self prvCheckClass: aClassName for: receiver.
  1350. stream nextPutAll: (aBoolean ifTrue: ['if(('] ifFalse: ['if(!!(']), (self useValueNamed: receiver), ')) {'
  1351. !
  1352. inline: aSelector receiver: receiver argumentNodes: aCollection
  1353. "-- Booleans --"
  1354. (aSelector = 'ifFalse:') ifTrue: [
  1355. aCollection first isBlockNode ifTrue: [
  1356. self checkClass: 'Boolean' for: receiver includeIf: false.
  1357. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1358. self prvPutAndElse: [ self nilIfValueWanted ].
  1359. ^true]].
  1360. (aSelector = 'ifTrue:') ifTrue: [
  1361. aCollection first isBlockNode ifTrue: [
  1362. self checkClass: 'Boolean' for: receiver includeIf: true.
  1363. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1364. self prvPutAndElse: [ self nilIfValueWanted ].
  1365. ^true]].
  1366. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  1367. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  1368. self checkClass: 'Boolean' for: receiver includeIf: true.
  1369. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1370. self prvPutAndElse: [ self visit: aCollection second nodes first ].
  1371. ^true]].
  1372. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  1373. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  1374. self checkClass: 'Boolean' for: receiver includeIf: false.
  1375. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1376. self prvPutAndElse: [ self visit: aCollection second nodes first ].
  1377. ^true]].
  1378. "-- Numbers --"
  1379. (aSelector = '<') ifTrue: [ | operand |
  1380. operand := self isolatedUse: aCollection first.
  1381. self checkClass: 'Number' for: receiver.
  1382. self prvPutAndElse: [
  1383. self lazyAssignExpression: '(', (self useValueNamed: receiver), '<', operand, ')' ].
  1384. ^{ VerbatimNode new value: operand }].
  1385. (aSelector = '<=') ifTrue: [ | operand |
  1386. operand := self isolatedUse: aCollection first.
  1387. self checkClass: 'Number' for: receiver.
  1388. self prvPutAndElse: [
  1389. self lazyAssignExpression: '(', (self useValueNamed: receiver), '<=', operand, ')' ].
  1390. ^{ VerbatimNode new value: operand }].
  1391. (aSelector = '>') ifTrue: [ | operand |
  1392. operand := self isolatedUse: aCollection first.
  1393. self checkClass: 'Number' for: receiver.
  1394. self prvPutAndElse: [
  1395. self lazyAssignExpression: '(', (self useValueNamed: receiver), '>', operand, ')' ].
  1396. ^{ VerbatimNode new value: operand }].
  1397. (aSelector = '>=') ifTrue: [ | operand |
  1398. operand := self isolatedUse: aCollection first.
  1399. self checkClass: 'Number' for: receiver.
  1400. self prvPutAndElse: [
  1401. self lazyAssignExpression: '(', (self useValueNamed: receiver), '>=', operand, ')' ].
  1402. ^{ VerbatimNode new value: operand }].
  1403. (aSelector = '+') ifTrue: [ | operand |
  1404. operand := self isolatedUse: aCollection first.
  1405. self checkClass: 'Number' for: receiver.
  1406. self prvPutAndElse: [
  1407. self lazyAssignExpression: '(', (self useValueNamed: receiver), '+', operand, ')' ].
  1408. ^{ VerbatimNode new value: operand }].
  1409. (aSelector = '-') ifTrue: [ | operand |
  1410. operand := self isolatedUse: aCollection first.
  1411. self checkClass: 'Number' for: receiver.
  1412. self prvPutAndElse: [
  1413. self lazyAssignExpression: '(', (self useValueNamed: receiver), '-', operand, ')' ].
  1414. ^{ VerbatimNode new value: operand }].
  1415. (aSelector = '*') ifTrue: [ | operand |
  1416. operand := self isolatedUse: aCollection first.
  1417. self checkClass: 'Number' for: receiver.
  1418. self prvPutAndElse: [
  1419. self lazyAssignExpression: '(', (self useValueNamed: receiver), '*', operand, ')' ].
  1420. ^{ VerbatimNode new value: operand }].
  1421. (aSelector = '/') ifTrue: [ | operand |
  1422. operand := self isolatedUse: aCollection first.
  1423. self checkClass: 'Number' for: receiver.
  1424. self prvPutAndElse: [
  1425. self lazyAssignExpression: '(', (self useValueNamed: receiver), '/', operand, ')' ].
  1426. ^{ VerbatimNode new value: operand }].
  1427. ^nil
  1428. !
  1429. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  1430. | inlined |
  1431. inlined := false.
  1432. "-- BlockClosures --"
  1433. (aSelector = 'whileTrue:') ifTrue: [
  1434. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [ | old |
  1435. self prvWhileConditionStatement: 'for(;;){' pre: 'if (!!(' condition: anObject post: ')) {'.
  1436. stream nextPutAll: 'break}', self mylf.
  1437. self prvPutAndClose: [ self visit: aCollection first nodes first targetBeing: nil ].
  1438. inlined := true]].
  1439. (aSelector = 'whileFalse:') ifTrue: [
  1440. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [ | old |
  1441. self prvWhileConditionStatement: 'for(;;){' pre: 'if ((' condition: anObject post: ')) {'.
  1442. stream nextPutAll: 'break}', self mylf.
  1443. self prvPutAndClose: [ self visit: aCollection first nodes first targetBeing: nil ].
  1444. inlined := true]].
  1445. (aSelector = 'whileTrue') ifTrue: [
  1446. anObject isBlockNode ifTrue: [
  1447. self prvWhileConditionStatement: 'do{' pre: '}while((' condition: anObject post: '));', self mylf.
  1448. inlined := true]].
  1449. (aSelector = 'whileFalse') ifTrue: [
  1450. anObject isBlockNode ifTrue: [
  1451. self prvWhileConditionStatement: 'do{' pre: '}while(!!(' condition: anObject post: '));', self mylf.
  1452. inlined := true]].
  1453. "-- Numbers --"
  1454. (#('+' '-' '*' '/' '<' '<=' '>=' '>') includes: aSelector) ifTrue: [
  1455. (self prvInlineNumberOperator: aSelector on: anObject and: aCollection first) ifTrue: [
  1456. inlined := true]].
  1457. "-- UndefinedObject --"
  1458. (aSelector = 'ifNil:') ifTrue: [
  1459. aCollection first isBlockNode ifTrue: [ | rcv |
  1460. self aboutToModifyState.
  1461. rcv := self isolatedUse: anObject.
  1462. rcv = 'super' ifTrue: [ rcv := 'self' ].
  1463. self makeTargetRealVariable.
  1464. stream nextPutAll: 'if((', rcv, ') === nil || (', rcv, ') == null) {'.
  1465. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1466. self prvPutAndClose: [ self lazyAssignValue: rcv ].
  1467. inlined := true]].
  1468. (aSelector = 'ifNotNil:') ifTrue: [
  1469. aCollection first isBlockNode ifTrue: [ | rcv |
  1470. self aboutToModifyState.
  1471. rcv := self isolatedUse: anObject.
  1472. rcv = 'super' ifTrue: [ rcv := 'self' ].
  1473. self makeTargetRealVariable.
  1474. stream nextPutAll: 'if((', rcv, ') !!== nil && (', rcv, ') !!= null) {'.
  1475. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1476. self prvPutAndClose: [ self lazyAssignValue: rcv ].
  1477. inlined := true]].
  1478. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  1479. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [ | rcv |
  1480. self aboutToModifyState.
  1481. rcv := self isolatedUse: anObject.
  1482. rcv = 'super' ifTrue: [ rcv := 'self' ].
  1483. self makeTargetRealVariable.
  1484. stream nextPutAll: 'if((', rcv, ') === nil || (', rcv, ') == null) {'.
  1485. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1486. self prvPutAndClose: [ self visit: aCollection second nodes first ].
  1487. inlined := true]].
  1488. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  1489. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [ | rcv |
  1490. self aboutToModifyState.
  1491. rcv := self isolatedUse: anObject.
  1492. rcv = 'super' ifTrue: [ rcv := 'self' ].
  1493. self makeTargetRealVariable.
  1494. stream nextPutAll: 'if((', rcv, ') !!== nil && (', rcv, ') !!= null) {'.
  1495. self prvPutAndElse: [ self visit: aCollection first nodes first ].
  1496. self prvPutAndClose: [ self visit: aCollection second nodes first ].
  1497. inlined := true]].
  1498. (aSelector = 'isNil') ifTrue: [ | rcv |
  1499. rcv := self isolatedUse: anObject.
  1500. rcv = 'super' ifTrue: [ rcv := 'self' ].
  1501. self lazyAssignValue: '((', rcv, ') === nil || (', rcv, ') == null)'.
  1502. inlined := true].
  1503. (aSelector = 'notNil') ifTrue: [ | rcv |
  1504. rcv := self isolatedUse: anObject.
  1505. rcv = 'super' ifTrue: [ rcv := 'self' ].
  1506. self lazyAssignValue: '((', rcv, ') !!== nil && (', rcv, ') !!= null)'.
  1507. inlined := true].
  1508. ^inlined
  1509. !
  1510. isNode: aNode ofClass: aClass
  1511. ^aNode isValueNode and: [
  1512. aNode value class = aClass or: [
  1513. aNode value = 'self' and: [self currentClass = aClass]]]
  1514. !
  1515. prvCheckClass: aClassName for: receiver
  1516. self makeTargetRealVariable.
  1517. self aboutToModifyState.
  1518. stream nextPutAll: 'if((', (self useValueNamed: receiver), ').klass === smalltalk.', aClassName, ') '
  1519. !
  1520. prvInlineNumberOperator: aSelector on: receiverNode and: operandNode
  1521. (aSelector = aSelector) ifTrue: [
  1522. (self isNode: receiverNode ofClass: Number) ifTrue: [
  1523. | rcv operand |
  1524. rcv := self isolated: receiverNode.
  1525. operand := self isolated: operandNode.
  1526. self lazyAssignValue: ((self useValueNamed: rcv), aSelector, (self useValueNamed: operand)).
  1527. ^true]].
  1528. ^false
  1529. !
  1530. prvWhileConditionStatement: stmtString pre: preString condition: anObject post: postString
  1531. | x |
  1532. stream nextPutAll: stmtString.
  1533. x := self isolatedUse: anObject nodes first.
  1534. x ifEmpty: [ x := '"should not reach - receiver includes ^"' ].
  1535. stream nextPutAll: preString, x, postString.
  1536. self nilIfValueWanted
  1537. ! !
  1538. !ImpCodeGenerator methodsFor: 'output'!
  1539. mylf
  1540. ^String lf, ((Array new: nestedBlocks+2) join: String tab)
  1541. !
  1542. prvPutAndClose: aBlock
  1543. aBlock value.
  1544. stream nextPutAll: '}', self mylf
  1545. !
  1546. prvPutAndElse: aBlock
  1547. aBlock value.
  1548. stream nextPutAll: '} else {'
  1549. !
  1550. putTemps: temps
  1551. temps ifNotEmpty: [
  1552. stream nextPutAll: 'var '.
  1553. temps do: [:each | | temp |
  1554. temp := self safeVariableNameFor: each.
  1555. tempVariables add: temp.
  1556. stream nextPutAll: temp, '=nil'] separatedBy: [ stream nextPutAll: ',' ].
  1557. stream nextPutAll: ';', self mylf
  1558. ]
  1559. ! !
  1560. !ImpCodeGenerator methodsFor: 'testing'!
  1561. assert: aBoolean
  1562. aBoolean ifFalse: [ self error: 'assertion failed' ]
  1563. !
  1564. performOptimizations
  1565. ^self class performOptimizations
  1566. ! !
  1567. !ImpCodeGenerator methodsFor: 'visiting'!
  1568. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  1569. | args |
  1570. args := self isolated: (DynamicArrayNode new nodes: aCollection; yourself).
  1571. self lazyAssignExpression: (String streamContents: [ :str |
  1572. str nextPutAll: 'smalltalk.send('.
  1573. str nextPutAll: (self useValueNamed: aReceiver).
  1574. str nextPutAll: ', "', aSelector asSelector, '", '.
  1575. str nextPutAll: (self useValueNamed: args).
  1576. aBoolean ifTrue: [
  1577. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
  1578. str nextPutAll: ')'
  1579. ])
  1580. !
  1581. sequenceOfNodes: nodes temps: temps
  1582. nodes isEmpty
  1583. ifFalse: [ | old index |
  1584. self putTemps: temps.
  1585. old :=self switchTarget: nil.
  1586. index := 0.
  1587. nodes do: [:each |
  1588. index := index + 1.
  1589. index = nodes size ifTrue: [ self switchTarget: old ].
  1590. self visit: each ]]
  1591. ifTrue: [ self nilIfValueWanted ]
  1592. !
  1593. visit: aNode
  1594. aNode accept: self
  1595. !
  1596. visitAssignmentNode: aNode
  1597. | olds oldt |
  1598. olds := stream.
  1599. stream := '' writeStream.
  1600. oldt := self switchTarget: self nextLazyvarName.
  1601. self visit: aNode left.
  1602. self assert: (lazyVars at: target) ~= target.
  1603. self switchTarget: (self useValueNamed: (self switchTarget: nil)).
  1604. self assert: (lazyVars includesKey: target) not.
  1605. stream := olds.
  1606. self visit: aNode right.
  1607. olds := self switchTarget: oldt.
  1608. self ifValueWanted: [ self lazyAssignExpression: olds ]
  1609. !
  1610. visitBlockNode: aNode
  1611. | oldt olds oldm |
  1612. self assert: aNode nodes size = 1.
  1613. oldt := self switchTarget: '^'.
  1614. olds := stream.
  1615. stream := '' writeStream.
  1616. stream nextPutAll: '(function('.
  1617. aNode parameters
  1618. do: [:each |
  1619. tempVariables add: each.
  1620. stream nextPutAll: each]
  1621. separatedBy: [stream nextPutAll: ', '].
  1622. stream nextPutAll: '){'.
  1623. nestedBlocks := nestedBlocks + 1.
  1624. oldm := mutables.
  1625. mutables := Set new.
  1626. self visit: aNode nodes first.
  1627. self assert: mutables isEmpty.
  1628. mutables := oldm.
  1629. nestedBlocks := nestedBlocks - 1.
  1630. stream nextPutAll: '})'.
  1631. self switchTarget: oldt.
  1632. oldt := stream contents.
  1633. stream := olds.
  1634. self lazyAssignExpression: oldt
  1635. !
  1636. visitBlockSequenceNode: aNode
  1637. self sequenceOfNodes: aNode nodes temps: aNode temps
  1638. !
  1639. visitCascadeNode: aNode
  1640. | rcv |
  1641. rcv := self isolated: aNode receiver.
  1642. self aboutToModifyState.
  1643. rcv := self useValueNamed: rcv.
  1644. aNode nodes do: [:each |
  1645. each receiver: (VerbatimNode new value: rcv) ].
  1646. self sequenceOfNodes: aNode nodes temps: #()
  1647. !
  1648. visitClassReferenceNode: aNode
  1649. (referencedClasses includes: aNode value) ifFalse: [
  1650. referencedClasses add: aNode value].
  1651. self lazyAssignExpression: '(smalltalk.', aNode value, ' || ', aNode value, ')'
  1652. !
  1653. visitDynamicArrayNode: aNode
  1654. | args |
  1655. args :=aNode nodes collect: [ :node | self isolated: node ].
  1656. self lazyAssignValue: (String streamContents: [ :str |
  1657. str nextPutAll: '['.
  1658. args
  1659. do: [:each | str nextPutAll: (self useValueNamed: each) ]
  1660. separatedBy: [str nextPutAll: ', '].
  1661. str nextPutAll: ']'
  1662. ])
  1663. !
  1664. visitDynamicDictionaryNode: aNode
  1665. | elements |
  1666. elements := self isolated: (DynamicArrayNode new nodes: aNode nodes; yourself).
  1667. self lazyAssignValue: 'smalltalk.HashedCollection._fromPairs_(', (self useValueNamed: elements), ')'
  1668. !
  1669. visitFailure: aFailure
  1670. self error: aFailure asString
  1671. !
  1672. visitJSStatementNode: aNode
  1673. self aboutToModifyState.
  1674. stream nextPutAll: ';', (aNode source replace: '>>' with: '>'), ';', self mylf
  1675. !
  1676. visitMethodNode: aNode
  1677. | str currentSelector |
  1678. currentSelector := aNode selector asSelector.
  1679. nestedBlocks := 0.
  1680. earlyReturn := false.
  1681. messageSends := #().
  1682. referencedClasses := #().
  1683. unknownVariables := #().
  1684. tempVariables := #().
  1685. argVariables := #().
  1686. lazyVars := HashedCollection new.
  1687. mutables := Set new.
  1688. realVarNames := Set new.
  1689. stream
  1690. nextPutAll: 'smalltalk.method({'; lf;
  1691. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  1692. stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
  1693. stream nextPutAll: 'fn: function('.
  1694. aNode arguments
  1695. do: [:each |
  1696. argVariables add: each.
  1697. stream nextPutAll: each]
  1698. separatedBy: [stream nextPutAll: ', '].
  1699. stream
  1700. nextPutAll: '){var self=this;', self mylf.
  1701. str := stream.
  1702. stream := '' writeStream.
  1703. self switchTarget: nil.
  1704. self assert: aNode nodes size = 1.
  1705. self visit: aNode nodes first.
  1706. realVarNames ifNotEmpty: [ str nextPutAll: 'var ', (realVarNames asArray join: ','), ';', self mylf ].
  1707. earlyReturn ifTrue: [
  1708. str nextPutAll: 'var $early={}; try{', self mylf].
  1709. str nextPutAll: stream contents.
  1710. stream := str.
  1711. (aNode nodes first nodes notEmpty and: [ |checker|
  1712. checker := ReturnNodeChecker new.
  1713. checker visit: aNode nodes first nodes last.
  1714. checker wasReturnNode]) ifFalse: [ self switchTarget: '^'. self lazyAssignValue: 'self'. self switchTarget: nil ].
  1715. earlyReturn ifTrue: [
  1716. stream nextPutAll: '} catch(e) {if(e===$early) return e[0]; throw e}'].
  1717. stream nextPutAll: '}'.
  1718. stream
  1719. nextPutAll: ',', String lf, 'messageSends: ';
  1720. nextPutAll: messageSends asJavascript, ','; lf;
  1721. nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
  1722. nextPutAll: 'referencedClasses: ['.
  1723. referencedClasses
  1724. do: [:each | stream nextPutAll: each printString]
  1725. separatedBy: [stream nextPutAll: ','].
  1726. stream nextPutAll: ']'.
  1727. stream nextPutAll: '})'.
  1728. self assert: mutables isEmpty
  1729. !
  1730. visitReturnNode: aNode
  1731. self assert: aNode nodes size = 1.
  1732. nestedBlocks > 0 ifTrue: [
  1733. earlyReturn := true].
  1734. self
  1735. visit: aNode nodes first
  1736. targetBeing: (nestedBlocks > 0 ifTrue: ['!!'] ifFalse: ['^']).
  1737. self lazyAssignValue: ''
  1738. !
  1739. visitSendNode: aNode
  1740. | receiver superSend rcv |
  1741. (messageSends includes: aNode selector) ifFalse: [
  1742. messageSends add: aNode selector].
  1743. self performOptimizations
  1744. ifTrue: [
  1745. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifTrue: [ ^self ].
  1746. ].
  1747. rcv := self isolated: aNode receiver.
  1748. superSend := (lazyVars at: rcv ifAbsent: []) = 'super'.
  1749. superSend ifTrue: [ mutables remove: rcv. lazyVars at: rcv put: 'self' ].
  1750. self performOptimizations
  1751. ifTrue: [ | inline |
  1752. inline := self inline: aNode selector receiver: rcv argumentNodes: aNode arguments.
  1753. inline ifNotNil: [ | args |
  1754. args := inline = true ifTrue: [ aNode arguments ] ifFalse: [ inline ].
  1755. self prvPutAndClose: [ self send: aNode selector to: rcv arguments: args superSend: superSend ].
  1756. ^self ]].
  1757. self send: aNode selector to: rcv arguments: aNode arguments superSend: superSend
  1758. !
  1759. visitSequenceNode: aNode
  1760. aNode nodes isEmpty ifFalse: [
  1761. self sequenceOfNodes: aNode nodes temps: aNode temps ]
  1762. !
  1763. visitValueNode: aNode
  1764. self lazyAssignValue: aNode value asJavascript
  1765. !
  1766. visitVariableNode: aNode
  1767. | varName |
  1768. (self currentClass allInstanceVariableNames includes: aNode value)
  1769. ifTrue: [self lazyAssignExpression: 'self[''@', aNode value, ''']']
  1770. ifFalse: [
  1771. varName := self safeVariableNameFor: aNode value.
  1772. (self knownVariables includes: varName)
  1773. ifFalse: [
  1774. unknownVariables add: aNode value.
  1775. aNode assigned
  1776. ifTrue: [self lazyAssignExpression: varName]
  1777. ifFalse: [self lazyAssignExpression: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
  1778. ifTrue: [
  1779. aNode value = 'thisContext'
  1780. ifTrue: [self lazyAssignExpression: '(smalltalk.getThisContext())']
  1781. ifFalse: [(self pseudoVariables includes: varName)
  1782. ifTrue: [ self lazyAssignValue: varName ]
  1783. ifFalse: [ self lazyAssignExpression: varName]]]]
  1784. !
  1785. visitVerbatimNode: aNode
  1786. self lazyAssignValue: aNode value
  1787. ! !
  1788. ImpCodeGenerator class instanceVariableNames: 'performOptimizations'!
  1789. !ImpCodeGenerator class methodsFor: 'accessing'!
  1790. performOptimizations
  1791. ^performOptimizations ifNil: [true]
  1792. !
  1793. performOptimizations: aBoolean
  1794. performOptimizations := aBoolean
  1795. ! !
  1796. NodeVisitor subclass: #ReturnNodeChecker
  1797. instanceVariableNames: 'wasReturnNode'
  1798. package: 'Compiler'!
  1799. !ReturnNodeChecker methodsFor: 'accessing'!
  1800. wasReturnNode
  1801. ^wasReturnNode
  1802. ! !
  1803. !ReturnNodeChecker methodsFor: 'initializing'!
  1804. initialize
  1805. wasReturnNode := false
  1806. ! !
  1807. !ReturnNodeChecker methodsFor: 'visiting'!
  1808. visitReturnNode: aNode
  1809. wasReturnNode := true
  1810. ! !