Compiler-Core.st 23 KB

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