Compiler.st 34 KB

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