Compiler.st 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490
  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. Object subclass: #NodeVisitor
  654. instanceVariableNames: ''
  655. package: 'Compiler'!
  656. !NodeVisitor methodsFor: 'visiting'!
  657. visit: aNode
  658. aNode accept: self
  659. !
  660. visitAssignmentNode: aNode
  661. self visitNode: aNode
  662. !
  663. visitBlockNode: aNode
  664. self visitNode: aNode
  665. !
  666. visitBlockSequenceNode: aNode
  667. self visitNode: aNode
  668. !
  669. visitCascadeNode: aNode
  670. self visitNode: aNode
  671. !
  672. visitClassReferenceNode: aNode
  673. self visitNode: aNode
  674. !
  675. visitDynamicArrayNode: aNode
  676. self visitNode: aNode
  677. !
  678. visitDynamicDictionaryNode: aNode
  679. self visitNode: aNode
  680. !
  681. visitJSStatementNode: aNode
  682. self visitNode: aNode
  683. !
  684. visitMethodNode: aNode
  685. self visitNode: aNode
  686. !
  687. visitNode: aNode
  688. !
  689. visitReturnNode: aNode
  690. self visitNode: aNode
  691. !
  692. visitSendNode: aNode
  693. self visitNode: aNode
  694. !
  695. visitSequenceNode: aNode
  696. self visitNode: aNode
  697. !
  698. visitValueNode: aNode
  699. self visitNode: aNode
  700. !
  701. visitVariableNode: aNode
  702. self visitNode: aNode
  703. ! !
  704. NodeVisitor subclass: #AbstractCodeGenerator
  705. instanceVariableNames: 'currentClass source'
  706. package: 'Compiler'!
  707. !AbstractCodeGenerator methodsFor: 'accessing'!
  708. classNameFor: aClass
  709. ^aClass isMetaclass
  710. ifTrue: [aClass instanceClass name, '.klass']
  711. ifFalse: [
  712. aClass isNil
  713. ifTrue: ['nil']
  714. ifFalse: [aClass name]]
  715. !
  716. currentClass
  717. ^currentClass
  718. !
  719. currentClass: aClass
  720. currentClass := aClass
  721. !
  722. pseudoVariables
  723. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  724. !
  725. safeVariableNameFor: aString
  726. ^(Smalltalk current reservedWords includes: aString)
  727. ifTrue: [aString, '_']
  728. ifFalse: [aString]
  729. !
  730. source
  731. ^source ifNil: ['']
  732. !
  733. source: aString
  734. source := aString
  735. ! !
  736. !AbstractCodeGenerator methodsFor: 'compiling'!
  737. compileNode: aNode
  738. self subclassResponsibility
  739. ! !
  740. AbstractCodeGenerator subclass: #FunCodeGenerator
  741. instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables'
  742. package: 'Compiler'!
  743. !FunCodeGenerator methodsFor: 'accessing'!
  744. argVariables
  745. ^argVariables copy
  746. !
  747. knownVariables
  748. ^self pseudoVariables
  749. addAll: self tempVariables;
  750. addAll: self argVariables;
  751. yourself
  752. !
  753. tempVariables
  754. ^tempVariables copy
  755. !
  756. unknownVariables
  757. ^unknownVariables copy
  758. ! !
  759. !FunCodeGenerator methodsFor: 'compiling'!
  760. compileNode: aNode
  761. stream := '' writeStream.
  762. self visit: aNode.
  763. ^stream contents
  764. ! !
  765. !FunCodeGenerator methodsFor: 'initialization'!
  766. initialize
  767. super initialize.
  768. stream := '' writeStream.
  769. unknownVariables := #().
  770. tempVariables := #().
  771. argVariables := #().
  772. messageSends := #().
  773. classReferenced := #()
  774. ! !
  775. !FunCodeGenerator methodsFor: 'optimizations'!
  776. checkClass: aClassName for: receiver
  777. stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
  778. !
  779. inline: aSelector receiver: receiver argumentNodes: aCollection
  780. | inlined |
  781. inlined := false.
  782. "-- Booleans --"
  783. (aSelector = 'ifFalse:') ifTrue: [
  784. aCollection first isBlockNode ifTrue: [
  785. self checkClass: 'Boolean' for: receiver.
  786. stream nextPutAll: '(!! $receiver ? '.
  787. self visit: aCollection first.
  788. stream nextPutAll: '() : nil)'.
  789. inlined := true]].
  790. (aSelector = 'ifTrue:') ifTrue: [
  791. aCollection first isBlockNode ifTrue: [
  792. self checkClass: 'Boolean' for: receiver.
  793. stream nextPutAll: '($receiver ? '.
  794. self visit: aCollection first.
  795. stream nextPutAll: '() : nil)'.
  796. inlined := true]].
  797. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  798. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  799. self checkClass: 'Boolean' for: receiver.
  800. stream nextPutAll: '($receiver ? '.
  801. self visit: aCollection first.
  802. stream nextPutAll: '() : '.
  803. self visit: aCollection second.
  804. stream nextPutAll: '())'.
  805. inlined := true]].
  806. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  807. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  808. self checkClass: 'Boolean' for: receiver.
  809. stream nextPutAll: '(!! $receiver ? '.
  810. self visit: aCollection first.
  811. stream nextPutAll: '() : '.
  812. self visit: aCollection second.
  813. stream nextPutAll: '())'.
  814. inlined := true]].
  815. "-- Numbers --"
  816. (aSelector = '<') ifTrue: [
  817. self checkClass: 'Number' for: receiver.
  818. stream nextPutAll: '$receiver <'.
  819. self visit: aCollection first.
  820. inlined := true].
  821. (aSelector = '<=') ifTrue: [
  822. self checkClass: 'Number' for: receiver.
  823. stream nextPutAll: '$receiver <='.
  824. self visit: aCollection first.
  825. inlined := true].
  826. (aSelector = '>') ifTrue: [
  827. self checkClass: 'Number' for: receiver.
  828. stream nextPutAll: '$receiver >'.
  829. self visit: aCollection first.
  830. inlined := true].
  831. (aSelector = '>=') ifTrue: [
  832. self checkClass: 'Number' for: receiver.
  833. stream nextPutAll: '$receiver >='.
  834. self visit: aCollection first.
  835. inlined := true].
  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. ^inlined
  857. !
  858. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  859. | inlined |
  860. inlined := false.
  861. "-- BlockClosures --"
  862. (aSelector = 'whileTrue:') ifTrue: [
  863. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  864. stream nextPutAll: '(function(){while('.
  865. self visit: anObject.
  866. stream nextPutAll: '()) {'.
  867. self visit: aCollection first.
  868. stream nextPutAll: '()}})()'.
  869. inlined := true]].
  870. (aSelector = 'whileFalse:') ifTrue: [
  871. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  872. stream nextPutAll: '(function(){while(!!'.
  873. self visit: anObject.
  874. stream nextPutAll: '()) {'.
  875. self visit: aCollection first.
  876. stream nextPutAll: '()}})()'.
  877. inlined := true]].
  878. (aSelector = 'whileTrue') ifTrue: [
  879. anObject isBlockNode ifTrue: [
  880. stream nextPutAll: '(function(){while('.
  881. self visit: anObject.
  882. stream nextPutAll: '()) {}})()'.
  883. inlined := true]].
  884. (aSelector = 'whileFalse') ifTrue: [
  885. anObject isBlockNode ifTrue: [
  886. stream nextPutAll: '(function(){while(!!'.
  887. self visit: anObject.
  888. stream nextPutAll: '()) {}})()'.
  889. inlined := true]].
  890. "-- Numbers --"
  891. (aSelector = '+') ifTrue: [
  892. (self isNode: anObject ofClass: Number) ifTrue: [
  893. self visit: anObject.
  894. stream nextPutAll: ' + '.
  895. self visit: aCollection first.
  896. inlined := true]].
  897. (aSelector = '-') ifTrue: [
  898. (self isNode: anObject ofClass: Number) ifTrue: [
  899. self visit: anObject.
  900. stream nextPutAll: ' - '.
  901. self visit: aCollection first.
  902. inlined := true]].
  903. (aSelector = '*') ifTrue: [
  904. (self isNode: anObject ofClass: Number) ifTrue: [
  905. self visit: anObject.
  906. stream nextPutAll: ' * '.
  907. self visit: aCollection first.
  908. inlined := true]].
  909. (aSelector = '/') ifTrue: [
  910. (self isNode: anObject ofClass: Number) ifTrue: [
  911. self visit: anObject.
  912. stream nextPutAll: ' / '.
  913. self visit: aCollection first.
  914. inlined := true]].
  915. (aSelector = '<') ifTrue: [
  916. (self isNode: anObject ofClass: Number) ifTrue: [
  917. self visit: anObject.
  918. stream nextPutAll: ' < '.
  919. self visit: aCollection first.
  920. inlined := true]].
  921. (aSelector = '<=') ifTrue: [
  922. (self isNode: anObject ofClass: Number) ifTrue: [
  923. self visit: anObject.
  924. stream nextPutAll: ' <= '.
  925. self visit: aCollection first.
  926. inlined := true]].
  927. (aSelector = '>') ifTrue: [
  928. (self isNode: anObject ofClass: Number) ifTrue: [
  929. self visit: anObject.
  930. stream nextPutAll: ' > '.
  931. self visit: aCollection first.
  932. inlined := true]].
  933. (aSelector = '>=') ifTrue: [
  934. (self isNode: anObject ofClass: Number) ifTrue: [
  935. self visit: anObject.
  936. stream nextPutAll: ' >= '.
  937. self visit: aCollection first.
  938. inlined := true]].
  939. "-- UndefinedObject --"
  940. (aSelector = 'ifNil:') ifTrue: [
  941. aCollection first isBlockNode ifTrue: [
  942. stream nextPutAll: '(($receiver = '.
  943. self visit: anObject.
  944. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  945. self visit: aCollection first.
  946. stream nextPutAll: '() : $receiver'.
  947. inlined := true]].
  948. (aSelector = 'ifNotNil:') ifTrue: [
  949. aCollection first isBlockNode ifTrue: [
  950. stream nextPutAll: '(($receiver = '.
  951. self visit: anObject.
  952. stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
  953. self visit: aCollection first.
  954. stream nextPutAll: '() : nil'.
  955. inlined := true]].
  956. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  957. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  958. stream nextPutAll: '(($receiver = '.
  959. self visit: anObject.
  960. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  961. self visit: aCollection first.
  962. stream nextPutAll: '() : '.
  963. self visit: aCollection second.
  964. stream nextPutAll: '()'.
  965. inlined := true]].
  966. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  967. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  968. stream nextPutAll: '(($receiver = '.
  969. self visit: anObject.
  970. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  971. self visit: aCollection second.
  972. stream nextPutAll: '() : '.
  973. self visit: aCollection first.
  974. stream nextPutAll: '()'.
  975. inlined := true]].
  976. ^inlined
  977. !
  978. isNode: aNode ofClass: aClass
  979. ^aNode isValueNode and: [
  980. aNode value class = aClass or: [
  981. aNode value = 'self' and: [self currentClass = aClass]]]
  982. ! !
  983. !FunCodeGenerator methodsFor: 'testing'!
  984. performOptimizations
  985. ^self class performOptimizations
  986. ! !
  987. !FunCodeGenerator methodsFor: 'visiting'!
  988. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  989. ^String streamContents: [:str || tmp |
  990. tmp := stream.
  991. str nextPutAll: 'smalltalk.send('.
  992. str nextPutAll: aReceiver.
  993. str nextPutAll: ', "', aSelector asSelector, '", ['.
  994. stream := str.
  995. aCollection
  996. do: [:each | self visit: each]
  997. separatedBy: [stream nextPutAll: ', '].
  998. stream := tmp.
  999. str nextPutAll: ']'.
  1000. aBoolean ifTrue: [
  1001. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass), '.superclass || nil'].
  1002. str nextPutAll: ')']
  1003. !
  1004. visit: aNode
  1005. aNode accept: self
  1006. !
  1007. visitAssignmentNode: aNode
  1008. stream nextPutAll: '('.
  1009. self visit: aNode left.
  1010. stream nextPutAll: '='.
  1011. self visit: aNode right.
  1012. stream nextPutAll: ')'
  1013. !
  1014. visitBlockNode: aNode
  1015. stream nextPutAll: '(function('.
  1016. aNode parameters
  1017. do: [:each |
  1018. tempVariables add: each.
  1019. stream nextPutAll: each]
  1020. separatedBy: [stream nextPutAll: ', '].
  1021. stream nextPutAll: '){'.
  1022. aNode nodes do: [:each | self visit: each].
  1023. stream nextPutAll: '})'
  1024. !
  1025. visitBlockSequenceNode: aNode
  1026. | index |
  1027. nestedBlocks := nestedBlocks + 1.
  1028. aNode nodes isEmpty
  1029. ifTrue: [
  1030. stream nextPutAll: 'return nil;']
  1031. ifFalse: [
  1032. aNode temps do: [:each | | temp |
  1033. temp := self safeVariableNameFor: each.
  1034. tempVariables add: temp.
  1035. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  1036. index := 0.
  1037. aNode nodes do: [:each |
  1038. index := index + 1.
  1039. index = aNode nodes size ifTrue: [
  1040. stream nextPutAll: 'return '].
  1041. self visit: each.
  1042. stream nextPutAll: ';']].
  1043. nestedBlocks := nestedBlocks - 1
  1044. !
  1045. visitCascadeNode: aNode
  1046. | index |
  1047. index := 0.
  1048. (tempVariables includes: '$rec') ifFalse: [
  1049. tempVariables add: '$rec'].
  1050. stream nextPutAll: '(function($rec){'.
  1051. aNode nodes do: [:each |
  1052. index := index + 1.
  1053. index = aNode nodes size ifTrue: [
  1054. stream nextPutAll: 'return '].
  1055. each receiver: (VariableNode new value: '$rec').
  1056. self visit: each.
  1057. stream nextPutAll: ';'].
  1058. stream nextPutAll: '})('.
  1059. self visit: aNode receiver.
  1060. stream nextPutAll: ')'
  1061. !
  1062. visitClassReferenceNode: aNode
  1063. (referencedClasses includes: aNode value) ifFalse: [
  1064. referencedClasses add: aNode value].
  1065. stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
  1066. !
  1067. visitDynamicArrayNode: aNode
  1068. stream nextPutAll: '['.
  1069. aNode nodes
  1070. do: [:each | self visit: each]
  1071. separatedBy: [stream nextPutAll: ','].
  1072. stream nextPutAll: ']'
  1073. !
  1074. visitDynamicDictionaryNode: aNode
  1075. stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.
  1076. aNode nodes
  1077. do: [:each | self visit: each]
  1078. separatedBy: [stream nextPutAll: ','].
  1079. stream nextPutAll: '])'
  1080. !
  1081. visitFailure: aFailure
  1082. self error: aFailure asString
  1083. !
  1084. visitJSStatementNode: aNode
  1085. stream nextPutAll: aNode source
  1086. !
  1087. visitMethodNode: aNode
  1088. | str currentSelector |
  1089. currentSelector := aNode selector asSelector.
  1090. nestedBlocks := 0.
  1091. earlyReturn := false.
  1092. messageSends := #().
  1093. referencedClasses := #().
  1094. unknownVariables := #().
  1095. tempVariables := #().
  1096. argVariables := #().
  1097. stream
  1098. nextPutAll: 'smalltalk.method({'; lf;
  1099. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  1100. stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
  1101. stream nextPutAll: 'fn: function('.
  1102. aNode arguments
  1103. do: [:each |
  1104. argVariables add: each.
  1105. stream nextPutAll: each]
  1106. separatedBy: [stream nextPutAll: ', '].
  1107. stream
  1108. nextPutAll: '){'; lf;
  1109. nextPutAll: 'var self=this;'; lf.
  1110. str := stream.
  1111. stream := '' writeStream.
  1112. aNode nodes do: [:each |
  1113. self visit: each].
  1114. earlyReturn ifTrue: [
  1115. str nextPutAll: 'var $early={};'; lf; nextPutAll: 'try{'].
  1116. str nextPutAll: stream contents.
  1117. stream := str.
  1118. stream
  1119. lf;
  1120. nextPutAll: 'return self;'.
  1121. earlyReturn ifTrue: [
  1122. stream lf; nextPutAll: '} catch(e) {if(e===$early)return e[0]; throw e}'].
  1123. stream nextPutAll: '}'.
  1124. stream
  1125. nextPutAll: ',', String lf, 'messageSends: ';
  1126. nextPutAll: messageSends asJavascript, ','; lf;
  1127. nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
  1128. nextPutAll: 'referencedClasses: ['.
  1129. referencedClasses
  1130. do: [:each | stream nextPutAll: each printString]
  1131. separatedBy: [stream nextPutAll: ','].
  1132. stream nextPutAll: ']'.
  1133. stream nextPutAll: '})'
  1134. !
  1135. visitReturnNode: aNode
  1136. nestedBlocks > 0 ifTrue: [
  1137. earlyReturn := true].
  1138. nestedBlocks > 0
  1139. ifTrue: [
  1140. stream
  1141. nextPutAll: '(function(){throw $early=[']
  1142. ifFalse: [stream nextPutAll: 'return '].
  1143. aNode nodes do: [:each |
  1144. self visit: each].
  1145. nestedBlocks > 0 ifTrue: [
  1146. stream nextPutAll: ']})()']
  1147. !
  1148. visitSendNode: aNode
  1149. | str receiver superSend inlined |
  1150. str := stream.
  1151. (messageSends includes: aNode selector) ifFalse: [
  1152. messageSends add: aNode selector].
  1153. stream := '' writeStream.
  1154. self visit: aNode receiver.
  1155. superSend := stream contents = 'super'.
  1156. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  1157. stream := str.
  1158. self performOptimizations
  1159. ifTrue: [
  1160. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
  1161. (self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
  1162. ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
  1163. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
  1164. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
  1165. !
  1166. visitSequenceNode: aNode
  1167. aNode temps do: [:each || temp |
  1168. temp := self safeVariableNameFor: each.
  1169. tempVariables add: temp.
  1170. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  1171. aNode nodes do: [:each |
  1172. self visit: each.
  1173. stream nextPutAll: ';']
  1174. separatedBy: [stream lf]
  1175. !
  1176. visitValueNode: aNode
  1177. stream nextPutAll: aNode value asJavascript
  1178. !
  1179. visitVariableNode: aNode
  1180. | varName |
  1181. (self currentClass allInstanceVariableNames includes: aNode value)
  1182. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  1183. ifFalse: [
  1184. varName := self safeVariableNameFor: aNode value.
  1185. (self knownVariables includes: varName)
  1186. ifFalse: [
  1187. unknownVariables add: aNode value.
  1188. aNode assigned
  1189. ifTrue: [stream nextPutAll: varName]
  1190. ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
  1191. ifTrue: [
  1192. aNode value = 'thisContext'
  1193. ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
  1194. ifFalse: [stream nextPutAll: varName]]]
  1195. ! !
  1196. FunCodeGenerator class instanceVariableNames: 'performOptimizations'!
  1197. !FunCodeGenerator class methodsFor: 'accessing'!
  1198. performOptimizations
  1199. ^performOptimizations ifNil: [true]
  1200. !
  1201. performOptimizations: aBoolean
  1202. performOptimizations := aBoolean
  1203. ! !