Compiler-Core.st 23 KB

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