Compiler.st 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. Object subclass: #Node instanceVariableNames: 'nodes' category: 'Compiler'! !Node methodsFor: 'accessing'! nodes
  2. ^nodes ifNil: [nodes := Array new]
  3. ! addNode: aNode
  4. self nodes add: aNode
  5. ! ! !Node methodsFor: 'building'! nodes: aCollection
  6. nodes := aCollection
  7. ! ! !Node methodsFor: 'visiting'! accept: aVisitor
  8. aVisitor visitNode: self
  9. ! ! Node subclass: #MethodNode instanceVariableNames: 'selector, arguments, source' category: 'Compiler'! !MethodNode methodsFor: 'accessing'! selector
  10. ^selector
  11. ! selector: aString
  12. selector := aString
  13. ! arguments
  14. ^arguments ifNil: [#()]
  15. ! arguments: aCollection
  16. arguments := aCollection
  17. ! source
  18. ^source
  19. ! source: aString
  20. source := aString
  21. ! ! !MethodNode methodsFor: 'visiting'! accept: aVisitor
  22. aVisitor visitMethodNode: self
  23. ! ! Node subclass: #SendNode instanceVariableNames: 'selector, arguments, receiver' category: 'Compiler'! !SendNode methodsFor: 'accessing'! selector
  24. ^selector
  25. ! selector: aString
  26. selector := aString
  27. ! arguments
  28. ^arguments ifNil: [arguments := #()]
  29. ! arguments: aCollection
  30. arguments := aCollection
  31. ! receiver
  32. ^receiver
  33. ! receiver: aNode
  34. receiver := aNode
  35. ! valueForReceiver: anObject
  36. ^SendNode new
  37. receiver: (self receiver
  38. ifNil: [anObject]
  39. ifNotNil: [self receiver valueForReceiver: anObject]);
  40. selector: self selector;
  41. arguments: self arguments;
  42. yourself
  43. ! cascadeNodeWithMessages: aCollection
  44. | first |
  45. first := SendNode new
  46. selector: self selector;
  47. arguments: self arguments;
  48. yourself.
  49. ^CascadeNode new
  50. receiver: self receiver;
  51. nodes: (Array with: first), aCollection;
  52. yourself
  53. ! ! !SendNode methodsFor: 'visiting'! accept: aVisitor
  54. aVisitor visitSendNode: self
  55. ! ! Node subclass: #CascadeNode instanceVariableNames: 'receiver' category: 'Compiler'! !CascadeNode methodsFor: 'accessing'! receiver
  56. ^receiver
  57. ! receiver: aNode
  58. receiver := aNode
  59. ! ! !CascadeNode methodsFor: 'visiting'! accept: aVisitor
  60. aVisitor visitCascadeNode: self
  61. ! ! Node subclass: #AssignmentNode instanceVariableNames: 'left, right' category: 'Compiler'! !AssignmentNode methodsFor: 'accessing'! left
  62. ^left
  63. ! left: aNode
  64. left := aNode
  65. ! right
  66. ^right
  67. ! right: aNode
  68. right := aNode
  69. ! ! !AssignmentNode methodsFor: 'visiting'! accept: aVisitor
  70. aVisitor visitAssignmentNode: self
  71. ! ! Node subclass: #BlockNode instanceVariableNames: 'parameters' category: 'Compiler'! !BlockNode methodsFor: 'accessing'! parameters
  72. ^parameters ifNil: [parameters := Array new]
  73. ! parameters: aCollection
  74. parameters := aCollection
  75. ! ! !BlockNode methodsFor: 'visiting'! accept: aVisitor
  76. aVisitor visitBlockNode: self
  77. ! ! Node subclass: #SequenceNode instanceVariableNames: 'temps' category: 'Compiler'! !SequenceNode methodsFor: 'accessing'! temps
  78. ^temps ifNil: [#()]
  79. ! temps: aCollection
  80. temps := aCollection
  81. ! ! !SequenceNode methodsFor: 'testing'! asBlockSequenceNode
  82. ^BlockSequenceNode new
  83. nodes: self nodes;
  84. temps: self temps;
  85. yourself
  86. ! ! !SequenceNode methodsFor: 'visiting'! accept: aVisitor
  87. aVisitor visitSequenceNode: self
  88. ! ! SequenceNode subclass: #BlockSequenceNode instanceVariableNames: '' category: 'Compiler'! !BlockSequenceNode methodsFor: 'visiting'! accept: aVisitor
  89. aVisitor visitBlockSequenceNode: self
  90. ! ! Node subclass: #ReturnNode instanceVariableNames: '' category: 'Compiler'! !ReturnNode methodsFor: 'visiting'! accept: aVisitor
  91. aVisitor visitReturnNode: self
  92. ! ! Node subclass: #ValueNode instanceVariableNames: 'value' category: 'Compiler'! !ValueNode methodsFor: 'accessing'! value
  93. ^value
  94. ! value: anObject
  95. value := anObject
  96. ! ! !ValueNode methodsFor: 'visiting'! accept: aVisitor
  97. aVisitor visitValueNode: self
  98. ! ! ValueNode subclass: #VariableNode instanceVariableNames: '' category: 'Compiler'! !VariableNode methodsFor: 'visiting'! accept: aVisitor
  99. aVisitor visitVariableNode: self
  100. ! ! VariableNode subclass: #ClassReferenceNode instanceVariableNames: '' category: 'Compiler'! !ClassReferenceNode methodsFor: 'visiting'! accept: aVisitor
  101. aVisitor visitClassReferenceNode: self
  102. ! ! Node subclass: #JSStatementNode instanceVariableNames: 'source' category: 'Compiler'! !JSStatementNode methodsFor: 'accessing'! source
  103. ^source ifNil: ['']
  104. ! source: aString
  105. source := aString
  106. ! ! !JSStatementNode methodsFor: 'visiting'! accept: aVisitor
  107. aVisitor visitJSStatementNode: self
  108. ! ! Object subclass: #NodeVisitor instanceVariableNames: '' category: 'Compiler'! !NodeVisitor methodsFor: 'visiting'! visit: aNode
  109. aNode accept: self
  110. ! visitNode: aNode
  111. ! visitMethodNode: aNode
  112. self visitNode: aNode
  113. ! visitSequenceNode: aNode
  114. self visitNode: aNode
  115. ! visitBlockSequenceNode: aNode
  116. self visitSequenceNode: aNode
  117. ! visitBlockNode: aNode
  118. self visitNode: aNode
  119. ! visitReturnNode: aNode
  120. self visitNode: aNode
  121. ! visitSendNode: aNode
  122. self visitNode: aNode
  123. ! visitCascadeNode: aNode
  124. self visitNode: aNode
  125. ! visitValueNode: aNode
  126. self visitNode: aNode
  127. ! visitVariableNode: aNode
  128. ! visitAssignmentNode: aNode
  129. self visitNode: aNode
  130. ! visitClassReferenceNode: aNode
  131. self
  132. nextPutAll: 'smalltalk.';
  133. nextPutAll: aNode value
  134. ! visitJSStatementNode: aNode
  135. self
  136. nextPutAll: 'function(){';
  137. nextPutAll: aNode source;
  138. nextPutAll: '})()'
  139. ! ! NodeVisitor subclass: #Compiler instanceVariableNames: 'stream, nestedBlocks, earlyReturn, currentClass, currentSelector, unknownVariables, tempVariables, messageSends, referencedClasses' category: 'Compiler'! !Compiler methodsFor: 'accessing'! parser
  140. ^SmalltalkParser new
  141. ! currentClass
  142. ^currentClass
  143. ! currentClass: aClass
  144. currentClass := aClass
  145. ! unknownVariables
  146. ^unknownVariables copy ! pseudoVariables
  147. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext') ! tempVariables
  148. ^tempVariables copy ! knownVariables
  149. ^self pseudoVariables
  150. addAll: self tempVariables;
  151. yourself ! classNameFor: aClass
  152. ^aClass isMetaclass
  153. ifTrue: [aClass instanceClass name, '.klass']
  154. ifFalse: [
  155. aClass isNil
  156. ifTrue: ['nil']
  157. ifFalse: [aClass name]] ! ! !Compiler methodsFor: 'compiling'! loadExpression: aString
  158. DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
  159. ^DoIt new doIt
  160. ! load: aString forClass: aClass
  161. ^self eval: (self compile: aString forClass: aClass)
  162. ! compile: aString forClass: aClass
  163. self currentClass: aClass.
  164. ^self compile: aString ! compileExpression: aString
  165. self currentClass: DoIt.
  166. ^self compileNode: (self parseExpression: aString)
  167. ! eval: aString
  168. {'return eval(aString)'} ! compile: aString
  169. ^self compileNode: (self parse: aString)
  170. ! compileNode: aNode
  171. stream := '' writeStream.
  172. self visit: aNode.
  173. ^stream contents
  174. ! parse: aString
  175. ^self parser parse: aString readStream
  176. ! parseExpression: aString
  177. ^self parse: 'doIt ^[', aString, '] value'
  178. ! recompile: aClass
  179. aClass methodDictionary do: [:each || method |
  180. method := self load: each source forClass: aClass.
  181. method category: each category.
  182. aClass addCompiledMethod: method].
  183. aClass isMetaclass ifFalse: [self recompile: aClass class] ! recompileAll
  184. Smalltalk current classes do: [:each |
  185. self recompile: each] ! ! !Compiler methodsFor: 'initialization'! initialize
  186. super initialize.
  187. stream := '' writeStream.
  188. unknownVariables := #().
  189. tempVariables := #().
  190. messageSends := #().
  191. classReferenced := #()
  192. ! ! !Compiler methodsFor: 'visiting'! visit: aNode
  193. aNode accept: self
  194. ! visitMethodNode: aNode
  195. | str currentSelector |
  196. currentSelector := aNode selector asSelector.
  197. nestedBlocks := 0.
  198. earlyReturn := false.
  199. messageSends := #().
  200. referencedClasses := #().
  201. unknownVariables := #().
  202. tempVariables := #().
  203. stream
  204. nextPutAll: 'smalltalk.method({', String cr;
  205. nextPutAll: 'selector: "', aNode selector, '",', String cr.
  206. Smalltalk current debugMode ifTrue: [
  207. stream nextPutAll: 'source: unescape("', aNode source escaped, '"),', String cr].
  208. stream nextPutAll: 'fn: function('.
  209. aNode arguments
  210. do: [:each |
  211. tempVariables add: each.
  212. stream nextPutAll: each]
  213. separatedBy: [stream nextPutAll: ', '].
  214. stream
  215. nextPutAll: '){', String cr;
  216. nextPutAll: 'var self=this;', String cr.
  217. str := stream.
  218. stream := '' writeStream.
  219. aNode nodes do: [:each |
  220. self visit: each].
  221. earlyReturn ifTrue: [
  222. str nextPutAll: 'try{'].
  223. str nextPutAll: stream contents.
  224. stream := str.
  225. stream
  226. nextPutAll: String cr;
  227. nextPutAll: 'return self;'.
  228. earlyReturn ifTrue: [
  229. stream nextPutAll: String cr, '} catch(e) {if(e.name === ''stReturn'' && e.selector === ', currentSelector printString, '){return e.fn()} throw(e)}'].
  230. stream nextPutAll: '}'.
  231. Smalltalk current debugMode ifTrue: [
  232. stream
  233. nextPutAll: ',', String cr, 'messageSends: ';
  234. nextPutAll: messageSends asJavascript, ',', String cr;
  235. nextPutAll: 'referencedClasses: ['.
  236. referencedClasses
  237. do: [:each | stream nextPutAll: each]
  238. separatedBy: [stream nextPutAll: ','].
  239. stream nextPutAll: ']'].
  240. stream nextPutAll: '})' ! visitBlockNode: aNode
  241. stream nextPutAll: '(function('.
  242. aNode parameters
  243. do: [:each |
  244. tempVariables add: each.
  245. stream nextPutAll: each]
  246. separatedBy: [stream nextPutAll: ', '].
  247. stream nextPutAll: '){'.
  248. aNode nodes do: [:each | self visit: each].
  249. stream nextPutAll: '})'
  250. ! visitSequenceNode: aNode
  251. aNode temps do: [:each |
  252. tempVariables add: each.
  253. stream nextPutAll: 'var ', each, '=nil;'.
  254. stream nextPutAll: String cr].
  255. aNode nodes do: [:each |
  256. self visit: each.
  257. stream nextPutAll: ';']
  258. separatedBy: [stream nextPutAll: String cr]
  259. ! visitBlockSequenceNode: aNode
  260. | index |
  261. nestedBlocks := nestedBlocks + 1.
  262. aNode nodes isEmpty
  263. ifTrue: [
  264. stream nextPutAll: 'return nil;']
  265. ifFalse: [
  266. aNode temps do: [:each |
  267. tempVariables add: each.
  268. stream nextPutAll: 'var ', each, '=nil;'.
  269. stream nextPutAll: String cr].
  270. index := 0.
  271. aNode nodes do: [:each |
  272. index := index + 1.
  273. index = aNode nodes size ifTrue: [
  274. stream nextPutAll: 'return '].
  275. self visit: each.
  276. stream nextPutAll: ';']].
  277. nestedBlocks := nestedBlocks - 1
  278. ! visitReturnNode: aNode
  279. nestedBlocks > 0 ifTrue: [
  280. earlyReturn := true].
  281. earlyReturn
  282. ifTrue: [
  283. stream
  284. nextPutAll: '(function(){throw(';
  285. nextPutAll: '{name: ''stReturn'', selector: ';
  286. nextPutAll: currentSelector printString;
  287. nextPutAll: ', fn: function(){return ']
  288. ifFalse: [stream nextPutAll: 'return '].
  289. aNode nodes do: [:each |
  290. self visit: each].
  291. earlyReturn ifTrue: [
  292. stream nextPutAll: '}})})()'] ! visitSendNode: aNode
  293. | str receiver superSend |
  294. str := stream.
  295. (messageSends includes: aNode selector) ifFalse: [
  296. messageSends add: aNode selector].
  297. stream := '' writeStream.
  298. self visit: aNode receiver.
  299. superSend := stream contents = 'super'.
  300. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  301. str nextPutAll: 'smalltalk.send('.
  302. str nextPutAll: receiver.
  303. stream := str.
  304. stream nextPutAll: ', "', aNode selector asSelector, '", ['.
  305. aNode arguments
  306. do: [:each | self visit: each]
  307. separatedBy: [stream nextPutAll: ', '].
  308. stream nextPutAll: ']'.
  309. superSend ifTrue: [
  310. stream nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
  311. stream nextPutAll: ')' ! visitCascadeNode: aNode
  312. | index |
  313. index := 0.
  314. (tempVariables includes: '$rec') ifFalse: [
  315. tempVariables add: '$rec'].
  316. stream nextPutAll: '(function($rec){'.
  317. aNode nodes do: [:each |
  318. index := index + 1.
  319. index = aNode nodes size ifTrue: [
  320. stream nextPutAll: 'return '].
  321. each receiver: (VariableNode new value: '$rec').
  322. self visit: each.
  323. stream nextPutAll: ';'].
  324. stream nextPutAll: '})('.
  325. self visit: aNode receiver.
  326. stream nextPutAll: ')'
  327. ! visitValueNode: aNode
  328. stream nextPutAll: aNode value asJavascript
  329. ! visitAssignmentNode: aNode
  330. self visit: aNode left.
  331. stream nextPutAll: '='.
  332. self visit: aNode right
  333. ! visitClassReferenceNode: aNode
  334. | klass |
  335. klass := 'smalltalk.', aNode value.
  336. (Smalltalk current at: aNode value) isClass ifTrue: [
  337. (referencedClasses includes: klass)
  338. ifFalse: [referencedClasses add: klass]].
  339. stream nextPutAll: klass ! visitVariableNode: aNode
  340. (self currentClass instanceVariableNames includes: aNode value)
  341. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  342. ifFalse: [
  343. (self knownVariables includes: aNode value) ifFalse: [
  344. unknownVariables add: aNode value].
  345. stream nextPutAll: aNode value]
  346. ! visitJSStatementNode: aNode
  347. stream nextPutAll: (aNode source value replace: '''''' with: '''') ! ! !Compiler class methodsFor: 'compiling'! recompile: aClass
  348. aClass methodDictionary do: [:each || method |
  349. method := self new load: each source forClass: aClass.
  350. method category: each category.
  351. aClass addCompiledMethod: method].
  352. aClass isMetaclass ifFalse: [self recompile: aClass class] ! recompileAll
  353. Smalltalk current classes do: [:each |
  354. self recompile: each] ! ! Object subclass: #DoIt instanceVariableNames: '' category: 'Compiler'! !DoIt methodsFor: ''! doIt ^[ChunkExporter new exportCategory: 'Parser' ] value ! !