SystemOrganization addCategory: #'QuasiQuote-Core'! SystemOrganization addCategory: #'QuasiQuote-Tests'! !RBAssignmentNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 09:24'! quasiquoteVariable: aVariableNode value: aValueNode ^ self variable: aVariableNode lift value: aValueNode lift! ! !String methodsFor: '*quasiquote' stamp: 'lr 4/16/2008 16:35'! flattenAndLift ^ Array with: self lift! ! !RBCascadeNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 09:53'! quasiquoteMessages: aCollection ^ self messages: aCollection flattenAndLift! ! !RBLiteralArrayNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 09:36'! quasiquoteStartPosition: startInteger contents: anArray stopPosition: stopInteger isByteArray: aBoolean ^ self startPosition: startInteger contents: anArray stopPosition: stopInteger isByteArray: aBoolean! ! !RBArrayNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 11:03'! quasiquoteStatements: aCollection ^ self quasiquoteFlattenStatements: aCollection into: (self statements: OrderedCollection new)! ! !RBProgramNode class methodsFor: '*quasiquote-private' stamp: 'lr 4/27/2010 11:02'! quasiquoteFlattenStatements: aCollection into: aNode aCollection flattenAndLift do: [ :statement | statement isSequence ifFalse: [ aNode addNode: statement ] ifTrue: [ aNode isSequence ifTrue: [ statement temporaries do: [ :variable | (aNode defines: variable name) ifFalse: [ aNode addTemporaryNamed: variable name ] ] ]. self quasiquoteFlattenStatements: statement statements into: aNode ] ]. ^ aNode! ! !RBProgramNode methodsFor: '*quasiquote' stamp: 'lr 4/26/2010 21:17'! adjustBy: anInteger self flag: #todo! ! !RBProgramNode methodsFor: '*quasiquote' stamp: 'lr 3/11/2009 15:28'! lift ^ self copy parent: nil; yourself! ! !RBProgramNode methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 19:21'! lift: aToken ^ self lift! ! !RBProgramNode methodsFor: '*quasiquote' stamp: 'lr 4/26/2010 21:17'! swapWith: aNode self flag: #todo. self replaceWith: aNode! ! !CompiledMethod methodsFor: '*quasiquote-override' stamp: 'lr 6/10/2008 21:40'! methodNode | source | ^ self properties at: #parseTree ifAbsent: [ (source := self getSourceFromFile) isNil ifTrue: [ self decompile ] ifFalse: [ self parserClass new parse: source class: (self methodClass ifNil: [ self sourceClass ]) ] ]! ! TestCase subclass: #QQTestCase instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Tests'! QQTestCase class instanceVariableNames: 'asfsadf'! QQTestCase class instanceVariableNames: 'asfsadf'! QQTestCase subclass: #QQCompilerTest instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Tests'! !QQCompilerTest class methodsFor: 'accessing' stamp: 'lr 2/18/2010 19:15'! packageNamesUnderTest ^ #('QuasiQuote')! ! !QQCompilerTest methodsFor: 'testing' stamp: 'lr 4/27/2010 11:05'! testDynamicArray | normalParseTree quotedParseTree | normalParseTree := self parse: '{ 1. 2. 3. 4. 5. 6. 7 }'. quotedParseTree := self evaluate: '| other | other := RBSequenceNode statements: ((3 to: 5) collect: [ :i | i lift ]). ``{ 1. 2. `,other. 6. 7 }'. self assert: normalParseTree = quotedParseTree! ! !QQCompilerTest methodsFor: 'testing' stamp: 'lr 4/27/2010 11:08'! testDynamicBlock | normalParseTree quotedParseTree | normalParseTree := self parse: '[ :a | | b c | 1. 2. 3. 4. 5. 6. 7 ]'. quotedParseTree := self evaluate: '| other | other := RBSequenceNode temporaries: ``c statements: ((3 to: 5) collect: [ :i | i lift ]). ``[ :a | | b | 1. 2. `,other. 6. 7 ]'. self assert: normalParseTree = quotedParseTree! ! !QQCompilerTest methodsFor: 'testing-quote' stamp: 'lr 2/18/2010 19:27'! testQuoteCompiler | normal quoted | self expressions do: [ :each | normal := self parse: each. quoted := self evaluate: '``(' , each , ')'. self assert: normal = quoted description: each ]! ! !QQCompilerTest methodsFor: 'testing-quote' stamp: 'lr 2/18/2010 19:14'! testQuoteParse1 | ast | ast := self parse: '``(self yourself)'. self assert: (ast isKindOf: QQQuoteNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '``(self yourself)'). ast := self parse: '``(1 + 2)'. self assert: (ast isKindOf: QQQuoteNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '``(1 + 2)'). ast := self parse: '``(self raised: 1 to: 2)'. self assert: (ast isKindOf: QQQuoteNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '``(self raised: 1 to: 2)'). ast := self parse: '``{ 1 }'. self assert: (ast isKindOf: QQQuoteNode). self assert: (ast value isKindOf: RBArrayNode). self assert: (ast formattedCode beginsWith: '``{'). ast := self parse: '``[ ]'. self assert: (ast isKindOf: QQQuoteNode). self assert: (ast value isKindOf: RBBlockNode). self assert: (ast formattedCode beginsWith: '``['). ast := self parse: '``123'. self assert: (ast isKindOf: QQQuoteNode). self assert: (ast value isKindOf: RBLiteralNode). self assert: (ast formattedCode = '``123'). ast := self parse: '``x'. self assert: (ast isKindOf: QQQuoteNode). self assert: (ast value isKindOf: RBVariableNode). self assert: (ast formattedCode = '``x'). ast := self parse: '``x := 1'. self assert: (ast variable isKindOf: QQQuoteNode). self assert: (ast isKindOf: RBAssignmentNode). self assert: (ast formattedCode = '``x := 1')! ! !QQCompilerTest methodsFor: 'testing-quote' stamp: 'lr 2/18/2010 19:22'! testQuoteParse2 | normal quote | self expressions do: [ :each | normal := self parse: each. quote := self parse: '``(' , each , ')'. self assert: (quote formattedCode beginsWith: '``'). self assert: (quote isKindOf: QQQuoteNode). self assert: (quote value = normal) ]! ! !QQCompilerTest methodsFor: 'testing-splice' stamp: 'lr 2/18/2010 19:27'! testSpliceLiterals self assert: (self evaluate: '`@(1)') = 1. self assert: (self evaluate: '`@($a)') = $a. self assert: (self evaluate: '`@(''a'')') = 'a'. self assert: (self evaluate: '`@(true)') = true. self assert: (self evaluate: '`@(false)') = false. self assert: (self evaluate: '`@(nil)') = nil! ! !QQCompilerTest methodsFor: 'testing-splice' stamp: 'lr 2/18/2010 19:13'! testSpliceParse1 | ast | ast := self parse: '`@(self yourself)'. self assert: (ast isKindOf: QQSpliceNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '`@(self yourself)'). ast := self parse: '`@(1 + 2)'. self assert: (ast isKindOf: QQSpliceNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '`@(1 + 2)'). ast := self parse: '`@(self raised: 1 to: 2)'. self assert: (ast isKindOf: QQSpliceNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '`@(self raised: 1 to: 2)'). ast := self parse: '`@{ 1 }'. self assert: (ast isKindOf: QQSpliceNode). self assert: (ast value isKindOf: RBArrayNode). self assert: (ast formattedCode beginsWith: '`@{'). ast := self parse: '`@[ ]'. self assert: (ast isKindOf: QQSpliceNode). self assert: (ast value isKindOf: RBBlockNode). self assert: (ast formattedCode beginsWith: '`@['). ast := self parse: '`@123'. self assert: (ast isKindOf: QQSpliceNode). self assert: (ast value isKindOf: RBLiteralNode). self assert: (ast formattedCode = '`@123'). ast := self parse: '`@x'. self assert: (ast isKindOf: QQSpliceNode). self assert: (ast value isKindOf: RBVariableNode). self assert: (ast formattedCode = '`@x'). ast := self parse: '`@x := 1'. self assert: (ast variable isKindOf: QQSpliceNode). self assert: (ast isKindOf: RBAssignmentNode). self assert: (ast formattedCode = '`@x := 1')! ! !QQCompilerTest methodsFor: 'testing-splice' stamp: 'lr 2/18/2010 19:14'! testSpliceParse2 | normal splice | self expressions do: [ :each | normal := self parse: each. splice := self parse: '`@(' , each , ')'. self assert: (splice formattedCode beginsWith: '`@'). self assert: (splice isKindOf: QQSpliceNode). self assert: (splice value = normal) ]! ! !QQCompilerTest methodsFor: 'testing-splice' stamp: 'lr 2/18/2010 19:27'! testSpliceReferences self assert: (self evaluate: '`@(self name)') = self class name. self assert: (self evaluate: '`@(super name)') = self class name! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 4/26/2010 23:00'! testUnquoteCompiler1 | normal quoted | self literals do: [ :each | quoted := self evaluate: '``(`,(' , each storeString , ') zork)'. self assert: quoted isMessage. self assert: quoted selector = #zork. self assert: quoted receiver isLiteral. self assert: quoted receiver value = each ]! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 4/26/2010 22:59'! testUnquoteCompiler2 | quoted | self literals do: [ :each | quoted := self evaluate: '| expr | expr := ' , each storeString , '. ^ ``(`,expr zork)'. self assert: quoted isMessage. self assert: quoted selector = #zork. self assert: quoted receiver isLiteral. self assert: quoted receiver value = each ]! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 4/26/2010 22:57'! testUnquoteCompiler3 | normal quoted | self expressions do: [ :each | normal := self parse: each. quoted := self evaluate: '| expr | expr := ``(' , each , '). ^ ``(`,expr zork)'. self assert: quoted isMessage. self assert: quoted selector = #zork. self assert: quoted receiver = normal ]! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 5/3/2010 22:37'! testUnquoteCompiler4 | quoted | quoted := self evaluate: '| expr | expr := Array with: ``(1 raisedTo: 2) with: ``(2 negated). ^ ``{ `,expr }'. self halt. self assert: quoted isArray! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 2/18/2010 19:27'! testUnquoteError1 self should: [ self evaluate: '`,1' ] raise: QQUnquoteNotInQuote! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 2/18/2010 19:27'! testUnquoteError2 self should: [ self evaluate: '1 + `,2' ] raise: QQUnquoteNotInQuote! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 2/18/2010 19:27'! testUnquoteError3 self should: [ self evaluate: '[ `,3 ]' ] raise: QQUnquoteNotInQuote! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 2/18/2010 19:12'! testUnquoteParse1 | ast | ast := self parse: '`,(self yourself)'. self assert: (ast isKindOf: QQUnquoteNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '`,(self yourself)'). ast := self parse: '`,(1 + 2)'. self assert: (ast isKindOf: QQUnquoteNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '`,(1 + 2)'). ast := self parse: '`,(self raised: 1 to: 2)'. self assert: (ast isKindOf: QQUnquoteNode). self assert: (ast value isKindOf: RBMessageNode). self assert: (ast formattedCode = '`,(self raised: 1 to: 2)'). ast := self parse: '`,{ 1 }'. self assert: (ast isKindOf: QQUnquoteNode). self assert: (ast value isKindOf: RBArrayNode). self assert: (ast formattedCode beginsWith: '`,{'). ast := self parse: '`,[ ]'. self assert: (ast isKindOf: QQUnquoteNode). self assert: (ast value isKindOf: RBBlockNode). self assert: (ast formattedCode beginsWith: '`,['). ast := self parse: '`,123'. self assert: (ast isKindOf: QQUnquoteNode). self assert: (ast value isKindOf: RBLiteralNode). self assert: (ast formattedCode = '`,123'). ast := self parse: '`,x'. self assert: (ast isKindOf: QQUnquoteNode). self assert: (ast value isKindOf: RBVariableNode). self assert: (ast formattedCode = '`,x'). ast := self parse: '`,x := 1'. self assert: (ast variable isKindOf: QQUnquoteNode). self assert: (ast isKindOf: RBAssignmentNode). self assert: (ast formattedCode = '`,x := 1')! ! !QQCompilerTest methodsFor: 'testing-unquote' stamp: 'lr 2/18/2010 19:13'! testUnquoteParse2 | normal unquoted | self expressions do: [ :each | normal := self parse: each. unquoted := self parse: '`,(' , each , ')'. self assert: (unquoted formattedCode beginsWith: '`,'). self assert: (unquoted isKindOf: QQUnquoteNode). self assert: (unquoted value = normal) ]! ! QQTestCase subclass: #QQLiftTest instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Tests'! !QQLiftTest methodsFor: 'testing' stamp: 'lr 4/27/2010 09:40'! testLiftObjects self assert: #(1) lift class = QQObjectNode. self assert: #[1] lift class = QQObjectNode. self assert: Object new lift class = QQObjectNode! ! !QQLiftTest methodsFor: 'testing' stamp: 'lr 4/17/2008 15:50'! testObjects self assert: Object new lift class = QQObjectNode. self assert: (1 @ 2) lift class = QQObjectNode. self assert: (1 -> 2) lift class = QQObjectNode! ! !QQLiftTest methodsFor: 'testing' stamp: 'lr 4/27/2010 09:41'! testParseTree self trees do: [ :each | self assert: each lift = each. self deny: each lift == each ]! ! !QQTestCase class methodsFor: 'testing' stamp: 'lr 2/19/2010 14:22'! isAbstract ^ self name = #QQTestCase! ! !QQTestCase methodsFor: 'accessing' stamp: 'lr 2/19/2010 14:23'! compilerClass ^ QQCompiler! ! !QQTestCase methodsFor: 'utilities' stamp: 'lr 2/19/2010 14:23'! evaluate: aString ^ self compilerClass new evaluate: aString in: nil to: self notifying: self ifFail: [ self fail ] logged: false! ! !QQTestCase methodsFor: 'accessing-examples' stamp: 'lr 2/19/2010 14:23'! expressions ^ #( 'self' 'super' 'nil' 'true' 'false' 'thisContext' '''''' '''foo''' '#foo' '#()' '#(1)' '#(1 (2 3))' '#[]' '#[1]' '#[1 2]' '1' '1.0' '1 + 2' '1 + 2 + 3' '1 negated' '1 raisedTo: 2' '1 interpolateTo: 2 at: 3' '1 negated; negated' '1 raisedTo: 1 + 2' '1 raisedTo: (1 negated; negated)' 'x' 'x := y' 'x := y := y' '[ ]' '[ :a | ]' '[ :a :b | 1 ]' '[ 1 ]' '[ 1. 2 ]' '[ 1. ^ 2 ]' '[ :a | a ]' 'self foo: [ ]' 'self foo: [ :a | ]' 'self foo: [ :a :b | 1 ]' 'self foo: [ 1 ]' 'self foo: [ 1. 2 ]' 'self foo: [ :a | 1. ^ 2 ]' 'self foo: [ :a | a ]' '{ }' '{ 1 }' '{ 1 + 2 }' '{ 1 + 2. 3 }' )! ! !QQTestCase methodsFor: 'accessing-examples' stamp: 'lr 4/26/2010 22:49'! literals ^ #(nil true false 'abc' $a 123 #() #[] #(1 2) #[1 2])! ! !QQTestCase methodsFor: 'accessing-examples' stamp: 'lr 2/19/2010 14:29'! methods ^ #( 'foo' 'foo self' 'foo | a |' 'foo ^ a' 'foo | a | a' 'foo | a | ^ a' 'foo ' 'foo self' 'foo | a |' 'foo ^ a' 'foo | a | a' 'foo | a | ^ a' )! ! !QQTestCase methodsFor: 'utilities' stamp: 'lr 2/19/2010 14:23'! parse: aString ^ self compilerClass new parserClass parseExpression: aString! ! !QQTestCase methodsFor: 'utilities' stamp: 'lr 2/19/2010 14:24'! parseExpression: aString ^ self parserClass parseExpression: aString! ! !QQTestCase methodsFor: 'utilities' stamp: 'lr 2/19/2010 14:25'! parseMethod: aString ^ self parserClass parseMethod: aString! ! !QQTestCase methodsFor: 'accessing' stamp: 'lr 2/19/2010 14:24'! parserClass ^ QQParser! ! !QQTestCase methodsFor: 'accessing-examples' stamp: 'lr 2/19/2010 14:28'! trees | result | result := OrderedCollection new. self expressions do: [ :each | result add: (self parseExpression: each) ]. self methods do: [ :each | result add: (self parseMethod: each) ]. ^ result! ! QQTestCase subclass: #QQVisitorTest instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Tests'! !QQVisitorTest methodsFor: 'testing-flatten' stamp: 'lr 2/19/2010 14:47'! testFlattenDeeply | original expected | original := RBSequenceNode new addTemporariesNamed: #('a'); addNode: (RBLiteralNode value: 1); addNode: (RBSequenceNode new addTemporariesNamed: #('b'); addNode: (RBLiteralNode value: 2); addNode: (RBSequenceNode new addTemporariesNamed: #('c'); addNode: (RBLiteralNode value: 3); yourself); yourself); yourself. expected := RBSequenceNode new addTemporariesNamed: #('a' 'b' 'c'); addNode: (RBLiteralNode value: 1); addNode: (RBLiteralNode value: 2); addNode: (RBLiteralNode value: 3); yourself. self assert: (QQFlattenVisitor visit: original) = expected! ! !QQVisitorTest methodsFor: 'testing-flatten' stamp: 'lr 2/19/2010 14:40'! testFlattenIdentity self trees do: [ :each | self assert: (QQTransformVisitor visit: each) = each ]! ! !QQVisitorTest methodsFor: 'testing-flatten' stamp: 'lr 2/19/2010 14:44'! testFlattenStatements | original expected | original := RBSequenceNode new addNode: (RBVariableNode named: 'a'); addNode: (RBSequenceNode new addNode: (RBVariableNode named: 'b'); addNode: (RBVariableNode named: 'c'); yourself); addNode: (RBVariableNode named: 'd'); yourself. expected := RBSequenceNode new addNode: (RBVariableNode named: 'a'); addNode: (RBVariableNode named: 'b'); addNode: (RBVariableNode named: 'c'); addNode: (RBVariableNode named: 'd'); yourself. self assert: (QQFlattenVisitor visit: original) = expected ! ! !QQVisitorTest methodsFor: 'testing-flatten' stamp: 'lr 2/19/2010 14:45'! testFlattenTemporaries | original expected | original := RBSequenceNode new addTemporariesNamed: #('a' 'b'); addNode: (RBSequenceNode new addTemporariesNamed: #('a' 'c'); yourself); yourself. expected := RBSequenceNode new addTemporariesNamed: #('a' 'b' 'c'); yourself. self assert: (QQFlattenVisitor visit: original) = expected! ! !QQVisitorTest methodsFor: 'testing' stamp: 'lr 4/26/2010 21:21'! testFold self should: [ #() fold: [ :a :b | a + b ] ] raise: Error. self assert: (#(1) fold: [ :a :b | a + b ]) = 1. self assert: (#(1 2) fold: [ :a :b | a + b ]) = 3. self assert: (#(1 2 3) fold: [ :a :b | a + b ]) = 6. self assert: (#(1 2 3 4) fold: [ :a :b | a + b ]) = 10! ! !QQVisitorTest methodsFor: 'testing' stamp: 'lr 2/19/2010 16:00'! testQuoteIdentity self trees do: [ :each | self assert: (QQExpandVisitor visit: each) = each ]! ! !QQVisitorTest methodsFor: 'testing' stamp: 'lr 2/19/2010 14:28'! testTransformIdentity self trees do: [ :each | self assert: (QQTransformVisitor visit: each) = each ]! ! !RBConfigurableFormatter methodsFor: '*quasiquote' stamp: 'lr 2/14/2010 11:40'! acceptObjectNode: aNode codeStream space; nextPutAll: aNode formattedCode! ! !RBConfigurableFormatter methodsFor: '*quasiquote' stamp: 'lr 2/14/2010 11:40'! acceptQuoteNode: aNode self formatMeta: aNode! ! !RBConfigurableFormatter methodsFor: '*quasiquote' stamp: 'lr 2/14/2010 11:40'! acceptSpliceNode: aNode self formatMeta: aNode! ! !RBConfigurableFormatter methodsFor: '*quasiquote' stamp: 'lr 2/14/2010 11:40'! acceptUnquoteNode: aNode self formatMeta: aNode! ! !RBConfigurableFormatter methodsFor: '*quasiquote' stamp: 'lr 2/14/2010 11:40'! formatMeta: aNode codeStream nextPut: $`; nextPut: aNode prefix. self visitNode: aNode value! ! !Object methodsFor: '*quasiquote' stamp: 'lr 3/5/2008 11:04'! flattenAndLift ^ Array with: self lift! ! !Object methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 16:05'! lift ^ self lift: (RBLiteralToken value: self start: 0 stop: -1)! ! !Object methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 16:08'! lift: aToken ^ (self isLiteral ifTrue: [ RBLiteralNode ] ifFalse: [ QQObjectNode ]) literalToken: aToken! ! PPSmalltalkParser subclass: #QQParser instanceVariableNames: 'meta' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! QQParser class instanceVariableNames: 'meta metaQuote metaUnquote metaSplice'! QQParser class instanceVariableNames: 'meta metaQuote metaUnquote metaSplice'! !QQParser methodsFor: 'grammar-meta' stamp: 'lr 2/19/2010 15:55'! meta ^ (self metaFor: QQQuoteNode) / (self metaFor: QQUnquoteNode) / (self metaFor: QQSpliceNode) / (nil asParser)! ! !QQParser methodsFor: 'private' stamp: 'lr 2/14/2010 11:19'! meta: aClass wrap: aNode ^ aClass isNil ifTrue: [ aNode ] ifFalse: [ aClass value: aNode ]! ! !QQParser methodsFor: 'grammar-meta' stamp: 'lr 2/14/2010 11:26'! metaFor: aClass ^ (String with: $` with: aClass prefix) asParser ==> [ :node | aClass ]! ! !QQParser methodsFor: 'grammar' stamp: 'lr 2/19/2010 15:55'! primary ^ meta , super primary map: [ :class :node | self meta: class wrap: node ]! ! !QQParser methodsFor: 'grammar' stamp: 'lr 2/19/2010 15:55'! variable ^ meta , super variable map: [ :class :node | self meta: class wrap: node ]! ! RBValueNode subclass: #QQMetaNode instanceVariableNames: 'value' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQMetaNode class methodsFor: 'accessing' stamp: 'lr 2/18/2010 19:20'! prefix self subclassResponsibility! ! !QQMetaNode class methodsFor: 'instance creation' stamp: 'lr 2/29/2008 09:11'! value: aNode ^ self new value: aNode! ! !QQMetaNode methodsFor: 'comparing' stamp: 'lr 2/29/2008 09:12'! = anObject self == anObject ifTrue: [ ^ true ]. self class = anObject class ifFalse: [ ^ false ]. ^ self value = anObject value! ! !QQMetaNode methodsFor: 'accessing' stamp: 'lr 2/29/2008 09:10'! children ^ Array with: value! ! !QQMetaNode methodsFor: 'comparing' stamp: 'lr 2/29/2008 09:12'! hash ^ self value hash! ! !QQMetaNode methodsFor: 'copying' stamp: 'lr 2/18/2010 19:21'! postCopy super postCopy. self parent: value copy! ! !QQMetaNode methodsFor: 'accessing' stamp: 'lr 2/18/2010 15:33'! precedence ^ 0! ! !QQMetaNode methodsFor: 'accessing' stamp: 'lr 2/3/2009 18:00'! prefix ^ self class prefix! ! !QQMetaNode methodsFor: 'replacing' stamp: 'lr 2/29/2008 09:12'! replaceNode: aNode withNode: anotherNode value == aNode ifTrue: [ self value: anotherNode ]! ! !QQMetaNode methodsFor: 'accessing-token' stamp: 'lr 2/29/2008 09:11'! startWithoutParentheses ^ value startWithoutParentheses! ! !QQMetaNode methodsFor: 'accessing-token' stamp: 'lr 2/29/2008 09:11'! stopWithoutParentheses ^ value stopWithoutParentheses! ! !QQMetaNode methodsFor: 'accessing' stamp: 'lr 2/29/2008 09:10'! value ^ value! ! !QQMetaNode methodsFor: 'accessing' stamp: 'lr 2/29/2008 11:16'! value: aNode value := aNode. value parent: self! ! QQMetaNode subclass: #QQQuoteNode instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQQuoteNode commentStamp: 'lr 2/29/2008 14:35' prior: 0! Quote inhibits the normal evaluation rule for the parse-tree value, allowing value to be employed as data. Example: `(1 + 2) --> RBMessageNode(1 + 2)! !QQQuoteNode class methodsFor: 'accessing' stamp: 'lr 2/3/2009 17:59'! prefix ^ $`! ! !QQQuoteNode methodsFor: 'visitor' stamp: 'lr 2/29/2008 10:40'! acceptVisitor: aVisitor ^ aVisitor acceptQuoteNode: self! ! QQMetaNode subclass: #QQSpliceNode instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQSpliceNode commentStamp: 'lr 2/28/2008 21:01' prior: 0! A splice evaluates the expression within at compile-time, replacing the splice annotation itself with the AST resulting from its evaluation.! !QQSpliceNode class methodsFor: 'accessing' stamp: 'lr 2/3/2009 17:59'! prefix ^ $@! ! !QQSpliceNode methodsFor: 'visitor' stamp: 'lr 2/29/2008 14:59'! acceptVisitor: aVisitor ^ aVisitor acceptSpliceNode: self! ! QQMetaNode subclass: #QQUnquoteNode instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQUnquoteNode class methodsFor: 'accessing' stamp: 'lr 2/3/2009 18:00'! prefix ^ $,! ! !QQUnquoteNode methodsFor: 'visitor' stamp: 'lr 2/29/2008 10:41'! acceptVisitor: aVisitor ^ aVisitor acceptUnquoteNode: self! ! !RBFormatter methodsFor: '*quasiquote' stamp: 'lr 4/17/2008 15:41'! acceptObjectNode: aNode codeStream space; nextPutAll: aNode formattedCode! ! !RBFormatter methodsFor: '*quasiquote' stamp: 'lr 2/29/2008 15:41'! acceptQuoteNode: aNode self formatMeta: aNode! ! !RBFormatter methodsFor: '*quasiquote' stamp: 'lr 2/29/2008 15:01'! acceptSpliceNode: aNode self formatMeta: aNode! ! !RBFormatter methodsFor: '*quasiquote' stamp: 'lr 2/29/2008 10:41'! acceptUnquoteNode: aNode self formatMeta: aNode! ! !RBFormatter methodsFor: '*quasiquote' stamp: 'lr 2/29/2008 19:58'! formatMeta: aNode codeStream nextPut: $`; nextPut: aNode prefix. self visitNode: aNode value! ! !RBSequenceNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 11:50'! quasiquoteTemporaries: variableNodes statements: statementNodes ^ self quasiquoteFlattenStatements: statementNodes into: (self temporaries: (variableNodes collect: [ :each | each lift ]) statements: OrderedCollection new)! ! Error subclass: #QQUnquoteNotInQuote instanceVariableNames: 'node' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! RBCompiler subclass: #QQCompiler instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQCompiler methodsFor: 'configuration' stamp: 'lr 2/14/2010 11:27'! parserClass ^ QQParser! ! !QQCompiler methodsFor: 'private' stamp: 'lr 4/27/2010 11:34'! translate: aProgramNode ^ super translate: (QQFlattenVisitor visit: (QQExpandVisitor visit: aProgramNode in: class theNonMetaClass))! ! !RBVariableNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 09:33'! quasiquoteNamed: aString ^ self named: aString! ! !RBCompilerTranslator methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 19:40'! acceptObjectNode: aNode ^ self acceptLiteralNode: aNode! ! !RBCompilerTranslator methodsFor: '*quasiquote' stamp: 'lr 2/19/2010 15:08'! acceptQuoteNode: aNode self error: aNode printString , ' should be gone for translation'! ! !RBCompilerTranslator methodsFor: '*quasiquote' stamp: 'lr 2/19/2010 15:08'! acceptSpliceNode: aNode self error: aNode printString , ' should be gone for translation'! ! !RBCompilerTranslator methodsFor: '*quasiquote' stamp: 'lr 2/19/2010 15:08'! acceptUnquoteNode: aNode self error: aNode printString , ' should be gone for translation'! ! !SHParserST80 methodsFor: '*quasiquote-override' stamp: 'lr 4/16/2008 14:21'! scanWhitespace | c | [ c := self currentChar. c notNil and: [ c isSeparator ] ] whileTrue: [ sourcePosition := sourcePosition + 1 ]. c = $` ifTrue: [ sourcePosition := sourcePosition + 2 ]. c = $" ifTrue: [ self scanComment ]! ! !Collection methodsFor: '*quasiquote' stamp: 'lr 4/16/2008 16:35'! flattenAndLift ^ self gather: [ :each | each flattenAndLift ]! ! !Collection methodsFor: '*quasiquote' stamp: 'lr 4/26/2010 21:19'! fold: aBlock | result marker | result := nil. marker := true. self emptyCheck. self do: [ :each | result := marker ifTrue: [ marker := false. each ] ifFalse: [ aBlock value: result value: each ] ]. ^ result! ! !RBBlockNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 11:51'! quasiquoteArguments: aCollection body: aSequenceNode ^ self arguments: (aCollection collect: [ :each | each lift ]) body: aSequenceNode lift! ! !Array methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 16:20'! lift: aToken ^ QQObjectNode literalToken: aToken! ! !RBMessageNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 11:51'! quasiquoteReceiver: aValueNode selector: aSymbol arguments: valueNodes ^ self receiver: aValueNode lift selector: aSymbol arguments: (valueNodes collect: [ :each | each lift ])! ! RBProgramNodeVisitor subclass: #QQTransformVisitor instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! QQTransformVisitor subclass: #QQExpandVisitor instanceVariableNames: 'context' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQExpandVisitor class methodsFor: 'instance creation' stamp: 'lr 2/19/2010 15:59'! visit: aNode in: aContext ^ self new context: aContext; start: aNode! ! !QQExpandVisitor methodsFor: 'visitor-quasiquote' stamp: 'lr 2/19/2010 14:11'! acceptQuoteNode: aNode "Create a quasiquoted expression from aNode and use the result to continue with the normal code transformation." ^ self visitNode: (QQQuotedVisitor visit: aNode value)! ! !QQExpandVisitor methodsFor: 'visitor-quasiquote' stamp: 'lr 2/19/2010 15:22'! acceptSpliceNode: aNode "Evaluate the splice in the given context and insert the result into the generated AST." | result | result := context class compilerClass new evaluate: aNode value formattedCode in: nil to: context notifying: nil ifFail: [ nil ] logged: false. ^ self visitNode: result lift! ! !QQExpandVisitor methodsFor: 'visitor-quasiquote' stamp: 'lr 2/19/2010 14:12'! acceptUnquoteNode: aNode "Unquote cannot appear outside a quote." ^ QQUnquoteNotInQuote signal! ! !QQExpandVisitor methodsFor: 'accessing' stamp: 'lr 2/19/2010 14:20'! context: anObject context := anObject! ! !QQExpandVisitor methodsFor: 'visitor' stamp: 'lr 4/27/2010 11:09'! start: aNode "Make sure to not lose the parent if we have a meta replacement at the root." | node | node := super start: aNode. aNode parent notNil ifTrue: [ aNode replaceWith: node ]. ^ node! ! QQTransformVisitor subclass: #QQFlattenVisitor instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQFlattenVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 11:36'! acceptArrayNode: aNode "Code transformation can cause arrays to nest sequences. Flatten those into a single array to not confuse follow-up transformations." | array statements | array := super acceptArrayNode: aNode. statements := OrderedCollection new: array statements size. array statements do: [ :statement | statement isSequence ifFalse: [ statements addLast: statement ] ifTrue: [ statements addAll: statement statements ] ]. ^ array statements: statements; yourself! ! !QQFlattenVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 11:35'! acceptSequenceNode: aNode "Code transformation can cause sequences to be nested. Flatten those into a single sequence to not confuse follow-up transformations." | sequence temporaries statements | sequence := super acceptSequenceNode: aNode. temporaries := OrderedCollection withAll: sequence temporaries. statements := OrderedCollection new: sequence statements size. sequence statements do: [ :statement | statement isSequence ifFalse: [ statements addLast: statement ] ifTrue: [ statement temporaries do: [ :variable | (temporaries includes: variable) ifFalse: [ temporaries addLast: variable ] ]. statements addAll: statement statements ] ]. ^ sequence temporaries: temporaries; statements: statements; yourself! ! QQTransformVisitor subclass: #QQQuotedVisitor instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQQuotedVisitor class methodsFor: 'instance creation' stamp: 'lr 2/18/2010 17:01'! visit: aNode ^ self new visitNode: aNode! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:53'! acceptArrayNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBArrayNode name) selector: #quasiquoteStatements: arguments: (Array with: (self visitAll: aNode statements))! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:24'! acceptAssignmentNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBAssignmentNode name) selector: #quasiquoteVariable:value: arguments: (Array with: (self visitNode: aNode variable) with: (self visitNode: aNode value))! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:54'! acceptBlockNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBBlockNode name) selector: #quasiquoteArguments:body: arguments: (Array with: (self visitAll: aNode arguments) with: (self visitNode: aNode body))! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:52'! acceptCascadeNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBCascadeNode name) selector: #quasiquoteMessages: arguments: (Array with: (self visitAll: aNode messages))! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:36'! acceptLiteralArrayNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBLiteralArrayNode name) selector: #quasiquoteStartPosition:contents:stopPosition:isByteArray: arguments: (Array with: aNode start lift with: (self visitAll: aNode contents) with: aNode stop lift with: aNode isForByteArray lift)! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:53'! acceptLiteralNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBLiteralValueNode name) selector: #quasiquoteValue: arguments: (Array with: aNode value lift)! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:49'! acceptMessageNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBMessageNode name) selector: #quasiquoteReceiver:selector:arguments: arguments: (Array with: (self visitNode: aNode receiver) with: (aNode selector lift) with: (self visitAll: aNode arguments))! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:53'! acceptReturnNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBReturnNode name) selector: #quasiquoteValue: arguments: (Array with: (self visitNode: aNode value))! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:32'! acceptSequenceNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBSequenceNode name) selector: #quasiquoteTemporaries:statements: arguments: (Array with: (self visitAll: aNode temporaries) with: (self visitAll: aNode statements))! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 11:46'! acceptUnquoteNode: aNode ^ aNode value! ! !QQQuotedVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 4/27/2010 09:52'! acceptVariableNode: aNode ^ RBMessageNode receiver: (RBVariableNode named: RBVariableNode name) selector: #quasiquoteNamed: arguments: (Array with: aNode name lift)! ! !QQQuotedVisitor methodsFor: 'visitor' stamp: 'lr 4/27/2010 09:46'! visitAll: aCollection ^ RBArrayNode statements: (super visitAll: aCollection)! ! !QQTransformVisitor class methodsFor: 'instance creation' stamp: 'lr 2/19/2010 15:33'! visit: aNode ^ self new start: aNode! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:43'! acceptArrayNode: aNode ^ aNode statements: (self visitAll: aNode statements); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:43'! acceptAssignmentNode: aNode ^ aNode variable: (self visitNode: aNode variable); value: (self visitNode: aNode value); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:43'! acceptBlockNode: aNode ^ aNode arguments: (self visitAll: aNode arguments); body: (self visitNode: aNode body); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:44'! acceptCascadeNode: aNode ^ aNode messages: (self visitAll: aNode messages); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:44'! acceptLiteralArrayNode: aNode ^ aNode contents: (self visitAll: aNode contents); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:43'! acceptLiteralNode: aNode ^ aNode! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:44'! acceptMessageNode: aNode ^ aNode receiver: (self visitNode: aNode receiver); arguments: (self visitAll: aNode arguments); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:44'! acceptMethodNode: aNode ^ aNode arguments: (self visitAll: aNode arguments); pragmas: (self visitAll: aNode pragmas); body: (self visitNode: aNode body); yourself! ! !QQTransformVisitor methodsFor: 'visitor-quasiquote' stamp: 'lr 2/19/2010 14:08'! acceptObjectNode: aNode ^ aNode! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:44'! acceptPragmaNode: aNode ^ aNode arguments: (self visitAll: aNode arguments); yourself! ! !QQTransformVisitor methodsFor: 'visitor-quasiquote' stamp: 'lr 2/19/2010 15:28'! acceptQuoteNode: aNode ^ aNode value: (self visitNode: aNode value); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:44'! acceptReturnNode: aNode ^ aNode value: (self visitNode: aNode value); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:45'! acceptSequenceNode: aNode ^ aNode temporaries: (self visitAll: aNode temporaries); statements: (self visitAll: aNode statements); yourself! ! !QQTransformVisitor methodsFor: 'visitor-quasiquote' stamp: 'lr 2/19/2010 15:28'! acceptSpliceNode: aNode ^ aNode value: (self visitNode: aNode value); yourself! ! !QQTransformVisitor methodsFor: 'visitor-quasiquote' stamp: 'lr 2/19/2010 15:28'! acceptUnquoteNode: aNode ^ aNode value: (self visitNode: aNode value); yourself! ! !QQTransformVisitor methodsFor: 'visitor-dispatching' stamp: 'lr 2/19/2010 13:45'! acceptVariableNode: aNode ^ aNode! ! !QQTransformVisitor methodsFor: 'visitor' stamp: 'lr 2/19/2010 15:33'! start: aNode ^ self visitNode: aNode! ! !QQTransformVisitor methodsFor: 'visitor' stamp: 'lr 2/19/2010 13:41'! visitAll: aCollection ^ aCollection collect: [ :each | self visitNode: each ]! ! !RBProgramNodeVisitor methodsFor: '*quasiquote' stamp: 'lr 4/17/2008 15:41'! acceptObjectNode: aNode self acceptLiteralNode: aNode! ! !RBProgramNodeVisitor methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 19:17'! acceptQuoteNode: aNode self visitNode: aNode value! ! !RBProgramNodeVisitor methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 19:17'! acceptSpliceNode: aNode self visitNode: aNode value! ! !RBProgramNodeVisitor methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 19:17'! acceptUnquoteNode: aNode self visitNode: aNode value! ! !ByteArray methodsFor: '*quasiquote' stamp: 'lr 2/18/2010 16:21'! lift: aToken ^ QQObjectNode literalToken: aToken! ! !RBReturnNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 09:56'! quasiquoteValue: aProgramNode ^ self value: aProgramNode lift! ! RBLiteralValueNode subclass: #QQObjectNode instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'QuasiQuote-Core'! !QQObjectNode methodsFor: 'comparing' stamp: 'lr 4/17/2008 15:39'! = anObject ^ self == anObject or: [ self class = anObject class and: [ self value = anObject value ] ]! ! !QQObjectNode methodsFor: 'visitor' stamp: 'lr 4/17/2008 15:40'! acceptVisitor: aVisitor ^ aVisitor acceptObjectNode: self! ! !QQObjectNode methodsFor: 'accessing' stamp: 'lr 4/17/2008 15:54'! formattedCode ^ self value printString! ! !QQObjectNode methodsFor: 'comparing' stamp: 'lr 3/18/2009 10:07'! hash ^ self value hash! ! !RBLiteralValueNode class methodsFor: '*quasiquote-instance creation' stamp: 'lr 4/27/2010 09:36'! quasiquoteValue: anObject ^ self value: anObject! !