Compiler-Core.st 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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. CompilerError signal: '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. Object subclass: #DoIt
  218. instanceVariableNames: ''
  219. package: 'Compiler-Core'!
  220. !DoIt commentStamp!
  221. `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
  222. Object subclass: #Evaluator
  223. instanceVariableNames: ''
  224. package: 'Compiler-Core'!
  225. !Evaluator commentStamp!
  226. I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
  227. !Evaluator methodsFor: 'evaluating'!
  228. evaluate: aString context: aContext
  229. "Similar to #evaluate:for:, with the following differences:
  230. - instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
  231. - instead of evaluating against a receiver, evaluate in the context of `aContext`"
  232. | compiler ast |
  233. compiler := Compiler new.
  234. [ ast := compiler parseExpression: aString ]
  235. on: Error
  236. do: [ :ex | ^ Terminal alert: ex messageText ].
  237. (AISemanticAnalyzer on: aContext receiver class)
  238. context: aContext;
  239. visit: ast.
  240. ^ aContext evaluateNode: ast
  241. !
  242. evaluate: aString for: anObject
  243. ^ anObject evaluate: aString on: self
  244. !
  245. evaluate: aString receiver: anObject
  246. | compiler |
  247. compiler := Compiler new.
  248. [ compiler parseExpression: aString ]
  249. on: Error
  250. do: [ :ex | ^ Terminal alert: ex messageText ].
  251. ^ compiler evaluateExpression: aString on: anObject
  252. ! !
  253. !Evaluator class methodsFor: 'instance creation'!
  254. evaluate: aString for: anObject
  255. ^ self new evaluate: aString for: anObject
  256. ! !
  257. NodeVisitor subclass: #Pragmator
  258. instanceVariableNames: 'methodNode sequenceNode'
  259. package: 'Compiler-Core'!
  260. !Pragmator commentStamp!
  261. I am abstract superclass for pragma-processing transformer.
  262. My subclasses should implement messages for each pragma
  263. they process. Pragma processing checks if a message is known
  264. to a class but not to its superclass. IOW, each and only those
  265. pragmas are processed which are defined as methods in the subclass.
  266. These messages can access sequence node in which
  267. a pragma occurred and its containing method node
  268. as `self sequenceNode` and `self methodNode`.
  269. See `EarlyPragmator` for an example.!
  270. !Pragmator methodsFor: 'accessing'!
  271. methodNode
  272. ^ methodNode
  273. !
  274. methodNode: anObject
  275. methodNode := anObject
  276. !
  277. sequenceNode
  278. ^ sequenceNode
  279. !
  280. sequenceNode: anObject
  281. sequenceNode := anObject
  282. ! !
  283. !Pragmator methodsFor: 'pragma processing'!
  284. canProcessPragma: aMessage
  285. | selector |
  286. selector := aMessage selector.
  287. ^ (self respondsTo: selector) and: [
  288. (self class superclass canUnderstand: selector) not]
  289. !
  290. processPragma: aMessage
  291. (self canProcessPragma: aMessage) ifTrue: [
  292. ^ aMessage sendTo: self ]
  293. !
  294. visitMethodNode: aNode
  295. self methodNode: aNode.
  296. ^ super visitMethodNode: aNode
  297. !
  298. visitSequenceNode: aNode
  299. self sequenceNode: aNode.
  300. aNode pragmas do: [ :each | self processPragma: each ].
  301. ^ super visitSequenceNode: aNode
  302. ! !
  303. Pragmator subclass: #EarlyPragmator
  304. instanceVariableNames: ''
  305. package: 'Compiler-Core'!
  306. !String methodsFor: '*Compiler-Core'!
  307. asVariableName
  308. ^ (Smalltalk reservedWords includes: self)
  309. ifTrue: [ self, '_' ]
  310. ifFalse: [ self ]
  311. ! !