Compiler-Core.st 22 KB

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