Compiler-Core.st 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. Smalltalk createPackage: 'Compiler-Core'!
  2. (Smalltalk packageAt: 'Compiler-Core' ifAbsent: [ self error: 'Package not created: Compiler-Core' ]) imports: {'smalltalkParser' -> 'amber/parser'}!
  3. Object subclass: #AbstractCodeGenerator
  4. slots: {#currentClass. #currentPackage. #source}
  5. package: 'Compiler-Core'!
  6. !AbstractCodeGenerator commentStamp!
  7. I am the abstract super class of all code generators and provide their common API.!
  8. !AbstractCodeGenerator methodsFor: 'accessing'!
  9. currentClass
  10. ^ currentClass
  11. !
  12. currentClass: aClass
  13. currentClass := aClass
  14. !
  15. currentPackage
  16. ^ currentPackage
  17. !
  18. currentPackage: anObject
  19. currentPackage := anObject
  20. !
  21. pseudoVariables
  22. ^ Smalltalk pseudoVariableNames
  23. !
  24. source
  25. ^ source ifNil: [ '' ]
  26. !
  27. source: aString
  28. source := aString
  29. ! !
  30. !AbstractCodeGenerator methodsFor: 'compiling'!
  31. compileNode: aNode
  32. ^ self transformers
  33. inject: aNode
  34. into: [ :input :transformer | transformer value: input ]
  35. !
  36. transformers
  37. | dict |
  38. dict := self transformersDictionary.
  39. ^ dict keys asArray sort collect: [ :each | dict at: each ]
  40. !
  41. transformersDictionary
  42. self subclassResponsibility
  43. ! !
  44. AbstractCodeGenerator subclass: #CodeGenerator
  45. slots: {#transformersDictionary}
  46. package: 'Compiler-Core'!
  47. !CodeGenerator commentStamp!
  48. I am a basic code generator. I generate a valid JavaScript output, but no not perform any inlining.
  49. See `InliningCodeGenerator` for an optimized JavaScript code generation.!
  50. !CodeGenerator methodsFor: 'compiling'!
  51. earlyAstPragmator
  52. ^ AstEarlyPragmator new
  53. !
  54. irTranslator
  55. ^ self irTranslatorClass new
  56. currentClass: self currentClass;
  57. yourself
  58. !
  59. irTranslatorClass
  60. ^ IRJSTranslator
  61. !
  62. lateIRPragmator
  63. ^ IRLatePragmator new
  64. !
  65. semanticAnalyzer
  66. ^ (SemanticAnalyzer on: self currentClass)
  67. thePackage: self currentPackage;
  68. yourself
  69. !
  70. transformersDictionary
  71. ^ transformersDictionary ifNil: [ transformersDictionary := Dictionary new
  72. at: '1000-earlyPragmas' put: self earlyAstPragmator;
  73. at: '2000-semantic' put: self semanticAnalyzer;
  74. at: '5000-astToIr' put: self translator;
  75. at: '8000-irToJs' put: self irTranslator;
  76. at: '9000-latePragmas' put: self lateIRPragmator;
  77. yourself ]
  78. !
  79. translator
  80. ^ IRASTTranslator new
  81. source: self source;
  82. theClass: self currentClass;
  83. yourself
  84. ! !
  85. Object subclass: #Compiler
  86. slots: {#currentPackage. #codeGeneratorClass. #codeGenerator}
  87. package: 'Compiler-Core'!
  88. !Compiler commentStamp!
  89. I provide the public interface for compiling Amber source code into JavaScript.
  90. The code generator used to produce JavaScript can be plugged with `#codeGeneratorClass`.
  91. The default code generator is an instance of `InlinedCodeGenerator`!
  92. !Compiler methodsFor: 'accessing'!
  93. cleanCodeGenerator
  94. codeGenerator := nil
  95. !
  96. codeGenerator
  97. ^ codeGenerator
  98. !
  99. codeGenerator: anObject
  100. codeGenerator := anObject
  101. !
  102. codeGeneratorClass
  103. ^ codeGeneratorClass ifNil: [ InliningCodeGenerator ]
  104. !
  105. codeGeneratorClass: aClass
  106. codeGeneratorClass := aClass
  107. !
  108. currentPackage
  109. ^ currentPackage
  110. !
  111. currentPackage: anObject
  112. currentPackage := anObject
  113. ! !
  114. !Compiler methodsFor: 'compiling'!
  115. ast: aString forClass: aClass protocol: anotherString
  116. self
  117. start: aString forClass: aClass protocol: anotherString;
  118. transformerAt: '2500-astCheckpoint' put: [ :x | ^x ];
  119. compileNode: (self parse: aString);
  120. error: 'AST transformation failed.'
  121. !
  122. compile: aString forClass: aClass protocol: anotherString
  123. | compilationResult result pragmas closureFactory |
  124. compilationResult := self
  125. start: aString forClass: aClass protocol: anotherString;
  126. compileNode: (self parse: aString).
  127. closureFactory := self
  128. eval: (self wrappedSourceOf: compilationResult)
  129. forPackage: self currentPackage.
  130. result := Smalltalk core method: #{
  131. #selector -> compilationResult selector.
  132. #protocol -> anotherString.
  133. #source -> aString.
  134. #messageSends -> compilationResult messageSends asArray.
  135. #args -> compilationResult arguments asArray.
  136. #referencedClasses -> compilationResult classReferences asArray.
  137. } withFactory: closureFactory.
  138. result pragmas: compilationResult pragmas.
  139. ^ result
  140. !
  141. compileNode: aNode
  142. | result |
  143. result := self codeGenerator compileNode: aNode.
  144. self cleanCodeGenerator.
  145. ^ result
  146. !
  147. eval: aString
  148. <inlineJS: 'return eval(aString)'>
  149. !
  150. eval: aString forPackage: aPackage
  151. ^ aPackage
  152. ifNil: [ self eval: aString ]
  153. ifNotNil: [ aPackage eval: aString ]
  154. !
  155. evaluateExpression: aString
  156. "Unlike #eval: evaluate a Smalltalk expression and answer the returned object"
  157. ^ self evaluateExpression: aString on: DoIt new
  158. !
  159. evaluateExpression: aString on: anObject
  160. "Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object"
  161. | result method |
  162. method := self
  163. install: (self sourceForExpression: aString)
  164. forClass: anObject class
  165. protocol: '**xxxDoIt'.
  166. result := anObject xxxDoIt.
  167. anObject class removeCompiledMethod: method.
  168. ^ result
  169. !
  170. install: aString forClass: aBehavior protocol: anotherString
  171. | compiledMethod |
  172. compiledMethod := self compile: aString forClass: aBehavior protocol: anotherString.
  173. aBehavior addCompiledMethod: compiledMethod.
  174. ^ compiledMethod
  175. !
  176. parse: aString
  177. | result |
  178. [ result := self basicParse: aString ]
  179. tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].
  180. ^ result
  181. !
  182. parseExpression: aString
  183. ^ self parse: (self sourceForExpression: aString)
  184. !
  185. recompile: aClass
  186. aClass includingPossibleMetaDo: [ :eachSide |
  187. eachSide methodDictionary values
  188. do: [ :each | each origin = eachSide ifTrue: [
  189. self
  190. install: each source
  191. forClass: eachSide
  192. protocol: each protocol ] ]
  193. displayingProgress: 'Recompiling ', eachSide name ]
  194. !
  195. recompileAll
  196. Smalltalk classes
  197. do: [ :each | self recompile: each ]
  198. displayingProgress: 'Compiling all classes...'
  199. !
  200. sourceForExpression: aString
  201. ^ 'xxxDoIt ^ [ ', aString, ' ] value'
  202. !
  203. start: aString forClass: aClass protocol: anotherString
  204. | package |
  205. package := aClass packageOfProtocol: anotherString.
  206. self
  207. currentPackage: package;
  208. codeGenerator: (self codeGeneratorClass new
  209. source: aString;
  210. currentClass: aClass;
  211. currentPackage: package;
  212. yourself)
  213. !
  214. transformerAt: aString put: anObject
  215. self codeGenerator transformersDictionary at: aString put: anObject
  216. ! !
  217. !Compiler methodsFor: 'error handling'!
  218. error: aString
  219. CompilerError signal: aString
  220. !
  221. parseError: anException parsing: aString
  222. (anException basicAt: 'location')
  223. ifNil: [ ^ anException pass ]
  224. ifNotNil: [ :loc |
  225. ^ ParseError new
  226. messageText:
  227. 'Parse error on line ', loc start line ,
  228. ' column ' , loc start column ,
  229. ' : Unexpected character ', (anException basicAt: 'found');
  230. yourself ]
  231. ! !
  232. !Compiler methodsFor: 'private'!
  233. basicParse: aString
  234. ^ smalltalkParser parse: aString
  235. !
  236. wrappedSourceOf: anIRMethod
  237. anIRMethod attachments
  238. ifEmpty: [ ^
  239. '(function ($methodClass){ return ',
  240. anIRMethod compiledSource,
  241. '; })' ]
  242. ifNotEmpty: [ :attachments | ^
  243. '(function ($methodClass){ return (function(method){Object.defineProperty(method,"a$atx",{enumerable:false,configurable:true,writable:true,value:',
  244. attachments asJavaScriptSource,
  245. '});return method})(',
  246. anIRMethod compiledSource,
  247. '); })' ]
  248. ! !
  249. !Compiler class methodsFor: 'compiling'!
  250. recompile: aClass
  251. self new recompile: aClass
  252. !
  253. recompileAll
  254. Smalltalk classes do: [ :each |
  255. self recompile: each ]
  256. ! !
  257. !Compiler class methodsFor: 'evaluating'!
  258. eval: aString
  259. ^ self new eval: aString
  260. ! !
  261. !Compiler class methodsFor: 'initialization'!
  262. initialize
  263. "TODO remove, backward compat"
  264. Smalltalk globals at: #SmalltalkParser put: smalltalkParser
  265. ! !
  266. !Compiler class methodsFor: 'parsing'!
  267. parse: aString
  268. ^ self new parse: aString
  269. !
  270. pseudoVariableNames
  271. ^ PseudoVar dictionary keys asArray
  272. ! !
  273. Object subclass: #DoIt
  274. slots: {}
  275. package: 'Compiler-Core'!
  276. !DoIt commentStamp!
  277. `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
  278. Object subclass: #Evaluator
  279. slots: {}
  280. package: 'Compiler-Core'!
  281. !Evaluator commentStamp!
  282. I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
  283. !Evaluator methodsFor: 'evaluating'!
  284. evaluate: aString context: aContext
  285. "Similar to #evaluate:for:, with the following differences:
  286. - instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
  287. - instead of evaluating against a receiver, evaluate in the context of `aContext`"
  288. | compiler ast |
  289. compiler := Compiler new.
  290. [ ast := compiler parseExpression: aString ]
  291. on: Error
  292. do: [ :ex | ^ Terminal alert: ex messageText ].
  293. (AISemanticAnalyzer on: aContext receiver class)
  294. context: aContext;
  295. visit: ast.
  296. ^ aContext evaluateNode: ast
  297. !
  298. evaluate: aString for: anObject
  299. ^ anObject evaluate: aString on: self
  300. !
  301. evaluate: aString receiver: anObject
  302. | compiler |
  303. compiler := Compiler new.
  304. [ compiler parseExpression: aString ]
  305. on: Error
  306. do: [ :ex | ^ Terminal alert: ex messageText ].
  307. ^ compiler evaluateExpression: aString on: anObject
  308. ! !
  309. !Evaluator class methodsFor: 'instance creation'!
  310. evaluate: aString for: anObject
  311. ^ self new evaluate: aString for: anObject
  312. ! !
  313. Error subclass: #ParseError
  314. slots: {}
  315. package: 'Compiler-Core'!
  316. !ParseError commentStamp!
  317. Instance of ParseError are signaled on any parsing error.
  318. See `Compiler >> #parse:`!
  319. !String methodsFor: '*Compiler-Core'!
  320. asVariableName
  321. ^ (Smalltalk reservedWords includes: self)
  322. ifTrue: [ self, '_' ]
  323. ifFalse: [ self ]
  324. ! !