Compiler-Core.st 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. Smalltalk createPackage: 'Compiler-Core'!
  2. Object subclass: #AbstractCodeGenerator
  3. slots: {#currentClass. #currentPackage. #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. currentClass
  9. ^ currentClass
  10. !
  11. currentClass: aClass
  12. currentClass := aClass
  13. !
  14. currentPackage
  15. ^ currentPackage
  16. !
  17. currentPackage: anObject
  18. currentPackage := anObject
  19. !
  20. pseudoVariables
  21. ^ Smalltalk pseudoVariableNames
  22. !
  23. source
  24. ^ source ifNil: [ '' ]
  25. !
  26. source: aString
  27. source := aString
  28. ! !
  29. !AbstractCodeGenerator methodsFor: 'compiling'!
  30. compileNode: aNode
  31. ^ self transformers
  32. inject: aNode
  33. into: [ :input :transformer | transformer value: input ]
  34. !
  35. transformers
  36. | dict |
  37. dict := self transformersDictionary.
  38. ^ dict keys asArray sort collect: [ :each | dict at: each ]
  39. !
  40. transformersDictionary
  41. self subclassResponsibility
  42. ! !
  43. AbstractCodeGenerator subclass: #CodeGenerator
  44. slots: {#transformersDictionary}
  45. package: 'Compiler-Core'!
  46. !CodeGenerator commentStamp!
  47. I am a basic code generator. I generate a valid JavaScript output, but no not perform any inlining.
  48. See `InliningCodeGenerator` for an optimized JavaScript code generation.!
  49. !CodeGenerator methodsFor: 'compiling'!
  50. earlyAstPragmator
  51. ^ AstEarlyPragmator new
  52. !
  53. irTranslator
  54. ^ self irTranslatorClass new
  55. currentClass: self currentClass;
  56. yourself
  57. !
  58. irTranslatorClass
  59. ^ IRJSTranslator
  60. !
  61. semanticAnalyzer
  62. ^ (SemanticAnalyzer on: self currentClass)
  63. thePackage: self currentPackage;
  64. yourself
  65. !
  66. transformersDictionary
  67. ^ transformersDictionary ifNil: [ transformersDictionary := Dictionary new
  68. at: '1000-earlyPragmas' put: self earlyAstPragmator;
  69. at: '2000-semantic' put: self semanticAnalyzer;
  70. at: '5000-astToIr' put: self translator;
  71. at: '8000-irToJs' put: self irTranslator;
  72. yourself ]
  73. !
  74. translator
  75. ^ IRASTTranslator new
  76. source: self source;
  77. theClass: self currentClass;
  78. yourself
  79. ! !
  80. Object subclass: #Compiler
  81. slots: {#currentClass. #currentPackage. #source. #codeGeneratorClass. #codeGenerator}
  82. package: 'Compiler-Core'!
  83. !Compiler commentStamp!
  84. I provide the public interface for compiling Amber source code into JavaScript.
  85. The code generator used to produce JavaScript can be plugged with `#codeGeneratorClass`.
  86. The default code generator is an instance of `InlinedCodeGenerator`!
  87. !Compiler methodsFor: 'accessing'!
  88. cleanCodeGenerator
  89. codeGenerator := nil
  90. !
  91. codeGenerator
  92. ^ codeGenerator ifNil: [ codeGenerator := self codeGeneratorClass new
  93. source: self source;
  94. currentClass: self currentClass;
  95. currentPackage: self currentPackage;
  96. yourself ]
  97. !
  98. codeGeneratorClass
  99. ^ codeGeneratorClass ifNil: [ InliningCodeGenerator ]
  100. !
  101. codeGeneratorClass: aClass
  102. codeGeneratorClass := aClass
  103. !
  104. currentClass
  105. ^ currentClass
  106. !
  107. currentClass: aClass
  108. currentClass := aClass
  109. !
  110. currentPackage
  111. ^ currentPackage
  112. !
  113. currentPackage: anObject
  114. currentPackage := anObject
  115. !
  116. source
  117. ^ source ifNil: [ '' ]
  118. !
  119. source: aString
  120. source := aString
  121. ! !
  122. !Compiler methodsFor: 'compiling'!
  123. ast: aString forClass: aClass protocol: anotherString
  124. self
  125. source: aString;
  126. forClass: aClass protocol: anotherString.
  127. self codeGenerator transformersDictionary at: '2500-astCheckpoint' put: [ :x | ^x ].
  128. self compileNode: (self parse: aString).
  129. CompilerError signal: 'AST transformation failed.'
  130. !
  131. compile: aString forClass: aClass protocol: anotherString
  132. | compilationResult result pragmas closure closureFactory |
  133. compilationResult :=
  134. self compileSource: aString forClass: aClass protocol: anotherString.
  135. pragmas := compilationResult removeKey: #pragmas.
  136. closure := (compilationResult removeKey: #fn ifAbsent: [])
  137. ifNotNil: [ :js | self eval: js forPackage: self currentPackage ].
  138. closureFactory := (compilationResult removeKey: #instantiateFn ifAbsent: [])
  139. ifNotNil: [ :js | self eval: js forPackage: self currentPackage ].
  140. result := Smalltalk core method: compilationResult.
  141. result protocol: anotherString; pragmas: pragmas.
  142. closure ifNotNil: [ result fn: closure ].
  143. closureFactory ifNotNil: [ result instantiateFn: closureFactory ].
  144. ^ result
  145. !
  146. compileExpression: aString on: anObject
  147. ^ self
  148. compile: 'xxxDoIt ^ [ ', aString, ' ] value'
  149. forClass: anObject class
  150. protocol: '**xxxDoIt'
  151. !
  152. compileNode: aNode
  153. | result |
  154. result := self codeGenerator compileNode: aNode.
  155. self cleanCodeGenerator.
  156. ^ result
  157. !
  158. compileSource: aString forClass: aClass protocol: anotherString
  159. ^ self
  160. source: aString;
  161. forClass: aClass protocol: anotherString;
  162. compileNode: (self parse: aString)
  163. !
  164. eval: aString
  165. <inlineJS: 'return eval(aString)'>
  166. !
  167. eval: aString forPackage: aPackage
  168. ^ aPackage
  169. ifNil: [ self eval: aString ]
  170. ifNotNil: [ aPackage eval: aString ]
  171. !
  172. evaluateExpression: aString
  173. "Unlike #eval: evaluate a Smalltalk expression and answer the returned object"
  174. ^ self evaluateExpression: aString on: DoIt new
  175. !
  176. evaluateExpression: aString on: anObject
  177. "Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object"
  178. | result method |
  179. method := self compileExpression: aString on: anObject.
  180. anObject class addCompiledMethod: method.
  181. result := anObject xxxDoIt.
  182. anObject class removeCompiledMethod: method.
  183. ^ result
  184. !
  185. forClass: aClass protocol: anotherString
  186. self
  187. currentPackage: (aClass packageOfProtocol: anotherString);
  188. currentClass: aClass
  189. !
  190. install: aString forClass: aBehavior protocol: anotherString
  191. | compiledMethod |
  192. compiledMethod := self compile: aString forClass: aBehavior protocol: anotherString.
  193. aBehavior addCompiledMethod: compiledMethod.
  194. ^ compiledMethod
  195. !
  196. parse: aString
  197. ^ Smalltalk parse: aString
  198. !
  199. parseExpression: aString
  200. ^ self parse: 'doIt ^ [ ', aString, ' ] value'
  201. !
  202. recompile: aClass
  203. aClass includingPossibleMetaDo: [ :eachSide |
  204. eachSide methodDictionary values
  205. do: [ :each | each origin = eachSide ifTrue: [
  206. self
  207. install: each source
  208. forClass: eachSide
  209. protocol: each protocol ] ]
  210. displayingProgress: 'Recompiling ', eachSide name ]
  211. !
  212. recompileAll
  213. Smalltalk classes
  214. do: [ :each | self recompile: each ]
  215. displayingProgress: 'Compiling all classes...'
  216. ! !
  217. !Compiler class methodsFor: 'compiling'!
  218. recompile: aClass
  219. self new recompile: aClass
  220. !
  221. recompileAll
  222. Smalltalk classes do: [ :each |
  223. self recompile: each ]
  224. ! !
  225. !Compiler class methodsFor: 'evaluating'!
  226. eval: aString
  227. ^ self new eval: aString
  228. ! !
  229. Object subclass: #DoIt
  230. slots: {}
  231. package: 'Compiler-Core'!
  232. !DoIt commentStamp!
  233. `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
  234. Object subclass: #Evaluator
  235. slots: {}
  236. package: 'Compiler-Core'!
  237. !Evaluator commentStamp!
  238. I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
  239. !Evaluator methodsFor: 'evaluating'!
  240. evaluate: aString context: aContext
  241. "Similar to #evaluate:for:, with the following differences:
  242. - instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
  243. - instead of evaluating against a receiver, evaluate in the context of `aContext`"
  244. | compiler ast |
  245. compiler := Compiler new.
  246. [ ast := compiler parseExpression: aString ]
  247. on: Error
  248. do: [ :ex | ^ Terminal alert: ex messageText ].
  249. (AISemanticAnalyzer on: aContext receiver class)
  250. context: aContext;
  251. visit: ast.
  252. ^ aContext evaluateNode: ast
  253. !
  254. evaluate: aString for: anObject
  255. ^ anObject evaluate: aString on: self
  256. !
  257. evaluate: aString receiver: anObject
  258. | compiler |
  259. compiler := Compiler new.
  260. [ compiler parseExpression: aString ]
  261. on: Error
  262. do: [ :ex | ^ Terminal alert: ex messageText ].
  263. ^ compiler evaluateExpression: aString on: anObject
  264. ! !
  265. !Evaluator class methodsFor: 'instance creation'!
  266. evaluate: aString for: anObject
  267. ^ self new evaluate: aString for: anObject
  268. ! !
  269. !String methodsFor: '*Compiler-Core'!
  270. asVariableName
  271. ^ (Smalltalk reservedWords includes: self)
  272. ifTrue: [ self, '_' ]
  273. ifFalse: [ self ]
  274. ! !