Compiler.st 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434
  1. Smalltalk current createPackage: 'Compiler' properties: #{}!
  2. Object subclass: #ChunkParser
  3. instanceVariableNames: 'stream'
  4. category: 'Compiler'!
  5. !ChunkParser methodsFor: 'accessing'!
  6. stream: aStream
  7. stream := aStream
  8. ! !
  9. !ChunkParser methodsFor: 'reading'!
  10. nextChunk
  11. "The chunk format (Smalltalk Interchange Format or Fileout format)
  12. is a trivial format but can be a bit tricky to understand:
  13. - Uses the exclamation mark as delimiter of chunks.
  14. - Inside a chunk a normal exclamation mark must be doubled.
  15. - A non empty chunk must be a valid Smalltalk expression.
  16. - A chunk on top level with a preceding empty chunk is an instruction chunk:
  17. - The object created by the expression then takes over reading chunks.
  18. This metod returns next chunk as a String (trimmed), empty String (all whitespace) or nil."
  19. | char result chunk |
  20. result := '' writeStream.
  21. [char := stream next.
  22. char notNil] whileTrue: [
  23. char = '!!' ifTrue: [
  24. stream peek = '!!'
  25. ifTrue: [stream next "skipping the escape double"]
  26. ifFalse: [^result contents trimBoth "chunk end marker found"]].
  27. result nextPut: char].
  28. ^nil "a chunk needs to end with !!"
  29. ! !
  30. !ChunkParser class methodsFor: 'not yet classified'!
  31. on: aStream
  32. ^self new stream: aStream
  33. ! !
  34. Object subclass: #DoIt
  35. instanceVariableNames: ''
  36. category: 'Compiler'!
  37. Object subclass: #Exporter
  38. instanceVariableNames: ''
  39. category: 'Compiler'!
  40. !Exporter methodsFor: 'fileOut'!
  41. exportAll
  42. "Export all packages in the system."
  43. ^String streamContents: [:stream |
  44. Smalltalk current packages do: [:pkg |
  45. stream nextPutAll: (self exportPackage: pkg name)]]
  46. !
  47. exportClass: aClass
  48. "Export a single class. Subclasses override these methods."
  49. ^String streamContents: [:stream |
  50. self exportDefinitionOf: aClass on: stream.
  51. self exportMethodsOf: aClass on: stream.
  52. self exportMetaDefinitionOf: aClass on: stream.
  53. self exportMethodsOf: aClass class on: stream]
  54. !
  55. exportPackage: packageName
  56. "Export a given package by name."
  57. | package |
  58. ^String streamContents: [:stream |
  59. package := Smalltalk current packageAt: packageName.
  60. self exportPackageDefinitionOf: package on: stream.
  61. "Export classes in dependency order"
  62. package sortedClasses do: [:each |
  63. stream nextPutAll: (self exportClass: each)].
  64. self exportPackageExtensionsOf: package on: stream]
  65. ! !
  66. !Exporter methodsFor: 'private'!
  67. classNameFor: aClass
  68. ^aClass isMetaclass
  69. ifTrue: [aClass instanceClass name, '.klass']
  70. ifFalse: [
  71. aClass isNil
  72. ifTrue: ['nil']
  73. ifFalse: [aClass name]]
  74. !
  75. exportDefinitionOf: aClass on: aStream
  76. aStream
  77. nextPutAll: 'smalltalk.addClass(';
  78. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  79. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  80. nextPutAll: ', ['.
  81. aClass instanceVariableNames
  82. do: [:each | aStream nextPutAll: '''', each, '''']
  83. separatedBy: [aStream nextPutAll: ', '].
  84. aStream
  85. nextPutAll: '], ''';
  86. nextPutAll: aClass category, '''';
  87. nextPutAll: ');'.
  88. aClass comment notEmpty ifTrue: [
  89. aStream
  90. lf;
  91. nextPutAll: 'smalltalk.';
  92. nextPutAll: (self classNameFor: aClass);
  93. nextPutAll: '.comment=';
  94. nextPutAll: 'unescape(''', aClass comment escaped, ''')'].
  95. aStream lf
  96. !
  97. exportMetaDefinitionOf: aClass on: aStream
  98. aClass class instanceVariableNames isEmpty ifFalse: [
  99. aStream
  100. nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
  101. nextPutAll: '.iVarNames = ['.
  102. aClass class instanceVariableNames
  103. do: [:each | aStream nextPutAll: '''', each, '''']
  104. separatedBy: [aStream nextPutAll: ','].
  105. aStream nextPutAll: '];', String lf]
  106. !
  107. exportMethod: aMethod of: aClass on: aStream
  108. aStream
  109. nextPutAll: 'smalltalk.addMethod(';lf;
  110. nextPutAll: 'unescape(''', aMethod selector asSelector escaped, '''),';lf;
  111. nextPutAll: 'smalltalk.method({';lf;
  112. nextPutAll: 'selector: unescape(''', aMethod selector escaped, '''),';lf;
  113. nextPutAll: 'category: ''', aMethod category, ''',';lf;
  114. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  115. nextPutAll: 'args: ', aMethod arguments asJavascript, ','; lf;
  116. nextPutAll: 'source: unescape(''', aMethod source escaped, '''),';lf;
  117. nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
  118. nextPutAll: 'referencedClasses: ', aMethod referencedClasses asJavascript.
  119. aStream
  120. lf;
  121. nextPutAll: '}),';lf;
  122. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  123. nextPutAll: ');';lf;lf
  124. !
  125. exportMethodsOf: aClass on: aStream
  126. "Issue #143: sort methods alphabetically"
  127. ((aClass methodDictionary values) sorted: [:a :b | a selector <= b selector]) do: [:each |
  128. (each category match: '^\*') ifFalse: [
  129. self exportMethod: each of: aClass on: aStream]].
  130. aStream lf
  131. !
  132. exportPackageDefinitionOf: package on: aStream
  133. aStream
  134. nextPutAll: 'smalltalk.addPackage(';
  135. nextPutAll: '''', package name, ''', ', package propertiesAsJSON , ');'.
  136. aStream lf
  137. !
  138. exportPackageExtensionsOf: package on: aStream
  139. | name |
  140. name := package name.
  141. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  142. each methodDictionary values do: [:method |
  143. method category = ('*', name) ifTrue: [
  144. self exportMethod: method of: each on: aStream]]]
  145. ! !
  146. Exporter subclass: #ChunkExporter
  147. instanceVariableNames: ''
  148. category: 'Compiler'!
  149. !ChunkExporter methodsFor: 'not yet classified'!
  150. chunkEscape: aString
  151. "Replace all occurrences of !! with !!!! and trim at both ends."
  152. ^(aString replace: '!!' with: '!!!!') trimBoth
  153. !
  154. classNameFor: aClass
  155. ^aClass isMetaclass
  156. ifTrue: [aClass instanceClass name, ' class']
  157. ifFalse: [
  158. aClass isNil
  159. ifTrue: ['nil']
  160. ifFalse: [aClass name]]
  161. !
  162. exportDefinitionOf: aClass on: aStream
  163. "Chunk format."
  164. aStream
  165. nextPutAll: (self classNameFor: aClass superclass);
  166. nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
  167. nextPutAll: ' instanceVariableNames: '''.
  168. aClass instanceVariableNames
  169. do: [:each | aStream nextPutAll: each]
  170. separatedBy: [aStream nextPutAll: ' '].
  171. aStream
  172. nextPutAll: ''''; lf;
  173. nextPutAll: ' category: ''', aClass category, '''!!'; lf.
  174. aClass comment notEmpty ifTrue: [
  175. aStream
  176. nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
  177. nextPutAll: (self chunkEscape: aClass comment), '!!';lf].
  178. aStream lf
  179. !
  180. exportMetaDefinitionOf: aClass on: aStream
  181. aClass class instanceVariableNames isEmpty ifFalse: [
  182. aStream
  183. nextPutAll: (self classNameFor: aClass class);
  184. nextPutAll: ' instanceVariableNames: '''.
  185. aClass class instanceVariableNames
  186. do: [:each | aStream nextPutAll: each]
  187. separatedBy: [aStream nextPutAll: ' '].
  188. aStream
  189. nextPutAll: '''!!'; lf; lf]
  190. !
  191. exportMethod: aMethod of: aClass on: aStream
  192. aStream
  193. lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;
  194. nextPutAll: '!!'
  195. !
  196. exportMethods: methods category: category of: aClass on: aStream
  197. "Issue #143: sort methods alphabetically"
  198. aStream
  199. nextPutAll: '!!', (self classNameFor: aClass);
  200. nextPutAll: ' methodsFor: ''', category, '''!!'.
  201. (methods sorted: [:a :b | a selector <= b selector]) do: [:each |
  202. self exportMethod: each of: aClass on: aStream].
  203. aStream nextPutAll: ' !!'; lf; lf
  204. !
  205. exportMethodsOf: aClass on: aStream
  206. "Issue #143: sort protocol alphabetically"
  207. | map |
  208. map := Dictionary new.
  209. aClass protocolsDo: [:category :methods |
  210. (category match: '^\*') ifFalse: [ map at: category put: methods ]].
  211. (map keys sorted: [:a :b | a <= b ]) do: [:category | | methods |
  212. methods := map at: category.
  213. self
  214. exportMethods: methods
  215. category: category
  216. of: aClass
  217. on: aStream ]
  218. !
  219. exportPackageDefinitionOf: package on: aStream
  220. "Chunk format."
  221. aStream
  222. nextPutAll: 'Smalltalk current createPackage: ''', package name,
  223. ''' properties: ', package properties storeString, '!!'; lf.
  224. !
  225. exportPackageExtensionsOf: package on: aStream
  226. "We need to override this one too since we need to group
  227. all methods in a given protocol under a leading methodsFor: chunk
  228. for that class."
  229. | name |
  230. name := package name.
  231. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  232. each protocolsDo: [:category :methods |
  233. category = ('*', name) ifTrue: [
  234. self exportMethods: methods category: category of: each on: aStream]]]
  235. ! !
  236. Exporter subclass: #StrippedExporter
  237. instanceVariableNames: ''
  238. category: 'Compiler'!
  239. !StrippedExporter methodsFor: 'private'!
  240. exportDefinitionOf: aClass on: aStream
  241. aStream
  242. nextPutAll: 'smalltalk.addClass(';
  243. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  244. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  245. nextPutAll: ', ['.
  246. aClass instanceVariableNames
  247. do: [:each | aStream nextPutAll: '''', each, '''']
  248. separatedBy: [aStream nextPutAll: ', '].
  249. aStream
  250. nextPutAll: '], ''';
  251. nextPutAll: aClass category, '''';
  252. nextPutAll: ');'.
  253. aStream lf
  254. !
  255. exportMethod: aMethod of: aClass on: aStream
  256. aStream
  257. nextPutAll: 'smalltalk.addMethod(';lf;
  258. nextPutAll: 'unescape(''', aMethod selector asSelector escaped, '''),';lf;
  259. nextPutAll: 'smalltalk.method({';lf;
  260. nextPutAll: 'selector: unescape(''', aMethod selector escaped, '''),';lf;
  261. nextPutAll: 'fn: ', aMethod fn compiledSource;lf;
  262. nextPutAll: '}),';lf;
  263. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  264. nextPutAll: ');';lf;lf
  265. ! !
  266. Object subclass: #Importer
  267. instanceVariableNames: ''
  268. category: 'Compiler'!
  269. !Importer methodsFor: 'fileIn'!
  270. import: aStream
  271. | chunk result parser lastEmpty |
  272. parser := ChunkParser on: aStream.
  273. lastEmpty := false.
  274. [chunk := parser nextChunk.
  275. chunk isNil] whileFalse: [
  276. chunk isEmpty
  277. ifTrue: [lastEmpty := true]
  278. ifFalse: [
  279. result := Compiler new loadExpression: chunk.
  280. lastEmpty
  281. ifTrue: [
  282. lastEmpty := false.
  283. result scanFrom: parser]]]
  284. ! !
  285. Object subclass: #Node
  286. instanceVariableNames: 'nodes'
  287. category: 'Compiler'!
  288. !Node methodsFor: 'accessing'!
  289. addNode: aNode
  290. self nodes add: aNode
  291. !
  292. nodes
  293. ^nodes ifNil: [nodes := Array new]
  294. ! !
  295. !Node methodsFor: 'building'!
  296. nodes: aCollection
  297. nodes := aCollection
  298. ! !
  299. !Node methodsFor: 'testing'!
  300. isBlockNode
  301. ^false
  302. !
  303. isBlockSequenceNode
  304. ^false
  305. !
  306. isValueNode
  307. ^false
  308. ! !
  309. !Node methodsFor: 'visiting'!
  310. accept: aVisitor
  311. aVisitor visitNode: self
  312. ! !
  313. Node subclass: #AssignmentNode
  314. instanceVariableNames: 'left right'
  315. category: 'Compiler'!
  316. !AssignmentNode methodsFor: 'accessing'!
  317. left
  318. ^left
  319. !
  320. left: aNode
  321. left := aNode.
  322. left assigned: true
  323. !
  324. right
  325. ^right
  326. !
  327. right: aNode
  328. right := aNode
  329. ! !
  330. !AssignmentNode methodsFor: 'visiting'!
  331. accept: aVisitor
  332. aVisitor visitAssignmentNode: self
  333. ! !
  334. Node subclass: #BlockNode
  335. instanceVariableNames: 'parameters inlined'
  336. category: 'Compiler'!
  337. !BlockNode methodsFor: 'accessing'!
  338. inlined
  339. ^inlined ifNil: [false]
  340. !
  341. inlined: aBoolean
  342. inlined := aBoolean
  343. !
  344. parameters
  345. ^parameters ifNil: [parameters := Array new]
  346. !
  347. parameters: aCollection
  348. parameters := aCollection
  349. ! !
  350. !BlockNode methodsFor: 'testing'!
  351. isBlockNode
  352. ^true
  353. ! !
  354. !BlockNode methodsFor: 'visiting'!
  355. accept: aVisitor
  356. aVisitor visitBlockNode: self
  357. ! !
  358. Node subclass: #CascadeNode
  359. instanceVariableNames: 'receiver'
  360. category: 'Compiler'!
  361. !CascadeNode methodsFor: 'accessing'!
  362. receiver
  363. ^receiver
  364. !
  365. receiver: aNode
  366. receiver := aNode
  367. ! !
  368. !CascadeNode methodsFor: 'visiting'!
  369. accept: aVisitor
  370. aVisitor visitCascadeNode: self
  371. ! !
  372. Node subclass: #DynamicArrayNode
  373. instanceVariableNames: ''
  374. category: 'Compiler'!
  375. !DynamicArrayNode methodsFor: 'visiting'!
  376. accept: aVisitor
  377. aVisitor visitDynamicArrayNode: self
  378. ! !
  379. Node subclass: #DynamicDictionaryNode
  380. instanceVariableNames: ''
  381. category: 'Compiler'!
  382. !DynamicDictionaryNode methodsFor: 'visiting'!
  383. accept: aVisitor
  384. aVisitor visitDynamicDictionaryNode: self
  385. ! !
  386. Node subclass: #JSStatementNode
  387. instanceVariableNames: 'source'
  388. category: 'Compiler'!
  389. !JSStatementNode methodsFor: 'accessing'!
  390. source
  391. ^source ifNil: ['']
  392. !
  393. source: aString
  394. source := aString
  395. ! !
  396. !JSStatementNode methodsFor: 'visiting'!
  397. accept: aVisitor
  398. aVisitor visitJSStatementNode: self
  399. ! !
  400. Node subclass: #MethodNode
  401. instanceVariableNames: 'selector arguments source'
  402. category: 'Compiler'!
  403. !MethodNode methodsFor: 'accessing'!
  404. arguments
  405. ^arguments ifNil: [#()]
  406. !
  407. arguments: aCollection
  408. arguments := aCollection
  409. !
  410. selector
  411. ^selector
  412. !
  413. selector: aString
  414. selector := aString
  415. !
  416. source
  417. ^source
  418. !
  419. source: aString
  420. source := aString
  421. ! !
  422. !MethodNode methodsFor: 'visiting'!
  423. accept: aVisitor
  424. aVisitor visitMethodNode: self
  425. ! !
  426. Node subclass: #ReturnNode
  427. instanceVariableNames: ''
  428. category: 'Compiler'!
  429. !ReturnNode methodsFor: 'visiting'!
  430. accept: aVisitor
  431. aVisitor visitReturnNode: self
  432. ! !
  433. Node subclass: #SendNode
  434. instanceVariableNames: 'selector arguments receiver'
  435. category: 'Compiler'!
  436. !SendNode methodsFor: 'accessing'!
  437. arguments
  438. ^arguments ifNil: [arguments := #()]
  439. !
  440. arguments: aCollection
  441. arguments := aCollection
  442. !
  443. cascadeNodeWithMessages: aCollection
  444. | first |
  445. first := SendNode new
  446. selector: self selector;
  447. arguments: self arguments;
  448. yourself.
  449. ^CascadeNode new
  450. receiver: self receiver;
  451. nodes: (Array with: first), aCollection;
  452. yourself
  453. !
  454. receiver
  455. ^receiver
  456. !
  457. receiver: aNode
  458. receiver := aNode
  459. !
  460. selector
  461. ^selector
  462. !
  463. selector: aString
  464. selector := aString
  465. !
  466. valueForReceiver: anObject
  467. ^SendNode new
  468. receiver: (self receiver
  469. ifNil: [anObject]
  470. ifNotNil: [self receiver valueForReceiver: anObject]);
  471. selector: self selector;
  472. arguments: self arguments;
  473. yourself
  474. ! !
  475. !SendNode methodsFor: 'visiting'!
  476. accept: aVisitor
  477. aVisitor visitSendNode: self
  478. ! !
  479. Node subclass: #SequenceNode
  480. instanceVariableNames: 'temps'
  481. category: 'Compiler'!
  482. !SequenceNode methodsFor: 'accessing'!
  483. temps
  484. ^temps ifNil: [#()]
  485. !
  486. temps: aCollection
  487. temps := aCollection
  488. ! !
  489. !SequenceNode methodsFor: 'testing'!
  490. asBlockSequenceNode
  491. ^BlockSequenceNode new
  492. nodes: self nodes;
  493. temps: self temps;
  494. yourself
  495. ! !
  496. !SequenceNode methodsFor: 'visiting'!
  497. accept: aVisitor
  498. aVisitor visitSequenceNode: self
  499. ! !
  500. SequenceNode subclass: #BlockSequenceNode
  501. instanceVariableNames: ''
  502. category: 'Compiler'!
  503. !BlockSequenceNode methodsFor: 'testing'!
  504. isBlockSequenceNode
  505. ^true
  506. ! !
  507. !BlockSequenceNode methodsFor: 'visiting'!
  508. accept: aVisitor
  509. aVisitor visitBlockSequenceNode: self
  510. ! !
  511. Node subclass: #ValueNode
  512. instanceVariableNames: 'value'
  513. category: 'Compiler'!
  514. !ValueNode methodsFor: 'accessing'!
  515. value
  516. ^value
  517. !
  518. value: anObject
  519. value := anObject
  520. ! !
  521. !ValueNode methodsFor: 'testing'!
  522. isValueNode
  523. ^true
  524. ! !
  525. !ValueNode methodsFor: 'visiting'!
  526. accept: aVisitor
  527. aVisitor visitValueNode: self
  528. ! !
  529. ValueNode subclass: #VariableNode
  530. instanceVariableNames: 'assigned'
  531. category: 'Compiler'!
  532. !VariableNode methodsFor: 'accessing'!
  533. assigned
  534. ^assigned ifNil: [false]
  535. !
  536. assigned: aBoolean
  537. assigned := aBoolean
  538. ! !
  539. !VariableNode methodsFor: 'visiting'!
  540. accept: aVisitor
  541. aVisitor visitVariableNode: self
  542. ! !
  543. VariableNode subclass: #ClassReferenceNode
  544. instanceVariableNames: ''
  545. category: 'Compiler'!
  546. !ClassReferenceNode methodsFor: 'visiting'!
  547. accept: aVisitor
  548. aVisitor visitClassReferenceNode: self
  549. ! !
  550. Object subclass: #NodeVisitor
  551. instanceVariableNames: ''
  552. category: 'Compiler'!
  553. !NodeVisitor methodsFor: 'visiting'!
  554. visit: aNode
  555. aNode accept: self
  556. !
  557. visitAssignmentNode: aNode
  558. self visitNode: aNode
  559. !
  560. visitBlockNode: aNode
  561. self visitNode: aNode
  562. !
  563. visitBlockSequenceNode: aNode
  564. self visitSequenceNode: aNode
  565. !
  566. visitCascadeNode: aNode
  567. self visitNode: aNode
  568. !
  569. visitClassReferenceNode: aNode
  570. self
  571. nextPutAll: 'smalltalk.';
  572. nextPutAll: aNode value
  573. !
  574. visitDynamicArrayNode: aNode
  575. self visitNode: aNode
  576. !
  577. visitDynamicDictionaryNode: aNode
  578. self visitNode: aNode
  579. !
  580. visitJSStatementNode: aNode
  581. self
  582. nextPutAll: 'function(){';
  583. nextPutAll: aNode source;
  584. nextPutAll: '})()'
  585. !
  586. visitMethodNode: aNode
  587. self visitNode: aNode
  588. !
  589. visitNode: aNode
  590. !
  591. visitReturnNode: aNode
  592. self visitNode: aNode
  593. !
  594. visitSendNode: aNode
  595. self visitNode: aNode
  596. !
  597. visitSequenceNode: aNode
  598. self visitNode: aNode
  599. !
  600. visitValueNode: aNode
  601. self visitNode: aNode
  602. !
  603. visitVariableNode: aNode
  604. ! !
  605. NodeVisitor subclass: #Compiler
  606. instanceVariableNames: 'stream nestedBlocks earlyReturn currentClass currentSelector unknownVariables tempVariables messageSends referencedClasses classReferenced source argVariables'
  607. category: 'Compiler'!
  608. !Compiler methodsFor: 'accessing'!
  609. argVariables
  610. ^argVariables copy
  611. !
  612. classNameFor: aClass
  613. ^aClass isMetaclass
  614. ifTrue: [aClass instanceClass name, '.klass']
  615. ifFalse: [
  616. aClass isNil
  617. ifTrue: ['nil']
  618. ifFalse: [aClass name]]
  619. !
  620. currentClass
  621. ^currentClass
  622. !
  623. currentClass: aClass
  624. currentClass := aClass
  625. !
  626. knownVariables
  627. ^self pseudoVariables
  628. addAll: self tempVariables;
  629. addAll: self argVariables;
  630. yourself
  631. !
  632. parser
  633. ^SmalltalkParser new
  634. !
  635. pseudoVariables
  636. ^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
  637. !
  638. safeVariableNameFor: aString
  639. ^(Smalltalk current reservedWords includes: aString)
  640. ifTrue: [aString, '_']
  641. ifFalse: [aString]
  642. !
  643. source
  644. ^source ifNil: ['']
  645. !
  646. source: aString
  647. source := aString
  648. !
  649. tempVariables
  650. ^tempVariables copy
  651. !
  652. unknownVariables
  653. ^unknownVariables copy
  654. ! !
  655. !Compiler methodsFor: 'compiling'!
  656. compile: aString
  657. ^self compileNode: (self parse: aString)
  658. !
  659. compile: aString forClass: aClass
  660. self currentClass: aClass.
  661. self source: aString.
  662. ^self compile: aString
  663. !
  664. compileExpression: aString
  665. self currentClass: DoIt.
  666. self source: 'doIt ^[', aString, '] value'.
  667. ^self compileNode: (self parse: self source)
  668. !
  669. compileNode: aNode
  670. stream := '' writeStream.
  671. self visit: aNode.
  672. ^stream contents
  673. !
  674. eval: aString
  675. <return eval(aString)>
  676. !
  677. load: aString forClass: aClass
  678. | compiled |
  679. compiled := self eval: (self compile: aString forClass: aClass).
  680. self setupClass: aClass.
  681. ^compiled
  682. !
  683. loadExpression: aString
  684. | result |
  685. DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
  686. result := DoIt new doIt.
  687. DoIt removeCompiledMethod: (DoIt methodDictionary at: 'doIt').
  688. ^result
  689. !
  690. parse: aString
  691. ^Smalltalk current parse: aString
  692. !
  693. parseExpression: aString
  694. ^self parse: 'doIt ^[', aString, '] value'
  695. !
  696. recompile: aClass
  697. aClass methodDictionary do: [:each || method |
  698. method := self load: each source forClass: aClass.
  699. method category: each category.
  700. aClass addCompiledMethod: method].
  701. aClass isMetaclass ifFalse: [self recompile: aClass class]
  702. !
  703. recompileAll
  704. Smalltalk current classes do: [:each |
  705. Transcript show: each; cr.
  706. [self recompile: each] valueWithTimeout: 100]
  707. !
  708. setupClass: aClass
  709. <smalltalk.init(aClass)>
  710. ! !
  711. !Compiler methodsFor: 'initialization'!
  712. initialize
  713. super initialize.
  714. stream := '' writeStream.
  715. unknownVariables := #().
  716. tempVariables := #().
  717. argVariables := #().
  718. messageSends := #().
  719. classReferenced := #()
  720. ! !
  721. !Compiler methodsFor: 'optimizations'!
  722. checkClass: aClassName for: receiver
  723. stream nextPutAll: '((($receiver = ', receiver, ').klass === smalltalk.', aClassName, ') ? '
  724. !
  725. inline: aSelector receiver: receiver argumentNodes: aCollection
  726. | inlined |
  727. inlined := false.
  728. "-- Booleans --"
  729. (aSelector = 'ifFalse:') ifTrue: [
  730. aCollection first isBlockNode ifTrue: [
  731. self checkClass: 'Boolean' for: receiver.
  732. stream nextPutAll: '(!! $receiver ? '.
  733. self visit: aCollection first.
  734. stream nextPutAll: '() : nil)'.
  735. inlined := true]].
  736. (aSelector = 'ifTrue:') ifTrue: [
  737. aCollection first isBlockNode ifTrue: [
  738. self checkClass: 'Boolean' for: receiver.
  739. stream nextPutAll: '($receiver ? '.
  740. self visit: aCollection first.
  741. stream nextPutAll: '() : nil)'.
  742. inlined := true]].
  743. (aSelector = 'ifTrue:ifFalse:') ifTrue: [
  744. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  745. self checkClass: 'Boolean' for: receiver.
  746. stream nextPutAll: '($receiver ? '.
  747. self visit: aCollection first.
  748. stream nextPutAll: '() : '.
  749. self visit: aCollection second.
  750. stream nextPutAll: '())'.
  751. inlined := true]].
  752. (aSelector = 'ifFalse:ifTrue:') ifTrue: [
  753. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  754. self checkClass: 'Boolean' for: receiver.
  755. stream nextPutAll: '(!! $receiver ? '.
  756. self visit: aCollection first.
  757. stream nextPutAll: '() : '.
  758. self visit: aCollection second.
  759. stream nextPutAll: '())'.
  760. inlined := true]].
  761. "-- Numbers --"
  762. (aSelector = '<') ifTrue: [
  763. self checkClass: 'Number' for: receiver.
  764. stream nextPutAll: '$receiver <'.
  765. self visit: aCollection first.
  766. inlined := true].
  767. (aSelector = '<=') ifTrue: [
  768. self checkClass: 'Number' for: receiver.
  769. stream nextPutAll: '$receiver <='.
  770. self visit: aCollection first.
  771. inlined := true].
  772. (aSelector = '>') ifTrue: [
  773. self checkClass: 'Number' for: receiver.
  774. stream nextPutAll: '$receiver >'.
  775. self visit: aCollection first.
  776. inlined := true].
  777. (aSelector = '>=') ifTrue: [
  778. self checkClass: 'Number' for: receiver.
  779. stream nextPutAll: '$receiver >='.
  780. self visit: aCollection first.
  781. inlined := true].
  782. (aSelector = '+') ifTrue: [
  783. self checkClass: 'Number' for: receiver.
  784. stream nextPutAll: '$receiver +'.
  785. self visit: aCollection first.
  786. inlined := true].
  787. (aSelector = '-') ifTrue: [
  788. self checkClass: 'Number' for: receiver.
  789. stream nextPutAll: '$receiver -'.
  790. self visit: aCollection first.
  791. inlined := true].
  792. (aSelector = '*') ifTrue: [
  793. self checkClass: 'Number' for: receiver.
  794. stream nextPutAll: '$receiver *'.
  795. self visit: aCollection first.
  796. inlined := true].
  797. (aSelector = '/') ifTrue: [
  798. self checkClass: 'Number' for: receiver.
  799. stream nextPutAll: '$receiver /'.
  800. self visit: aCollection first.
  801. inlined := true].
  802. ^inlined
  803. !
  804. inlineLiteral: aSelector receiverNode: anObject argumentNodes: aCollection
  805. | inlined |
  806. inlined := false.
  807. "-- BlockClosures --"
  808. (aSelector = 'whileTrue:') ifTrue: [
  809. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  810. stream nextPutAll: '(function(){while('.
  811. self visit: anObject.
  812. stream nextPutAll: '()) {'.
  813. self visit: aCollection first.
  814. stream nextPutAll: '()}})()'.
  815. inlined := true]].
  816. (aSelector = 'whileFalse:') ifTrue: [
  817. (anObject isBlockNode and: [aCollection first isBlockNode]) ifTrue: [
  818. stream nextPutAll: '(function(){while(!!'.
  819. self visit: anObject.
  820. stream nextPutAll: '()) {'.
  821. self visit: aCollection first.
  822. stream nextPutAll: '()}})()'.
  823. inlined := true]].
  824. (aSelector = 'whileTrue') ifTrue: [
  825. anObject isBlockNode ifTrue: [
  826. stream nextPutAll: '(function(){while('.
  827. self visit: anObject.
  828. stream nextPutAll: '()) {}})()'.
  829. inlined := true]].
  830. (aSelector = 'whileFalse') ifTrue: [
  831. anObject isBlockNode ifTrue: [
  832. stream nextPutAll: '(function(){while(!!'.
  833. self visit: anObject.
  834. stream nextPutAll: '()) {}})()'.
  835. inlined := true]].
  836. "-- Numbers --"
  837. (aSelector = '+') ifTrue: [
  838. (self isNode: anObject ofClass: Number) ifTrue: [
  839. self visit: anObject.
  840. stream nextPutAll: ' + '.
  841. self visit: aCollection first.
  842. inlined := true]].
  843. (aSelector = '-') ifTrue: [
  844. (self isNode: anObject ofClass: Number) ifTrue: [
  845. self visit: anObject.
  846. stream nextPutAll: ' - '.
  847. self visit: aCollection first.
  848. inlined := true]].
  849. (aSelector = '*') ifTrue: [
  850. (self isNode: anObject ofClass: Number) ifTrue: [
  851. self visit: anObject.
  852. stream nextPutAll: ' * '.
  853. self visit: aCollection first.
  854. inlined := true]].
  855. (aSelector = '/') ifTrue: [
  856. (self isNode: anObject ofClass: Number) ifTrue: [
  857. self visit: anObject.
  858. stream nextPutAll: ' / '.
  859. self visit: aCollection first.
  860. inlined := true]].
  861. (aSelector = '<') ifTrue: [
  862. (self isNode: anObject ofClass: Number) ifTrue: [
  863. self visit: anObject.
  864. stream nextPutAll: ' < '.
  865. self visit: aCollection first.
  866. inlined := true]].
  867. (aSelector = '<=') ifTrue: [
  868. (self isNode: anObject ofClass: Number) ifTrue: [
  869. self visit: anObject.
  870. stream nextPutAll: ' <= '.
  871. self visit: aCollection first.
  872. inlined := true]].
  873. (aSelector = '>') ifTrue: [
  874. (self isNode: anObject ofClass: Number) ifTrue: [
  875. self visit: anObject.
  876. stream nextPutAll: ' > '.
  877. self visit: aCollection first.
  878. inlined := true]].
  879. (aSelector = '>=') ifTrue: [
  880. (self isNode: anObject ofClass: Number) ifTrue: [
  881. self visit: anObject.
  882. stream nextPutAll: ' >= '.
  883. self visit: aCollection first.
  884. inlined := true]].
  885. "-- UndefinedObject --"
  886. (aSelector = 'ifNil:') ifTrue: [
  887. aCollection first isBlockNode ifTrue: [
  888. stream nextPutAll: '(($receiver = '.
  889. self visit: anObject.
  890. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  891. self visit: aCollection first.
  892. stream nextPutAll: '() : $receiver'.
  893. inlined := true]].
  894. (aSelector = 'ifNotNil:') ifTrue: [
  895. aCollection first isBlockNode ifTrue: [
  896. stream nextPutAll: '(($receiver = '.
  897. self visit: anObject.
  898. stream nextPutAll: ') !!= nil && $receiver !!= undefined) ? '.
  899. self visit: aCollection first.
  900. stream nextPutAll: '() : nil'.
  901. inlined := true]].
  902. (aSelector = 'ifNil:ifNotNil:') ifTrue: [
  903. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  904. stream nextPutAll: '(($receiver = '.
  905. self visit: anObject.
  906. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  907. self visit: aCollection first.
  908. stream nextPutAll: '() : '.
  909. self visit: aCollection second.
  910. stream nextPutAll: '()'.
  911. inlined := true]].
  912. (aSelector = 'ifNotNil:ifNil:') ifTrue: [
  913. (aCollection first isBlockNode and: [aCollection second isBlockNode]) ifTrue: [
  914. stream nextPutAll: '(($receiver = '.
  915. self visit: anObject.
  916. stream nextPutAll: ') == nil || $receiver == undefined) ? '.
  917. self visit: aCollection second.
  918. stream nextPutAll: '() : '.
  919. self visit: aCollection first.
  920. stream nextPutAll: '()'.
  921. inlined := true]].
  922. ^inlined
  923. !
  924. isNode: aNode ofClass: aClass
  925. ^aNode isValueNode and: [
  926. aNode value class = aClass or: [
  927. aNode value = 'self' and: [self currentClass = aClass]]]
  928. ! !
  929. !Compiler methodsFor: 'testing'!
  930. performOptimizations
  931. ^self class performOptimizations
  932. ! !
  933. !Compiler methodsFor: 'visiting'!
  934. send: aSelector to: aReceiver arguments: aCollection superSend: aBoolean
  935. ^String streamContents: [:str || tmp |
  936. tmp := stream.
  937. str nextPutAll: 'smalltalk.send('.
  938. str nextPutAll: aReceiver.
  939. str nextPutAll: ', "', aSelector asSelector, '", ['.
  940. stream := str.
  941. aCollection
  942. do: [:each | self visit: each]
  943. separatedBy: [stream nextPutAll: ', '].
  944. stream := tmp.
  945. str nextPutAll: ']'.
  946. aBoolean ifTrue: [
  947. str nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
  948. str nextPutAll: ')']
  949. !
  950. visit: aNode
  951. aNode accept: self
  952. !
  953. visitAssignmentNode: aNode
  954. stream nextPutAll: '('.
  955. self visit: aNode left.
  956. stream nextPutAll: '='.
  957. self visit: aNode right.
  958. stream nextPutAll: ')'
  959. !
  960. visitBlockNode: aNode
  961. stream nextPutAll: '(function('.
  962. aNode parameters
  963. do: [:each |
  964. tempVariables add: each.
  965. stream nextPutAll: each]
  966. separatedBy: [stream nextPutAll: ', '].
  967. stream nextPutAll: '){'.
  968. aNode nodes do: [:each | self visit: each].
  969. stream nextPutAll: '})'
  970. !
  971. visitBlockSequenceNode: aNode
  972. | index |
  973. nestedBlocks := nestedBlocks + 1.
  974. aNode nodes isEmpty
  975. ifTrue: [
  976. stream nextPutAll: 'return nil;']
  977. ifFalse: [
  978. aNode temps do: [:each | | temp |
  979. temp := self safeVariableNameFor: each.
  980. tempVariables add: temp.
  981. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  982. index := 0.
  983. aNode nodes do: [:each |
  984. index := index + 1.
  985. index = aNode nodes size ifTrue: [
  986. stream nextPutAll: 'return '].
  987. self visit: each.
  988. stream nextPutAll: ';']].
  989. nestedBlocks := nestedBlocks - 1
  990. !
  991. visitCascadeNode: aNode
  992. | index |
  993. index := 0.
  994. (tempVariables includes: '$rec') ifFalse: [
  995. tempVariables add: '$rec'].
  996. stream nextPutAll: '(function($rec){'.
  997. aNode nodes do: [:each |
  998. index := index + 1.
  999. index = aNode nodes size ifTrue: [
  1000. stream nextPutAll: 'return '].
  1001. each receiver: (VariableNode new value: '$rec').
  1002. self visit: each.
  1003. stream nextPutAll: ';'].
  1004. stream nextPutAll: '})('.
  1005. self visit: aNode receiver.
  1006. stream nextPutAll: ')'
  1007. !
  1008. visitClassReferenceNode: aNode
  1009. (referencedClasses includes: aNode value) ifFalse: [
  1010. referencedClasses add: aNode value].
  1011. stream nextPutAll: '(smalltalk.', aNode value, ' || ', aNode value, ')'
  1012. !
  1013. visitDynamicArrayNode: aNode
  1014. stream nextPutAll: '['.
  1015. aNode nodes
  1016. do: [:each | self visit: each]
  1017. separatedBy: [stream nextPutAll: ','].
  1018. stream nextPutAll: ']'
  1019. !
  1020. visitDynamicDictionaryNode: aNode
  1021. stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.
  1022. aNode nodes
  1023. do: [:each | self visit: each]
  1024. separatedBy: [stream nextPutAll: ','].
  1025. stream nextPutAll: '])'
  1026. !
  1027. visitFailure: aFailure
  1028. self error: aFailure asString
  1029. !
  1030. visitJSStatementNode: aNode
  1031. stream nextPutAll: (aNode source replace: '>>' with: '>')
  1032. !
  1033. visitMethodNode: aNode
  1034. | str currentSelector |
  1035. currentSelector := aNode selector asSelector.
  1036. nestedBlocks := 0.
  1037. earlyReturn := false.
  1038. messageSends := #().
  1039. referencedClasses := #().
  1040. unknownVariables := #().
  1041. tempVariables := #().
  1042. argVariables := #().
  1043. stream
  1044. nextPutAll: 'smalltalk.method({'; lf;
  1045. nextPutAll: 'selector: "', aNode selector, '",'; lf.
  1046. stream nextPutAll: 'source: unescape("', self source escaped, '"),';lf.
  1047. stream nextPutAll: 'fn: function('.
  1048. aNode arguments
  1049. do: [:each |
  1050. argVariables add: each.
  1051. stream nextPutAll: each]
  1052. separatedBy: [stream nextPutAll: ', '].
  1053. stream
  1054. nextPutAll: '){'; lf;
  1055. nextPutAll: 'var self=this;'; lf.
  1056. str := stream.
  1057. stream := '' writeStream.
  1058. aNode nodes do: [:each |
  1059. self visit: each].
  1060. earlyReturn ifTrue: [
  1061. str nextPutAll: 'try{'].
  1062. str nextPutAll: stream contents.
  1063. stream := str.
  1064. stream
  1065. lf;
  1066. nextPutAll: 'return self;'.
  1067. earlyReturn ifTrue: [
  1068. stream lf; nextPutAll: '} catch(e) {if(e.name === ''stReturn'' && e.selector === ', currentSelector printString, '){return e.fn()} throw(e)}'].
  1069. stream nextPutAll: '}'.
  1070. stream
  1071. nextPutAll: ',', String lf, 'messageSends: ';
  1072. nextPutAll: messageSends asJavascript, ','; lf;
  1073. nextPutAll: 'args: ', argVariables asJavascript, ','; lf;
  1074. nextPutAll: 'referencedClasses: ['.
  1075. referencedClasses
  1076. do: [:each | stream nextPutAll: each printString]
  1077. separatedBy: [stream nextPutAll: ','].
  1078. stream nextPutAll: ']'.
  1079. stream nextPutAll: '})'
  1080. !
  1081. visitReturnNode: aNode
  1082. nestedBlocks > 0 ifTrue: [
  1083. earlyReturn := true].
  1084. earlyReturn
  1085. ifTrue: [
  1086. stream
  1087. nextPutAll: '(function(){throw(';
  1088. nextPutAll: '{name: ''stReturn'', selector: ';
  1089. nextPutAll: currentSelector printString;
  1090. nextPutAll: ', fn: function(){return ']
  1091. ifFalse: [stream nextPutAll: 'return '].
  1092. aNode nodes do: [:each |
  1093. self visit: each].
  1094. earlyReturn ifTrue: [
  1095. stream nextPutAll: '}})})()']
  1096. !
  1097. visitSendNode: aNode
  1098. | str receiver superSend inlined |
  1099. str := stream.
  1100. (messageSends includes: aNode selector) ifFalse: [
  1101. messageSends add: aNode selector].
  1102. stream := '' writeStream.
  1103. self visit: aNode receiver.
  1104. superSend := stream contents = 'super'.
  1105. receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
  1106. stream := str.
  1107. self performOptimizations
  1108. ifTrue: [
  1109. (self inlineLiteral: aNode selector receiverNode: aNode receiver argumentNodes: aNode arguments) ifFalse: [
  1110. (self inline: aNode selector receiver: receiver argumentNodes: aNode arguments)
  1111. ifTrue: [stream nextPutAll: ' : ', (self send: aNode selector to: '$receiver' arguments: aNode arguments superSend: superSend), ')']
  1112. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]]]
  1113. ifFalse: [stream nextPutAll: (self send: aNode selector to: receiver arguments: aNode arguments superSend: superSend)]
  1114. !
  1115. visitSequenceNode: aNode
  1116. aNode temps do: [:each || temp |
  1117. temp := self safeVariableNameFor: each.
  1118. tempVariables add: temp.
  1119. stream nextPutAll: 'var ', temp, '=nil;'; lf].
  1120. aNode nodes do: [:each |
  1121. self visit: each.
  1122. stream nextPutAll: ';']
  1123. separatedBy: [stream lf]
  1124. !
  1125. visitValueNode: aNode
  1126. stream nextPutAll: aNode value asJavascript
  1127. !
  1128. visitVariableNode: aNode
  1129. | varName |
  1130. (self currentClass allInstanceVariableNames includes: aNode value)
  1131. ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
  1132. ifFalse: [
  1133. varName := self safeVariableNameFor: aNode value.
  1134. (self knownVariables includes: varName)
  1135. ifFalse: [
  1136. unknownVariables add: aNode value.
  1137. aNode assigned
  1138. ifTrue: [stream nextPutAll: varName]
  1139. ifFalse: [stream nextPutAll: '(typeof ', varName, ' == ''undefined'' ? nil : ', varName, ')']]
  1140. ifTrue: [
  1141. aNode value = 'thisContext'
  1142. ifTrue: [stream nextPutAll: '(smalltalk.getThisContext())']
  1143. ifFalse: [stream nextPutAll: varName]]]
  1144. ! !
  1145. Compiler class instanceVariableNames: 'performOptimizations'!
  1146. !Compiler class methodsFor: 'accessing'!
  1147. performOptimizations
  1148. ^performOptimizations ifNil: [true]
  1149. !
  1150. performOptimizations: aBoolean
  1151. performOptimizations := aBoolean
  1152. ! !
  1153. !Compiler class methodsFor: 'compiling'!
  1154. recompile: aClass
  1155. aClass methodDictionary do: [:each || method |
  1156. method := self new load: each source forClass: aClass.
  1157. method category: each category.
  1158. aClass addCompiledMethod: method].
  1159. aClass isMetaclass ifFalse: [self recompile: aClass class]
  1160. !
  1161. recompileAll
  1162. Smalltalk current classes do: [:each |
  1163. self recompile: each]
  1164. ! !