Compiler-Core.st 7.0 KB

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