Compiler.st 35 KB

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