Compiler-Core.st 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. Smalltalk createPackage: 'Compiler-Core'!
  2. Object subclass: #AbstractCodeGenerator
  3. instanceVariableNames: 'currentClass source'
  4. package: 'Compiler-Core'!
  5. !AbstractCodeGenerator commentStamp!
  6. I am the abstract super class of all code generators and provide their common API.!
  7. !AbstractCodeGenerator methodsFor: 'accessing'!
  8. classNameFor: aClass
  9. ^ aClass isMetaclass
  10. ifTrue: [ aClass instanceClass name, '.klass' ]
  11. ifFalse: [
  12. aClass isNil
  13. ifTrue: [ 'nil' ]
  14. ifFalse: [ aClass name ]]
  15. !
  16. currentClass
  17. ^ currentClass
  18. !
  19. currentClass: aClass
  20. currentClass := aClass
  21. !
  22. pseudoVariables
  23. ^ Smalltalk pseudoVariableNames
  24. !
  25. source
  26. ^ source ifNil: [ '' ]
  27. !
  28. source: aString
  29. source := aString
  30. ! !
  31. !AbstractCodeGenerator methodsFor: 'compiling'!
  32. compileNode: aNode
  33. self subclassResponsibility
  34. ! !
  35. AbstractCodeGenerator subclass: #CodeGenerator
  36. instanceVariableNames: ''
  37. package: 'Compiler-Core'!
  38. !CodeGenerator commentStamp!
  39. I am a basic code generator. I generate a valid JavaScript output, but no not perform any inlining.
  40. See `InliningCodeGenerator` for an optimized JavaScript code generation.!
  41. !CodeGenerator methodsFor: 'compiling'!
  42. compileNode: aNode
  43. | ir stream |
  44. self semanticAnalyzer visit: aNode.
  45. ir := self translator visit: aNode.
  46. ^ self irTranslator
  47. currentClass: self currentClass;
  48. visit: ir;
  49. contents
  50. !
  51. irTranslator
  52. ^ IRJSTranslator new
  53. !
  54. semanticAnalyzer
  55. ^ SemanticAnalyzer on: self currentClass
  56. !
  57. translator
  58. ^ IRASTTranslator new
  59. source: self source;
  60. theClass: self currentClass;
  61. yourself
  62. ! !
  63. Object subclass: #Compiler
  64. instanceVariableNames: 'currentClass source unknownVariables codeGeneratorClass'
  65. package: 'Compiler-Core'!
  66. !Compiler commentStamp!
  67. I provide the public interface for compiling Amber source code into JavaScript.
  68. The code generator used to produce JavaScript can be plugged with `#codeGeneratorClass`.
  69. The default code generator is an instance of `InlinedCodeGenerator`!
  70. !Compiler methodsFor: 'accessing'!
  71. codeGeneratorClass
  72. ^ codeGeneratorClass ifNil: [ InliningCodeGenerator ]
  73. !
  74. codeGeneratorClass: aClass
  75. codeGeneratorClass := aClass
  76. !
  77. currentClass
  78. ^ currentClass
  79. !
  80. currentClass: aClass
  81. currentClass := aClass
  82. !
  83. source
  84. ^ source ifNil: [ '' ]
  85. !
  86. source: aString
  87. source := aString
  88. !
  89. unknownVariables
  90. ^ unknownVariables
  91. !
  92. unknownVariables: aCollection
  93. unknownVariables := aCollection
  94. ! !
  95. !Compiler methodsFor: 'compiling'!
  96. compile: aString
  97. ^ self compileNode: (self parse: aString)
  98. !
  99. compile: aString forClass: aClass
  100. self currentClass: aClass.
  101. self source: aString.
  102. ^ self compile: aString
  103. !
  104. compileExpression: aString
  105. self currentClass: DoIt.
  106. self source: 'doIt ^ [ ', aString, ' ] value'.
  107. ^ self compileNode: (self parse: self source)
  108. !
  109. compileExpression: aString on: anObject
  110. self currentClass: anObject class.
  111. self source: 'xxxDoIt ^ [ ', aString, ' ] value'.
  112. ^ self compileNode: (self parse: self source)
  113. !
  114. compileNode: aNode
  115. | generator result |
  116. generator := self codeGeneratorClass new.
  117. generator
  118. source: self source;
  119. currentClass: self currentClass.
  120. result := generator compileNode: aNode.
  121. self unknownVariables: #().
  122. ^ result
  123. !
  124. eval: aString
  125. <return eval(aString)>
  126. !
  127. eval: aString forPackage: aPackage
  128. <return aPackage && aPackage.innerEval
  129. ? aPackage.innerEval(aString)
  130. : eval(aString)>
  131. !
  132. evaluateExpression: aString
  133. "Unlike #eval: evaluate a Smalltalk expression and answer the returned object"
  134. ^ self evaluateExpression: aString on: DoIt new
  135. !
  136. evaluateExpression: aString on: anObject
  137. "Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object"
  138. | result method |
  139. method := self eval: (self compileExpression: aString on: anObject).
  140. method protocol: '**xxxDoIt'.
  141. anObject class addCompiledMethod: method.
  142. result := anObject xxxDoIt.
  143. anObject class removeCompiledMethod: method.
  144. ^ result
  145. !
  146. install: aString forClass: aBehavior protocol: anotherString
  147. | compiledMethod |
  148. compiledMethod := self
  149. eval: (self compile: aString forClass: aBehavior)
  150. forPackage: (aBehavior packageOfProtocol: anotherString).
  151. ^ ClassBuilder new
  152. installMethod: compiledMethod
  153. forClass: aBehavior
  154. protocol: anotherString
  155. !
  156. parse: aString
  157. ^ Smalltalk parse: aString
  158. !
  159. parseExpression: aString
  160. ^ self parse: 'doIt ^ [ ', aString, ' ] value'
  161. !
  162. recompile: aClass
  163. aClass methodDictionary values
  164. do: [ :each |
  165. self
  166. install: each source
  167. forClass: aClass
  168. protocol: each protocol ]
  169. displayingProgress: 'Recompiling ', aClass name.
  170. aClass isMetaclass ifFalse: [ self recompile: aClass class ]
  171. !
  172. recompileAll
  173. Smalltalk classes
  174. do: [ :each | self recompile: each ]
  175. displayingProgress: 'Compiling all classes...'
  176. ! !
  177. !Compiler class methodsFor: 'compiling'!
  178. recompile: aClass
  179. self new recompile: aClass
  180. !
  181. recompileAll
  182. Smalltalk classes do: [ :each |
  183. self recompile: each ]
  184. ! !
  185. Object subclass: #DoIt
  186. instanceVariableNames: ''
  187. package: 'Compiler-Core'!
  188. !DoIt commentStamp!
  189. `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
  190. InterfacingObject subclass: #Evaluator
  191. instanceVariableNames: ''
  192. package: 'Compiler-Core'!
  193. !Evaluator commentStamp!
  194. I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
  195. !Evaluator methodsFor: 'evaluating'!
  196. evaluate: aString context: aContext
  197. "Similar to #evaluate:for:, with the following differences:
  198. - instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
  199. - instead of evaluating against a receiver, evaluate in the context of `aContext`"
  200. | compiler ast |
  201. compiler := Compiler new.
  202. [ ast := compiler parseExpression: aString ]
  203. on: Error
  204. do: [ :ex | ^ self alert: ex messageText ].
  205. (AISemanticAnalyzer on: aContext receiver class)
  206. context: aContext;
  207. visit: ast.
  208. ^ aContext evaluateNode: ast
  209. !
  210. evaluate: aString for: anObject
  211. ^ anObject evaluate: aString on: self
  212. !
  213. evaluate: aString receiver: anObject
  214. | compiler |
  215. compiler := Compiler new.
  216. [ compiler parseExpression: aString ]
  217. on: Error
  218. do: [ :ex | ^ self alert: ex messageText ].
  219. ^ compiler evaluateExpression: aString on: anObject
  220. ! !
  221. !Evaluator class methodsFor: 'instance creation'!
  222. evaluate: aString for: anObject
  223. ^ self new evaluate: aString for: anObject
  224. ! !
  225. Object subclass: #NodeVisitor
  226. instanceVariableNames: ''
  227. package: 'Compiler-Core'!
  228. !NodeVisitor commentStamp!
  229. I am the abstract super class of all AST node visitors.!
  230. !NodeVisitor methodsFor: 'visiting'!
  231. visit: aNode
  232. ^ aNode accept: self
  233. !
  234. visitAll: aCollection
  235. ^ aCollection collect: [ :each | self visit: each ]
  236. !
  237. visitAssignmentNode: aNode
  238. ^ self visitNode: aNode
  239. !
  240. visitBlockNode: aNode
  241. ^ self visitNode: aNode
  242. !
  243. visitBlockSequenceNode: aNode
  244. ^ self visitSequenceNode: aNode
  245. !
  246. visitCascadeNode: aNode
  247. ^ self visitNode: aNode
  248. !
  249. visitDynamicArrayNode: aNode
  250. ^ self visitNode: aNode
  251. !
  252. visitDynamicDictionaryNode: aNode
  253. ^ self visitNode: aNode
  254. !
  255. visitJSStatementNode: aNode
  256. ^ self visitNode: aNode
  257. !
  258. visitMethodNode: aNode
  259. ^ self visitNode: aNode
  260. !
  261. visitNode: aNode
  262. ^ self visitAll: aNode nodes
  263. !
  264. visitReturnNode: aNode
  265. ^ self visitNode: aNode
  266. !
  267. visitSendNode: aNode
  268. ^ self visitNode: aNode
  269. !
  270. visitSequenceNode: aNode
  271. ^ self visitNode: aNode
  272. !
  273. visitValueNode: aNode
  274. ^ self visitNode: aNode
  275. !
  276. visitVariableNode: aNode
  277. ^ self visitNode: aNode
  278. ! !
  279. !String methodsFor: '*Compiler-Core'!
  280. asVariableName
  281. ^ (Smalltalk reservedWords includes: self)
  282. ifTrue: [ self, '_' ]
  283. ifFalse: [ self ]
  284. ! !