Compiler.st 35 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. export: aClass
  57. "Export a single class. Subclasses override these methods."
  58. ^String streamContents: [:stream |
  59. self exportDefinitionOf: aClass on: stream.
  60. self exportMethodsOf: aClass on: stream.
  61. self exportMetaDefinitionOf: aClass on: stream.
  62. self exportMethodsOf: aClass class on: stream]
  63. !
  64. exportPackage: packageName
  65. "Export a given package by name."
  66. ^String streamContents: [:stream |
  67. (Smalltalk current packageAt: packageName)
  68. classes do: [:each |
  69. stream nextPutAll: (self export: each)].
  70. self exportPackageExtensions: packageName on: stream]
  71. !
  72. exportAll
  73. "Export all packages in the system."
  74. ^String streamContents: [:stream |
  75. Smalltalk current packages do: [:pkg |
  76. stream nextPutAll: (self exportPackage: pkg name)]]
  77. ! !
  78. !Exporter methodsFor: 'private'!
  79. exportDefinitionOf: aClass on: aStream
  80. aStream
  81. nextPutAll: 'smalltalk.addClass(';
  82. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  83. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  84. nextPutAll: ', ['.
  85. aClass instanceVariableNames
  86. do: [:each | aStream nextPutAll: '''', each, '''']
  87. separatedBy: [aStream nextPutAll: ', '].
  88. aStream
  89. nextPutAll: '], ''';
  90. nextPutAll: aClass category, '''';
  91. nextPutAll: ');'.
  92. aClass comment notEmpty ifTrue: [
  93. aStream
  94. lf;
  95. nextPutAll: 'smalltalk.';
  96. nextPutAll: (self classNameFor: aClass);
  97. nextPutAll: '.comment=';
  98. nextPutAll: 'unescape(''', aClass comment escaped, ''')'].
  99. aStream lf
  100. !
  101. exportMetaDefinitionOf: aClass on: aStream
  102. aClass class instanceVariableNames isEmpty ifFalse: [
  103. aStream
  104. nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
  105. nextPutAll: '.iVarNames = ['.
  106. aClass class instanceVariableNames
  107. do: [:each | aStream nextPutAll: '''', each, '''']
  108. separatedBy: [aStream nextPutAll: ','].
  109. aStream nextPutAll: '];', String lf]
  110. !
  111. exportMethodsOf: aClass on: aStream
  112. aClass methodDictionary values do: [:each |
  113. (each category match: '^\*') ifFalse: [
  114. self exportMethod: each of: aClass on: aStream]].
  115. aStream lf
  116. !
  117. classNameFor: aClass
  118. ^aClass isMetaclass
  119. ifTrue: [aClass instanceClass name, '.klass']
  120. ifFalse: [
  121. aClass isNil
  122. ifTrue: ['nil']
  123. ifFalse: [aClass name]]
  124. !
  125. exportMethod: aMethod of: aClass on: aStream
  126. aStream
  127. nextPutAll: 'smalltalk.addMethod(';lf;
  128. nextPutAll: 'unescape(''', aMethod selector asSelector escaped, '''),';lf;
  129. nextPutAll: 'smalltalk.method({';lf;
  130. nextPutAll: 'selector: unescape(''', aMethod selector escaped, '''),';lf;
  131. nextPutAll: 'category: ''', aMethod category, ''',';lf;
  132. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  133. nextPutAll: 'args: ', aMethod arguments asJavascript, ','; lf;
  134. nextPutAll: 'source: unescape(''', aMethod source escaped, '''),';lf;
  135. nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
  136. nextPutAll: 'referencedClasses: ', aMethod referencedClasses asJavascript.
  137. aStream
  138. lf;
  139. nextPutAll: '}),';lf;
  140. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  141. nextPutAll: ');';lf;lf
  142. !
  143. exportPackageExtensions: packageName on: aStream
  144. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  145. each methodDictionary values do: [:method |
  146. method category = ('*', packageName) ifTrue: [
  147. self exportMethod: method of: each on: aStream]]]
  148. ! !
  149. Exporter subclass: #ChunkExporter
  150. instanceVariableNames: ''
  151. category: 'Compiler'!
  152. !ChunkExporter methodsFor: 'not yet classified'!
  153. exportDefinitionOf: aClass on: aStream
  154. "Chunk format."
  155. aStream
  156. nextPutAll: (self classNameFor: aClass superclass);
  157. nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
  158. nextPutAll: ' instanceVariableNames: '''.
  159. aClass instanceVariableNames
  160. do: [:each | aStream nextPutAll: each]
  161. separatedBy: [aStream nextPutAll: ' '].
  162. aStream
  163. nextPutAll: ''''; lf;
  164. nextPutAll: ' category: ''', aClass category, '''!!'; lf.
  165. aClass comment notEmpty ifTrue: [
  166. aStream
  167. nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
  168. nextPutAll: (self chunkEscape: aClass comment), '!!';lf].
  169. aStream lf
  170. !
  171. exportMethod: aMethod of: aClass on: aStream
  172. aStream
  173. lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;
  174. nextPutAll: '!!'
  175. !
  176. exportMethodsOf: aClass on: aStream
  177. aClass protocolsDo: [:category :methods |
  178. (category match: '^\*') ifFalse: [
  179. self
  180. exportMethods: methods
  181. category: category
  182. of: aClass
  183. on: aStream]]
  184. !
  185. exportMetaDefinitionOf: aClass on: aStream
  186. aClass class instanceVariableNames isEmpty ifFalse: [
  187. aStream
  188. nextPutAll: (self classNameFor: aClass class);
  189. nextPutAll: ' instanceVariableNames: '''.
  190. aClass class instanceVariableNames
  191. do: [:each | aStream nextPutAll: each]
  192. separatedBy: [aStream nextPutAll: ' '].
  193. aStream
  194. nextPutAll: '''!!'; lf; lf]
  195. !
  196. classNameFor: aClass
  197. ^aClass isMetaclass
  198. ifTrue: [aClass instanceClass name, ' class']
  199. ifFalse: [
  200. aClass isNil
  201. ifTrue: ['nil']
  202. ifFalse: [aClass name]]
  203. !
  204. chunkEscape: aString
  205. "Replace all occurrences of !! with !!!! and trim at both ends."
  206. ^(aString replace: '!!' with: '!!!!') trimBoth
  207. !
  208. exportMethods: methods category: category of: aClass on: aStream
  209. aStream
  210. nextPutAll: '!!', (self classNameFor: aClass);
  211. nextPutAll: ' methodsFor: ''', category, '''!!'.
  212. methods do: [:each |
  213. self exportMethod: each of: aClass on: aStream].
  214. aStream nextPutAll: ' !!'; lf; lf
  215. !
  216. exportPackageExtensions: aString on: aStream
  217. "We need to override this one too since we need to group
  218. all methods in a given protocol under a leading methodsFor: chunk
  219. for that class."
  220. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  221. each protocolsDo: [:category :methods |
  222. category = ('*', aString) ifTrue: [
  223. self exportMethods: methods category: category of: each on: aStream]]]
  224. ! !
  225. Exporter subclass: #StrippedExporter
  226. instanceVariableNames: ''
  227. category: 'Compiler'!
  228. !StrippedExporter methodsFor: 'private'!
  229. exportDefinitionOf: aClass on: aStream
  230. aStream
  231. nextPutAll: 'smalltalk.addClass(';
  232. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  233. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  234. nextPutAll: ', ['.
  235. aClass instanceVariableNames
  236. do: [:each | aStream nextPutAll: '''', each, '''']
  237. separatedBy: [aStream nextPutAll: ', '].
  238. aStream
  239. nextPutAll: '], ''';
  240. nextPutAll: aClass category, '''';
  241. nextPutAll: ');'.
  242. aStream lf
  243. !
  244. exportMethod: aMethod of: aClass on: aStream
  245. aStream
  246. nextPutAll: 'smalltalk.addMethod(';lf;
  247. nextPutAll: '''', aMethod selector asSelector, ''',';lf;
  248. nextPutAll: 'smalltalk.method({';lf;
  249. nextPutAll: 'selector: ''', aMethod selector, ''',';lf;
  250. nextPutAll: 'fn: ', aMethod fn compiledSource;lf;
  251. nextPutAll: '}),';lf;
  252. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  253. nextPutAll: ');';lf;lf
  254. ! !
  255. Object subclass: #Node
  256. instanceVariableNames: 'nodes'
  257. category: 'Compiler'!
  258. !Node methodsFor: 'accessing'!
  259. nodes
  260. ^nodes ifNil: [nodes := Array new]
  261. !
  262. addNode: aNode
  263. self nodes add: aNode
  264. ! !
  265. !Node methodsFor: 'building'!
  266. nodes: aCollection
  267. nodes := aCollection
  268. ! !
  269. !Node methodsFor: 'testing'!
  270. isValueNode
  271. ^false
  272. !
  273. isBlockNode
  274. ^false
  275. !
  276. isBlockSequenceNode
  277. ^false
  278. ! !
  279. !Node methodsFor: 'visiting'!
  280. accept: aVisitor
  281. aVisitor visitNode: self
  282. ! !
  283. Node subclass: #MethodNode
  284. instanceVariableNames: 'selector arguments source'
  285. category: 'Compiler'!
  286. !MethodNode methodsFor: 'accessing'!
  287. selector
  288. ^selector
  289. !
  290. selector: aString
  291. selector := aString
  292. !
  293. arguments
  294. ^arguments ifNil: [#()]
  295. !
  296. arguments: aCollection
  297. arguments := aCollection
  298. !
  299. source
  300. ^source
  301. !
  302. source: aString
  303. source := aString
  304. ! !
  305. !MethodNode methodsFor: 'visiting'!
  306. accept: aVisitor
  307. aVisitor visitMethodNode: self
  308. ! !
  309. Node subclass: #SendNode
  310. instanceVariableNames: 'selector arguments receiver'
  311. category: 'Compiler'!
  312. !SendNode methodsFor: 'accessing'!
  313. selector
  314. ^selector
  315. !
  316. selector: aString
  317. selector := aString
  318. !
  319. arguments
  320. ^arguments ifNil: [arguments := #()]
  321. !
  322. arguments: aCollection
  323. arguments := aCollection
  324. !
  325. receiver
  326. ^receiver
  327. !
  328. receiver: aNode
  329. receiver := aNode
  330. !
  331. valueForReceiver: anObject
  332. ^SendNode new
  333. receiver: (self receiver
  334. ifNil: [anObject]
  335. ifNotNil: [self receiver valueForReceiver: anObject]);
  336. selector: self selector;
  337. arguments: self arguments;
  338. yourself
  339. !
  340. cascadeNodeWithMessages: aCollection
  341. | first |
  342. first := SendNode new
  343. selector: self selector;
  344. arguments: self arguments;
  345. yourself.
  346. ^CascadeNode new
  347. receiver: self receiver;
  348. nodes: (Array with: first), aCollection;
  349. yourself
  350. ! !
  351. !SendNode methodsFor: 'visiting'!
  352. accept: aVisitor
  353. aVisitor visitSendNode: self
  354. ! !
  355. Node subclass: #CascadeNode
  356. instanceVariableNames: 'receiver'
  357. category: 'Compiler'!
  358. !CascadeNode methodsFor: 'accessing'!
  359. receiver
  360. ^receiver
  361. !
  362. receiver: aNode
  363. receiver := aNode
  364. ! !
  365. !CascadeNode methodsFor: 'visiting'!
  366. accept: aVisitor
  367. aVisitor visitCascadeNode: self
  368. ! !
  369. Node subclass: #AssignmentNode
  370. instanceVariableNames: 'left right'
  371. category: 'Compiler'!
  372. !AssignmentNode methodsFor: 'accessing'!
  373. left
  374. ^left
  375. !
  376. left: aNode
  377. left := aNode.
  378. left assigned: true
  379. !
  380. right
  381. ^right
  382. !
  383. right: aNode
  384. right := aNode
  385. ! !
  386. !AssignmentNode methodsFor: 'visiting'!
  387. accept: aVisitor
  388. aVisitor visitAssignmentNode: self
  389. ! !
  390. Node subclass: #BlockNode
  391. instanceVariableNames: 'parameters inlined'
  392. category: 'Compiler'!
  393. !BlockNode methodsFor: 'accessing'!
  394. parameters
  395. ^parameters ifNil: [parameters := Array new]
  396. !
  397. parameters: aCollection
  398. parameters := aCollection
  399. !
  400. inlined
  401. ^inlined ifNil: [false]
  402. !
  403. inlined: aBoolean
  404. inlined := aBoolean
  405. ! !
  406. !BlockNode methodsFor: 'testing'!
  407. isBlockNode
  408. ^true
  409. ! !
  410. !BlockNode methodsFor: 'visiting'!
  411. accept: aVisitor
  412. aVisitor visitBlockNode: self
  413. ! !
  414. Node subclass: #SequenceNode
  415. instanceVariableNames: 'temps'
  416. category: 'Compiler'!
  417. !SequenceNode methodsFor: 'accessing'!
  418. temps
  419. ^temps ifNil: [#()]
  420. !
  421. temps: aCollection
  422. temps := aCollection
  423. ! !
  424. !SequenceNode methodsFor: 'testing'!
  425. asBlockSequenceNode
  426. ^BlockSequenceNode new
  427. nodes: self nodes;
  428. temps: self temps;
  429. yourself
  430. ! !
  431. !SequenceNode methodsFor: 'visiting'!
  432. accept: aVisitor
  433. aVisitor visitSequenceNode: self
  434. ! !
  435. SequenceNode subclass: #BlockSequenceNode
  436. instanceVariableNames: ''
  437. category: 'Compiler'!
  438. !BlockSequenceNode methodsFor: 'testing'!
  439. isBlockSequenceNode
  440. ^true
  441. ! !
  442. !BlockSequenceNode methodsFor: 'visiting'!
  443. accept: aVisitor
  444. aVisitor visitBlockSequenceNode: self
  445. ! !
  446. Node subclass: #ReturnNode
  447. instanceVariableNames: ''
  448. category: 'Compiler'!
  449. !ReturnNode methodsFor: 'visiting'!
  450. accept: aVisitor
  451. aVisitor visitReturnNode: self
  452. ! !
  453. Node subclass: #ValueNode
  454. instanceVariableNames: 'value'
  455. category: 'Compiler'!
  456. !ValueNode methodsFor: 'accessing'!
  457. value
  458. ^value
  459. !
  460. value: anObject
  461. value := anObject
  462. ! !
  463. !ValueNode methodsFor: 'testing'!
  464. isValueNode
  465. ^true
  466. ! !
  467. !ValueNode methodsFor: 'visiting'!
  468. accept: aVisitor
  469. aVisitor visitValueNode: self
  470. ! !
  471. ValueNode subclass: #VariableNode
  472. instanceVariableNames: 'assigned'
  473. category: 'Compiler'!
  474. !VariableNode methodsFor: 'accessing'!
  475. assigned
  476. ^assigned ifNil: [false]
  477. !
  478. assigned: aBoolean
  479. assigned := aBoolean
  480. ! !
  481. !VariableNode methodsFor: 'visiting'!
  482. accept: aVisitor
  483. aVisitor visitVariableNode: self
  484. ! !
  485. VariableNode subclass: #ClassReferenceNode
  486. instanceVariableNames: ''
  487. category: 'Compiler'!
  488. !ClassReferenceNode methodsFor: 'visiting'!
  489. accept: aVisitor
  490. aVisitor visitClassReferenceNode: self
  491. ! !
  492. Node subclass: #JSStatementNode
  493. instanceVariableNames: 'source'
  494. category: 'Compiler'!
  495. !JSStatementNode methodsFor: 'accessing'!
  496. source
  497. ^source ifNil: ['']
  498. !
  499. source: aString
  500. source := aString
  501. ! !
  502. !JSStatementNode methodsFor: 'visiting'!
  503. accept: aVisitor
  504. aVisitor visitJSStatementNode: self
  505. ! !
  506. Object subclass: #NodeVisitor
  507. instanceVariableNames: ''
  508. category: 'Compiler'!
  509. !NodeVisitor methodsFor: 'visiting'!
  510. visit: aNode
  511. aNode accept: self
  512. !
  513. visitNode: aNode
  514. !
  515. visitMethodNode: aNode
  516. self visitNode: aNode
  517. !
  518. visitSequenceNode: aNode
  519. self visitNode: aNode
  520. !
  521. visitBlockSequenceNode: aNode
  522. self visitSequenceNode: aNode
  523. !
  524. visitBlockNode: aNode
  525. self visitNode: aNode
  526. !
  527. visitReturnNode: aNode
  528. self visitNode: aNode
  529. !
  530. visitSendNode: aNode
  531. self visitNode: aNode
  532. !
  533. visitCascadeNode: aNode
  534. self visitNode: aNode
  535. !
  536. visitValueNode: aNode
  537. self visitNode: aNode
  538. !
  539. visitVariableNode: aNode
  540. !
  541. visitAssignmentNode: aNode
  542. self visitNode: aNode
  543. !
  544. visitClassReferenceNode: aNode
  545. self
  546. nextPutAll: 'smalltalk.';
  547. nextPutAll: aNode value
  548. !
  549. visitJSStatementNode: aNode
  550. self
  551. nextPutAll: 'function(){';
  552. nextPutAll: aNode source;
  553. nextPutAll: '})()'
  554. !
  555. visitDynamicArrayNode: aNode
  556. self visitNode: aNode
  557. !
  558. visitDynamicDictionaryNode: aNode
  559. self visitNode: aNode
  560. ! !
  561. NodeVisitor subclass: #Compiler
  562. instanceVariableNames: 'stream nestedBlocks earlyReturn currentClass currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced source argVariables'
  563. category: 'Compiler'!
  564. !Compiler methodsFor: 'accessing'!
  565. parser
  566. ^SmalltalkParser new
  567. !
  568. currentClass
  569. ^currentClass
  570. !
  571. currentClass: aClass
  572. currentClass := aClass
  573. !
  574. unknownVariables
  575. ^unknownVariables copy
  576. !
  577. pseudoVariables
  578. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  579. !
  580. tempVariables
  581. ^tempVariables copy
  582. !
  583. knownVariables
  584. ^self pseudoVariables
  585. addAll: self tempVariables;
  586. addAll: self argVariables;
  587. yourself
  588. !
  589. classNameFor: aClass
  590. ^aClass isMetaclass
  591. ifTrue: [aClass instanceClass name, '.klass']
  592. ifFalse: [
  593. aClass isNil
  594. ifTrue: ['nil']
  595. ifFalse: [aClass name]]
  596. !
  597. source
  598. ^source ifNil: ['']
  599. !
  600. source: aString
  601. source := aString
  602. !
  603. argVariables
  604. ^argVariables copy
  605. !
  606. safeVariableNameFor: aString
  607. ^(Smalltalk current reservedWords includes: aString)
  608. ifTrue: [aString, '_']
  609. ifFalse: [aString]
  610. ! !
  611. !Compiler methodsFor: 'compiling'!
  612. loadExpression: aString
  613. | result |
  614. DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
  615. result := DoIt new doIt.
  616. DoIt removeCompiledMethod: (DoIt methodDictionary at: #doIt).
  617. ^result
  618. !
  619. load: aString forClass: aClass
  620. | compiled |
  621. compiled := self eval: (self compile: aString forClass: aClass).
  622. self setupClass: aClass.
  623. ^compiled
  624. !
  625. compile: aString forClass: aClass
  626. self currentClass: aClass.
  627. self source: aString.
  628. ^self compile: aString
  629. !
  630. compileExpression: aString
  631. self currentClass: DoIt.
  632. self source: 'doIt ^[', aString, '] value'.
  633. ^self compileNode: (self parse: self source)
  634. !
  635. eval: aString
  636. <return eval(aString)>
  637. !
  638. compile: aString
  639. ^self compileNode: (self parse: aString)
  640. !
  641. compileNode: aNode
  642. stream := '' writeStream.
  643. self visit: aNode.
  644. ^stream contents
  645. !
  646. parse: aString
  647. ^Smalltalk current parse: aString
  648. !
  649. parseExpression: aString
  650. ^self parse: 'doIt ^[', aString, '] value'
  651. !
  652. recompile: aClass
  653. aClass methodDictionary do: [:each || method |
  654. method := self load: each source forClass: aClass.
  655. method category: each category.
  656. aClass addCompiledMethod: method].
  657. aClass isMetaclass ifFalse: [self recompile: aClass class]
  658. !
  659. recompileAll
  660. Smalltalk current classes do: [:each |
  661. Transcript show: each; cr.
  662. [self recompile: each] valueWithTimeout: 100]
  663. !
  664. setupClass: aClass
  665. <smalltalk.init(aClass)>
  666. ! !
  667. !Compiler methodsFor: 'initialization'!
  668. initialize
  669. super initialize.
  670. stream := '' writeStream.
  671. unknownVariables := #().
  672. tempVariables := #().
  673. argVariables := #().
  674. messageSends := #().
  675. classReferenced := #()
  676. ! !
  677. !Compiler methodsFor: 'optimizations'!
  678. checkClass: aClassName for: receiver
  679. stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
  680. !
  681. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  682. | inlined |
  683. inlined := false.
  684. "-- BlockClosures --"
  685. (aSelector = 'whileTrue:') ifTrue: [
  686. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  687. stream nextPutAll: '(function(){while('.
  688. self visit: anObject.
  689. stream nextPutAll: '()) {'.
  690. self visit: aCollection first.
  691. stream nextPutAll: '()}})()'.
  692. inlined := true]].
  693. (aSelector = 'whileFalse:') ifTrue: [
  694. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  695. stream nextPutAll: '(function(){while(!!'.
  696. self visit: anObject.
  697. stream nextPutAll: '()) {'.
  698. self visit: aCollection first.
  699. stream nextPutAll: '()}})()'.
  700. inlined := true]].
  701. (aSelector = 'whileTrue') ifTrue: [
  702. anObject isBlockNode ifTrue: [
  703. stream nextPutAll: '(function(){while('.
  704. self visit: anObject.
  705. stream nextPutAll: '()) {}})()'.
  706. inlined := true]].
  707. (aSelector = 'whileFalse') ifTrue: [
  708. anObject isBlockNode ifTrue: [
  709. stream nextPutAll: '(function(){while(!!'.
  710. self visit: anObject.
  711. stream nextPutAll: '()) {}})()'.
  712. inlined := true]].
  713. "-- Numbers --"
  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 printString]
  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 || temp |
  954. temp := self safeVariableNameFor: each.
  955. tempVariables add: temp.
  956. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  957. aNode nodes do: [:each |
  958. self visit: each.
  959. stream nextPutAll: ';']
  960. separatedBy: [stream lf]
  961. !
  962. visitBlockSequenceNode: aNode
  963. | index |
  964. nestedBlocks := nestedBlocks + 1.
  965. aNode nodes isEmpty
  966. ifTrue: [
  967. stream nextPutAll: 'return nil;']
  968. ifFalse: [
  969. aNode temps do: [:each | | temp |
  970. temp := self safeVariableNameFor: each.
  971. tempVariables add: temp.
  972. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  973. index := 0.
  974. aNode nodes do: [:each |
  975. index := index + 1.
  976. index = aNode nodes size ifTrue: [
  977. stream nextPutAll: 'return '].
  978. self visit: each.
  979. stream nextPutAll: ';']].
  980. nestedBlocks := nestedBlocks - 1
  981. !
  982. visitReturnNode: aNode
  983. nestedBlocks > 0 ifTrue: [
  984. earlyReturn := true].
  985. earlyReturn
  986. ifTrue: [
  987. stream
  988. nextPutAll: '(function(){throw(';
  989. nextPutAll: '{name: ''stReturn'', selector: ';
  990. nextPutAll: currentSelector printString;
  991. nextPutAll: ', fn: function(){return ']
  992. ifFalse: [stream nextPutAll: 'return '].
  993. aNode nodes do: [:each |
  994. self visit: each].
  995. earlyReturn ifTrue: [
  996. stream nextPutAll: '}})})()']
  997. !
  998. visitSendNode: aNode
  999. | str receiver superSend inlined |
  1000. str := stream.
  1001. (messageSends includes: aNode selector) ifFalse: [
  1002. messageSends add: aNode selector].
  1003. stream := '' writeStream.
  1004. self visit: aNode receiver.
  1005. superSend := stream contents = 'super'.
  1006. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  1007. stream := str.
  1008. self performOptimizations
  1009. ifTrue: [
  1010. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
  1011. (self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
  1012. ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
  1013. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
  1014. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
  1015. !
  1016. visitCascadeNode: aNode
  1017. | index |
  1018. index := 0.
  1019. (tempVariables includes: '$rec') ifFalse: [
  1020. tempVariables add: '$rec'].
  1021. stream nextPutAll: '(function($rec){'.
  1022. aNode nodes do: [:each |
  1023. index := index + 1.
  1024. index = aNode nodes size ifTrue: [
  1025. stream nextPutAll: 'return '].
  1026. each receiver: (VariableNode new value: '$rec').
  1027. self visit: each.
  1028. stream nextPutAll: ';'].
  1029. stream nextPutAll: '})('.
  1030. self visit: aNode receiver.
  1031. stream nextPutAll: ')'
  1032. !
  1033. visitValueNode: aNode
  1034. stream nextPutAll: aNode value asJavascript
  1035. !
  1036. visitAssignmentNode: aNode
  1037. self visit: aNode left.
  1038. stream nextPutAll: '='.
  1039. self visit: aNode right
  1040. !
  1041. visitClassReferenceNode: aNode
  1042. (referencedClasses includes: aNode value) ifFalse: [
  1043. referencedClasses add: aNode value].
  1044. stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
  1045. !
  1046. visitVariableNode: aNode
  1047. | varName |
  1048. (self currentClass allInstanceVariableNames includes: aNode value)
  1049. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  1050. ifFalse: [
  1051. varName := self safeVariableNameFor: aNode value.
  1052. (self knownVariables includes: varName)
  1053. ifFalse: [
  1054. unknownVariables add: aNode value.
  1055. aNode assigned
  1056. ifTrue: [stream nextPutAll: varName]
  1057. ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
  1058. ifTrue: [
  1059. aNode value = 'thisContext'
  1060. ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
  1061. ifFalse: [stream nextPutAll: varName]]]
  1062. !
  1063. visitJSStatementNode: aNode
  1064. stream nextPutAll: (aNode source replace: '>>' with: '>')
  1065. !
  1066. visitFailure: aFailure
  1067. self error: aFailure asString
  1068. !
  1069. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  1070. ^String streamContents: [:str || tmp |
  1071. tmp := stream.
  1072. str nextPutAll: 'smalltalk.send('.
  1073. str nextPutAll: aReceiver.
  1074. str nextPutAll: ', "', aSelector asSelector, '", ['.
  1075. stream := str.
  1076. aCollection
  1077. do: [:each | self visit: each]
  1078. separatedBy: [stream nextPutAll: ', '].
  1079. stream := tmp.
  1080. str nextPutAll: ']'.
  1081. aBoolean ifTrue: [
  1082. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
  1083. str nextPutAll: ')']
  1084. !
  1085. visitDynamicArrayNode: aNode
  1086. stream nextPutAll: '['.
  1087. aNode nodes
  1088. do: [:each | self visit: each]
  1089. separatedBy: [stream nextPutAll: ','].
  1090. stream nextPutAll: ']'
  1091. !
  1092. visitDynamicDictionaryNode: aNode
  1093. stream nextPutAll: 'smalltalk.Dictionary._fromPairs_(['.
  1094. aNode nodes
  1095. do: [:each | self visit: each]
  1096. separatedBy: [stream nextPutAll: ','].
  1097. stream nextPutAll: '])'
  1098. ! !
  1099. Compiler class instanceVariableNames: 'performOptimizations'!
  1100. !Compiler class methodsFor: 'accessing'!
  1101. performOptimizations
  1102. ^performOptimizations ifNil: [true]
  1103. !
  1104. performOptimizations: aBoolean
  1105. performOptimizations := aBoolean
  1106. ! !
  1107. !Compiler class methodsFor: 'compiling'!
  1108. recompile: aClass
  1109. aClass methodDictionary do: [:each || method |
  1110. method := self new load: each source forClass: aClass.
  1111. method category: each category.
  1112. aClass addCompiledMethod: method].
  1113. aClass isMetaclass ifFalse: [self recompile: aClass class]
  1114. !
  1115. recompileAll
  1116. Smalltalk current classes do: [:each |
  1117. self recompile: each]
  1118. ! !
  1119. Object subclass: #DoIt
  1120. instanceVariableNames: ''
  1121. category: 'Compiler'!
  1122. Node subclass: #DynamicArrayNode
  1123. instanceVariableNames: ''
  1124. category: 'Compiler'!
  1125. !DynamicArrayNode methodsFor: 'visiting'!
  1126. accept: aVisitor
  1127. aVisitor visitDynamicArrayNode: self
  1128. ! !
  1129. Node subclass: #DynamicDictionaryNode
  1130. instanceVariableNames: ''
  1131. category: 'Compiler'!
  1132. !DynamicDictionaryNode methodsFor: 'visiting'!
  1133. accept: aVisitor
  1134. aVisitor visitDynamicDictionaryNode: self
  1135. ! !