Compiler-Core.st 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. Smalltalk current createPackage: 'Compiler-Core' properties: #{}!
  2. Object subclass: #Compiler
  3. instanceVariableNames: 'currentClass source unknownVariables codeGeneratorClass'
  4. package: 'Compiler-Core'!
  5. !Compiler methodsFor: 'accessing'!
  6. codeGeneratorClass
  7. ^codeGeneratorClass ifNil: [FunCodeGenerator]
  8. !
  9. codeGeneratorClass: aClass
  10. codeGeneratorClass := aClass
  11. !
  12. currentClass
  13. ^currentClass
  14. !
  15. currentClass: aClass
  16. currentClass := aClass
  17. !
  18. source
  19. ^source ifNil: ['']
  20. !
  21. source: aString
  22. source := aString
  23. !
  24. unknownVariables
  25. ^unknownVariables
  26. !
  27. unknownVariables: aCollection
  28. unknownVariables := aCollection
  29. ! !
  30. !Compiler methodsFor: 'compiling'!
  31. compile: aString
  32. ^self compileNode: (self parse: aString)
  33. !
  34. compile: aString forClass: aClass
  35. self currentClass: aClass.
  36. self source: aString.
  37. ^self compile: aString
  38. !
  39. compileExpression: aString
  40. self currentClass: DoIt.
  41. self source: 'doIt ^[', aString, '] value'.
  42. ^self compileNode: (self parse: self source)
  43. !
  44. compileNode: aNode
  45. | generator result |
  46. generator := self codeGeneratorClass new.
  47. generator
  48. source: self source;
  49. currentClass: self currentClass.
  50. result := generator compileNode: aNode.
  51. self unknownVariables: #().
  52. ^result
  53. !
  54. eval: aString
  55. <return eval(aString)>
  56. !
  57. evaluateExpression: aString
  58. "Unlike #eval: evaluate a Smalltalk expression and answer the returned object"
  59. | result |
  60. DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
  61. result := DoIt new doIt.
  62. DoIt removeCompiledMethod: (DoIt methodDictionary at: 'doIt').
  63. ^result
  64. !
  65. install: aString forClass: aBehavior category: anotherString
  66. | compiled |
  67. compiled := self eval: (self compile: aString forClass: aBehavior).
  68. compiled category: anotherString.
  69. aBehavior addCompiledMethod: compiled.
  70. ^compiled
  71. !
  72. parse: aString
  73. ^Smalltalk current parse: aString
  74. !
  75. parseExpression: aString
  76. ^self parse: 'doIt ^[', aString, '] value'
  77. !
  78. recompile: aClass
  79. aClass methodDictionary do: [:each |
  80. self install: each source forClass: aClass category: each category].
  81. self setupClass: aClass.
  82. aClass isMetaclass ifFalse: [self recompile: aClass class]
  83. !
  84. recompileAll
  85. Smalltalk current classes do: [:each |
  86. Transcript show: each; cr.
  87. [self recompile: each] valueWithTimeout: 100]
  88. !
  89. setupClass: aClass
  90. <smalltalk.init(aClass)>
  91. ! !
  92. !Compiler class methodsFor: 'compiling'!
  93. recompile: aClass
  94. self new recompile: aClass
  95. !
  96. recompileAll
  97. Smalltalk current classes do: [:each |
  98. self recompile: each]
  99. ! !
  100. Object subclass: #DoIt
  101. instanceVariableNames: ''
  102. package: 'Compiler-Core'!
  103. Object subclass: #NodeVisitor
  104. instanceVariableNames: ''
  105. package: 'Compiler-Core'!
  106. !NodeVisitor methodsFor: 'visiting'!
  107. visit: aNode
  108. aNode accept: self
  109. !
  110. visitAll: aCollection
  111. aCollection do: [ :each | self visit: each ]
  112. !
  113. visitAssignmentNode: aNode
  114. self visitNode: aNode
  115. !
  116. visitBlockNode: aNode
  117. self visitNode: aNode
  118. !
  119. visitBlockSequenceNode: aNode
  120. self visitSequenceNode: aNode
  121. !
  122. visitCascadeNode: aNode
  123. self visitNode: aNode
  124. !
  125. visitClassReferenceNode: aNode
  126. self visitNode: aNode
  127. !
  128. visitDynamicArrayNode: aNode
  129. self visitNode: aNode
  130. !
  131. visitDynamicDictionaryNode: aNode
  132. self visitNode: aNode
  133. !
  134. visitJSStatementNode: aNode
  135. self visitNode: aNode
  136. !
  137. visitMethodNode: aNode
  138. self visitNode: aNode
  139. !
  140. visitNode: aNode
  141. aNode nodes do: [ :each | self visit: each ]
  142. !
  143. visitReturnNode: aNode
  144. self visitNode: aNode
  145. !
  146. visitSendNode: aNode
  147. self visitNode: aNode
  148. !
  149. visitSequenceNode: aNode
  150. self visitNode: aNode
  151. !
  152. visitValueNode: aNode
  153. self visitNode: aNode
  154. !
  155. visitVariableNode: aNode
  156. self visitNode: aNode
  157. ! !
  158. NodeVisitor subclass: #AbstractCodeGenerator
  159. instanceVariableNames: 'currentClass source'
  160. package: 'Compiler-Core'!
  161. !AbstractCodeGenerator methodsFor: 'accessing'!
  162. classNameFor: aClass
  163. ^aClass isMetaclass
  164. ifTrue: [aClass instanceClass name, '.klass']
  165. ifFalse: [
  166. aClass isNil
  167. ifTrue: ['nil']
  168. ifFalse: [aClass name]]
  169. !
  170. currentClass
  171. ^currentClass
  172. !
  173. currentClass: aClass
  174. currentClass := aClass
  175. !
  176. pseudoVariables
  177. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  178. !
  179. safeVariableNameFor: aString
  180. ^(Smalltalk current reservedWords includes: aString)
  181. ifTrue: [aString, '_']
  182. ifFalse: [aString]
  183. !
  184. source
  185. ^source ifNil: ['']
  186. !
  187. source: aString
  188. source := aString
  189. ! !
  190. !AbstractCodeGenerator methodsFor: 'compiling'!
  191. compileNode: aNode
  192. self subclassResponsibility
  193. ! !
  194. AbstractCodeGenerator subclass: #CodeGenerator
  195. instanceVariableNames: ''
  196. package: 'Compiler-Core'!
  197. !CodeGenerator methodsFor: 'compiling'!
  198. compileNode: aNode
  199. | ir stream |
  200. self semanticAnalyzer visit: aNode.
  201. ir := self translator visit: aNode; builder.
  202. stream := JSStream new.
  203. ir emitOn: stream.
  204. ^ stream contents
  205. !
  206. semanticAnalyzer
  207. ^ SemanticAnalyzer on: self currentClass
  208. !
  209. translator
  210. ^ IRASTResolver new
  211. source: self source;
  212. yourself
  213. ! !
  214. AbstractCodeGenerator subclass: #FunCodeGenerator
  215. instanceVariableNames: 'stream nestedBlocks earlyReturn currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced argVariables'
  216. package: 'Compiler-Core'!
  217. !FunCodeGenerator methodsFor: 'accessing'!
  218. argVariables
  219. ^argVariables copy
  220. !
  221. knownVariables
  222. ^self pseudoVariables
  223. addAll: self tempVariables;
  224. addAll: self argVariables;
  225. yourself
  226. !
  227. tempVariables
  228. ^tempVariables copy
  229. !
  230. unknownVariables
  231. ^unknownVariables copy
  232. ! !
  233. !FunCodeGenerator methodsFor: 'compiling'!
  234. compileNode: aNode
  235. stream := '' writeStream.
  236. self visit: aNode.
  237. ^stream contents
  238. ! !
  239. !FunCodeGenerator methodsFor: 'initialization'!
  240. initialize
  241. super initialize.
  242. stream := '' writeStream.
  243. unknownVariables := #().
  244. tempVariables := #().
  245. argVariables := #().
  246. messageSends := #().
  247. classReferenced := #()
  248. ! !
  249. !FunCodeGenerator methodsFor: 'optimizations'!
  250. checkClass: aClassName for: receiver
  251. stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
  252. !
  253. inline: aSelector receiver: receiver argumentNodes: aCollection
  254. | inlined |
  255. inlined := false.
  256. "-- Booleans --"
  257. (aSelector = 'ifFalse:') ifTrue: [
  258. aCollection first isBlockNode ifTrue: [
  259. self checkClass: 'Boolean' for: receiver.
  260. stream nextPutAll: '(!! $receiver ? '.
  261. self visit: aCollection first.
  262. stream nextPutAll: '() : nil)'.
  263. inlined := true]].
  264. (aSelector = 'ifTrue:') ifTrue: [
  265. aCollection first isBlockNode ifTrue: [
  266. self checkClass: 'Boolean' for: receiver.
  267. stream nextPutAll: '($receiver ? '.
  268. self visit: aCollection first.
  269. stream nextPutAll: '() : nil)'.
  270. inlined := true]].
  271. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  272. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  273. self checkClass: 'Boolean' for: receiver.
  274. stream nextPutAll: '($receiver ? '.
  275. self visit: aCollection first.
  276. stream nextPutAll: '() : '.
  277. self visit: aCollection second.
  278. stream nextPutAll: '())'.
  279. inlined := true]].
  280. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  281. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  282. self checkClass: 'Boolean' for: receiver.
  283. stream nextPutAll: '(!! $receiver ? '.
  284. self visit: aCollection first.
  285. stream nextPutAll: '() : '.
  286. self visit: aCollection second.
  287. stream nextPutAll: '())'.
  288. inlined := true]].
  289. "-- Numbers --"
  290. (aSelector = '<') ifTrue: [
  291. self checkClass: 'Number' for: receiver.
  292. stream nextPutAll: '$receiver <'.
  293. self visit: aCollection first.
  294. inlined := true].
  295. (aSelector = '<=') ifTrue: [
  296. self checkClass: 'Number' for: receiver.
  297. stream nextPutAll: '$receiver <='.
  298. self visit: aCollection first.
  299. inlined := true].
  300. (aSelector = '>') ifTrue: [
  301. self checkClass: 'Number' for: receiver.
  302. stream nextPutAll: '$receiver >'.
  303. self visit: aCollection first.
  304. inlined := true].
  305. (aSelector = '>=') ifTrue: [
  306. self checkClass: 'Number' for: receiver.
  307. stream nextPutAll: '$receiver >='.
  308. self visit: aCollection first.
  309. inlined := true].
  310. (aSelector = '+') ifTrue: [
  311. self checkClass: 'Number' for: receiver.
  312. stream nextPutAll: '$receiver +'.
  313. self visit: aCollection first.
  314. inlined := true].
  315. (aSelector = '-') ifTrue: [
  316. self checkClass: 'Number' for: receiver.
  317. stream nextPutAll: '$receiver -'.
  318. self visit: aCollection first.
  319. inlined := true].
  320. (aSelector = '*') ifTrue: [
  321. self checkClass: 'Number' for: receiver.
  322. stream nextPutAll: '$receiver *'.
  323. self visit: aCollection first.
  324. inlined := true].
  325. (aSelector = '/') ifTrue: [
  326. self checkClass: 'Number' for: receiver.
  327. stream nextPutAll: '$receiver /'.
  328. self visit: aCollection first.
  329. inlined := true].
  330. ^inlined
  331. !
  332. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  333. | inlined |
  334. inlined := false.
  335. "-- BlockClosures --"
  336. (aSelector = 'whileTrue:') ifTrue: [
  337. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  338. stream nextPutAll: '(function(){while('.
  339. self visit: anObject.
  340. stream nextPutAll: '()) {'.
  341. self visit: aCollection first.
  342. stream nextPutAll: '()}})()'.
  343. inlined := true]].
  344. (aSelector = 'whileFalse:') ifTrue: [
  345. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  346. stream nextPutAll: '(function(){while(!!'.
  347. self visit: anObject.
  348. stream nextPutAll: '()) {'.
  349. self visit: aCollection first.
  350. stream nextPutAll: '()}})()'.
  351. inlined := true]].
  352. (aSelector = 'whileTrue') ifTrue: [
  353. anObject isBlockNode ifTrue: [
  354. stream nextPutAll: '(function(){while('.
  355. self visit: anObject.
  356. stream nextPutAll: '()) {}})()'.
  357. inlined := true]].
  358. (aSelector = 'whileFalse') ifTrue: [
  359. anObject isBlockNode ifTrue: [
  360. stream nextPutAll: '(function(){while(!!'.
  361. self visit: anObject.
  362. stream nextPutAll: '()) {}})()'.
  363. inlined := true]].
  364. "-- Numbers --"
  365. (aSelector = '+') ifTrue: [
  366. (self isNode: anObject ofClass: Number) ifTrue: [
  367. self visit: anObject.
  368. stream nextPutAll: ' + '.
  369. self visit: aCollection first.
  370. inlined := true]].
  371. (aSelector = '-') ifTrue: [
  372. (self isNode: anObject ofClass: Number) ifTrue: [
  373. self visit: anObject.
  374. stream nextPutAll: ' - '.
  375. self visit: aCollection first.
  376. inlined := true]].
  377. (aSelector = '*') ifTrue: [
  378. (self isNode: anObject ofClass: Number) ifTrue: [
  379. self visit: anObject.
  380. stream nextPutAll: ' * '.
  381. self visit: aCollection first.
  382. inlined := true]].
  383. (aSelector = '/') ifTrue: [
  384. (self isNode: anObject ofClass: Number) ifTrue: [
  385. self visit: anObject.
  386. stream nextPutAll: ' / '.
  387. self visit: aCollection first.
  388. inlined := true]].
  389. (aSelector = '<') ifTrue: [
  390. (self isNode: anObject ofClass: Number) ifTrue: [
  391. self visit: anObject.
  392. stream nextPutAll: ' < '.
  393. self visit: aCollection first.
  394. inlined := true]].
  395. (aSelector = '<=') ifTrue: [
  396. (self isNode: anObject ofClass: Number) ifTrue: [
  397. self visit: anObject.
  398. stream nextPutAll: ' <= '.
  399. self visit: aCollection first.
  400. inlined := true]].
  401. (aSelector = '>') ifTrue: [
  402. (self isNode: anObject ofClass: Number) ifTrue: [
  403. self visit: anObject.
  404. stream nextPutAll: ' > '.
  405. self visit: aCollection first.
  406. inlined := true]].
  407. (aSelector = '>=') ifTrue: [
  408. (self isNode: anObject ofClass: Number) ifTrue: [
  409. self visit: anObject.
  410. stream nextPutAll: ' >= '.
  411. self visit: aCollection first.
  412. inlined := true]].
  413. "-- UndefinedObject --"
  414. (aSelector = 'ifNil:') ifTrue: [
  415. aCollection first isBlockNode ifTrue: [
  416. stream nextPutAll: '(($receiver = '.
  417. self visit: anObject.
  418. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  419. self visit: aCollection first.
  420. stream nextPutAll: '() : $receiver'.
  421. inlined := true]].
  422. (aSelector = 'ifNotNil:') ifTrue: [
  423. aCollection first isBlockNode ifTrue: [
  424. stream nextPutAll: '(($receiver = '.
  425. self visit: anObject.
  426. stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
  427. self visit: aCollection first.
  428. stream nextPutAll: '() : nil'.
  429. inlined := true]].
  430. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  431. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  432. stream nextPutAll: '(($receiver = '.
  433. self visit: anObject.
  434. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  435. self visit: aCollection first.
  436. stream nextPutAll: '() : '.
  437. self visit: aCollection second.
  438. stream nextPutAll: '()'.
  439. inlined := true]].
  440. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  441. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  442. stream nextPutAll: '(($receiver = '.
  443. self visit: anObject.
  444. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  445. self visit: aCollection second.
  446. stream nextPutAll: '() : '.
  447. self visit: aCollection first.
  448. stream nextPutAll: '()'.
  449. inlined := true]].
  450. ^inlined
  451. !
  452. isNode: aNode ofClass: aClass
  453. ^aNode isValueNode and: [
  454. aNode value class = aClass or: [
  455. aNode value = 'self' and: [self currentClass = aClass]]]
  456. ! !
  457. !FunCodeGenerator methodsFor: 'testing'!
  458. performOptimizations
  459. ^self class performOptimizations
  460. ! !
  461. !FunCodeGenerator methodsFor: 'visiting'!
  462. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  463. ^String streamContents: [:str || tmp |
  464. tmp := stream.
  465. str nextPutAll: 'smalltalk.send('.
  466. str nextPutAll: aReceiver.
  467. str nextPutAll: ', "', aSelector asSelector, '", ['.
  468. stream := str.
  469. aCollection
  470. do: [:each | self visit: each]
  471. separatedBy: [stream nextPutAll: ', '].
  472. stream := tmp.
  473. str nextPutAll: ']'.
  474. aBoolean ifTrue: [
  475. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass), '.superclass || nil'].
  476. str nextPutAll: ')']
  477. !
  478. visit: aNode
  479. aNode accept: self
  480. !
  481. visitAssignmentNode: aNode
  482. stream nextPutAll: '('.
  483. self visit: aNode left.
  484. stream nextPutAll: '='.
  485. self visit: aNode right.
  486. stream nextPutAll: ')'
  487. !
  488. visitBlockNode: aNode
  489. stream nextPutAll: '(function('.
  490. aNode parameters
  491. do: [:each |
  492. tempVariables add: each.
  493. stream nextPutAll: each]
  494. separatedBy: [stream nextPutAll: ', '].
  495. stream nextPutAll: '){'.
  496. aNode nodes do: [:each | self visit: each].
  497. stream nextPutAll: '})'
  498. !
  499. visitBlockSequenceNode: aNode
  500. | index |
  501. nestedBlocks := nestedBlocks + 1.
  502. aNode nodes isEmpty
  503. ifTrue: [
  504. stream nextPutAll: 'return nil;']
  505. ifFalse: [
  506. aNode temps do: [:each | | temp |
  507. temp := self safeVariableNameFor: each.
  508. tempVariables add: temp.
  509. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  510. index := 0.
  511. aNode nodes do: [:each |
  512. index := index + 1.
  513. index = aNode nodes size ifTrue: [
  514. stream nextPutAll: 'return '].
  515. self visit: each.
  516. stream nextPutAll: ';']].
  517. nestedBlocks := nestedBlocks - 1
  518. !
  519. visitCascadeNode: aNode
  520. | index |
  521. index := 0.
  522. (tempVariables includes: '$rec') ifFalse: [
  523. tempVariables add: '$rec'].
  524. stream nextPutAll: '(function($rec){'.
  525. aNode nodes do: [:each |
  526. index := index + 1.
  527. index = aNode nodes size ifTrue: [
  528. stream nextPutAll: 'return '].
  529. each receiver: (VariableNode new value: '$rec').
  530. self visit: each.
  531. stream nextPutAll: ';'].
  532. stream nextPutAll: '})('.
  533. self visit: aNode receiver.
  534. stream nextPutAll: ')'
  535. !
  536. visitClassReferenceNode: aNode
  537. (referencedClasses includes: aNode value) ifFalse: [
  538. referencedClasses add: aNode value].
  539. stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
  540. !
  541. visitDynamicArrayNode: aNode
  542. stream nextPutAll: '['.
  543. aNode nodes
  544. do: [:each | self visit: each]
  545. separatedBy: [stream nextPutAll: ','].
  546. stream nextPutAll: ']'
  547. !
  548. visitDynamicDictionaryNode: aNode
  549. stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.
  550. aNode nodes
  551. do: [:each | self visit: each]
  552. separatedBy: [stream nextPutAll: ','].
  553. stream nextPutAll: '])'
  554. !
  555. visitFailure: aFailure
  556. self error: aFailure asString
  557. !
  558. visitJSStatementNode: aNode
  559. stream nextPutAll: aNode source
  560. !
  561. visitMethodNode: aNode
  562. | str currentSelector |
  563. currentSelector := aNode selector asSelector.
  564. nestedBlocks := 0.
  565. earlyReturn := false.
  566. messageSends := #().
  567. referencedClasses := #().
  568. unknownVariables := #().
  569. tempVariables := #().
  570. argVariables := #().
  571. stream
  572. nextPutAll: 'smalltalk.method({'; lf;
  573. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  574. stream nextPutAll: 'source: ', self source asJavascript, ',';lf.
  575. stream nextPutAll: 'fn: function('.
  576. aNode arguments
  577. do: [:each |
  578. argVariables add: each.
  579. stream nextPutAll: each]
  580. separatedBy: [stream nextPutAll: ', '].
  581. stream
  582. nextPutAll: '){'; lf;
  583. nextPutAll: 'var self=this;'; lf.
  584. str := stream.
  585. stream := '' writeStream.
  586. aNode nodes do: [:each |
  587. self visit: each].
  588. earlyReturn ifTrue: [
  589. str nextPutAll: 'var $early={};'; lf; nextPutAll: 'try{'].
  590. str nextPutAll: stream contents.
  591. stream := str.
  592. stream
  593. lf;
  594. nextPutAll: 'return self;'.
  595. earlyReturn ifTrue: [
  596. stream lf; nextPutAll: '} catch(e) {if(e===$early)return e[0]; throw e}'].
  597. stream nextPutAll: '}'.
  598. stream
  599. nextPutAll: ',', String lf, 'messageSends: ';
  600. nextPutAll: messageSends asJavascript, ','; lf;
  601. nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
  602. nextPutAll: 'referencedClasses: ['.
  603. referencedClasses
  604. do: [:each | stream nextPutAll: each printString]
  605. separatedBy: [stream nextPutAll: ','].
  606. stream nextPutAll: ']'.
  607. stream nextPutAll: '})'
  608. !
  609. visitReturnNode: aNode
  610. nestedBlocks > 0 ifTrue: [
  611. earlyReturn := true].
  612. nestedBlocks > 0
  613. ifTrue: [
  614. stream
  615. nextPutAll: '(function(){throw $early=[']
  616. ifFalse: [stream nextPutAll: 'return '].
  617. aNode nodes do: [:each |
  618. self visit: each].
  619. nestedBlocks > 0 ifTrue: [
  620. stream nextPutAll: ']})()']
  621. !
  622. visitSendNode: aNode
  623. | str receiver superSend inlined |
  624. str := stream.
  625. (messageSends includes: aNode selector) ifFalse: [
  626. messageSends add: aNode selector].
  627. stream := '' writeStream.
  628. self visit: aNode receiver.
  629. superSend := stream contents = 'super'.
  630. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  631. stream := str.
  632. self performOptimizations
  633. ifTrue: [
  634. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
  635. (self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
  636. ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
  637. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
  638. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
  639. !
  640. visitSequenceNode: aNode
  641. aNode temps do: [:each || temp |
  642. temp := self safeVariableNameFor: each.
  643. tempVariables add: temp.
  644. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  645. aNode nodes do: [:each |
  646. self visit: each.
  647. stream nextPutAll: ';']
  648. separatedBy: [stream lf]
  649. !
  650. visitValueNode: aNode
  651. stream nextPutAll: aNode value asJavascript
  652. !
  653. visitVariableNode: aNode
  654. | varName |
  655. (self currentClass allInstanceVariableNames includes: aNode value)
  656. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  657. ifFalse: [
  658. varName := self safeVariableNameFor: aNode value.
  659. (self knownVariables includes: varName)
  660. ifFalse: [
  661. unknownVariables add: aNode value.
  662. aNode assigned
  663. ifTrue: [stream nextPutAll: varName]
  664. ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
  665. ifTrue: [
  666. aNode value = 'thisContext'
  667. ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
  668. ifFalse: [stream nextPutAll: varName]]]
  669. ! !
  670. FunCodeGenerator class instanceVariableNames: 'performOptimizations'!
  671. !FunCodeGenerator class methodsFor: 'accessing'!
  672. performOptimizations
  673. ^performOptimizations ifNil: [true]
  674. !
  675. performOptimizations: aBoolean
  676. performOptimizations := aBoolean
  677. ! !