Compiler-Core.st 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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 wrappedJs result pragmas closureFactory |
  124. compilationResult := self
  125. start: aString forClass: aClass protocol: anotherString;
  126. compileNode: (self parse: aString).
  127. wrappedJs := compilationResult attachments
  128. ifEmpty: [ '(function ($methodClass){ return ', compilationResult compiledSource, '; })' ]
  129. ifNotEmpty: [ :attachments | '(function ($methodClass){ return (function(method){Object.defineProperty(method,"a$atx",{enumerable:false,configurable:true,writable:true,value:', attachments asJavaScriptSource, '});return method})(', compilationResult compiledSource, '); })' ].
  130. closureFactory := self
  131. eval: wrappedJs
  132. forPackage: self currentPackage.
  133. result := Smalltalk core method: #{
  134. #selector -> compilationResult selector.
  135. #protocol -> anotherString.
  136. #source -> compilationResult source.
  137. #messageSends -> compilationResult messageSends asArray.
  138. #args -> compilationResult arguments asArray.
  139. #referencedClasses -> compilationResult classReferences asArray.
  140. } withFactory: closureFactory.
  141. result pragmas: compilationResult pragmas.
  142. ^ result
  143. !
  144. compileNode: aNode
  145. | result |
  146. result := self codeGenerator compileNode: aNode.
  147. self cleanCodeGenerator.
  148. ^ result
  149. !
  150. eval: aString
  151. <inlineJS: 'return eval(aString)'>
  152. !
  153. eval: aString forPackage: aPackage
  154. ^ aPackage
  155. ifNil: [ self eval: aString ]
  156. ifNotNil: [ aPackage eval: aString ]
  157. !
  158. evaluateExpression: aString
  159. "Unlike #eval: evaluate a Smalltalk expression and answer the returned object"
  160. ^ self evaluateExpression: aString on: DoIt new
  161. !
  162. evaluateExpression: aString on: anObject
  163. "Unlike #eval: evaluate a Smalltalk expression with anObject as the receiver and answer the returned object"
  164. | result method |
  165. method := self
  166. install: (self sourceForExpression: aString)
  167. forClass: anObject class
  168. protocol: '**xxxDoIt'.
  169. result := anObject xxxDoIt.
  170. anObject class removeCompiledMethod: method.
  171. ^ result
  172. !
  173. install: aString forClass: aBehavior protocol: anotherString
  174. | compiledMethod |
  175. compiledMethod := self compile: aString forClass: aBehavior protocol: anotherString.
  176. aBehavior addCompiledMethod: compiledMethod.
  177. ^ compiledMethod
  178. !
  179. parse: aString
  180. | result |
  181. [ result := self basicParse: aString ]
  182. tryCatch: [ :ex | (self parseError: ex parsing: aString) signal ].
  183. ^ result
  184. !
  185. parseExpression: aString
  186. ^ self parse: (self sourceForExpression: aString)
  187. !
  188. recompile: aClass
  189. aClass includingPossibleMetaDo: [ :eachSide |
  190. eachSide methodDictionary values
  191. do: [ :each | each origin = eachSide ifTrue: [
  192. self
  193. install: each source
  194. forClass: eachSide
  195. protocol: each protocol ] ]
  196. displayingProgress: 'Recompiling ', eachSide name ]
  197. !
  198. recompileAll
  199. Smalltalk classes
  200. do: [ :each | self recompile: each ]
  201. displayingProgress: 'Compiling all classes...'
  202. !
  203. sourceForExpression: aString
  204. ^ 'xxxDoIt ^ [ ', aString, ' ] value'
  205. !
  206. start: aString forClass: aClass protocol: anotherString
  207. | package |
  208. package := aClass packageOfProtocol: anotherString.
  209. self
  210. currentPackage: package;
  211. codeGenerator: (self codeGeneratorClass new
  212. source: aString;
  213. currentClass: aClass;
  214. currentPackage: package;
  215. yourself)
  216. !
  217. transformerAt: aString put: anObject
  218. self codeGenerator transformersDictionary at: aString put: anObject
  219. ! !
  220. !Compiler methodsFor: 'error handling'!
  221. error: aString
  222. CompilerError signal: aString
  223. !
  224. parseError: anException parsing: aString
  225. (anException basicAt: 'location')
  226. ifNil: [ ^ anException pass ]
  227. ifNotNil: [ :loc |
  228. ^ ParseError new
  229. messageText:
  230. 'Parse error on line ', loc start line ,
  231. ' column ' , loc start column ,
  232. ' : Unexpected character ', (anException basicAt: 'found');
  233. yourself ]
  234. ! !
  235. !Compiler methodsFor: 'private'!
  236. basicParse: aString
  237. ^ smalltalkParser parse: aString
  238. ! !
  239. !Compiler class methodsFor: 'compiling'!
  240. recompile: aClass
  241. self new recompile: aClass
  242. !
  243. recompileAll
  244. Smalltalk classes do: [ :each |
  245. self recompile: each ]
  246. ! !
  247. !Compiler class methodsFor: 'evaluating'!
  248. eval: aString
  249. ^ self new eval: aString
  250. ! !
  251. !Compiler class methodsFor: 'initialization'!
  252. initialize
  253. "TODO remove, backward compat"
  254. Smalltalk globals at: #SmalltalkParser put: smalltalkParser
  255. ! !
  256. !Compiler class methodsFor: 'parsing'!
  257. parse: aString
  258. ^ self new parse: aString
  259. !
  260. pseudoVariableNames
  261. ^ PseudoVar dictionary keys asArray
  262. ! !
  263. Object subclass: #DoIt
  264. slots: {}
  265. package: 'Compiler-Core'!
  266. !DoIt commentStamp!
  267. `DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!
  268. Object subclass: #Evaluator
  269. slots: {}
  270. package: 'Compiler-Core'!
  271. !Evaluator commentStamp!
  272. I evaluate code against a receiver, dispatching #evaluate:on: to the receiver.!
  273. !Evaluator methodsFor: 'evaluating'!
  274. evaluate: aString context: aContext
  275. "Similar to #evaluate:for:, with the following differences:
  276. - instead of compiling and running `aString`, `aString` is interpreted using an `ASTInterpreter`
  277. - instead of evaluating against a receiver, evaluate in the context of `aContext`"
  278. | compiler ast |
  279. compiler := Compiler new.
  280. [ ast := compiler parseExpression: aString ]
  281. on: Error
  282. do: [ :ex | ^ Terminal alert: ex messageText ].
  283. (AISemanticAnalyzer on: aContext receiver class)
  284. context: aContext;
  285. visit: ast.
  286. ^ aContext evaluateNode: ast
  287. !
  288. evaluate: aString for: anObject
  289. ^ anObject evaluate: aString on: self
  290. !
  291. evaluate: aString receiver: anObject
  292. | compiler |
  293. compiler := Compiler new.
  294. [ compiler parseExpression: aString ]
  295. on: Error
  296. do: [ :ex | ^ Terminal alert: ex messageText ].
  297. ^ compiler evaluateExpression: aString on: anObject
  298. ! !
  299. !Evaluator class methodsFor: 'instance creation'!
  300. evaluate: aString for: anObject
  301. ^ self new evaluate: aString for: anObject
  302. ! !
  303. Error subclass: #ParseError
  304. slots: {}
  305. package: 'Compiler-Core'!
  306. !ParseError commentStamp!
  307. Instance of ParseError are signaled on any parsing error.
  308. See `Compiler >> #parse:`!
  309. !String methodsFor: '*Compiler-Core'!
  310. asVariableName
  311. ^ (Smalltalk reservedWords includes: self)
  312. ifTrue: [ self, '_' ]
  313. ifFalse: [ self ]
  314. ! !