Compiler-Core.st 7.5 KB

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