Compiler.st 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341
  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. NodeVisitor subclass: #Compiler
  554. instanceVariableNames: 'stream nestedBlocks earlyReturn currentClass currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced source'
  555. category: 'Compiler'!
  556. !Compiler methodsFor: 'accessing'!
  557. parser
  558. ^SmalltalkParser new
  559. !
  560. currentClass
  561. ^currentClass
  562. !
  563. currentClass: aClass
  564. currentClass := aClass
  565. !
  566. unknownVariables
  567. ^unknownVariables copy
  568. !
  569. pseudoVariables
  570. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  571. !
  572. tempVariables
  573. ^tempVariables copy
  574. !
  575. knownVariables
  576. ^self pseudoVariables
  577. addAll: self tempVariables;
  578. yourself
  579. !
  580. classNameFor: aClass
  581. ^aClass isMetaclass
  582. ifTrue: [aClass instanceClass name, '.klass']
  583. ifFalse: [
  584. aClass isNil
  585. ifTrue: ['nil']
  586. ifFalse: [aClass name]]
  587. !
  588. source
  589. ^source ifNil: ['']
  590. !
  591. source: aString
  592. source := aString
  593. ! !
  594. !Compiler methodsFor: 'compiling'!
  595. loadExpression: aString
  596. | result |
  597. DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
  598. result := DoIt new doIt.
  599. DoIt removeCompiledMethod: (DoIt methodDictionary at: #doIt).
  600. ^result
  601. !
  602. load: aString forClass: aClass
  603. | compiled |
  604. compiled := self eval: (self compile: aString forClass: aClass).
  605. self setupClass: aClass.
  606. ^compiled
  607. !
  608. compile: aString forClass: aClass
  609. self currentClass: aClass.
  610. self source: aString.
  611. ^self compile: aString
  612. !
  613. compileExpression: aString
  614. self currentClass: DoIt.
  615. self source: 'doIt ^[', aString, '] value'.
  616. ^self compileNode: (self parse: self source)
  617. !
  618. eval: aString
  619. <return eval(aString)>
  620. !
  621. compile: aString
  622. ^self compileNode: (self parse: aString)
  623. !
  624. compileNode: aNode
  625. stream := '' writeStream.
  626. self visit: aNode.
  627. ^stream contents
  628. !
  629. parse: aString
  630. ^Smalltalk current parse: aString
  631. !
  632. parseExpression: aString
  633. ^self parse: 'doIt ^[', aString, '] value'
  634. !
  635. recompile: aClass
  636. aClass methodDictionary do: [:each || method |
  637. method := self load: each source forClass: aClass.
  638. method category: each category.
  639. aClass addCompiledMethod: method].
  640. aClass isMetaclass ifFalse: [self recompile: aClass class]
  641. !
  642. recompileAll
  643. Smalltalk current classes do: [:each |
  644. Transcript show: each; cr.
  645. [self recompile: each] valueWithTimeout: 100]
  646. !
  647. setupClass: aClass
  648. <smalltalk.init(aClass)>
  649. ! !
  650. !Compiler methodsFor: 'initialization'!
  651. initialize
  652. super initialize.
  653. stream := '' writeStream.
  654. unknownVariables := #().
  655. tempVariables := #().
  656. messageSends := #().
  657. classReferenced := #()
  658. ! !
  659. !Compiler methodsFor: 'optimizations'!
  660. checkClass: aClassName for: receiver
  661. stream nextPutAll: '(($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
  662. !
  663. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  664. | inlined |
  665. inlined := false.
  666. "-- BlockClosures --"
  667. (aSelector = 'whileTrue:') ifTrue: [
  668. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  669. stream nextPutAll: '(function(){while('.
  670. self visit: anObject.
  671. stream nextPutAll: '()) {'.
  672. self visit: aCollection first.
  673. stream nextPutAll: '()}})()'.
  674. inlined := true]].
  675. (aSelector = 'whileFalse:') ifTrue: [
  676. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  677. stream nextPutAll: '(function(){while(!!'.
  678. self visit: anObject.
  679. stream nextPutAll: '()) {'.
  680. self visit: aCollection first.
  681. stream nextPutAll: '()}})()'.
  682. inlined := true]].
  683. (aSelector = 'whileTrue') ifTrue: [
  684. anObject isBlockNode ifTrue: [
  685. stream nextPutAll: '(function(){while('.
  686. self visit: anObject.
  687. stream nextPutAll: '()) {}})()'.
  688. inlined := true]].
  689. (aSelector = 'whileFalse') ifTrue: [
  690. anObject isBlockNode ifTrue: [
  691. stream nextPutAll: '(function(){while(!!'.
  692. self visit: anObject.
  693. stream nextPutAll: '()) {}})()'.
  694. inlined := true]].
  695. "-- Numbers --"
  696. (aSelector = '+') ifTrue: [
  697. (self isNode: anObject ofClass: Number) ifTrue: [
  698. self visit: anObject.
  699. stream nextPutAll: ' + '.
  700. self visit: aCollection first.
  701. inlined := true]].
  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. "-- UndefinedObject --"
  751. (aSelector = 'ifNil:') ifTrue: [
  752. aCollection first isBlockNode ifTrue: [
  753. stream nextPutAll: '(($receiver = '.
  754. self visit: anObject.
  755. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  756. self visit: aCollection first.
  757. stream nextPutAll: '() : $receiver'.
  758. inlined := true]].
  759. (aSelector = 'ifNotNil:') ifTrue: [
  760. aCollection first isBlockNode ifTrue: [
  761. stream nextPutAll: '(($receiver = '.
  762. self visit: anObject.
  763. stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
  764. self visit: aCollection first.
  765. stream nextPutAll: '() : nil'.
  766. inlined := true]].
  767. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  768. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  769. stream nextPutAll: '(($receiver = '.
  770. self visit: anObject.
  771. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  772. self visit: aCollection first.
  773. stream nextPutAll: '() : '.
  774. self visit: aCollection second.
  775. stream nextPutAll: '()'.
  776. inlined := true]].
  777. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  778. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  779. stream nextPutAll: '(($receiver = '.
  780. self visit: anObject.
  781. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  782. self visit: aCollection second.
  783. stream nextPutAll: '() : '.
  784. self visit: aCollection first.
  785. stream nextPutAll: '()'.
  786. inlined := true]].
  787. ^inlined
  788. !
  789. isNode: aNode ofClass: aClass
  790. ^aNode isValueNode and: [
  791. aNode value class = aClass or: [
  792. aNode value = 'self' and: [self currentClass = aClass]]]
  793. !
  794. inline: aSelector receiver: receiver argumentNodes: aCollection
  795. | inlined |
  796. inlined := false.
  797. "-- Booleans --"
  798. (aSelector = 'ifFalse:') ifTrue: [
  799. aCollection first isBlockNode ifTrue: [
  800. self checkClass: 'Boolean' for: receiver.
  801. stream nextPutAll: '(!! $receiver ? '.
  802. self visit: aCollection first.
  803. stream nextPutAll: '() : nil)'.
  804. inlined := true]].
  805. (aSelector = 'ifTrue:') ifTrue: [
  806. aCollection first isBlockNode ifTrue: [
  807. self checkClass: 'Boolean' for: receiver.
  808. stream nextPutAll: '($receiver ? '.
  809. self visit: aCollection first.
  810. stream nextPutAll: '() : nil)'.
  811. inlined := true]].
  812. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  813. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  814. self checkClass: 'Boolean' for: receiver.
  815. stream nextPutAll: '($receiver ? '.
  816. self visit: aCollection first.
  817. stream nextPutAll: '() : '.
  818. self visit: aCollection second.
  819. stream nextPutAll: '())'.
  820. inlined := true]].
  821. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  822. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  823. self checkClass: 'Boolean' for: receiver.
  824. stream nextPutAll: '(!! $receiver ? '.
  825. self visit: aCollection first.
  826. stream nextPutAll: '() : '.
  827. self visit: aCollection second.
  828. stream nextPutAll: '())'.
  829. inlined := true]].
  830. "-- Numbers --"
  831. (aSelector = '<') ifTrue: [
  832. self checkClass: 'Number' for: receiver.
  833. stream nextPutAll: '$receiver <'.
  834. self visit: aCollection first.
  835. inlined := true].
  836. (aSelector = '<=') ifTrue: [
  837. self checkClass: 'Number' for: receiver.
  838. stream nextPutAll: '$receiver <='.
  839. self visit: aCollection first.
  840. inlined := true].
  841. (aSelector = '>') ifTrue: [
  842. self checkClass: 'Number' for: receiver.
  843. stream nextPutAll: '$receiver >'.
  844. self visit: aCollection first.
  845. inlined := true].
  846. (aSelector = '>=') ifTrue: [
  847. self checkClass: 'Number' for: receiver.
  848. stream nextPutAll: '$receiver >='.
  849. self visit: aCollection first.
  850. inlined := true].
  851. (aSelector = '+') ifTrue: [
  852. self checkClass: 'Number' for: receiver.
  853. stream nextPutAll: '$receiver +'.
  854. self visit: aCollection first.
  855. inlined := true].
  856. (aSelector = '-') ifTrue: [
  857. self checkClass: 'Number' for: receiver.
  858. stream nextPutAll: '$receiver -'.
  859. self visit: aCollection first.
  860. inlined := true].
  861. (aSelector = '*') ifTrue: [
  862. self checkClass: 'Number' for: receiver.
  863. stream nextPutAll: '$receiver *'.
  864. self visit: aCollection first.
  865. inlined := true].
  866. (aSelector = '/') ifTrue: [
  867. self checkClass: 'Number' for: receiver.
  868. stream nextPutAll: '$receiver /'.
  869. self visit: aCollection first.
  870. inlined := true].
  871. ^inlined
  872. ! !
  873. !Compiler methodsFor: 'testing'!
  874. performOptimizations
  875. ^self class performOptimizations
  876. ! !
  877. !Compiler methodsFor: 'visiting'!
  878. visit: aNode
  879. aNode accept: self
  880. !
  881. visitMethodNode: aNode
  882. | str currentSelector |
  883. currentSelector := aNode selector asSelector.
  884. nestedBlocks := 0.
  885. earlyReturn := false.
  886. messageSends := #().
  887. referencedClasses := #().
  888. unknownVariables := #().
  889. tempVariables := #().
  890. stream
  891. nextPutAll: 'smalltalk.method({'; lf;
  892. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  893. stream nextPutAll: 'source: unescape("', self source escaped, '"),';lf.
  894. stream nextPutAll: 'fn: function('.
  895. aNode arguments
  896. do: [:each |
  897. tempVariables add: each.
  898. stream nextPutAll: each]
  899. separatedBy: [stream nextPutAll: ', '].
  900. stream
  901. nextPutAll: '){'; lf;
  902. nextPutAll: 'var self=this;'; lf.
  903. str := stream.
  904. stream := '' writeStream.
  905. aNode nodes do: [:each |
  906. self visit: each].
  907. earlyReturn ifTrue: [
  908. str nextPutAll: 'try{'].
  909. str nextPutAll: stream contents.
  910. stream := str.
  911. stream
  912. lf;
  913. nextPutAll: 'return self;'.
  914. earlyReturn ifTrue: [
  915. stream lf; nextPutAll: '} catch(e) {if(e.name === ''stReturn'' && e.selector === ', currentSelector printString, '){return e.fn()} throw(e)}'].
  916. stream nextPutAll: '}'.
  917. stream
  918. nextPutAll: ',', String lf, 'messageSends: ';
  919. nextPutAll: messageSends asJavascript, ','; lf;
  920. nextPutAll: 'referencedClasses: ['.
  921. referencedClasses
  922. do: [:each | stream nextPutAll: each]
  923. separatedBy: [stream nextPutAll: ','].
  924. stream nextPutAll: ']'.
  925. stream nextPutAll: '})'
  926. !
  927. visitBlockNode: aNode
  928. stream nextPutAll: '(function('.
  929. aNode parameters
  930. do: [:each |
  931. tempVariables add: each.
  932. stream nextPutAll: each]
  933. separatedBy: [stream nextPutAll: ', '].
  934. stream nextPutAll: '){'.
  935. aNode nodes do: [:each | self visit: each].
  936. stream nextPutAll: '})'
  937. !
  938. visitSequenceNode: aNode
  939. aNode temps do: [:each |
  940. tempVariables add: each.
  941. stream nextPutAll: 'var ', each, '=nil;'; lf].
  942. aNode nodes do: [:each |
  943. self visit: each.
  944. stream nextPutAll: ';']
  945. separatedBy: [stream lf]
  946. !
  947. visitBlockSequenceNode: aNode
  948. | index |
  949. nestedBlocks := nestedBlocks + 1.
  950. aNode nodes isEmpty
  951. ifTrue: [
  952. stream nextPutAll: 'return nil;']
  953. ifFalse: [
  954. aNode temps do: [:each |
  955. tempVariables add: each.
  956. stream nextPutAll: 'var ', each, '=nil;'; lf].
  957. index := 0.
  958. aNode nodes do: [:each |
  959. index := index + 1.
  960. index = aNode nodes size ifTrue: [
  961. stream nextPutAll: 'return '].
  962. self visit: each.
  963. stream nextPutAll: ';']].
  964. nestedBlocks := nestedBlocks - 1
  965. !
  966. visitReturnNode: aNode
  967. nestedBlocks > 0 ifTrue: [
  968. earlyReturn := true].
  969. earlyReturn
  970. ifTrue: [
  971. stream
  972. nextPutAll: '(function(){throw(';
  973. nextPutAll: '{name: ''stReturn'', selector: ';
  974. nextPutAll: currentSelector printString;
  975. nextPutAll: ', fn: function(){return ']
  976. ifFalse: [stream nextPutAll: 'return '].
  977. aNode nodes do: [:each |
  978. self visit: each].
  979. earlyReturn ifTrue: [
  980. stream nextPutAll: '}})})()']
  981. !
  982. visitSendNode: aNode
  983. | str receiver superSend inlined |
  984. str := stream.
  985. (messageSends includes: aNode selector) ifFalse: [
  986. messageSends add: aNode selector].
  987. stream := '' writeStream.
  988. self visit: aNode receiver.
  989. superSend := stream contents = 'super'.
  990. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  991. stream := str.
  992. self performOptimizations
  993. ifTrue: [
  994. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
  995. (self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
  996. ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend)]
  997. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
  998. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
  999. !
  1000. visitCascadeNode: aNode
  1001. | index |
  1002. index := 0.
  1003. (tempVariables includes: '$rec') ifFalse: [
  1004. tempVariables add: '$rec'].
  1005. stream nextPutAll: '(function($rec){'.
  1006. aNode nodes do: [:each |
  1007. index := index + 1.
  1008. index = aNode nodes size ifTrue: [
  1009. stream nextPutAll: 'return '].
  1010. each receiver: (VariableNode new value: '$rec').
  1011. self visit: each.
  1012. stream nextPutAll: ';'].
  1013. stream nextPutAll: '})('.
  1014. self visit: aNode receiver.
  1015. stream nextPutAll: ')'
  1016. !
  1017. visitValueNode: aNode
  1018. stream nextPutAll: aNode value asJavascript
  1019. !
  1020. visitAssignmentNode: aNode
  1021. self visit: aNode left.
  1022. stream nextPutAll: '='.
  1023. self visit: aNode right
  1024. !
  1025. visitClassReferenceNode: aNode
  1026. | klass |
  1027. klass := '(smalltalk.', aNode value, ' || ', aNode value, ')'.
  1028. (Smalltalk current at: aNode value) isClass ifTrue: [
  1029. (referencedClasses includes: klass)
  1030. ifFalse: [referencedClasses add: klass]].
  1031. stream nextPutAll: klass
  1032. !
  1033. visitVariableNode: aNode
  1034. (self currentClass allInstanceVariableNames includes: aNode value)
  1035. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  1036. ifFalse: [
  1037. (self knownVariables includes: aNode value)
  1038. ifFalse: [
  1039. unknownVariables add: aNode value.
  1040. aNode assigned
  1041. ifTrue: [stream nextPutAll: aNode value]
  1042. ifFalse: [stream nextPutAll: '(typeof ', aNode value, ' == ''undefined'' ? nil : ', aNode value, ')']]
  1043. ifTrue: [
  1044. stream nextPutAll:aNode value]]
  1045. !
  1046. visitJSStatementNode: aNode
  1047. stream nextPutAll: (aNode source replace: '>>' with: '>')
  1048. !
  1049. visitFailure: aFailure
  1050. self error: aFailure asString
  1051. !
  1052. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  1053. ^String streamContents: [:str || tmp |
  1054. tmp := stream.
  1055. str nextPutAll: 'smalltalk.send('.
  1056. str nextPutAll: aReceiver.
  1057. str nextPutAll: ', "', aSelector asSelector, '", ['.
  1058. stream := str.
  1059. aCollection
  1060. do: [:each | self visit: each]
  1061. separatedBy: [stream nextPutAll: ', '].
  1062. stream := tmp.
  1063. str nextPutAll: ']'.
  1064. aBoolean ifTrue: [
  1065. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
  1066. str nextPutAll: ')']
  1067. ! !
  1068. Compiler class instanceVariableNames: 'performOptimizations'!
  1069. !Compiler class methodsFor: 'accessing'!
  1070. performOptimizations
  1071. ^performOptimizations ifNil: [true]
  1072. !
  1073. performOptimizations: aBoolean
  1074. performOptimizations := aBoolean
  1075. ! !
  1076. !Compiler class methodsFor: 'compiling'!
  1077. recompile: aClass
  1078. aClass methodDictionary do: [:each || method |
  1079. method := self new load: each source forClass: aClass.
  1080. method category: each category.
  1081. aClass addCompiledMethod: method].
  1082. aClass isMetaclass ifFalse: [self recompile: aClass class]
  1083. !
  1084. recompileAll
  1085. Smalltalk current classes do: [:each |
  1086. self recompile: each]
  1087. ! !
  1088. Object subclass: #DoIt
  1089. instanceVariableNames: ''
  1090. category: 'Compiler'!