Parser.st 25 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. Object subclass: #PPParser
  2. instanceVariableNames: 'memo'
  3. category: 'Parser'!
  4. !PPParser methodsFor: 'accessing'!
  5. memo
  6. ^memo
  7. ! !
  8. !PPParser methodsFor: 'initialization'!
  9. initialize
  10. memo := Dictionary new
  11. ! !
  12. !PPParser methodsFor: 'operations'!
  13. flatten
  14. ^PPFlattenParser on: self
  15. !
  16. withSource
  17. ^PPSourceParser on: self
  18. !
  19. ==> aBlock
  20. ^PPActionParser on: self block: aBlock
  21. !
  22. , aParser
  23. ^PPSequenceParser with: self with: aParser
  24. !
  25. / aParser
  26. ^PPChoiceParser with: self with: aParser
  27. !
  28. plus
  29. ^PPRepeatingParser on: self min: 1
  30. !
  31. star
  32. ^PPRepeatingParser on: self min: 0
  33. !
  34. not
  35. ^PPNotParser on: self
  36. !
  37. optional
  38. ^self / PPEpsilonParser new
  39. !
  40. memoizedParse: aStream
  41. | start end node |
  42. start := aStream position.
  43. ^self memo at: start
  44. ifPresent: [:value |
  45. aStream position: (self memo at: start) second.
  46. value first]
  47. ifAbsent: [
  48. node := self parse: aStream.
  49. end := aStream position.
  50. self memo at: start put: (Array with: node with: end).
  51. node]
  52. ! !
  53. !PPParser methodsFor: 'parsing'!
  54. parse: aStream
  55. self subclassResponsibility
  56. !
  57. parseAll: aStream
  58. | result |
  59. result := (PPSequenceParser with: self with: PPEOFParser new) memoizedParse: aStream.
  60. ^result isParseFailure
  61. ifTrue: [self error: (result messageFor: aStream contents)]
  62. ifFalse: [result first]
  63. ! !
  64. smalltalk.setup(smalltalk.PPParser);
  65. PPParser subclass: #PPEOFParser
  66. instanceVariableNames: ''
  67. category: 'Parser'!
  68. !PPEOFParser methodsFor: 'parsing'!
  69. parse: aStream
  70. ^aStream atEnd
  71. ifFalse: [
  72. PPFailure new reason: aStream contents, String lf, '---------------', String lf, 'EOF expected' at: aStream position]
  73. ifTrue: [nil]
  74. ! !
  75. smalltalk.setup(smalltalk.PPEOFParser);
  76. PPParser subclass: #PPAnyParser
  77. instanceVariableNames: ''
  78. category: 'Parser'!
  79. !PPAnyParser methodsFor: 'parsing'!
  80. parse: aStream
  81. ^aStream atEnd
  82. ifTrue: [PPFailure new
  83. reason: 'did not expect EOF' at: aStream position]
  84. ifFalse: [aStream next]
  85. ! !
  86. smalltalk.setup(smalltalk.PPAnyParser);
  87. PPParser subclass: #PPEpsilonParser
  88. instanceVariableNames: ''
  89. category: 'Parser'!
  90. !PPEpsilonParser methodsFor: 'parsing'!
  91. parse: aStream
  92. ^nil
  93. ! !
  94. smalltalk.setup(smalltalk.PPEpsilonParser);
  95. PPParser subclass: #PPStringParser
  96. instanceVariableNames: 'string'
  97. category: 'Parser'!
  98. !PPStringParser methodsFor: 'accessing'!
  99. string
  100. ^string
  101. !
  102. string: aString
  103. string := aString
  104. ! !
  105. !PPStringParser methodsFor: 'parsing'!
  106. parse: aStream
  107. | position result |
  108. position := aStream position.
  109. result := aStream next: self string size.
  110. ^result = self string
  111. ifTrue: [result]
  112. ifFalse: [
  113. aStream position: position.
  114. PPFailure new reason: 'Expected ', self string, ' but got ', (result at: position) printString; yourself]
  115. ! !
  116. smalltalk.setup(smalltalk.PPStringParser);
  117. PPParser subclass: #PPCharacterParser
  118. instanceVariableNames: 'regexp'
  119. category: 'Parser'!
  120. !PPCharacterParser methodsFor: 'accessing'!
  121. string: aString
  122. regexp := RegularExpression fromString: '[', aString, ']'
  123. ! !
  124. !PPCharacterParser methodsFor: 'parsing'!
  125. parse: aStream
  126. ^(aStream peek notNil and: [self match: aStream peek])
  127. ifTrue: [aStream next]
  128. ifFalse: [PPFailure new reason: 'Could not match' at: aStream position]
  129. ! !
  130. !PPCharacterParser methodsFor: 'private'!
  131. match: aString
  132. ^aString match: regexp
  133. ! !
  134. smalltalk.setup(smalltalk.PPCharacterParser);
  135. PPParser subclass: #PPListParser
  136. instanceVariableNames: 'parsers'
  137. category: 'Parser'!
  138. !PPListParser methodsFor: 'accessing'!
  139. parsers
  140. ^parsers ifNil: [#()]
  141. !
  142. parsers: aCollection
  143. parsers := aCollection
  144. ! !
  145. !PPListParser methodsFor: 'copying'!
  146. copyWith: aParser
  147. ^self class withAll: (self parsers copyWith: aParser)
  148. ! !
  149. !PPListParser class methodsFor: 'instance creation'!
  150. withAll: aCollection
  151. ^self new
  152. parsers: aCollection;
  153. yourself
  154. !
  155. with: aParser with: anotherParser
  156. ^self withAll: (Array with: aParser with: anotherParser)
  157. ! !
  158. smalltalk.setup(smalltalk.PPListParser);
  159. PPListParser subclass: #PPSequenceParser
  160. instanceVariableNames: ''
  161. category: 'Parser'!
  162. !PPSequenceParser methodsFor: 'copying'!
  163. , aRule
  164. ^self copyWith: aRule
  165. ! !
  166. !PPSequenceParser methodsFor: 'parsing'!
  167. parse: aStream
  168. | start elements element |
  169. start := aStream position.
  170. elements := #().
  171. self parsers
  172. detect: [:each |
  173. element := each memoizedParse: aStream.
  174. elements add: element.
  175. element isParseFailure]
  176. ifNone: [].
  177. ^element isParseFailure
  178. ifFalse: [elements]
  179. ifTrue: [aStream position: start. element]
  180. ! !
  181. smalltalk.setup(smalltalk.PPSequenceParser);
  182. PPListParser subclass: #PPChoiceParser
  183. instanceVariableNames: ''
  184. category: 'Parser'!
  185. !PPChoiceParser methodsFor: 'copying'!
  186. / aRule
  187. ^self copyWith: aRule
  188. ! !
  189. !PPChoiceParser methodsFor: 'parsing'!
  190. parse: aStream
  191. | result |
  192. self parsers
  193. detect: [:each |
  194. result := each memoizedParse: aStream.
  195. result isParseFailure not]
  196. ifNone: [].
  197. ^result
  198. ! !
  199. smalltalk.setup(smalltalk.PPChoiceParser);
  200. PPParser subclass: #PPDelegateParser
  201. instanceVariableNames: 'parser'
  202. category: 'Parser'!
  203. !PPDelegateParser methodsFor: 'accessing'!
  204. parser
  205. ^parser
  206. !
  207. parser: aParser
  208. parser := aParser
  209. ! !
  210. !PPDelegateParser methodsFor: 'parsing'!
  211. parse: aStream
  212. ^self parser memoizedParse: aStream
  213. ! !
  214. !PPDelegateParser class methodsFor: 'instance creation'!
  215. on: aParser
  216. ^self new
  217. parser: aParser;
  218. yourself
  219. ! !
  220. smalltalk.setup(smalltalk.PPDelegateParser);
  221. PPDelegateParser subclass: #PPAndParser
  222. instanceVariableNames: ''
  223. category: 'Parser'!
  224. !PPAndParser methodsFor: 'parsing'!
  225. parse: aStream
  226. ^self basicParse: aStream
  227. !
  228. basicParse: aStream
  229. | element position |
  230. position := aStream position.
  231. element := self parser memoizedParse: aStream.
  232. aStream position: position.
  233. ^element
  234. ! !
  235. smalltalk.setup(smalltalk.PPAndParser);
  236. PPAndParser subclass: #PPNotParser
  237. instanceVariableNames: ''
  238. category: 'Parser'!
  239. !PPNotParser methodsFor: 'parsing'!
  240. parse: aStream
  241. | element |
  242. element := self basicParse: aStream.
  243. ^element isParseFailure
  244. ifTrue: [nil]
  245. ifFalse: [PPFailure reason: element at: aStream position]
  246. ! !
  247. smalltalk.setup(smalltalk.PPNotParser);
  248. PPDelegateParser subclass: #PPActionParser
  249. instanceVariableNames: 'block'
  250. category: 'Parser'!
  251. !PPActionParser methodsFor: 'accessing'!
  252. block
  253. ^block
  254. !
  255. block: aBlock
  256. block := aBlock
  257. ! !
  258. !PPActionParser methodsFor: 'parsing'!
  259. parse: aStream
  260. | element |
  261. element := self parser memoizedParse: aStream.
  262. ^element isParseFailure
  263. ifFalse: [self block value: element]
  264. ifTrue: [element]
  265. ! !
  266. !PPActionParser class methodsFor: 'instance creation'!
  267. on: aParser block: aBlock
  268. ^self new
  269. parser: aParser;
  270. block: aBlock;
  271. yourself
  272. ! !
  273. smalltalk.setup(smalltalk.PPActionParser);
  274. PPDelegateParser subclass: #PPFlattenParser
  275. instanceVariableNames: ''
  276. category: 'Parser'!
  277. !PPFlattenParser methodsFor: 'parsing'!
  278. parse: aStream
  279. | start element stop |
  280. start := aStream position.
  281. element := self parser memoizedParse: aStream.
  282. ^element isParseFailure
  283. ifTrue: [element]
  284. ifFalse: [aStream collection
  285. copyFrom: start + 1
  286. to: aStream position]
  287. ! !
  288. smalltalk.setup(smalltalk.PPFlattenParser);
  289. PPDelegateParser subclass: #PPSourceParser
  290. instanceVariableNames: ''
  291. category: 'Parser'!
  292. !PPSourceParser methodsFor: 'parsing'!
  293. parse: aStream
  294. | start element stop result |
  295. start := aStream position.
  296. element := self parser memoizedParse: aStream.
  297. ^element isParseFailure
  298. ifTrue: [element]
  299. ifFalse: [result := aStream collection copyFrom: start + 1 to: aStream position.
  300. Array with: element with: result].
  301. ! !
  302. smalltalk.setup(smalltalk.PPSourceParser);
  303. PPDelegateParser subclass: #PPRepeatingParser
  304. instanceVariableNames: 'min'
  305. category: 'Parser'!
  306. !PPRepeatingParser methodsFor: 'accessing'!
  307. min
  308. ^min
  309. !
  310. min: aNumber
  311. min := aNumber
  312. ! !
  313. !PPRepeatingParser methodsFor: 'parsing'!
  314. parse: aStream
  315. | start element elements failure |
  316. start := aStream position.
  317. elements := Array new.
  318. [(elements size < self min) and: [failure isNil]] whileTrue: [
  319. element := self parser memoizedParse: aStream.
  320. element isParseFailure
  321. ifFalse: [elements addLast: element]
  322. ifTrue: [aStream position: start.
  323. failure := element]].
  324. ^failure ifNil: [
  325. [failure isNil] whileTrue: [
  326. element := self parser memoizedParse: aStream.
  327. element isParseFailure
  328. ifTrue: [failure := element]
  329. ifFalse: [elements addLast: element]].
  330. elements]
  331. ifNotNil: [failure].
  332. ! !
  333. !PPRepeatingParser class methodsFor: 'instance creation'!
  334. on: aParser min: aNumber
  335. ^self new
  336. parser: aParser;
  337. min: aNumber;
  338. yourself
  339. ! !
  340. smalltalk.setup(smalltalk.PPRepeatingParser);
  341. Object subclass: #PPFailure
  342. instanceVariableNames: 'position reason'
  343. category: 'Parser'!
  344. !PPFailure methodsFor: 'accessing'!
  345. position
  346. ^position ifNil: [0]
  347. !
  348. position: aNumber
  349. position := aNumber
  350. !
  351. reason
  352. ^reason ifNil: ['']
  353. !
  354. reason: aString
  355. reason := aString
  356. !
  357. reason: aString at: anInteger
  358. self
  359. reason: aString;
  360. position: anInteger
  361. !
  362. accept: aVisitor
  363. aVisitor visitFailure: self
  364. ! !
  365. !PPFailure methodsFor: 'testing'!
  366. isParseFailure
  367. ^true
  368. !
  369. asString
  370. ^reason, ' at ', position asString
  371. ! !
  372. !PPFailure class methodsFor: 'instance creation'!
  373. reason: aString at: anInteger
  374. ^self new
  375. reason: aString at: anInteger;
  376. yourself
  377. ! !
  378. smalltalk.setup(smalltalk.PPFailure);
  379. Object subclass: #SmalltalkParser
  380. instanceVariableNames: ''
  381. category: 'Parser'!
  382. !SmalltalkParser methodsFor: 'grammar'!
  383. parser
  384. | method expression separator comment ws identifier keyword className string symbol number literalArray variable reference classReference literal ret methodParser expressionParser keyword unarySelector binarySelector keywordPattern unaryPattern binaryPattern assignment temps blockParamList block expression expressions subexpression statements sequence operand unaryMessage unarySend unaryTail binaryMessage binarySend binaryTail keywordMessage keywordSend keywordPair cascade message jsStatement |
  385. separator := (String cr, String space, String lf, String tab) asChoiceParser.
  386. comment := ('"' asCharacterParser, ('"' asParser not, PPAnyParser new) star, '"' asCharacterParser) flatten.
  387. ws := (separator / comment) star.
  388. identifier := ('a-z' asCharacterParser, 'a-zA-Z0-9' asCharacterParser star) flatten.
  389. keyword := (identifier, ':' asParser) flatten.
  390. className := ('A-Z' asCharacterParser, 'a-zA-Z0-9' asCharacterParser star) flatten.
  391. string := '''' asParser, ('''''' asParser / ('''' asParser not, PPAnyParser new)) star flatten, '''' asParser
  392. ==> [:node | ValueNode new value: ((node at: 2) replace: '''''' with: '''')].
  393. symbol := '#' asParser, 'a-zA-Z0-9' asCharacterParser plus flatten
  394. ==> [:node | ValueNode new value: node second].
  395. number := ('0-9' asCharacterParser plus, ('.' asParser, '0-9' asCharacterParser plus) optional) flatten
  396. ==> [:node | ValueNode new value: node asNumber].
  397. literal := PPDelegateParser new.
  398. literalArray := '#(' asParser, (ws, literal, ws) star, ')' asParser
  399. ==> [:node | ValueNode new value: (Array withAll: (node second collect: [:each | each second value]))].
  400. variable := identifier ==> [:token | VariableNode new value: token].
  401. classReference := className ==> [:token | ClassReferenceNode new value: token].
  402. reference := variable / classReference.
  403. binarySelector := '+*/=><,@%~-' asCharacterParser plus flatten.
  404. unarySelector := identifier.
  405. keywordPattern := (ws, keyword, ws, identifier) plus
  406. ==> [:nodes | Array
  407. with: ((nodes collect: [:each | each at: 2]) join: '')
  408. with: (nodes collect: [:each | each at: 4])].
  409. binaryPattern := ws, binarySelector, ws, identifier
  410. ==> [:node | Array with: node second with: (Array with: node fourth)].
  411. unaryPattern := ws, unarySelector
  412. ==> [:node | Array with: node second with: Array new].
  413. expression := PPDelegateParser new.
  414. expressions := expression, ((ws, '.' asParser, ws, expression) ==> [:node | node fourth]) star
  415. ==> [:node || result |
  416. result := Array with: node first.
  417. node second do: [:each | result add: each].
  418. result].
  419. assignment := reference, ws, ':=' asParser, ws, expression
  420. ==> [:node | AssignmentNode new left: node first; right: (node at: 5)].
  421. ret := '^' asParser, ws, expression, ws, '.' asParser optional
  422. ==> [:node | ReturnNode new
  423. addNode: node third;
  424. yourself].
  425. temps := '|' asParser, (ws, identifier) star, ws, '|' asParser
  426. ==> [:node | node second collect: [:each | each second]].
  427. blockParamList := (':' asParser, identifier, ws) plus, '|' asParser
  428. ==> [:node | node first collect: [:each | each second]].
  429. subexpression := '(' asParser, ws, expression, ws, ')' asParser
  430. ==> [:node | node third].
  431. statements := (ret ==> [:node | Array with: node]) / (expressions, ws, '.' asParser, ws, ret ==> [:node | node first add: (node at: 5); yourself]) / (expressions , '.' asParser optional ==> [:node | node first]).
  432. sequence := temps optional, ws, statements optional, ws
  433. ==> [:node | SequenceNode new
  434. temps: node first;
  435. nodes: node third;
  436. yourself].
  437. block := '[' asParser, ws, blockParamList optional, ws, sequence optional, ws, ']' asParser
  438. ==> [:node |
  439. BlockNode new
  440. parameters: node third;
  441. addNode: (node at: 5) asBlockSequenceNode].
  442. operand := literal / reference / subexpression.
  443. literal parser: number / string / literalArray / symbol / block.
  444. unaryMessage := ws, unarySelector, ':' asParser not
  445. ==> [:node | SendNode new selector: node second].
  446. unaryTail := PPDelegateParser new.
  447. unaryTail parser: (unaryMessage, unaryTail optional
  448. ==> [:node |
  449. node second
  450. ifNil: [node first]
  451. ifNotNil: [node second valueForReceiver: node first]]).
  452. unarySend := operand, unaryTail optional
  453. ==> [:node |
  454. node second
  455. ifNil: [node first]
  456. ifNotNil: [node second valueForReceiver: node first]].
  457. binaryMessage := ws, binarySelector, ws, (unarySend / operand)
  458. ==> [:node |
  459. SendNode new
  460. selector: node second;
  461. arguments: (Array with: node fourth)].
  462. binaryTail := PPDelegateParser new.
  463. binaryTail parser: (binaryMessage, binaryTail optional
  464. ==> [:node |
  465. node second
  466. ifNil: [node first]
  467. ifNotNil: [ node second valueForReceiver: node first]]).
  468. binarySend := unarySend, binaryTail optional
  469. ==> [:node |
  470. node second
  471. ifNil: [node first]
  472. ifNotNil: [node second valueForReceiver: node first]].
  473. keywordPair := keyword, ws, binarySend.
  474. keywordMessage := (ws, keywordPair) plus
  475. ==> [:nodes |
  476. SendNode new
  477. selector: ((nodes collect: [:each | each second first]) join: '');
  478. arguments: (nodes collect: [:each | each second third])].
  479. keywordSend := binarySend, keywordMessage
  480. ==> [:node |
  481. node second valueForReceiver: node first].
  482. message := binaryMessage / unaryMessage / keywordMessage.
  483. cascade := (keywordSend / binarySend), (ws, ';' asParser, message) plus
  484. ==> [:node |
  485. node first cascadeNodeWithMessages:
  486. (node second collect: [:each | each third])].
  487. jsStatement := '<' asParser, ('>>' asParser / ('>' asParser not, PPAnyParser new)) star flatten, '>' asParser
  488. ==> [:node | JSStatementNode new
  489. source: node second;
  490. yourself].
  491. expression parser: assignment / cascade / keywordSend / binarySend / jsStatement.
  492. method := (ws, (keywordPattern / binaryPattern / unaryPattern), ws, sequence optional, ws) withSource
  493. ==> [:node |
  494. MethodNode new
  495. selector: node first second first;
  496. arguments: node first second second;
  497. addNode: node first fourth;
  498. source: node second;
  499. yourself].
  500. ^method, PPEOFParser new ==> [:node | node first]
  501. ! !
  502. !SmalltalkParser methodsFor: 'parsing'!
  503. parse: aStream
  504. ^self parser parse: aStream
  505. ! !
  506. !SmalltalkParser class methodsFor: 'instance creation'!
  507. parse: aStream
  508. ^self new
  509. parse: aStream
  510. ! !
  511. smalltalk.setup(smalltalk.SmalltalkParser);
  512. Object subclass: #Chunk
  513. instanceVariableNames: 'contents'
  514. category: 'Parser'!
  515. !Chunk methodsFor: 'accessing'!
  516. contents
  517. ^contents ifNil: ['']
  518. !
  519. contents: aString
  520. contents := aString
  521. ! !
  522. !Chunk methodsFor: 'testing'!
  523. isEmptyChunk
  524. ^false
  525. !
  526. isInstructionChunk
  527. ^false
  528. ! !
  529. smalltalk.setup(smalltalk.Chunk);
  530. Chunk subclass: #InstructionChunk
  531. instanceVariableNames: ''
  532. category: 'Parser'!
  533. !InstructionChunk methodsFor: 'testing'!
  534. isInstructionChunk
  535. ^true
  536. ! !
  537. smalltalk.setup(smalltalk.InstructionChunk);
  538. Chunk subclass: #EmptyChunk
  539. instanceVariableNames: ''
  540. category: 'Parser'!
  541. !EmptyChunk methodsFor: 'testing'!
  542. isEmptyChunk
  543. ^true
  544. ! !
  545. smalltalk.setup(smalltalk.EmptyChunk);
  546. Object subclass: #ChunkParser
  547. instanceVariableNames: 'parser separator eof ws chunk emptyChunk instructionChunk'
  548. category: 'Parser'!
  549. !ChunkParser methodsFor: ''!
  550. instructionChunk
  551. ^instructionChunk ifNil: [
  552. instructionChunk := self ws, '!!' asParser, self chunk
  553. ==> [:node | InstructionChunk new contents: node last contents]]
  554. ! !
  555. !ChunkParser methodsFor: 'accessing'!
  556. parser
  557. ^parser ifNil: [
  558. parser := self instructionChunk / self emptyChunk / self chunk / self eof]
  559. !
  560. eof
  561. ^eof ifNil: [eof := self ws, PPEOFParser new ==> [:node | nil]]
  562. !
  563. separator
  564. ^separator ifNil: [separator := (String cr, String space, String lf, String tab) asChoiceParser]
  565. !
  566. ws
  567. ^ws ifNil: [ws := self separator star]
  568. !
  569. chunk
  570. ^chunk ifNil: [chunk := self ws, ('!!!!' asParser / ('!!' asParser not, PPAnyParser new)) plus flatten, '!!' asParser
  571. ==> [:node | Chunk new contents: (node second replace: '!!!!' with: '!!') trimBoth]]
  572. !
  573. emptyChunk
  574. ^emptyChunk ifNil: [emptyChunk := self separator plus, '!!' asParser, self ws ==> [:node | EmptyChunk new]]
  575. ! !
  576. smalltalk.setup(smalltalk.ChunkParser);
  577. Object subclass: #Importer
  578. instanceVariableNames: 'chunkParser'
  579. category: 'Parser'!
  580. !Importer methodsFor: 'accessing'!
  581. chunkParser
  582. ^chunkParser ifNil: [chunkParser := ChunkParser new parser]
  583. ! !
  584. !Importer methodsFor: 'fileIn'!
  585. import: aStream
  586. aStream atEnd ifFalse: [
  587. | nextChunk |
  588. nextChunk := self chunkParser parse: aStream.
  589. nextChunk ifNotNil: [
  590. nextChunk isInstructionChunk
  591. ifTrue: [(Compiler new loadExpression: nextChunk contents)
  592. scanFrom: aStream]
  593. ifFalse: [Compiler new loadExpression: nextChunk contents].
  594. self import: aStream]]
  595. ! !
  596. smalltalk.setup(smalltalk.Importer);
  597. Object subclass: #Exporter
  598. instanceVariableNames: ''
  599. category: 'Parser'!
  600. !Exporter methodsFor: 'fileOut'!
  601. exportCategory: aString
  602. | stream |
  603. stream := '' writeStream.
  604. (Smalltalk current classes
  605. select: [:each | each category = aString])
  606. do: [:each | stream nextPutAll: (self export: each)].
  607. self exportCategoryExtensions: aString on: stream.
  608. ^stream contents
  609. !
  610. export: aClass
  611. | stream |
  612. stream := '' writeStream.
  613. self exportDefinitionOf: aClass on: stream.
  614. self exportMethodsOf: aClass on: stream.
  615. self exportMetaDefinitionOf: aClass on: stream.
  616. self exportMethodsOf: aClass class on: stream.
  617. self exportSetupOf: aClass on: stream.
  618. ^stream contents
  619. ! !
  620. !Exporter methodsFor: 'private'!
  621. exportDefinitionOf: aClass on: aStream
  622. aStream
  623. nextPutAll: 'smalltalk.addClass(';
  624. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  625. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  626. nextPutAll: ', ['.
  627. aClass instanceVariableNames
  628. do: [:each | aStream nextPutAll: '''', each, '''']
  629. separatedBy: [aStream nextPutAll: ', '].
  630. aStream
  631. nextPutAll: '], ''';
  632. nextPutAll: aClass category, '''';
  633. nextPutAll: ');'.
  634. aClass comment notEmpty ifTrue: [
  635. aStream
  636. lf;
  637. nextPutAll: 'smalltalk.';
  638. nextPutAll: (self classNameFor: aClass);
  639. nextPutAll: '.comment=';
  640. nextPutAll: 'unescape(''', aClass comment escaped, ''')'].
  641. aStream lf
  642. !
  643. exportMetaDefinitionOf: aClass on: aStream
  644. aClass class instanceVariableNames isEmpty ifFalse: [
  645. aStream
  646. nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
  647. nextPutAll: '.iVarNames = ['.
  648. aClass class instanceVariableNames
  649. do: [:each | aStream nextPutAll: '''', each, '''']
  650. separatedBy: [aStream nextPutAll: ','].
  651. aStream nextPutAll: '];', String lf]
  652. !
  653. exportMethodsOf: aClass on: aStream
  654. aClass methodDictionary values do: [:each |
  655. (each category match: '^\*') ifFalse: [
  656. self exportMethod: each of: aClass on: aStream]].
  657. aStream lf
  658. !
  659. classNameFor: aClass
  660. ^aClass isMetaclass
  661. ifTrue: [aClass instanceClass name, '.klass']
  662. ifFalse: [
  663. aClass isNil
  664. ifTrue: ['nil']
  665. ifFalse: [aClass name]]
  666. !
  667. exportMethod: aMethod of: aClass on: aStream
  668. aStream
  669. nextPutAll: 'smalltalk.addMethod(';lf;
  670. nextPutAll: '''', aMethod selector asSelector, ''',';lf;
  671. nextPutAll: 'smalltalk.method({';lf;
  672. nextPutAll: 'selector: ''', aMethod selector, ''',';lf;
  673. nextPutAll: 'category: ''', aMethod category, ''',';lf;
  674. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  675. nextPutAll: 'source: unescape(''', aMethod source escaped, '''),';lf;
  676. nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
  677. nextPutAll: 'referencedClasses: ['.
  678. aMethod referencedClasses
  679. do: [:each | aStream nextPutAll: 'smalltalk.', (self classNameFor: each)]
  680. separatedBy: [aStream nextPutAll: ','].
  681. aStream
  682. nextPutAll: ']';lf;
  683. nextPutAll: '}),';lf;
  684. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  685. nextPutAll: ');';lf;lf
  686. !
  687. exportCategoryExtensions: aString on: aStream
  688. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  689. each methodDictionary values do: [:method |
  690. method category = ('*', aString) ifTrue: [
  691. self exportMethod: method of: each on: aStream]]]
  692. !
  693. exportSetupOf: aClass on: aStream
  694. aStream
  695. nextPutAll: 'smalltalk.setup(smalltalk.', (self classNameFor: aClass);
  696. nextPutAll: ');'.
  697. aStream lf
  698. ! !
  699. smalltalk.setup(smalltalk.Exporter);
  700. Exporter subclass: #ChunkExporter
  701. instanceVariableNames: ''
  702. category: 'Parser'!
  703. !ChunkExporter methodsFor: 'not yet classified'!
  704. exportDefinitionOf: aClass on: aStream
  705. "Chunk format."
  706. aStream
  707. nextPutAll: (self classNameFor: aClass superclass);
  708. nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
  709. nextPutAll: ' instanceVariableNames: '''.
  710. aClass instanceVariableNames
  711. do: [:each | aStream nextPutAll: each]
  712. separatedBy: [aStream nextPutAll: ' '].
  713. aStream
  714. nextPutAll: ''''; lf;
  715. nextPutAll: ' category: ''', aClass category, '''!!'; lf.
  716. aClass comment notEmpty ifTrue: [
  717. aStream
  718. nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
  719. nextPutAll: (self chunkEscape: aClass comment), '!!';lf].
  720. aStream lf
  721. !
  722. exportMethod: aMethod of: aClass on: aStream
  723. aStream
  724. lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;
  725. nextPutAll: '!!'
  726. !
  727. exportMethodsOf: aClass on: aStream
  728. aClass protocolsDo: [:category :methods |
  729. (category match: '^\*') ifFalse: [
  730. self
  731. exportMethods: methods
  732. category: category
  733. of: aClass
  734. on: aStream]]
  735. !
  736. exportMetaDefinitionOf: aClass on: aStream
  737. aClass class instanceVariableNames isEmpty ifFalse: [
  738. aStream
  739. nextPutAll: (self classNameFor: aClass class);
  740. nextPutAll: ' instanceVariableNames: '''.
  741. aClass class instanceVariableNames
  742. do: [:each | aStream nextPutAll: each]
  743. separatedBy: [aStream nextPutAll: ' '].
  744. aStream
  745. nextPutAll: '''!!'; lf; lf]
  746. !
  747. classNameFor: aClass
  748. ^aClass isMetaclass
  749. ifTrue: [aClass instanceClass name, ' class']
  750. ifFalse: [
  751. aClass isNil
  752. ifTrue: ['nil']
  753. ifFalse: [aClass name]]
  754. !
  755. chunkEscape: aString
  756. "Replace all occurrences of !! with !!!! and trim at both ends."
  757. ^(aString replace: '!!' with: '!!!!') trimBoth
  758. !
  759. exportCategoryExtensions: aString on: aStream
  760. "We need to override this one too since we need to group
  761. all methods in a given protocol under a leading methodsFor: chunk
  762. for that class."
  763. Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
  764. each protocolsDo: [:category :methods |
  765. category = ('*', aString) ifTrue: [
  766. self exportMethods: methods category: category of: each on: aStream]]]
  767. !
  768. exportMethods: methods category: category of: aClass on: aStream
  769. aStream
  770. nextPutAll: '!!', (self classNameFor: aClass);
  771. nextPutAll: ' methodsFor: ''', category, '''!!'.
  772. methods do: [:each |
  773. self exportMethod: each of: aClass on: aStream].
  774. aStream nextPutAll: ' !!'; lf; lf
  775. ! !
  776. smalltalk.setup(smalltalk.ChunkExporter);
  777. Exporter subclass: #StrippedExporter
  778. instanceVariableNames: ''
  779. category: 'Parser'!
  780. !StrippedExporter methodsFor: 'private'!
  781. exportDefinitionOf: aClass on: aStream
  782. aStream
  783. nextPutAll: 'smalltalk.addClass(';
  784. nextPutAll: '''', (self classNameFor: aClass), ''', ';
  785. nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
  786. nextPutAll: ', ['.
  787. aClass instanceVariableNames
  788. do: [:each | aStream nextPutAll: '''', each, '''']
  789. separatedBy: [aStream nextPutAll: ', '].
  790. aStream
  791. nextPutAll: '], ''';
  792. nextPutAll: aClass category, '''';
  793. nextPutAll: ');'.
  794. aStream lf
  795. !
  796. exportMethod: aMethod of: aClass on: aStream
  797. aStream
  798. nextPutAll: 'smalltalk.addMethod(';lf;
  799. nextPutAll: '''', aMethod selector asSelector, ''',';lf;
  800. nextPutAll: 'smalltalk.method({';lf;
  801. nextPutAll: 'selector: ''', aMethod selector, ''',';lf;
  802. nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
  803. nextPutAll: ']';lf;
  804. nextPutAll: '}),';lf;
  805. nextPutAll: 'smalltalk.', (self classNameFor: aClass);
  806. nextPutAll: ');';lf;lf
  807. ! !
  808. smalltalk.setup(smalltalk.StrippedExporter);