Compiler-Core.st 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. Smalltalk createPackage: 'Compiler-Core'!
  2. Object subclass: #AbstractCodeGenerator
  3. instanceVariableNames: '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. instanceVariableNames: '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. irTranslator
  51. ^ self irTranslatorClass new
  52. currentClass: self currentClass;
  53. yourself
  54. !
  55. irTranslatorClass
  56. ^ IRJSTranslator
  57. !
  58. semanticAnalyzer
  59. ^ (SemanticAnalyzer on: self currentClass)
  60. thePackage: self currentPackage;
  61. yourself
  62. !
  63. transformersDictionary
  64. ^ transformersDictionary ifNil: [ transformersDictionary := Dictionary new
  65. at: '1000-earlyPragmas' put: EarlyPragmator new;
  66. at: '2000-semantic' put: self semanticAnalyzer;
  67. at: '5000-astToIr' put: self translator;
  68. at: '8000-irToJs' put: self irTranslator;
  69. yourself ]
  70. !
  71. translator
  72. ^ IRASTTranslator new
  73. source: self source;
  74. theClass: self currentClass;
  75. yourself
  76. ! !
  77. Object subclass: #Compiler
  78. instanceVariableNames: 'currentClass currentPackage source codeGeneratorClass'
  79. package: 'Compiler-Core'!
  80. !Compiler commentStamp!
  81. I provide the public interface for compiling Amber source code into JavaScript.
  82. The code generator used to produce JavaScript can be plugged with `#codeGeneratorClass`.
  83. The default code generator is an instance of `InlinedCodeGenerator`!
  84. !Compiler methodsFor: 'accessing'!
  85. codeGeneratorClass
  86. ^ codeGeneratorClass ifNil: [ InliningCodeGenerator ]
  87. !
  88. codeGeneratorClass: aClass
  89. codeGeneratorClass := aClass
  90. !
  91. currentClass
  92. ^ currentClass
  93. !
  94. currentClass: aClass
  95. currentClass := aClass
  96. !
  97. currentPackage
  98. ^ currentPackage
  99. !
  100. currentPackage: anObject
  101. currentPackage := anObject
  102. !
  103. source
  104. ^ source ifNil: [ '' ]
  105. !
  106. source: aString
  107. source := aString
  108. ! !
  109. !Compiler methodsFor: 'compiling'!
  110. compile: aString forClass: aClass protocol: anotherString
  111. ^ self
  112. source: aString;
  113. compileNode: (self parse: aString)
  114. forClass: aClass
  115. package: (aClass packageOfProtocol: anotherString)
  116. !
  117. compileExpression: aString on: anObject
  118. ^ self
  119. compile: 'xxxDoIt ^ [ ', aString, ' ] value'
  120. forClass: anObject class
  121. protocol: '**xxxDoIt'
  122. !
  123. compileNode: aNode
  124. | generator result |
  125. generator := self codeGeneratorClass new.
  126. generator
  127. source: self source;
  128. currentClass: self currentClass;
  129. currentPackage: self currentPackage.
  130. result := generator compileNode: aNode.
  131. ^ result
  132. !
  133. compileNode: aNode forClass: aClass package: aPackage
  134. ^ self
  135. currentClass: aClass;
  136. currentPackage: aPackage;
  137. compileNode: aNode
  138. !
  139. eval: aString
  140. <inlineJS: 'return eval(aString)'>
  141. !
  142. eval: aString forPackage: aPackage
  143. ^ aPackage
  144. ifNil: [ self eval: aString ]
  145. ifNotNil: [ aPackage eval: aString ]
  146. !
  147. evaluateExpression: aString
  148. "Unlike #eval: evaluate a Smalltalk expression and answer the returned object"
  149. ^ self evaluateExpression: aString on: DoIt new
  150. !
  151. evaluateExpression: aString on: anObject
  152. "Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object"
  153. | result method |
  154. method := self eval: (self compileExpression: aString on: anObject).
  155. method protocol: '**xxxDoIt'.
  156. anObject class addCompiledMethod: method.
  157. result := anObject xxxDoIt.
  158. anObject class removeCompiledMethod: method.
  159. ^ result
  160. !
  161. install: aString forClass: aBehavior protocol: anotherString
  162. | compiledMethod |
  163. compiledMethod := self
  164. eval: (self compile: aString forClass: aBehavior protocol: anotherString)
  165. forPackage: (aBehavior packageOfProtocol: anotherString).
  166. ^ ClassBuilder new
  167. installMethod: compiledMethod
  168. forClass: aBehavior
  169. protocol: anotherString
  170. !
  171. parse: aString
  172. ^ Smalltalk parse: aString
  173. !
  174. parseExpression: aString
  175. ^ self parse: 'doIt ^ [ ', aString, ' ] value'
  176. !
  177. recompile: aClass
  178. aClass methodDictionary values
  179. do: [ :each | each methodClass = aClass ifTrue: [
  180. self
  181. install: each source
  182. forClass: aClass
  183. protocol: each protocol ] ]
  184. displayingProgress: 'Recompiling ', aClass name.
  185. aClass theMetaClass ifNotNil: [ :meta |
  186. meta = aClass ifFalse: [ self recompile: meta ] ]
  187. !
  188. recompileAll
  189. Smalltalk classes
  190. do: [ :each | self recompile: each ]
  191. displayingProgress: 'Compiling all classes...'
  192. ! !
  193. !Compiler class methodsFor: 'compiling'!
  194. recompile: aClass
  195. self new recompile: aClass
  196. !
  197. recompileAll
  198. Smalltalk classes do: [ :each |
  199. self recompile: each ]
  200. ! !
  201. !Compiler class methodsFor: 'evaluating'!
  202. eval: aString
  203. ^ self new eval: aString
  204. ! !
  205. Error subclass: #CompilerError
  206. instanceVariableNames: ''
  207. package: 'Compiler-Core'!
  208. !CompilerError commentStamp!
  209. I am the common superclass of all compiling errors.!
  210. Object subclass: #DoIt
  211. instanceVariableNames: ''
  212. package: 'Compiler-Core'!
  213. !DoIt commentStamp!
  214. `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
  215. Object subclass: #Evaluator
  216. instanceVariableNames: ''
  217. package: 'Compiler-Core'!
  218. !Evaluator commentStamp!
  219. I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
  220. !Evaluator methodsFor: 'evaluating'!
  221. evaluate: aString context: aContext
  222. "Similar to #evaluate:for:, with the following differences:
  223. - instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
  224. - instead of evaluating against a receiver, evaluate in the context of `aContext`"
  225. | compiler ast |
  226. compiler := Compiler new.
  227. [ ast := compiler parseExpression: aString ]
  228. on: Error
  229. do: [ :ex | ^ Terminal alert: ex messageText ].
  230. (AISemanticAnalyzer on: aContext receiver class)
  231. context: aContext;
  232. visit: ast.
  233. ^ aContext evaluateNode: ast
  234. !
  235. evaluate: aString for: anObject
  236. ^ anObject evaluate: aString on: self
  237. !
  238. evaluate: aString receiver: anObject
  239. | compiler |
  240. compiler := Compiler new.
  241. [ compiler parseExpression: aString ]
  242. on: Error
  243. do: [ :ex | ^ Terminal alert: ex messageText ].
  244. ^ compiler evaluateExpression: aString on: anObject
  245. ! !
  246. !Evaluator class methodsFor: 'instance creation'!
  247. evaluate: aString for: anObject
  248. ^ self new evaluate: aString for: anObject
  249. ! !
  250. !String methodsFor: '*Compiler-Core'!
  251. asVariableName
  252. ^ (Smalltalk reservedWords includes: self)
  253. ifTrue: [ self, '_' ]
  254. ifFalse: [ self ]
  255. ! !