Compiler-Core.st 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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. NodeVisitor subclass: #Pragmator
  263. instanceVariableNames: 'methodNode sequenceNode'
  264. package: 'Compiler-Core'!
  265. !Pragmator commentStamp!
  266. I am abstract superclass for pragma-processing transformer.
  267. My subclasses should implement messages for each pragma
  268. they process. Pragma processing checks if a message is known
  269. to a class but not to its superclass. IOW, each and only those
  270. pragmas are processed which are defined as methods in the subclass.
  271. These messages can access sequence node in which
  272. a pragma occurred and its containing method node
  273. as `self sequenceNode` and `self methodNode`.
  274. See `EarlyPragmator` for an example.!
  275. !Pragmator methodsFor: 'accessing'!
  276. methodNode
  277. ^ methodNode
  278. !
  279. methodNode: anObject
  280. methodNode := anObject
  281. !
  282. sequenceNode
  283. ^ sequenceNode
  284. !
  285. sequenceNode: anObject
  286. sequenceNode := anObject
  287. ! !
  288. !Pragmator methodsFor: 'pragma processing'!
  289. canProcessPragma: aMessage
  290. | selector |
  291. selector := aMessage selector.
  292. ^ (self respondsTo: selector) and: [
  293. (self class superclass canUnderstand: selector) not]
  294. !
  295. processPragma: aMessage
  296. (self canProcessPragma: aMessage) ifTrue: [
  297. ^ aMessage sendTo: self ]
  298. !
  299. visitMethodNode: aNode
  300. self methodNode: aNode.
  301. ^ super visitMethodNode: aNode
  302. !
  303. visitSequenceNode: aNode
  304. self sequenceNode: aNode.
  305. aNode pragmas do: [ :each | self processPragma: each ].
  306. ^ super visitSequenceNode: aNode
  307. ! !
  308. Pragmator subclass: #EarlyPragmator
  309. instanceVariableNames: ''
  310. package: 'Compiler-Core'!
  311. !String methodsFor: '*Compiler-Core'!
  312. asVariableName
  313. ^ (Smalltalk reservedWords includes: self)
  314. ifTrue: [ self, '_' ]
  315. ifFalse: [ self ]
  316. ! !