1
0

Compiler.st 57 KB

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