[squeak-dev] The Inbox: Compiler.quasiquote-eem.248.mcz
commits at source.squeak.org
commits at source.squeak.org
Wed Feb 6 05:54:46 UTC 2013
A new version of Compiler was added to project The Inbox:
http://source.squeak.org/inbox/Compiler.quasiquote-eem.248.mcz
==================== Summary ====================
Name: Compiler.quasiquote-eem.248
Author: eem
Time: 5 February 2013, 9:54:20.317 pm
UUID: ef044906-3339-48cc-856b-9b5172e3e81b
Ancestors: Compiler-cwp.247
Add a quasi-quote form that allows convenient embedding
of substrings within a format string, and provides a
convenient way of embedding literal strings within an
alternative literal string whose string delimiter is different.
e.g.
`hello [#cruel] world!`
evaluates to
'hello cruel world'.
`S1[B1]...SN[BN]SN+1`
is equivalent to
{ 'S1'. [B1] value. ... 'SN'. [BN] value. 'SN+1' } concatenateQuasiQuote
where concatenateQuasiQuote sends asString to each
element and answers the concatenation of those elements.
however, single-statement blocks are inlined, so e.g. the
above `hello [#cruel] world!` is compiled as
{ 'hello '. #cruel. ' world!' } concatenateQuasiQuote
See Tests.quasiquote-eem.188 for tests and examples.
=============== Diff against Compiler-cwp.247 ===============
Item was added:
+ ----- Method: Array>>concatenateQuasiQuote (in category '*Compiler-support') -----
+ concatenateQuasiQuote
+ "This method is used in compilation of quasi-quote constructs.
+ It MUST NOT be deleted or altered."
+
+ | s sz |
+ sz := self size.
+ s := WriteStream on: (String new: sz * 16).
+ 1 to: sz do:
+ [:i| s nextPutAll: (self at: i) asString].
+ ^s contents!
Item was removed:
- ----- Method: Decompiler>>checkForBlock:selector:arguments: (in category 'control') -----
- checkForBlock: receiver selector: selector arguments: arguments
- selector == #blockCopy: ifTrue:
- [^self checkForBlockCopy: receiver].
- self assert: selector == #closureCopy:copiedValues:.
- ^self checkForClosureCopy: receiver arguments: arguments!
Item was added:
+ ----- Method: Decompiler>>checkForMacroMessage:selector:arguments: (in category 'control') -----
+ checkForMacroMessage: rcvr selector: selector arguments: args
+ ^ (selector == #concatenateQuasiQuote
+ and: [self checkForQuasiQuote: rcvr selector: selector arguments: args])
+ or: [(#closureCopy:copiedValues: == selector
+ and: [self checkForClosureCopy: rcvr arguments: args])
+ or: [#blockCopy: == selector
+ and: [self checkForBlockCopy: rcvr]]]!
Item was added:
+ ----- Method: Decompiler>>checkForQuasiQuote:selector:arguments: (in category 'control') -----
+ checkForQuasiQuote: rcvr "<BraceNode>" selector: selector "<Symbol>" arguments: args "<Array>"
+ stack addLast:
+ ((MessageNode new
+ receiver: rcvr
+ selector: (SelectorNode new key: #concatenateQuasiQuote code: nil)
+ arguments: args
+ precedence: 1)
+ notePrintingSelector: #printQuasiQuoteOn:indent:;
+ yourself).
+ ^true!
Item was changed:
----- Method: Decompiler>>send:super:numArgs: (in category 'instruction decoding') -----
send: selector super: superFlag numArgs: numArgs
| args rcvr selNode msgNode messages |
args := Array new: numArgs.
(numArgs to: 1 by: -1) do:
[:i | args at: i put: stack removeLast].
rcvr := stack removeLast.
superFlag ifTrue: [rcvr := constructor codeSuper].
+ (self checkForMacroMessage: rcvr selector: selector arguments: args) ifFalse:
- ((#(blockCopy: closureCopy:copiedValues:) includes: selector)
- and: [self checkForBlock: rcvr selector: selector arguments: args]) ifFalse:
[selNode := constructor codeAnySelector: selector.
rcvr == CascadeFlag
ifTrue:
["May actually be a cascade or an ifNil: for value."
self willJumpIfFalse
ifTrue: "= generated by a case macro"
[selector == #= ifTrue:
[" = signals a case statement..."
statements addLast: args first.
stack addLast: rcvr. "restore CascadeFlag"
^ self].
selector == #== ifTrue:
[" == signals an ifNil: for value..."
stack removeLast; removeLast.
rcvr := stack removeLast.
stack addLast: IfNilFlag;
addLast: (constructor
codeMessage: rcvr
selector: selNode
arguments: args).
^ self]]
ifFalse:
[(self willJumpIfTrue and: [selector == #==]) ifTrue:
[" == signals an ifNotNil: for value..."
stack removeLast; removeLast.
rcvr := stack removeLast.
stack addLast: IfNilFlag;
addLast: (constructor
codeMessage: rcvr
selector: selNode
arguments: args).
^ self]].
msgNode := constructor
codeCascadedMessage: selNode
arguments: args.
stack last == CascadeFlag ifFalse:
["Last message of a cascade"
statements addLast: msgNode.
messages := self popTo: stack removeLast. "Depth saved by first dup"
msgNode := constructor
codeCascade: stack removeLast
messages: messages]]
ifFalse:
[msgNode := constructor
codeMessage: rcvr
selector: selNode
arguments: args].
stack addLast: msgNode]!
Item was changed:
----- Method: MessageNode class>>initialize (in category 'class initialization') -----
initialize
"MessageNode initialize"
MacroSelectors :=
#( ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue:
and: or:
whileFalse: whileTrue: whileFalse whileTrue
to:do: to:by:do:
caseOf: caseOf:otherwise:
ifNil: ifNotNil: ifNil:ifNotNil: ifNotNil:ifNil:
+ repeat
+ nil "space for concatenateQuasiQuote" ).
- repeat ).
MacroTransformers :=
#( transformIfTrue: transformIfFalse: transformIfTrueIfFalse: transformIfFalseIfTrue:
transformAnd: transformOr:
transformWhile: transformWhile: transformWhile: transformWhile:
transformToDo: transformToDo:
transformCase: transformCase:
transformIfNil: transformIfNil: transformIfNilIfNotNil: transformIfNotNilIfNil:
+ transformRepeat:
+ nil "space for concatenateQuasiQuote" ).
- transformRepeat: ).
MacroEmitters :=
#( emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
emitCodeForWhile:encoder:value: emitCodeForWhile:encoder:value:
emitCodeForWhile:encoder:value: emitCodeForWhile:encoder:value:
emitCodeForToDo:encoder:value: emitCodeForToDo:encoder:value:
emitCodeForCase:encoder:value: emitCodeForCase:encoder:value:
emitCodeForIfNil:encoder:value: emitCodeForIfNil:encoder:value:
emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
+ emitCodeForRepeat:encoder:value:
+ nil "space for concatenateQuasiQuote").
- emitCodeForRepeat:encoder:value:).
MacroSizers :=
#( sizeCodeForIf:value: sizeCodeForIf:value: sizeCodeForIf:value: sizeCodeForIf:value:
sizeCodeForIf:value: sizeCodeForIf:value:
sizeCodeForWhile:value: sizeCodeForWhile:value: sizeCodeForWhile:value: sizeCodeForWhile:value:
sizeCodeForToDo:value: sizeCodeForToDo:value:
sizeCodeForCase:value: sizeCodeForCase:value:
sizeCodeForIfNil:value: sizeCodeForIfNil:value: sizeCodeForIf:value: sizeCodeForIf:value:
+ sizeCodeForRepeat:value:
+ nil "space for concatenateQuasiQuote").
- sizeCodeForRepeat:value:).
MacroPrinters :=
#( printIfOn:indent: printIfOn:indent: printIfOn:indent: printIfOn:indent:
printIfOn:indent: printIfOn:indent:
printWhileOn:indent: printWhileOn:indent: printWhileOn:indent: printWhileOn:indent:
printToDoOn:indent: printToDoOn:indent:
printCaseOn:indent: printCaseOn:indent:
printIfNil:indent: printIfNil:indent: printIfNilNotNil:indent: printIfNilNotNil:indent:
+ printRepeatOn:indent:
+ printQuasiQuoteOn:indent:)!
- printRepeatOn:indent:)!
Item was added:
+ ----- Method: MessageNode>>notePrintingSelector: (in category 'macro transformations') -----
+ notePrintingSelector: printingSelectorSymbol
+ "decompile"
+
+ special := MacroPrinters indexOf: printingSelectorSymbol!
Item was added:
+ ----- Method: MessageNode>>printQuasiQuoteOn:indent: (in category 'printing') -----
+ printQuasiQuoteOn: aStream indent: level
+ aStream nextPut: $`.
+ receiver elements do:
+ [:parseNode|
+ (parseNode isLiteralNode
+ and: [parseNode key class == 'literal' class])
+ ifTrue:
+ [parseNode key do:
+ [:char|
+ ('`[\' includes: char) ifTrue:
+ [aStream nextPut: $\].
+ aStream nextPut: char]]
+ ifFalse:
+ [(parseNode isMessageNode
+ and: [parseNode selector key == #value
+ and: [parseNode receiver isBlockNode]])
+ ifTrue:
+ [parseNode receiver printOn: aStream indent: 0]
+ ifFalse:
+ [aStream nextPut: $[.
+ parseNode printOn: aStream indent: 0.
+ aStream nextPut: $]]]].
+ aStream nextPut: $`!
Item was changed:
----- Method: Parser>>advance (in category 'scanning') -----
advance
| this |
prevMark := hereMark.
prevEnd := hereEnd.
this := here.
here := token.
hereType := tokenType.
hereMark := mark.
hereEnd := source position - (aheadChar == DoItCharacter
ifTrue: [hereChar == DoItCharacter
ifTrue: [0]
ifFalse: [1]]
ifFalse: [2]).
+ hereType ~~ #backQuote ifTrue:
+ [self scanToken].
- self scanToken.
"Transcript show: 'here: ', here printString, ' mark: ', hereMark printString, ' end: ', hereEnd printString; cr."
^this!
Item was changed:
----- Method: Parser>>expression (in category 'expression types') -----
expression
+ (hereType == #word and: [tokenType == #leftArrow]) ifTrue:
+ [^self assignment: self variable].
+ hereType == #backQuote
+ ifTrue: [self quasiQuoteExpression]
+ ifFalse:
+ [hereType == #leftBrace
+ ifTrue: [self braceExpression]
+ ifFalse:
+ [self primaryExpression ifFalse:
+ [^false]]].
+ (self messagePart: 3 repeat: true) ifTrue:
+ [hereType == #semicolon ifTrue:
+ [self cascade]].
+ ^true!
- (hereType == #word and: [tokenType == #leftArrow])
- ifTrue: [^ self assignment: self variable].
- hereType == #leftBrace
- ifTrue: [self braceExpression]
- ifFalse: [self primaryExpression ifFalse: [^ false]].
- (self messagePart: 3 repeat: true)
- ifTrue: [hereType == #semicolon ifTrue: [self cascade]].
- ^ true!
Item was added:
+ ----- Method: Parser>>nonQuasiQuoteExpression (in category 'expression types') -----
+ nonQuasiQuoteExpression
+
+ (hereType == #word and: [tokenType == #leftArrow])
+ ifTrue: [^ self assignment: self variable].
+ hereType == #leftBrace
+ ifTrue: [self braceExpression]
+ ifFalse: [self primaryExpression ifFalse: [^ false]].
+ (self messagePart: 3 repeat: true)
+ ifTrue: [hereType == #semicolon ifTrue: [self cascade]].
+ ^ true!
Item was added:
+ ----- Method: Parser>>quasiQuoteExpression (in category 'expression types') -----
+ quasiQuoteExpression
+ "`quasi-quote`
+ => { elements } concatenateQuasiQuote
+ => MessageNode receiver: BraceNode selector: #concatenateQuasiQuote.
+
+ The syntax of quasi-quote is
+ quasi-quote := $` (characters | blockExpression) * $`
+ characters := (unescapedCharacter | $\ escapedCharacter) *
+
+ The semantics of quasi-quote are that each blockExpression is evaluated
+ left-to-right in the scope of the enclosing method or block. The sequence
+ of interspersed character sequences and expressions are concatenated
+ left-to-right, sending asString to each element immediately prior to concatenation.
+ The concatenation is then the result of the expression. It is always a new string.
+
+ The implementation inlines single-statement blocks into the brace expression that
+ comprises the receiver of concatenateQuasiQuote"
+
+ | elements locations stringStream loc |
+ elements := OrderedCollection new.
+ locations := OrderedCollection new.
+ stringStream := WriteStream on: (String new: 16).
+ [loc := hereMark + requestorOffset.
+ hereType == #doit ifTrue:
+ [^self expected: 'back quote'].
+ hereType == #leftBracket
+ ifTrue:
+ [self scanToken; advance.
+ parseNode := nil.
+ self blockExpression.
+ parseNode statements size = 1
+ ifTrue:
+ [elements addLast: parseNode statements first]
+ ifFalse:
+ [elements addLast: (MessageNode new
+ receiver: parseNode
+ selector: #value
+ arguments: #()
+ precedence: 1
+ from: encoder)].
+ source position: hereMark - 1.
+ [source peek ~~ $]] whileTrue:
+ [source position: source position - 1].
+ source next.
+ self step; step.
+ self setHereTypeForQuasiQuote.
+ locations addLast: loc]
+ ifFalse:
+ [(self scanQuasiQuoteCharactersUsing: stringStream) ifNotNil:
+ [:lit|
+ elements addLast: lit.
+ locations addLast: loc]].
+ hereType ~~ #backQuote] whileTrue.
+ parseNode := MessageNode new
+ receiver: (BraceNode new elements: elements sourceLocations: locations)
+ selector: #concatenateQuasiQuote
+ arguments: #()
+ precedence: 1
+ from: encoder.
+ self scanToken; advance.
+ ^true!
Item was changed:
+ ----- Method: Parser>>queriedUnusedTemporaries (in category 'temps') -----
- ----- Method: Parser>>queriedUnusedTemporaries (in category 'accessing') -----
queriedUnusedTemporaries
queriedUnusedTemporaries ifNil:
[queriedUnusedTemporaries := Dictionary new].
^queriedUnusedTemporaries!
Item was added:
+ ----- Method: Parser>>scanQuasiQuoteCharactersUsing: (in category 'scanning') -----
+ scanQuasiQuoteCharactersUsing: stringStream
+ "Answer the next non-empty sequence of characters in a quasi-quote string, or nil, if none."
+ stringStream reset.
+ [hereChar ~~ $` and: [hereChar ~~ $[ and: [hereChar ~~ DoItCharacter]]] whileTrue:
+ [hereChar == $\
+ ifTrue:
+ [stringStream nextPut: aheadChar. self step]
+ ifFalse:
+ [stringStream nextPut: hereChar].
+ self step].
+ self setHereTypeForQuasiQuote.
+ ^stringStream position > 0 ifTrue:
+ [encoder encodeLiteral: stringStream contents]!
Item was added:
+ ----- Method: Parser>>setHereTypeForQuasiQuote (in category 'scanning') -----
+ setHereTypeForQuasiQuote
+ "Set hereType appropriately based on hereChar. Used only for quasi-quote parsing."
+ hereChar == $`
+ ifTrue:
+ [hereType := #backQuote.
+ self step]
+ ifFalse:
+ [hereChar == $[
+ ifTrue:
+ [hereType := #leftBracket.
+ self step]
+ ifFalse:
+ [hereChar == DoItCharacter ifTrue:
+ [hereType := #doit]]]!
Item was changed:
+ ----- Method: Parser>>tempsMark (in category 'temps') -----
- ----- Method: Parser>>tempsMark (in category 'accessing') -----
tempsMark
^ tempsMark!
Item was changed:
+ ----- Method: Parser>>tempsMark: (in category 'temps') -----
- ----- Method: Parser>>tempsMark: (in category 'accessing') -----
tempsMark: aNumber
tempsMark := aNumber!
Item was changed:
----- Method: Scanner class>>initializeTypeTable (in category 'initialization') -----
initializeTypeTable
"self initializeTypeTable"
| newTable |
newTable := Array new: 256 withAll: #xBinary. "default"
newTable atAll: #(9 10 12 13 32 ) put: #xDelimiter. "tab lf ff cr space"
newTable atAll: ($0 asciiValue to: $9 asciiValue) put: #xDigit.
1 to: 255
do: [:index |
(Character value: index) isLetter
ifTrue: [newTable at: index put: #xLetter]].
newTable at: $" asciiValue put: #xDoubleQuote.
newTable at: $# asciiValue put: #xLitQuote.
newTable at: $$ asciiValue put: #xDollar.
newTable at: $' asciiValue put: #xSingleQuote.
+ newTable at: $` asciiValue put: #backQuote.
newTable at: $: asciiValue put: #xColon.
newTable at: $( asciiValue put: #leftParenthesis.
newTable at: $) asciiValue put: #rightParenthesis.
newTable at: $. asciiValue put: #period.
newTable at: $; asciiValue put: #semicolon.
newTable at: $[ asciiValue put: #leftBracket.
newTable at: $] asciiValue put: #rightBracket.
newTable at: ${ asciiValue put: #leftBrace.
newTable at: $} asciiValue put: #rightBrace.
newTable at: $^ asciiValue put: #upArrow.
newTable at: $_ asciiValue put: #xUnderscore.
newTable at: $| asciiValue put: #verticalBar.
TypeTable := newTable "bon voyage!!"!
More information about the Squeak-dev
mailing list
|