Compiler.st 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385
  1. Object subclass: #ChunkParser
  2. instanceVariableNames: 'stream'
  3. category: 'Compiler'!
  4. !ChunkParser methodsFor: 'accessing'!
  5. stream: aStream
  6. stream := aStream
  7. ! !
  8. !ChunkParser methodsFor: 'reading'!
  9. nextChunk
  10. "The chunk format (Smalltalk Interchange Format or Fileout format)
  11. is a trivial format but can be a bit tricky to understand:
  12. - Uses the exclamation mark as delimiter of chunks.
  13. - Inside a chunk a normal exclamation mark must be doubled.
  14. - A non empty chunk must be a valid Smalltalk expression.
  15. - A chunk on top level with a preceding empty chunk is an instruction chunk:
  16. - The object created by the expression then takes over reading chunks.
  17. This metod returns next chunk as a String (trimmed), empty String (all whitespace) or nil."
  18. | char result chunk |
  19. result := '' writeStream.
  20. [char := stream next.
  21. char notNil] whileTrue: [
  22. char = '!!' ifTrue: [
  23. stream peek = '!!'
  24. ifTrue: [stream next "skipping the escape double"]
  25. ifFalse: [^result contents trimBoth "chunk end marker found"]].
  26. result nextPut: char].
  27. ^nil "a chunk needs to end with !!"
  28. ! !
  29. !ChunkParser class methodsFor: 'not yet classified'!
  30. on: aStream
  31. ^self new stream: aStream
  32. ! !
  33. Object subclass: #Importer
  34. instanceVariableNames: ''
  35. category: 'Compiler'!
  36. !Importer methodsFor: 'fileIn'!
  37. import: aStream
  38. | chunk result parser lastEmpty |
  39. parser := ChunkParser on: aStream.
  40. lastEmpty := false.
  41. [chunk := parser nextChunk.
  42. chunk isNil] whileFalse: [
  43. chunk isEmpty
  44. ifTrue: [lastEmpty := true]
  45. ifFalse: [
  46. result := Compiler new loadExpression: chunk.
  47. lastEmpty
  48. ifTrue: [
  49. lastEmpty := false.
  50. result scanFrom: parser]]]
  51. ! !
  52. Object subclass: #Exporter
  53. instanceVariableNames: ''
  54. category: 'Compiler'!
  55. !Exporter methodsFor: 'fileOut'!
  56. exportCategory: aString
  57. | stream |
  58. stream := '' writeStream.
  59. (Smalltalk current classes
  60. select: [:each | each category = aString])
  61. do: [:each | stream nextPutAll: (self export: each)].
  62. self exportCategoryExtensions: aString on: stream.
  63. ^stream contents
  64. !
  65. export: aClass
  66. | stream |
  67. stream := '' writeStream.
  68. self exportDefinitionOf: aClass on: stream.
  69. self exportMethodsOf: aClass on: stream.
  70. self exportMetaDefinitionOf: aClass on: stream.
  71. self exportMethodsOf: aClass class on: stream.
  72. ^stream contents
  73. ! !
  74. !Exporter methodsFor: 'private'!
  75. exportDefinitionOf: aClass on: aStream
  76. aStream
  77. nextPutAll: 'smalltalk.addClass(';
  78. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  79. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  80. nextPutAll: ', ['.
  81. aClass instanceVariableNames
  82. do: [:each | aStream nextPutAll: '''', each, '''']
  83. separatedBy: [aStream nextPutAll: ', '].
  84. aStream
  85. nextPutAll: '], ''';
  86. nextPutAll: aClass category, '''';
  87. nextPutAll: ');'.
  88. aClass comment notEmpty ifTrue: [
  89. aStream
  90. lf;
  91. nextPutAll: 'smalltalk.';
  92. nextPutAll: (self classNameFor: aClass);
  93. nextPutAll: '.comment=';
  94. nextPutAll: 'unescape(''', aClass comment escaped, ''')'].
  95. aStream lf
  96. !
  97. exportMetaDefinitionOf: aClass on: aStream
  98. aClass class instanceVariableNames isEmpty ifFalse: [
  99. aStream
  100. nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
  101. nextPutAll: '.iVarNames = ['.
  102. aClass class instanceVariableNames
  103. do: [:each | aStream nextPutAll: '''', each, '''']
  104. separatedBy: [aStream nextPutAll: ','].
  105. aStream nextPutAll: '];', String lf]
  106. !
  107. exportMethodsOf: aClass on: aStream
  108. aClass methodDictionary values do: [:each |
  109. (each category match: '^\*') ifFalse: [
  110. self exportMethod: each of: aClass on: aStream]].
  111. aStream lf
  112. !
  113. classNameFor: aClass
  114. ^aClass isMetaclass
  115. ifTrue: [aClass instanceClass name, '.klass']
  116. ifFalse: [
  117. aClass isNil
  118. ifTrue: ['nil']
  119. ifFalse: [aClass name]]
  120. !
  121. exportMethod: aMethod of: aClass on: aStream
  122. aStream
  123. nextPutAll: 'smalltalk.addMethod(';lf;
  124. nextPutAll: '''', aMethod selector asSelector, ''',';lf;
  125. nextPutAll: 'smalltalk.method({';lf;
  126. nextPutAll: 'selector: ''', aMethod selector, ''',';lf;
  127. nextPutAll: 'category: ''', aMethod category, ''',';lf;
  128. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  129. nextPutAll: 'source: unescape(''', aMethod source escaped, '''),';lf;
  130. nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
  131. nextPutAll: 'referencedClasses: ['.
  132. aMethod referencedClasses
  133. do: [:each | aStream nextPutAll: 'smalltalk.', (self classNameFor: each)]
  134. separatedBy: [aStream nextPutAll: ','].
  135. aStream
  136. nextPutAll: ']';lf;
  137. nextPutAll: '}),';lf;
  138. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  139. nextPutAll: ');';lf;lf
  140. !
  141. exportCategoryExtensions: aString on: aStream
  142. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  143. each methodDictionary values do: [:method |
  144. method category = ('*', aString) ifTrue: [
  145. self exportMethod: method of: each on: aStream]]]
  146. ! !
  147. Exporter subclass: #ChunkExporter
  148. instanceVariableNames: ''
  149. category: 'Compiler'!
  150. !ChunkExporter methodsFor: 'not yet classified'!
  151. exportDefinitionOf: aClass on: aStream
  152. "Chunk format."
  153. aStream
  154. nextPutAll: (self classNameFor: aClass superclass);
  155. nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
  156. nextPutAll: ' instanceVariableNames: '''.
  157. aClass instanceVariableNames
  158. do: [:each | aStream nextPutAll: each]
  159. separatedBy: [aStream nextPutAll: ' '].
  160. aStream
  161. nextPutAll: ''''; lf;
  162. nextPutAll: ' category: ''', aClass category, '''!!'; lf.
  163. aClass comment notEmpty ifTrue: [
  164. aStream
  165. nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
  166. nextPutAll: (self chunkEscape: aClass comment), '!!';lf].
  167. aStream lf
  168. !
  169. exportMethod: aMethod of: aClass on: aStream
  170. aStream
  171. lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;
  172. nextPutAll: '!!'
  173. !
  174. exportMethodsOf: aClass on: aStream
  175. aClass protocolsDo: [:category :methods |
  176. (category match: '^\*') ifFalse: [
  177. self
  178. exportMethods: methods
  179. category: category
  180. of: aClass
  181. on: aStream]]
  182. !
  183. exportMetaDefinitionOf: aClass on: aStream
  184. aClass class instanceVariableNames isEmpty ifFalse: [
  185. aStream
  186. nextPutAll: (self classNameFor: aClass class);
  187. nextPutAll: ' instanceVariableNames: '''.
  188. aClass class instanceVariableNames
  189. do: [:each | aStream nextPutAll: each]
  190. separatedBy: [aStream nextPutAll: ' '].
  191. aStream
  192. nextPutAll: '''!!'; lf; lf]
  193. !
  194. classNameFor: aClass
  195. ^aClass isMetaclass
  196. ifTrue: [aClass instanceClass name, ' class']
  197. ifFalse: [
  198. aClass isNil
  199. ifTrue: ['nil']
  200. ifFalse: [aClass name]]
  201. !
  202. chunkEscape: aString
  203. "Replace all occurrences of !! with !!!! and trim at both ends."
  204. ^(aString replace: '!!' with: '!!!!') trimBoth
  205. !
  206. exportCategoryExtensions: aString on: aStream
  207. "We need to override this one too since we need to group
  208. all methods in a given protocol under a leading methodsFor: chunk
  209. for that class."
  210. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  211. each protocolsDo: [:category :methods |
  212. category = ('*', aString) ifTrue: [
  213. self exportMethods: methods category: category of: each on: aStream]]]
  214. !
  215. exportMethods: methods category: category of: aClass on: aStream
  216. aStream
  217. nextPutAll: '!!', (self classNameFor: aClass);
  218. nextPutAll: ' methodsFor: ''', category, '''!!'.
  219. methods do: [:each |
  220. self exportMethod: each of: aClass on: aStream].
  221. aStream nextPutAll: ' !!'; lf; lf
  222. ! !
  223. Exporter subclass: #StrippedExporter
  224. instanceVariableNames: ''
  225. category: 'Compiler'!
  226. !StrippedExporter methodsFor: 'private'!
  227. exportDefinitionOf: aClass on: aStream
  228. aStream
  229. nextPutAll: 'smalltalk.addClass(';
  230. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  231. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  232. nextPutAll: ', ['.
  233. aClass instanceVariableNames
  234. do: [:each | aStream nextPutAll: '''', each, '''']
  235. separatedBy: [aStream nextPutAll: ', '].
  236. aStream
  237. nextPutAll: '], ''';
  238. nextPutAll: aClass category, '''';
  239. nextPutAll: ');'.
  240. aStream lf
  241. !
  242. exportMethod: aMethod of: aClass on: aStream
  243. aStream
  244. nextPutAll: 'smalltalk.addMethod(';lf;
  245. nextPutAll: '''', aMethod selector asSelector, ''',';lf;
  246. nextPutAll: 'smalltalk.method({';lf;
  247. nextPutAll: 'selector: ''', aMethod selector, ''',';lf;
  248. nextPutAll: 'fn: ', aMethod fn compiledSource;lf;
  249. nextPutAll: '}),';lf;
  250. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  251. nextPutAll: ');';lf;lf
  252. ! !
  253. Object subclass: #Node
  254. instanceVariableNames: 'nodes'
  255. category: 'Compiler'!
  256. !Node methodsFor: 'accessing'!
  257. nodes
  258. ^nodes ifNil: [nodes := Array new]
  259. !
  260. addNode: aNode
  261. self nodes add: aNode
  262. ! !
  263. !Node methodsFor: 'building'!
  264. nodes: aCollection
  265. nodes := aCollection
  266. ! !
  267. !Node methodsFor: 'testing'!
  268. isValueNode
  269. ^false
  270. !
  271. isBlockNode
  272. ^false
  273. !
  274. isBlockSequenceNode
  275. ^false
  276. ! !
  277. !Node methodsFor: 'visiting'!
  278. accept: aVisitor
  279. aVisitor visitNode: self
  280. ! !
  281. Node subclass: #MethodNode
  282. instanceVariableNames: 'selector arguments source'
  283. category: 'Compiler'!
  284. !MethodNode methodsFor: 'accessing'!
  285. selector
  286. ^selector
  287. !
  288. selector: aString
  289. selector := aString
  290. !
  291. arguments
  292. ^arguments ifNil: [#()]
  293. !
  294. arguments: aCollection
  295. arguments := aCollection
  296. !
  297. source
  298. ^source
  299. !
  300. source: aString
  301. source := aString
  302. ! !
  303. !MethodNode methodsFor: 'visiting'!
  304. accept: aVisitor
  305. aVisitor visitMethodNode: self
  306. ! !
  307. Node subclass: #SendNode
  308. instanceVariableNames: 'selector arguments receiver'
  309. category: 'Compiler'!
  310. !SendNode methodsFor: 'accessing'!
  311. selector
  312. ^selector
  313. !
  314. selector: aString
  315. selector := aString
  316. !
  317. arguments
  318. ^arguments ifNil: [arguments := #()]
  319. !
  320. arguments: aCollection
  321. arguments := aCollection
  322. !
  323. receiver
  324. ^receiver
  325. !
  326. receiver: aNode
  327. receiver := aNode
  328. !
  329. valueForReceiver: anObject
  330. ^SendNode new
  331. receiver: (self receiver
  332. ifNil: [anObject]
  333. ifNotNil: [self receiver valueForReceiver: anObject]);
  334. selector: self selector;
  335. arguments: self arguments;
  336. yourself
  337. !
  338. cascadeNodeWithMessages: aCollection
  339. | first |
  340. first := SendNode new
  341. selector: self selector;
  342. arguments: self arguments;
  343. yourself.
  344. ^CascadeNode new
  345. receiver: self receiver;
  346. nodes: (Array with: first), aCollection;
  347. yourself
  348. ! !
  349. !SendNode methodsFor: 'visiting'!
  350. accept: aVisitor
  351. aVisitor visitSendNode: self
  352. ! !
  353. Node subclass: #CascadeNode
  354. instanceVariableNames: 'receiver'
  355. category: 'Compiler'!
  356. !CascadeNode methodsFor: 'accessing'!
  357. receiver
  358. ^receiver
  359. !
  360. receiver: aNode
  361. receiver := aNode
  362. ! !
  363. !CascadeNode methodsFor: 'visiting'!
  364. accept: aVisitor
  365. aVisitor visitCascadeNode: self
  366. ! !
  367. Node subclass: #AssignmentNode
  368. instanceVariableNames: 'left right'
  369. category: 'Compiler'!
  370. !AssignmentNode methodsFor: 'accessing'!
  371. left
  372. ^left
  373. !
  374. left: aNode
  375. left := aNode.
  376. left assigned: true
  377. !
  378. right
  379. ^right
  380. !
  381. right: aNode
  382. right := aNode
  383. ! !
  384. !AssignmentNode methodsFor: 'visiting'!
  385. accept: aVisitor
  386. aVisitor visitAssignmentNode: self
  387. ! !
  388. Node subclass: #BlockNode
  389. instanceVariableNames: 'parameters inlined'
  390. category: 'Compiler'!
  391. !BlockNode methodsFor: 'accessing'!
  392. parameters
  393. ^parameters ifNil: [parameters := Array new]
  394. !
  395. parameters: aCollection
  396. parameters := aCollection
  397. !
  398. inlined
  399. ^inlined ifNil: [false]
  400. !
  401. inlined: aBoolean
  402. inlined := aBoolean
  403. ! !
  404. !BlockNode methodsFor: 'testing'!
  405. isBlockNode
  406. ^true
  407. ! !
  408. !BlockNode methodsFor: 'visiting'!
  409. accept: aVisitor
  410. aVisitor visitBlockNode: self
  411. ! !
  412. Node subclass: #SequenceNode
  413. instanceVariableNames: 'temps'
  414. category: 'Compiler'!
  415. !SequenceNode methodsFor: 'accessing'!
  416. temps
  417. ^temps ifNil: [#()]
  418. !
  419. temps: aCollection
  420. temps := aCollection
  421. ! !
  422. !SequenceNode methodsFor: 'testing'!
  423. asBlockSequenceNode
  424. ^BlockSequenceNode new
  425. nodes: self nodes;
  426. temps: self temps;
  427. yourself
  428. ! !
  429. !SequenceNode methodsFor: 'visiting'!
  430. accept: aVisitor
  431. aVisitor visitSequenceNode: self
  432. ! !
  433. SequenceNode subclass: #BlockSequenceNode
  434. instanceVariableNames: ''
  435. category: 'Compiler'!
  436. !BlockSequenceNode methodsFor: 'testing'!
  437. isBlockSequenceNode
  438. ^true
  439. ! !
  440. !BlockSequenceNode methodsFor: 'visiting'!
  441. accept: aVisitor
  442. aVisitor visitBlockSequenceNode: self
  443. ! !
  444. Node subclass: #ReturnNode
  445. instanceVariableNames: ''
  446. category: 'Compiler'!
  447. !ReturnNode methodsFor: 'visiting'!
  448. accept: aVisitor
  449. aVisitor visitReturnNode: self
  450. ! !
  451. Node subclass: #ValueNode
  452. instanceVariableNames: 'value'
  453. category: 'Compiler'!
  454. !ValueNode methodsFor: 'accessing'!
  455. value
  456. ^value
  457. !
  458. value: anObject
  459. value := anObject
  460. ! !
  461. !ValueNode methodsFor: 'testing'!
  462. isValueNode
  463. ^true
  464. ! !
  465. !ValueNode methodsFor: 'visiting'!
  466. accept: aVisitor
  467. aVisitor visitValueNode: self
  468. ! !
  469. ValueNode subclass: #VariableNode
  470. instanceVariableNames: 'assigned'
  471. category: 'Compiler'!
  472. !VariableNode methodsFor: 'accessing'!
  473. assigned
  474. ^assigned ifNil: [false]
  475. !
  476. assigned: aBoolean
  477. assigned := aBoolean
  478. ! !
  479. !VariableNode methodsFor: 'visiting'!
  480. accept: aVisitor
  481. aVisitor visitVariableNode: self
  482. ! !
  483. VariableNode subclass: #ClassReferenceNode
  484. instanceVariableNames: ''
  485. category: 'Compiler'!
  486. !ClassReferenceNode methodsFor: 'visiting'!
  487. accept: aVisitor
  488. aVisitor visitClassReferenceNode: self
  489. ! !
  490. Node subclass: #JSStatementNode
  491. instanceVariableNames: 'source'
  492. category: 'Compiler'!
  493. !JSStatementNode methodsFor: 'accessing'!
  494. source
  495. ^source ifNil: ['']
  496. !
  497. source: aString
  498. source := aString
  499. ! !
  500. !JSStatementNode methodsFor: 'visiting'!
  501. accept: aVisitor
  502. aVisitor visitJSStatementNode: self
  503. ! !
  504. Object subclass: #NodeVisitor
  505. instanceVariableNames: ''
  506. category: 'Compiler'!
  507. !NodeVisitor methodsFor: 'visiting'!
  508. visit: aNode
  509. aNode accept: self
  510. !
  511. visitNode: aNode
  512. !
  513. visitMethodNode: aNode
  514. self visitNode: aNode
  515. !
  516. visitSequenceNode: aNode
  517. self visitNode: aNode
  518. !
  519. visitBlockSequenceNode: aNode
  520. self visitSequenceNode: aNode
  521. !
  522. visitBlockNode: aNode
  523. self visitNode: aNode
  524. !
  525. visitReturnNode: aNode
  526. self visitNode: aNode
  527. !
  528. visitSendNode: aNode
  529. self visitNode: aNode
  530. !
  531. visitCascadeNode: aNode
  532. self visitNode: aNode
  533. !
  534. visitValueNode: aNode
  535. self visitNode: aNode
  536. !
  537. visitVariableNode: aNode
  538. !
  539. visitAssignmentNode: aNode
  540. self visitNode: aNode
  541. !
  542. visitClassReferenceNode: aNode
  543. self
  544. nextPutAll: 'smalltalk.';
  545. nextPutAll: aNode value
  546. !
  547. visitJSStatementNode: aNode
  548. self
  549. nextPutAll: 'function(){';
  550. nextPutAll: aNode source;
  551. nextPutAll: '})()'
  552. !
  553. visitDynamicArrayNode: aNode
  554. self visitNode: aNode
  555. !
  556. visitDynamicDictionaryNode: aNode
  557. self visitNode: aNode
  558. ! !
  559. NodeVisitor subclass: #Compiler
  560. instanceVariableNames: 'stream nestedBlocks earlyReturn currentClass currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced source'
  561. category: 'Compiler'!
  562. !Compiler methodsFor: 'accessing'!
  563. parser
  564. ^SmalltalkParser new
  565. !
  566. currentClass
  567. ^currentClass
  568. !
  569. currentClass: aClass
  570. currentClass := aClass
  571. !
  572. unknownVariables
  573. ^unknownVariables copy
  574. !
  575. pseudoVariables
  576. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  577. !
  578. tempVariables
  579. ^tempVariables copy
  580. !
  581. knownVariables
  582. ^self pseudoVariables
  583. addAll: self tempVariables;
  584. yourself
  585. !
  586. classNameFor: aClass
  587. ^aClass isMetaclass
  588. ifTrue: [aClass instanceClass name, '.klass']
  589. ifFalse: [
  590. aClass isNil
  591. ifTrue: ['nil']
  592. ifFalse: [aClass name]]
  593. !
  594. source
  595. ^source ifNil: ['']
  596. !
  597. source: aString
  598. source := aString
  599. ! !
  600. !Compiler methodsFor: 'compiling'!
  601. loadExpression: aString
  602. | result |
  603. DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
  604. result := DoIt new doIt.
  605. DoIt removeCompiledMethod: (DoIt methodDictionary at: #doIt).
  606. ^result
  607. !
  608. load: aString forClass: aClass
  609. | compiled |
  610. compiled := self eval: (self compile: aString forClass: aClass).
  611. self setupClass: aClass.
  612. ^compiled
  613. !
  614. compile: aString forClass: aClass
  615. self currentClass: aClass.
  616. self source: aString.
  617. ^self compile: aString
  618. !
  619. compileExpression: aString
  620. self currentClass: DoIt.
  621. self source: 'doIt ^[', aString, '] value'.
  622. ^self compileNode: (self parse: self source)
  623. !
  624. eval: aString
  625. <return eval(aString)>
  626. !
  627. compile: aString
  628. ^self compileNode: (self parse: aString)
  629. !
  630. compileNode: aNode
  631. stream := '' writeStream.
  632. self visit: aNode.
  633. ^stream contents
  634. !
  635. parse: aString
  636. ^Smalltalk current parse: aString
  637. !
  638. parseExpression: aString
  639. ^self parse: 'doIt ^[', aString, '] value'
  640. !
  641. recompile: aClass
  642. aClass methodDictionary do: [:each || method |
  643. method := self load: each source forClass: aClass.
  644. method category: each category.
  645. aClass addCompiledMethod: method].
  646. aClass isMetaclass ifFalse: [self recompile: aClass class]
  647. !
  648. recompileAll
  649. Smalltalk current classes do: [:each |
  650. Transcript show: each; cr.
  651. [self recompile: each] valueWithTimeout: 100]
  652. !
  653. setupClass: aClass
  654. <smalltalk.init(aClass)>
  655. ! !
  656. !Compiler methodsFor: 'initialization'!
  657. initialize
  658. super initialize.
  659. stream := '' writeStream.
  660. unknownVariables := #().
  661. tempVariables := #().
  662. messageSends := #().
  663. classReferenced := #()
  664. ! !
  665. !Compiler methodsFor: 'optimizations'!
  666. checkClass: aClassName for: receiver
  667. stream nextPutAll: '(($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
  668. !
  669. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  670. | inlined |
  671. inlined := false.
  672. "-- BlockClosures --"
  673. (aSelector = 'whileTrue:') ifTrue: [
  674. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  675. stream nextPutAll: '(function(){while('.
  676. self visit: anObject.
  677. stream nextPutAll: '()) {'.
  678. self visit: aCollection first.
  679. stream nextPutAll: '()}})()'.
  680. inlined := true]].
  681. (aSelector = 'whileFalse:') ifTrue: [
  682. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  683. stream nextPutAll: '(function(){while(!!'.
  684. self visit: anObject.
  685. stream nextPutAll: '()) {'.
  686. self visit: aCollection first.
  687. stream nextPutAll: '()}})()'.
  688. inlined := true]].
  689. (aSelector = 'whileTrue') ifTrue: [
  690. anObject isBlockNode ifTrue: [
  691. stream nextPutAll: '(function(){while('.
  692. self visit: anObject.
  693. stream nextPutAll: '()) {}})()'.
  694. inlined := true]].
  695. (aSelector = 'whileFalse') ifTrue: [
  696. anObject isBlockNode ifTrue: [
  697. stream nextPutAll: '(function(){while(!!'.
  698. self visit: anObject.
  699. stream nextPutAll: '()) {}})()'.
  700. inlined := true]].
  701. "-- Numbers --"
  702. (aSelector = '+') ifTrue: [
  703. (self isNode: anObject ofClass: Number) ifTrue: [
  704. self visit: anObject.
  705. stream nextPutAll: ' + '.
  706. self visit: aCollection first.
  707. inlined := true]].
  708. (aSelector = '-') ifTrue: [
  709. (self isNode: anObject ofClass: Number) ifTrue: [
  710. self visit: anObject.
  711. stream nextPutAll: ' - '.
  712. self visit: aCollection first.
  713. inlined := true]].
  714. (aSelector = '*') ifTrue: [
  715. (self isNode: anObject ofClass: Number) ifTrue: [
  716. self visit: anObject.
  717. stream nextPutAll: ' * '.
  718. self visit: aCollection first.
  719. inlined := true]].
  720. (aSelector = '/') ifTrue: [
  721. (self isNode: anObject ofClass: Number) ifTrue: [
  722. self visit: anObject.
  723. stream nextPutAll: ' / '.
  724. self visit: aCollection first.
  725. inlined := true]].
  726. (aSelector = '<') ifTrue: [
  727. (self isNode: anObject ofClass: Number) ifTrue: [
  728. self visit: anObject.
  729. stream nextPutAll: ' < '.
  730. self visit: aCollection first.
  731. inlined := true]].
  732. (aSelector = '<=') ifTrue: [
  733. (self isNode: anObject ofClass: Number) ifTrue: [
  734. self visit: anObject.
  735. stream nextPutAll: ' <= '.
  736. self visit: aCollection first.
  737. inlined := true]].
  738. (aSelector = '=') ifTrue: [
  739. (self isNode: anObject ofClass: Number) ifTrue: [
  740. self visit: anObject.
  741. stream nextPutAll: ' == '.
  742. self visit: aCollection first.
  743. inlined := true]].
  744. (aSelector = '>') ifTrue: [
  745. (self isNode: anObject ofClass: Number) ifTrue: [
  746. self visit: anObject.
  747. stream nextPutAll: ' > '.
  748. self visit: aCollection first.
  749. inlined := true]].
  750. (aSelector = '>=') ifTrue: [
  751. (self isNode: anObject ofClass: Number) ifTrue: [
  752. self visit: anObject.
  753. stream nextPutAll: ' >= '.
  754. self visit: aCollection first.
  755. inlined := true]].
  756. "-- UndefinedObject --"
  757. (aSelector = 'ifNil:') ifTrue: [
  758. aCollection first isBlockNode ifTrue: [
  759. stream nextPutAll: '(($receiver = '.
  760. self visit: anObject.
  761. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  762. self visit: aCollection first.
  763. stream nextPutAll: '() : $receiver'.
  764. inlined := true]].
  765. (aSelector = 'ifNotNil:') ifTrue: [
  766. aCollection first isBlockNode ifTrue: [
  767. stream nextPutAll: '(($receiver = '.
  768. self visit: anObject.
  769. stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
  770. self visit: aCollection first.
  771. stream nextPutAll: '() : nil'.
  772. inlined := true]].
  773. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  774. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  775. stream nextPutAll: '(($receiver = '.
  776. self visit: anObject.
  777. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  778. self visit: aCollection first.
  779. stream nextPutAll: '() : '.
  780. self visit: aCollection second.
  781. stream nextPutAll: '()'.
  782. inlined := true]].
  783. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  784. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  785. stream nextPutAll: '(($receiver = '.
  786. self visit: anObject.
  787. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  788. self visit: aCollection second.
  789. stream nextPutAll: '() : '.
  790. self visit: aCollection first.
  791. stream nextPutAll: '()'.
  792. inlined := true]].
  793. ^inlined
  794. !
  795. isNode: aNode ofClass: aClass
  796. ^aNode isValueNode and: [
  797. aNode value class = aClass or: [
  798. aNode value = 'self' and: [self currentClass = aClass]]]
  799. !
  800. inline: aSelector receiver: receiver argumentNodes: aCollection
  801. | inlined |
  802. inlined := false.
  803. "-- Booleans --"
  804. (aSelector = 'ifFalse:') ifTrue: [
  805. aCollection first isBlockNode ifTrue: [
  806. self checkClass: 'Boolean' for: receiver.
  807. stream nextPutAll: '(!! $receiver ? '.
  808. self visit: aCollection first.
  809. stream nextPutAll: '() : nil)'.
  810. inlined := true]].
  811. (aSelector = 'ifTrue:') ifTrue: [
  812. aCollection first isBlockNode ifTrue: [
  813. self checkClass: 'Boolean' for: receiver.
  814. stream nextPutAll: '($receiver ? '.
  815. self visit: aCollection first.
  816. stream nextPutAll: '() : nil)'.
  817. inlined := true]].
  818. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  819. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  820. self checkClass: 'Boolean' for: receiver.
  821. stream nextPutAll: '($receiver ? '.
  822. self visit: aCollection first.
  823. stream nextPutAll: '() : '.
  824. self visit: aCollection second.
  825. stream nextPutAll: '())'.
  826. inlined := true]].
  827. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  828. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  829. self checkClass: 'Boolean' for: receiver.
  830. stream nextPutAll: '(!! $receiver ? '.
  831. self visit: aCollection first.
  832. stream nextPutAll: '() : '.
  833. self visit: aCollection second.
  834. stream nextPutAll: '())'.
  835. inlined := true]].
  836. "-- Numbers --"
  837. (aSelector = '<') ifTrue: [
  838. self checkClass: 'Number' for: receiver.
  839. stream nextPutAll: '$receiver <'.
  840. self visit: aCollection first.
  841. inlined := true].
  842. (aSelector = '<=') ifTrue: [
  843. self checkClass: 'Number' for: receiver.
  844. stream nextPutAll: '$receiver <='.
  845. self visit: aCollection first.
  846. inlined := true].
  847. (aSelector = '>') ifTrue: [
  848. self checkClass: 'Number' for: receiver.
  849. stream nextPutAll: '$receiver >'.
  850. self visit: aCollection first.
  851. inlined := true].
  852. (aSelector = '>=') ifTrue: [
  853. self checkClass: 'Number' for: receiver.
  854. stream nextPutAll: '$receiver >='.
  855. self visit: aCollection first.
  856. inlined := true].
  857. (aSelector = '+') ifTrue: [
  858. self checkClass: 'Number' for: receiver.
  859. stream nextPutAll: '$receiver +'.
  860. self visit: aCollection first.
  861. inlined := true].
  862. (aSelector = '-') ifTrue: [
  863. self checkClass: 'Number' for: receiver.
  864. stream nextPutAll: '$receiver -'.
  865. self visit: aCollection first.
  866. inlined := true].
  867. (aSelector = '*') ifTrue: [
  868. self checkClass: 'Number' for: receiver.
  869. stream nextPutAll: '$receiver *'.
  870. self visit: aCollection first.
  871. inlined := true].
  872. (aSelector = '/') ifTrue: [
  873. self checkClass: 'Number' for: receiver.
  874. stream nextPutAll: '$receiver /'.
  875. self visit: aCollection first.
  876. inlined := true].
  877. ^inlined
  878. ! !
  879. !Compiler methodsFor: 'testing'!
  880. performOptimizations
  881. ^self class performOptimizations
  882. ! !
  883. !Compiler methodsFor: 'visiting'!
  884. visit: aNode
  885. aNode accept: self
  886. !
  887. visitMethodNode: aNode
  888. | str currentSelector |
  889. currentSelector := aNode selector asSelector.
  890. nestedBlocks := 0.
  891. earlyReturn := false.
  892. messageSends := #().
  893. referencedClasses := #().
  894. unknownVariables := #().
  895. tempVariables := #().
  896. stream
  897. nextPutAll: 'smalltalk.method({'; lf;
  898. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  899. stream nextPutAll: 'source: unescape("', self source escaped, '"),';lf.
  900. stream nextPutAll: 'fn: function('.
  901. aNode arguments
  902. do: [:each |
  903. tempVariables add: each.
  904. stream nextPutAll: each]
  905. separatedBy: [stream nextPutAll: ', '].
  906. stream
  907. nextPutAll: '){'; lf;
  908. nextPutAll: 'var self=this;'; lf.
  909. str := stream.
  910. stream := '' writeStream.
  911. aNode nodes do: [:each |
  912. self visit: each].
  913. earlyReturn ifTrue: [
  914. str nextPutAll: 'try{'].
  915. str nextPutAll: stream contents.
  916. stream := str.
  917. stream
  918. lf;
  919. nextPutAll: 'return self;'.
  920. earlyReturn ifTrue: [
  921. stream lf; nextPutAll: '} catch(e) {if(e.name === ''stReturn'' && e.selector === ', currentSelector printString, '){return e.fn()} throw(e)}'].
  922. stream nextPutAll: '}'.
  923. stream
  924. nextPutAll: ',', String lf, 'messageSends: ';
  925. nextPutAll: messageSends asJavascript, ','; lf;
  926. nextPutAll: 'referencedClasses: ['.
  927. referencedClasses
  928. do: [:each | stream nextPutAll: each]
  929. separatedBy: [stream nextPutAll: ','].
  930. stream nextPutAll: ']'.
  931. stream nextPutAll: '})'
  932. !
  933. visitBlockNode: aNode
  934. stream nextPutAll: '(function('.
  935. aNode parameters
  936. do: [:each |
  937. tempVariables add: each.
  938. stream nextPutAll: each]
  939. separatedBy: [stream nextPutAll: ', '].
  940. stream nextPutAll: '){'.
  941. aNode nodes do: [:each | self visit: each].
  942. stream nextPutAll: '})'
  943. !
  944. visitSequenceNode: aNode
  945. aNode temps do: [:each |
  946. tempVariables add: each.
  947. stream nextPutAll: 'var ', each, '=nil;'; lf].
  948. aNode nodes do: [:each |
  949. self visit: each.
  950. stream nextPutAll: ';']
  951. separatedBy: [stream lf]
  952. !
  953. visitBlockSequenceNode: aNode
  954. | index |
  955. nestedBlocks := nestedBlocks + 1.
  956. aNode nodes isEmpty
  957. ifTrue: [
  958. stream nextPutAll: 'return nil;']
  959. ifFalse: [
  960. aNode temps do: [:each |
  961. tempVariables add: each.
  962. stream nextPutAll: 'var ', each, '=nil;'; lf].
  963. index := 0.
  964. aNode nodes do: [:each |
  965. index := index + 1.
  966. index = aNode nodes size ifTrue: [
  967. stream nextPutAll: 'return '].
  968. self visit: each.
  969. stream nextPutAll: ';']].
  970. nestedBlocks := nestedBlocks - 1
  971. !
  972. visitReturnNode: aNode
  973. nestedBlocks > 0 ifTrue: [
  974. earlyReturn := true].
  975. earlyReturn
  976. ifTrue: [
  977. stream
  978. nextPutAll: '(function(){throw(';
  979. nextPutAll: '{name: ''stReturn'', selector: ';
  980. nextPutAll: currentSelector printString;
  981. nextPutAll: ', fn: function(){return ']
  982. ifFalse: [stream nextPutAll: 'return '].
  983. aNode nodes do: [:each |
  984. self visit: each].
  985. earlyReturn ifTrue: [
  986. stream nextPutAll: '}})})()']
  987. !
  988. visitSendNode: aNode
  989. | str receiver superSend inlined |
  990. str := stream.
  991. (messageSends includes: aNode selector) ifFalse: [
  992. messageSends add: aNode selector].
  993. stream := '' writeStream.
  994. self visit: aNode receiver.
  995. superSend := stream contents = 'super'.
  996. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  997. stream := str.
  998. self performOptimizations
  999. ifTrue: [
  1000. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
  1001. (self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
  1002. ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend)]
  1003. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
  1004. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
  1005. !
  1006. visitCascadeNode: aNode
  1007. | index |
  1008. index := 0.
  1009. (tempVariables includes: '$rec') ifFalse: [
  1010. tempVariables add: '$rec'].
  1011. stream nextPutAll: '(function($rec){'.
  1012. aNode nodes do: [:each |
  1013. index := index + 1.
  1014. index = aNode nodes size ifTrue: [
  1015. stream nextPutAll: 'return '].
  1016. each receiver: (VariableNode new value: '$rec').
  1017. self visit: each.
  1018. stream nextPutAll: ';'].
  1019. stream nextPutAll: '})('.
  1020. self visit: aNode receiver.
  1021. stream nextPutAll: ')'
  1022. !
  1023. visitValueNode: aNode
  1024. stream nextPutAll: aNode value asJavascript
  1025. !
  1026. visitAssignmentNode: aNode
  1027. self visit: aNode left.
  1028. stream nextPutAll: '='.
  1029. self visit: aNode right
  1030. !
  1031. visitClassReferenceNode: aNode
  1032. | klass |
  1033. klass := '(smalltalk.', aNode value, ' || ', aNode value, ')'.
  1034. (Smalltalk current at: aNode value) isClass ifTrue: [
  1035. (referencedClasses includes: klass)
  1036. ifFalse: [referencedClasses add: klass]].
  1037. stream nextPutAll: klass
  1038. !
  1039. visitVariableNode: aNode
  1040. (self currentClass allInstanceVariableNames includes: aNode value)
  1041. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  1042. ifFalse: [
  1043. (self knownVariables includes: aNode value)
  1044. ifFalse: [
  1045. unknownVariables add: aNode value.
  1046. aNode assigned
  1047. ifTrue: [stream nextPutAll: aNode value]
  1048. ifFalse: [stream nextPutAll: '(typeof ', aNode value, ' == ''undefined'' ? nil : ', aNode value, ')']]
  1049. ifTrue: [
  1050. stream nextPutAll:aNode value]]
  1051. !
  1052. visitJSStatementNode: aNode
  1053. stream nextPutAll: (aNode source replace: '>>' with: '>')
  1054. !
  1055. visitFailure: aFailure
  1056. self error: aFailure asString
  1057. !
  1058. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  1059. ^String streamContents: [:str || tmp |
  1060. tmp := stream.
  1061. str nextPutAll: 'smalltalk.send('.
  1062. str nextPutAll: aReceiver.
  1063. str nextPutAll: ', "', aSelector asSelector, '", ['.
  1064. stream := str.
  1065. aCollection
  1066. do: [:each | self visit: each]
  1067. separatedBy: [stream nextPutAll: ', '].
  1068. stream := tmp.
  1069. str nextPutAll: ']'.
  1070. aBoolean ifTrue: [
  1071. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
  1072. str nextPutAll: ')']
  1073. !
  1074. visitDynamicArrayNode: aNode
  1075. stream nextPutAll: '['.
  1076. aNode nodes
  1077. do: [:each | self visit: each]
  1078. separatedBy: [stream nextPutAll: ','].
  1079. stream nextPutAll: ']'
  1080. !
  1081. visitDynamicDictionaryNode: aNode
  1082. stream nextPutAll: 'smalltalk.Dictionary._fromPairs_(['.
  1083. aNode nodes
  1084. do: [:each | self visit: each]
  1085. separatedBy: [stream nextPutAll: ','].
  1086. stream nextPutAll: '])'
  1087. ! !
  1088. Compiler class instanceVariableNames: 'performOptimizations'!
  1089. !Compiler class methodsFor: 'accessing'!
  1090. performOptimizations
  1091. ^performOptimizations ifNil: [true]
  1092. !
  1093. performOptimizations: aBoolean
  1094. performOptimizations := aBoolean
  1095. ! !
  1096. !Compiler class methodsFor: 'compiling'!
  1097. recompile: aClass
  1098. aClass methodDictionary do: [:each || method |
  1099. method := self new load: each source forClass: aClass.
  1100. method category: each category.
  1101. aClass addCompiledMethod: method].
  1102. aClass isMetaclass ifFalse: [self recompile: aClass class]
  1103. !
  1104. recompileAll
  1105. Smalltalk current classes do: [:each |
  1106. self recompile: each]
  1107. ! !
  1108. Object subclass: #DoIt
  1109. instanceVariableNames: ''
  1110. category: 'Compiler'!
  1111. Node subclass: #DynamicArrayNode
  1112. instanceVariableNames: ''
  1113. category: 'Compiler'!
  1114. !DynamicArrayNode methodsFor: 'visiting'!
  1115. accept: aVisitor
  1116. aVisitor visitDynamicArrayNode: self
  1117. ! !
  1118. Node subclass: #DynamicDictionaryNode
  1119. instanceVariableNames: ''
  1120. category: 'Compiler'!
  1121. !DynamicDictionaryNode methodsFor: 'visiting'!
  1122. accept: aVisitor
  1123. aVisitor visitDynamicDictionaryNode: self
  1124. ! !