[NIT] Pretty pretting #ifFalse:ifTrue:

Henrik Gedenryd henrik.gedenryd at lucs.lu.se
Mon Nov 19 12:23:18 UTC 2001


Bijan Parsia wrote:

> Inlining strikes again!
> 
> Turns out that pretty printing rewrites #ifFalse:ifTrue: to
> #ifTrue:ifFalse:
> 
> Looks like it actually happens as Macro Transformation, see
> MessageNode>>transformIfFalseIfTrue:
> 
> Bummer! This sort of thing is rather serious weakness, IMHO, of the
> current parse tree based pretty printing and colorizing.

What you really need is an ability to parse code without having
transformations applied. (Parse source in a separate step from generating
code--what a preposterous idea!)

I once made a (somewhat hard-earned) refactoring that puts all inlining in a
specialized subclass of MessageNode, so that ordinary MessageNodes don't do
any code transformations. (One instvar should still be demoted to the new
subclass though.) From that you can then ask to parse either with or without
applying transformations, which you would find useful here.

The attached change sets may be stale, they're from 2.9a if my memory serves
me correctly. (Btw, it's a lot of fun to generate change sets that modify
the compiler, since it is at the same time being used to file in the code to
modify it!)

Henrik

-------------- next part --------------
'From Squeak2.9alpha of 8 July 2000 [latest update: #2447] on 26 September 2000 at 11:59:13 am'!
"Change Set:		ParserNoinline1-hg
Date:			25 September 2000
Author:			Henrik Gedenryd

It's tricky to modify the Parser while also using the Parser to fileIn the code that modifies it!!!!
Do it in 3 steps to ensure that coherent parse trees are generated at all times.

1. Ensure that non-transformed instances of MessageNode are used during the install: File in a new version of MessageNode>>noteSpecialSelector: that disables macro generation, plus an interim version of Encoder>>newMessageNode that always return the old kind of MessageNode.

File in the code for the new subclass TransformedMessageNode.
Also fileIn the methods for the new scheme that lets you choose between the two kinds of MessageNode to generate--but not the actual method that makes the compiler use the new scheme.
2. File in the (modified) methods which use the new scheme for creating MessageNodes.
Rip the macro transformation code (which is no longer used) out of MessageNode.
3. 
Finally, fileIn the final version of Encoder>>newMessageNode that selects the kind of MessageNode to use, plus the methods that switch the Compiler to use the new scheme.
"!

Scanner subclass: #Parser
	instanceVariableNames: 'here hereType hereMark prevToken prevMark encoder requestor parseNode failBlock requestorOffset tempsMark doitFlag transformMessages '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'System-Compiler'!
MessageNode subclass: #TransformedMessageNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'System-Compiler'!

!TransformedMessageNode commentStamp: 'hg 8/31/2000 21:04' prior: 0!
If special>0, I compile special code in-line instead of sending messages with literal methods as remotely copied contexts.!

!Encoder methodsFor: 'code transformation' stamp: 'hg 9/26/2000 11:48'!
newMessageNode
	"interim version used during fileIn to ensure consistent parse trees. Only nontransformed MessageNodes are generated"
 
	^MessageNode new! !


!MessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:56'!
noteSpecialSelector: selectorSymbol
	"placeholder for method hook that performs message xformation in subclass"

	special _ 0! !


!Parser methodsFor: 'transformation' stamp: 'hg 9/1/2000 19:56'!
transformMessages
	"should I apply (macro) transformations to messages during parsing?"

	^transformMessages ~~ false		"transform unless told not to"! !

!Parser methodsFor: 'transformation' stamp: 'hg 8/31/2000 20:34'!
transformMessages: aBoolean
	"should I apply (macro) transformations to messages during parsing?"

	transformMessages _ aBoolean
! !


!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:34'!
noteSpecialSelector: selectorSymbol
	" special > 0 denotes specially treated messages. "

	"Deconvert initial keywords from SQ2K"
	special _ #(:Test:Yes: :Test:No: :Test:Yes:No: :Test:No:Yes:
				and: or:
				:Until:do: :While:do: whileFalse whileTrue
				:Repeat:to:do: :Repeat:to:by:do:
				) indexOf: selectorSymbol.
	special > 0 ifTrue: [^ self].

	special _ MacroSelectors indexOf: selectorSymbol.
! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:58'!
transform: encoder
	special = 0 ifTrue: [^false].
	(self perform: (MacroTransformers at: special) with: encoder)
		ifTrue: 
			[^true]
		ifFalse: 
			[special _ 0. ^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:39'!
transformAnd: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments _ 
				Array 
					with: (arguments at: 1)
					with: (BlockNode withJust: NodeFalse).
			^true]
		ifFalse: 
			[^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:39'!
transformBoolean: encoder
	^self
		checkBlock: (arguments at: 1)
		as: 'argument'
		from: encoder! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 21:02'!
transformCase: encoder

	| caseNode |
	caseNode _ arguments first.
	(caseNode isKindOf: BraceNode)
		ifTrue:
			[^(caseNode blockAssociationCheck: encoder) and:
			 	[arguments size = 1 or:
					[self checkBlock: arguments last as: 'otherwise arg' from: encoder]]].
	(caseNode canBeSpecialArgument and: [(caseNode isMemberOf: BlockNode) not])
		ifTrue:
			[^false]. "caseOf: variable"
	^encoder notify: 'caseOf: argument must be a brace construct or a variable'! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:40'!
transformIfFalse: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments _ 
				Array 
					with: (BlockNode withJust: NodeNil)
					with: (arguments at: 1).
			^true]
		ifFalse:
			[^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:40'!
transformIfFalseIfTrue: encoder
	((self checkBlock: (arguments at: 1) as: 'False arg' from: encoder)
		and: [self checkBlock: (arguments at: 2) as: 'True arg' from: encoder])
		ifTrue: 
			[selector _ #ifTrue:ifFalse:.
			arguments swap: 1 with: 2.
			^true]
		ifFalse: 
			[^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:40'!
transformIfNil: encoder

	(self transformBoolean: encoder) ifFalse: [^ false].
	(MacroSelectors at: special) = #ifNotNil:
	ifTrue:
		[(self checkBlock: arguments first as: 'ifNotNil arg' from: encoder) ifFalse: [^ false].

		"Transform 'ifNotNil: [stuff]' to 'ifNil: [nil] ifNotNil: [stuff]'.
		Slightly better code and more consistent with decompilation."
		self noteSpecialSelector: #ifNil:ifNotNil:.
		selector _ SelectorNode new key: (MacroSelectors at: special) code: #macro.
		arguments _ {BlockNode withJust: NodeNil. arguments first}.
		(self transform: encoder) ifFalse: [self error: 'compiler logic error'].
		^ true]
	ifFalse:
		[^ self checkBlock: arguments first as: 'ifNil arg' from: encoder]
! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 9/25/2000 20:23'!
transformIfNilIfNotNil: encoder
	((self checkBlock: (arguments at: 1) as: 'Nil arg' from: encoder)
		and: [self checkBlock: (arguments at: 2) as: 'NotNil arg' from: encoder])
		ifTrue: 
			[selector _ SelectorNode new key: #ifTrue:ifFalse: code: #macro.
			receiver _ encoder newMessageNode
				receiver: receiver
				selector: #==
				arguments: (Array with: NodeNil)
				precedence: 2
				from: encoder.
			^true]
		ifFalse: 
			[^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 9/25/2000 20:23'!
transformIfNotNilIfNil: encoder
	((self checkBlock: (arguments at: 1) as: 'NotNil arg' from: encoder)
		and: [self checkBlock: (arguments at: 2) as: 'Nil arg' from: encoder])
		ifTrue: 
			[selector _ SelectorNode new key: #ifTrue:ifFalse: code: #macro.
			receiver _ encoder newMessageNode
				receiver: receiver
				selector: #==
				arguments: (Array with: NodeNil)
				precedence: 2
				from: encoder.
			arguments swap: 1 with: 2.
			^true]
		ifFalse: 
			[^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:41'!
transformIfTrue: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments _ 
				Array 
					with: (arguments at: 1)
					with: (BlockNode withJust: NodeNil).
			^true]
		ifFalse: 
			[^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:41'!
transformIfTrueIfFalse: encoder
	^(self checkBlock: (arguments at: 1) as: 'True arg' from: encoder)
		and: [self checkBlock: (arguments at: 2) as: 'False arg' from: encoder]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:42'!
transformOr: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments _ 
				Array 
					with: (BlockNode withJust: NodeTrue)
					with: (arguments at: 1).
			^true]
		ifFalse: 
			[^false]! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 9/25/2000 20:24'!
transformToDo: encoder
	" var _ rcvr. L1: [var <= arg1] Bfp(L2) [block body. var _ var + inc] 
Jmp(L1) L2: "
	| limit increment block initStmt test incStmt limitInit blockVar |
	"First check for valid arguments"
	((arguments last isMemberOf: BlockNode)
			and: [arguments last numberOfArguments = 1])
		ifFalse: [^ false].
	arguments last firstArgument isVariableReference
		ifFalse: [^ false]. "As with debugger remote vars"
	arguments size = 3
		ifTrue: [increment _ arguments at: 2.
				(increment isConstantNumber and:
					[increment literalValue ~= 0]) ifFalse: [^ false]]
		ifFalse: [increment _ encoder encodeLiteral: 1].
	arguments size < 3 ifTrue:   "transform to full form"
		[selector _ SelectorNode new key: #to:by:do: code: #macro].

	"Now generate auxiliary structures"
	block _ arguments last.
	blockVar _ block firstArgument.
	initStmt _ AssignmentNode new variable: blockVar value: receiver.
	limit _ arguments at: 1.
	limit isVariableReference | limit isConstantNumber
		ifTrue: [limitInit _ nil]
		ifFalse:  "Need to store limit in a var"
			[limit _ encoder autoBind: blockVar key , 'LimiT'.
			limit scope: -2.  "Already done parsing block"
			limitInit _ AssignmentNode new
					variable: limit
					value: (arguments at: 1)].
	test _ encoder newMessageNode
			receiver: blockVar
			selector: (increment key > 0 ifTrue: [#<=] ifFalse: [#>=])
			arguments: (Array with: limit)
			precedence: precedence from: encoder.
	incStmt _ AssignmentNode new
			variable: blockVar
			value: (encoder newMessageNode
				receiver: blockVar selector: #+
				arguments: (Array with: increment)
				precedence: precedence from: encoder).
	arguments _ (Array with: limit with: increment with: block)
		, (Array with: initStmt with: test with: incStmt with: limitInit).
	^ true! !

!TransformedMessageNode methodsFor: 'macro transformations' stamp: 'hg 8/31/2000 19:43'!
transformWhile: encoder
	(self checkBlock: receiver as: 'receiver' from: encoder)
		ifFalse: [^ false].
	arguments size = 0   "transform bodyless form to body form"
		ifTrue: [selector _ SelectorNode new
					key: (special = 10 ifTrue: [#whileTrue:] ifFalse: [#whileFalse:])
					code: #macro.
				arguments _ Array with: (BlockNode withJust: NodeNil).
				^ true]
		ifFalse: [^ self transformBoolean: encoder]! !

!TransformedMessageNode methodsFor: 'initialize-release' stamp: 'hg 8/31/2000 19:53'!
receiver: rcvr selector: aSelector arguments: args precedence: p from: encoder 
	"Compile, transforming message if applicable."

	| theSelector |
	self receiver: rcvr
		arguments: args
		precedence: p.
	aSelector = #:Repeat:do:
		ifTrue: [theSelector _ #do:]
		ifFalse: [theSelector _ aSelector].
	self noteSpecialSelector: theSelector.
	(self transform: encoder)
		ifTrue: 
			[selector isNil
				ifTrue: [selector _ SelectorNode new 
							key: (MacroSelectors at: special)
							code: #macro]]
		ifFalse: 
			[selector _ encoder encodeSelector: theSelector.
			rcvr == NodeSuper ifTrue: [encoder noteSuper]].
	self pvtCheckForPvtSelector: encoder! !

!TransformedMessageNode methodsFor: 'testing' stamp: 'hg 8/31/2000 21:41'!
canCascade

	^special = 0 and: [super canCascade]! !

!TransformedMessageNode methodsFor: 'testing' stamp: 'hg 8/31/2000 21:40'!
isComplex
	
	^(special between: 1 and: 10) or: [super isComplex]! !

!TransformedMessageNode methodsFor: 'testing' stamp: 'hg 8/31/2000 21:37'!
isIf

	^special between: 3 and: 4
! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
emitCase: stack on: strm value: forValue

	| braceNode sizeStream thenSize elseSize |
	forValue not
		ifTrue: [^super emitForEffect: stack on: strm].
	braceNode _ arguments first.
	sizeStream _ ReadStream on: sizes.
	receiver emitForValue: stack on: strm.
	braceNode casesForwardDo:
		[:keyNode :valueNode :last |
		thenSize _ sizeStream next.
		elseSize _ sizeStream next.
		last ifFalse: [strm nextPut: Dup. stack push: 1].
		keyNode emitForEvaluatedValue: stack on: strm.
		equalNode emit: stack args: 1 on: strm.
		self emitBranchOn: false dist: thenSize pop: stack on: strm.
		last ifFalse: [strm nextPut: Pop. stack pop: 1].
		valueNode emitForEvaluatedValue: stack on: strm.
		last ifTrue: [stack pop: 1].
		valueNode returns ifFalse: [self emitJump: elseSize on: strm]].
	arguments size = 2
		ifTrue:
			[arguments last emitForEvaluatedValue: stack on: strm] "otherwise: [...]"
		ifFalse:
			[NodeSelf emitForValue: stack on: strm.
			caseErrorNode emit: stack args: 0 on: strm]! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 20:09'!
emitForEffect: stack on: strm

	special > 0
		ifTrue: 
			[self perform: (MacroEmitters at: special) with: stack with: strm with: false.
			pc _ 0]
		ifFalse: 
			[super emitForEffect: stack on: strm]! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 20:11'!
emitForValue: stack on: strm

	special > 0
		ifTrue: 
			[self perform: (MacroEmitters at: special) with: stack with: strm with: true.
			pc _ 0]
		ifFalse: 
			[super emitForValue: stack on: strm]	! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
emitIf: stack on: strm value: forValue
	| thenExpr thenSize elseExpr elseSize |
	thenSize _ sizes at: 1.
	elseSize _ sizes at: 2.
	(forValue not and: [(elseSize*thenSize) > 0])
		ifTrue:  "Two-armed IFs forEffect share a single pop"
			[^ super emitForEffect: stack on: strm].
	thenExpr _ arguments at: 1.
	elseExpr _ arguments at: 2.
	receiver emitForValue: stack on: strm.
	forValue
		ifTrue:  "Code all forValue as two-armed"
			[self emitBranchOn: false dist: thenSize pop: stack on: strm.
			thenExpr emitForEvaluatedValue: stack on: strm.
			stack pop: 1.  "then and else alternate; they don't accumulate"
			thenExpr returns not
				ifTrue:  "Elide jump over else after a return"
					[self emitJump: elseSize on: strm].
			elseExpr emitForEvaluatedValue: stack on: strm]
		ifFalse:  "One arm is empty here (two-arms code forValue)"
			[thenSize > 0
				ifTrue:
					[self emitBranchOn: false dist: thenSize pop: stack on: strm.
					thenExpr emitForEvaluatedEffect: stack on: strm]
				ifFalse:
					[self emitBranchOn: true dist: elseSize pop: stack on: strm.
					elseExpr emitForEvaluatedEffect: stack on: strm]]! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
emitIfNil: stack on: strm value: forValue

	| theNode theSize theSelector |
	theNode _ arguments first.
	theSize _ sizes at: 1.
	theSelector _ #ifNotNil:.
	receiver emitForValue: stack on: strm.
	forValue ifTrue: [strm nextPut: Dup. stack push: 1].
	strm nextPut: LdNil. stack push: 1.
	equalNode emit: stack args: 1 on: strm.
	self 
		emitBranchOn: (selector key == theSelector)
		dist: theSize 
		pop: stack 
		on: strm.
	forValue 
		ifTrue: 
			[strm nextPut: Pop. stack pop: 1.
			theNode emitForEvaluatedValue: stack on: strm]	
		ifFalse: [theNode emitForEvaluatedEffect: stack on: strm].! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
emitToDo: stack on: strm value: forValue 
	" var _ rcvr. L1: [var <= arg1] Bfp(L2) [block body. var _ var + inc] Jmp(L1) L2: "
	| loopSize initStmt limitInit test block incStmt blockSize |
	initStmt _ arguments at: 4.
	limitInit _ arguments at: 7.
	test _ arguments at: 5.
	block _ arguments at: 3.
	incStmt _ arguments at: 6.
	blockSize _ sizes at: 1.
	loopSize _ sizes at: 2.
	limitInit == nil
		ifFalse: [limitInit emitForEffect: stack on: strm].
	initStmt emitForEffect: stack on: strm.
	test emitForValue: stack on: strm.
	self emitBranchOn: false dist: blockSize pop: stack on: strm. 
	block emitForEvaluatedEffect: stack on: strm.
	incStmt emitForEffect: stack on: strm.
	self emitJump: 0 - loopSize on: strm.
	forValue ifTrue: [strm nextPut: LdNil. stack push: 1]! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
emitWhile: stack on: strm value: forValue 
	" L1: ... Bfp(L2)|Btp(L2) ... Jmp(L1) L2: "
	| cond stmt stmtSize loopSize |
	cond _ receiver.
	stmt _ arguments at: 1.
	stmtSize _ sizes at: 1.
	loopSize _ sizes at: 2.
	cond emitForEvaluatedValue: stack on: strm.
	self emitBranchOn: (selector key == #whileFalse:)  "Bfp for whileTrue"
					dist: stmtSize pop: stack on: strm.   "Btp for whileFalse"
	stmt emitForEvaluatedEffect: stack on: strm.
	self emitJump: 0 - loopSize on: strm.
	forValue ifTrue: [strm nextPut: LdNil. stack push: 1]! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
sizeCase: encoder value: forValue

	| braceNode sizeIndex thenSize elseSize |
	forValue not
		ifTrue: [^super sizeForEffect: encoder].
	equalNode _ encoder encodeSelector: #=.
	braceNode _ arguments first.
	sizes _ Array new: 2 * braceNode numElements.
	sizeIndex _ sizes size.
	elseSize _ arguments size = 2
		ifTrue:
			[arguments last sizeForEvaluatedValue: encoder] "otherwise: [...]"
		ifFalse:
			[caseErrorNode _ encoder encodeSelector: #caseError.
			 1 + (caseErrorNode size: encoder args: 0 super: false)]. "self caseError"
	braceNode casesReverseDo:
		[:keyNode :valueNode :last |
		sizes at: sizeIndex put: elseSize.
		thenSize _ valueNode sizeForEvaluatedValue: encoder.
		last ifFalse: [thenSize _ thenSize + 1]. "Pop"
		valueNode returns ifFalse: [thenSize _ thenSize + (self sizeJump: elseSize)].
		sizes at: sizeIndex-1 put: thenSize.
		last ifFalse: [elseSize _ elseSize + 1]. "Dup"
		elseSize _ elseSize + (keyNode sizeForEvaluatedValue: encoder) +
			(equalNode size: encoder args: 1 super: false) +
			(self sizeBranchOn: false dist: thenSize) + thenSize.
		sizeIndex _ sizeIndex - 2].
	^(receiver sizeForValue: encoder) + elseSize
! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 20:12'!
sizeForEffect: encoder

	special > 0 
		ifTrue: [^self perform: (MacroSizers at: special) with: encoder with: false]
		ifFalse: [^super sizeForEffect: encoder]! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 20:13'!
sizeForValue: encoder
	special > 0 
		ifTrue: [^self perform: (MacroSizers at: special) with: encoder with: true]
		ifFalse: [^super sizeForValue: encoder]! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
sizeIf: encoder value: forValue
	| thenExpr elseExpr branchSize thenSize elseSize |
	thenExpr _ arguments at: 1.
	elseExpr _ arguments at: 2.
	(forValue
		or: [(thenExpr isJust: NodeNil)
		or: [elseExpr isJust: NodeNil]]) not
			"(...not ifTrue: avoids using ifFalse: alone during this compile)"
		ifTrue:  "Two-armed IFs forEffect share a single pop"
			[^ super sizeForEffect: encoder].
	forValue
		ifTrue:  "Code all forValue as two-armed"
			[elseSize _ elseExpr sizeForEvaluatedValue: encoder.
			thenSize _ (thenExpr sizeForEvaluatedValue: encoder)
					+ (thenExpr returns
						ifTrue: [0]  "Elide jump over else after a return"
						ifFalse: [self sizeJump: elseSize]).
			branchSize _ self sizeBranchOn: false dist: thenSize]
		ifFalse:  "One arm is empty here (two-arms code forValue)"
			[(elseExpr isJust: NodeNil)
				ifTrue:
					[elseSize _ 0.
					thenSize _ thenExpr sizeForEvaluatedEffect: encoder.
					branchSize _ self sizeBranchOn: false dist: thenSize]
				ifFalse:
					[thenSize _ 0.
					elseSize _ elseExpr sizeForEvaluatedEffect: encoder.
					branchSize _ self sizeBranchOn: true dist: elseSize]].
	sizes _ Array with: thenSize with: elseSize.
	^ (receiver sizeForValue: encoder) + branchSize
			+ thenSize + elseSize! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
sizeIfNil: encoder value: forValue

	| theNode theSize theSelector |
	equalNode _ encoder encodeSelector: #==.
	sizes _ Array new: 1.
	theNode _ arguments first.
	theSelector _ #ifNotNil:.
	forValue
		ifTrue:
			[sizes at: 1 put: (theSize _ (1 "pop" + (theNode sizeForEvaluatedValue: encoder))).
			 ^(receiver sizeForValue: encoder) +
				2 "Dup. LdNil" +
				(equalNode size: encoder args: 1 super: false) +
				(self 
					sizeBranchOn: (selector key == theSelector) 
					dist: theSize) +
				theSize]
		ifFalse:
			[sizes at: 1 put: (theSize _ (theNode sizeForEvaluatedEffect: encoder)).
			 ^(receiver sizeForValue: encoder) +
				1 "LdNil" +
				(equalNode size: encoder args: 1 super: false) +
				(self 
					sizeBranchOn: (selector key == theSelector) 
					dist: theSize) +
				theSize]

! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
sizeToDo: encoder value: forValue 
	" var _ rcvr. L1: [var <= arg1] Bfp(L2) [block body. var _ var + inc] Jmp(L1) L2: "
	| loopSize initStmt test block incStmt blockSize blockVar initSize limitInit |
	block _ arguments at: 3.
	blockVar _ block firstArgument.
	initStmt _ arguments at: 4.
	test _ arguments at: 5.
	incStmt _ arguments at: 6.
	limitInit _ arguments at: 7.
	initSize _ initStmt sizeForEffect: encoder.
	limitInit == nil
		ifFalse: [initSize _ initSize + (limitInit sizeForEffect: encoder)].
	blockSize _ (block sizeForEvaluatedEffect: encoder)
			+ (incStmt sizeForEffect: encoder) + 2.  "+2 for Jmp backward"
	loopSize _ (test sizeForValue: encoder)
			+ (self sizeBranchOn: false dist: blockSize)
			+ blockSize.
	sizes _ Array with: blockSize with: loopSize.
	^ initSize + loopSize
			+ (forValue ifTrue: [1] ifFalse: [0])    " +1 for value (push nil) "! !

!TransformedMessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 19:59'!
sizeWhile: encoder value: forValue 
	"L1: ... Bfp(L2) ... Jmp(L1) L2: nil (nil for value only);
	justStmt, wholeLoop, justJump."
	| cond stmt stmtSize loopSize branchSize |
	cond _ receiver.
	stmt _ arguments at: 1.
	stmtSize _ (stmt sizeForEvaluatedEffect: encoder) + 2.
	branchSize _ self sizeBranchOn: (selector key == #whileFalse:)  "Btp for whileFalse"
					dist: stmtSize.
	loopSize _ (cond sizeForEvaluatedValue: encoder)
			+ branchSize + stmtSize.
	sizes _ Array with: stmtSize with: loopSize.
	^ loopSize    " +1 for value (push nil) "
		+ (forValue ifTrue: [1] ifFalse: [0])! !

!TransformedMessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:56'!
printCaseOn: aStream indent: level 
	"receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
	| braceNode otherwise extra |
	braceNode _ arguments first.
	otherwise _ arguments last.
	(arguments size = 1 or: [otherwise isJustCaseError])
		ifTrue: [otherwise _ nil].
	receiver
		printOn: aStream
		indent: level
		precedence: 3.
	aStream dialect = #SQ00 ifTrue: [aStream nextPutAll: ' caseOf (']
		ifFalse: [aStream nextPutAll: ' caseOf: '].
	braceNode isVariableReference ifTrue: [braceNode printOn: aStream indent: level]
		ifFalse: 
			[aStream nextPutAll: '{';
				 crtab: level + 1.
			braceNode
				casesForwardDo: 
					[:keyNode :valueNode :last | 
					keyNode printOn: aStream indent: level + 1.
					aStream nextPutAll: ' -> '.
					valueNode isComplex
						ifTrue: 
							[aStream crtab: level + 2.
							extra _ 1]
						ifFalse: [extra _ 0].
					valueNode printOn: aStream indent: level + 1 + extra.
					last ifTrue: [aStream nextPut: $}]
						ifFalse: [aStream nextPut: $.;
								 crtab: level + 1]]].
	aStream dialect = #SQ00 ifTrue: [aStream nextPutAll: ')'].
	otherwise isNil
		ifFalse: 
			[aStream dialect = #SQ00 ifTrue: [aStream crtab: level + 1;
					 nextPutAll: ' otherwise (']
				ifFalse: [aStream crtab: level + 1;
						 nextPutAll: ' otherwise: '].
			otherwise isComplex
				ifTrue: 
					[aStream crtab: level + 2.
					extra _ 1]
				ifFalse: [extra _ 0].
			otherwise printOn: aStream indent: level + 1 + extra.
			aStream dialect = #SQ00 ifTrue: [aStream nextPutAll: ')']]! !

!TransformedMessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:56'!
printIfNil: aStream indent: level

	self printReceiver: receiver on: aStream indent: level.

	^self printKeywords: selector key
		arguments: (Array with: arguments first)
		on: aStream indent: level! !

!TransformedMessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:56'!
printIfNilNotNil: aStream indent: level

	self printReceiver: receiver ifNilReceiver on: aStream indent: level.

	(arguments first isJust: NodeNil) ifTrue:
		[^ self printKeywords: #ifNotNil:
				arguments: { arguments second }
				on: aStream indent: level].
	(arguments second isJust: NodeNil) ifTrue:
		[^ self printKeywords: #ifNil:
				arguments: { arguments first }
				on: aStream indent: level].
	^ self printKeywords: #ifNil:ifNotNil:
			arguments: arguments
			on: aStream indent: level! !

!TransformedMessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:56'!
printIfOn: aStream indent: level

	aStream dialect = #SQ00 ifTrue:
		["Convert to if-then-else"
		(arguments last isJust: NodeNil) ifTrue:
			[aStream withStyleFor: #prefixKeyword do: [aStream nextPutAll: 'Test '].
			self printParenReceiver: receiver on: aStream indent: level + 1.
			^ self printKeywords: #Yes: arguments: (Array with: arguments first)
						on: aStream indent: level prefix: true].
		(arguments last isJust: NodeFalse) ifTrue:
			[self printReceiver: receiver on: aStream indent: level.
			^ self printKeywords: #and: arguments: (Array with: arguments first)
						on: aStream indent: level].
		(arguments first isJust: NodeNil) ifTrue:
			[aStream withStyleFor: #prefixKeyword do: [aStream nextPutAll: 'Test '].
			self printParenReceiver: receiver on: aStream indent: level + 1.
			^ self printKeywords: #No: arguments: (Array with: arguments last)
						on: aStream indent: level prefix: true].
		(arguments first isJust: NodeTrue) ifTrue:
			[self printReceiver: receiver on: aStream indent: level.
			^ self printKeywords: #or: arguments: (Array with: arguments last)
						on: aStream indent: level].
		aStream withStyleFor: #prefixKeyword do: [aStream nextPutAll: 'Test '].
		self printParenReceiver: receiver on: aStream indent: level + 1.
		^ self printKeywords: #Yes:No: arguments: arguments
						on: aStream indent: level prefix: true].

	receiver printOn: aStream indent: level + 1 precedence: precedence.
	(arguments last isJust: NodeNil) ifTrue:
		[^ self printKeywords: #ifTrue: arguments: (Array with: arguments first)
					on: aStream indent: level].
	(arguments last isJust: NodeFalse) ifTrue:
		[^ self printKeywords: #and: arguments: (Array with: arguments first)
					on: aStream indent: level].
	(arguments first isJust: NodeNil) ifTrue:
		[^ self printKeywords: #ifFalse: arguments: (Array with: arguments last)
					on: aStream indent: level].
	(arguments first isJust: NodeTrue) ifTrue:
		[^ self printKeywords: #or: arguments: (Array with: arguments last)
					on: aStream indent: level].
	self printKeywords: #ifTrue:ifFalse: arguments: arguments
					on: aStream indent: level! !

!TransformedMessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:58'!
printOn: aStream indent: level

	| printer |
	special > 0 ifTrue: [printer _ MacroPrinters at: special].
	(special > 0)
		ifTrue: [self perform: printer with: aStream with: level]
		ifFalse: [super printOn: aStream indent: level]! !

!TransformedMessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:56'!
printToDoOn: aStream indent: level

	| limitNode |
	aStream dialect = #SQ00
		ifTrue: ["Add prefix keyword"
				aStream withStyleFor: #prefixKeyword do: [aStream nextPutAll: 'Repeat '].
				self printParenReceiver: receiver on: aStream indent: level + 1]
		ifFalse: [self printReceiver: receiver on: aStream indent: level].

	(arguments last == nil or: [(arguments last isMemberOf: AssignmentNode) not])
		ifTrue: [limitNode _ arguments first]
		ifFalse: [limitNode _ arguments last value].
	(selector key = #to:by:do:
			and: [(arguments at: 2) isConstantNumber
				and: [(arguments at: 2) key = 1]])
		ifTrue: [self printKeywords: #to:do:
					arguments: (Array with: limitNode with: (arguments at: 3))
					on: aStream indent: level prefix: true]
		ifFalse: [self printKeywords: selector key
					arguments: (Array with: limitNode) , arguments allButFirst
					on: aStream indent: level prefix: true]! !

!TransformedMessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:56'!
printWhileOn: aStream indent: level

	aStream dialect = #SQ00
		ifTrue: ["Add prefix keyword"
				aStream withStyleFor: #prefixKeyword
						do: [aStream nextPutAll: (selector key == #whileTrue:
									ifTrue: ['While '] ifFalse: ['Until '])].
				self printParenReceiver: receiver on: aStream indent: level + 1.
				self printKeywords: #do: arguments: arguments
					on: aStream indent: level prefix: true]
		ifFalse: [self printReceiver: receiver on: aStream indent: level.
				(arguments first isJust: NodeNil) ifTrue:
						[selector _ SelectorNode new
								key: (selector key == #whileTrue:
									ifTrue: [#whileTrue] ifFalse: [#whileFalse])
								code: #macro.
						arguments _ Array new].
				self printKeywords: selector key arguments: arguments
					on: aStream indent: level]! !

!TransformedMessageNode methodsFor: 'private' stamp: 'hg 8/31/2000 21:43'!
checkBlock: node as: nodeName from: encoder

	node canBeSpecialArgument ifTrue: [^node isMemberOf: BlockNode].
	((node isKindOf: BlockNode) and: [node numberOfArguments > 0])
		ifTrue:	[^encoder notify: '<- ', nodeName , ' of ' ,
					(MacroSelectors at: special) , ' must be 0-argument block']
		ifFalse: [^encoder notify: '<- ', nodeName , ' of ' ,
					(MacroSelectors at: special) , ' must be a block or variable']! !


!TransformedMessageNode class methodsFor: 'class initialization' stamp: 'hg 8/31/2000 19:37'!
initialize		"TransformedMessageNode 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:).
	MacroTransformers _ 
		#(transformIfTrue: transformIfFalse: transformIfTrueIfFalse: transformIfFalseIfTrue:
			transformAnd: transformOr:
			transformWhile: transformWhile: transformWhile: transformWhile:
			transformToDo: transformToDo:
			transformCase: transformCase:
			transformIfNil: transformIfNil:  transformIfNilIfNotNil: transformIfNotNilIfNil:).
	MacroEmitters _ 
		#(emitIf:on:value: emitIf:on:value: emitIf:on:value: emitIf:on:value:
			emitIf:on:value: emitIf:on:value:
			emitWhile:on:value: emitWhile:on:value: emitWhile:on:value: emitWhile:on:value:
			emitToDo:on:value: emitToDo:on:value:
			emitCase:on:value: emitCase:on:value:
			emitIfNil:on:value: emitIfNil:on:value: emitIf:on:value: emitIf:on:value:).
	MacroSizers _ 
		#(sizeIf:value: sizeIf:value: sizeIf:value: sizeIf:value:
			sizeIf:value: sizeIf:value:
			sizeWhile:value: sizeWhile:value: sizeWhile:value: sizeWhile:value:
			sizeToDo:value: sizeToDo:value:
			sizeCase:value: sizeCase:value:
			sizeIfNil:value: sizeIfNil:value: sizeIf:value: sizeIf: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:)! !

TransformedMessageNode initialize!
TransformedMessageNode removeSelector: #pc!
TransformedMessageNode removeSelector: #precedence!
TransformedMessageNode removeSelector: #printKeywords:arguments:on:indent:!
TransformedMessageNode removeSelector: #printKeywords:arguments:on:indent:prefix:!
TransformedMessageNode removeSelector: #printOn:indent:precedence:!
TransformedMessageNode removeSelector: #printParenReceiver:on:indent:!
TransformedMessageNode removeSelector: #printReceiver:on:indent:!
TransformedMessageNode removeSelector: #test!
Parser removeSelector: #doTransformMessages!
-------------- next part --------------
'From Squeak2.9alpha of 8 July 2000 [latest update: #2447] on 26 September 2000 at 11:59:20 am'!

!MessageNode commentStamp: 'hg 8/31/2000 21:03' prior: 0!
I represent a receiver and its message.
	
Precedence codes:
	1 unary
	2 binary
	3 keyword
	4 other
	
!

!AssignmentNode methodsFor: 'initialize-release' stamp: 'hg 9/25/2000 20:19'!
toDoIncrement: var
	var = variable ifFalse: [^ nil].
	(value isKindOf: MessageNode) 
		ifTrue: [^ value toDoIncrement: var]
		ifFalse: [^ nil]! !


!BraceNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 20:17'!
sizeForValue: encoder

	emitNode _ elements size <= 4
		ifTrue: ["Short form: Array braceWith: a with: b ... "
				encoder newMessageNode
					receiver: (encoder encodeVariable: #Array)
					selector: (self selectorForShortForm: elements size)
					arguments: elements precedence: 3 from: encoder]
		ifFalse: ["Long form: (Array braceStream: N) nextPut: a; nextPut: b; ...; braceArray"
				CascadeNode new
					receiver: (encoder newMessageNode
								receiver: (encoder encodeVariable: #Array)
								selector: #braceStream:
								arguments: (Array with: (encoder encodeLiteral: elements size))
								precedence: 3 from: encoder)
					messages: ((elements collect: [:elt | encoder newMessageNode 
														receiver: nil
														selector: #nextPut:
														arguments: (Array with: elt)
														precedence: 3 from: encoder])
								copyWith: (encoder newMessageNode 
														receiver: nil
														selector: #braceArray
														arguments: (Array new)
														precedence: 1 from: encoder))].
	^ emitNode sizeForValue: encoder! !


!Compiler methodsFor: 'public access' stamp: 'hg 9/8/2000 16:01'!
parse: textOrStream in: aClass notifying: req dialect: useDialect transformMessages: doTransform
        "Compile the argument, textOrStream, with respect to the class, aClass, 
        and answer the MethodNode that is the root of the resulting parse tree. 
        Notify the argument, req, if an error occurs. The failBlock is defaulted to 
        an empty block.
	transformMessages concerns whether to generate specialized nodes for some messages in order to generate more efficient bytecodes.
	This makes manipulating the parse tree more difficult."

        | parser | 
	self from: textOrStream class: aClass context: nil notifying: req.
        parser _ ((useDialect and: [RequestAlternateSyntaxSetting signal])
                ifTrue: [DialectParser]
                ifFalse: [Parser]) new.
	parser transformMessages: doTransform.		"do apply macro transformations"
	^parser	
		parse: sourceStream
                class: class
                noPattern: false
                context: context
                notifying: requestor
                ifFail: []! !


!Debugger methodsFor: 'code pane' stamp: 'hg 9/1/2000 19:58'!
pcRange
	"Answer the indices in the source code for the method corresponding to 
	the selected context's program counter value."

	| i methodNode pc end |
	(selectingPC and: [contextStackIndex ~= 0])
		ifFalse: [^1 to: 0].
	sourceMap == nil ifTrue:
		[methodNode _ self selectedClass compilerClass new
			parse: contents in: self selectedClass
			notifying: nil dialect: true transformMessages: true.
		sourceMap _ methodNode sourceMap.
		tempNames _ methodNode tempNames.
		self selectedContext method cacheTempNames: tempNames].
	sourceMap size = 0 ifTrue: [^1 to: 0].
	pc_ self selectedContext pc -
		((externalInterrupt and: [contextStackIndex=1])
			ifTrue: [1]
			ifFalse: [2]).
	i _ sourceMap indexForInserting: (Association key: pc value: nil).
	i < 1 ifTrue: [^1 to: 0].
	i > sourceMap size
		ifTrue:
			[end _ sourceMap inject: 0 into:
				[:prev :this | prev max: this value last].
			^ end+1 to: end].
	^(sourceMap at: i) value ! !


!MessageNode methodsFor: 'initialize-release' stamp: 'hg 8/31/2000 19:55'!
receiver: rcvr selector: aSelector arguments: args precedence: p from: encoder 
	"Compile."

	self receiver: rcvr
		arguments: args
		precedence: p.
	self noteSpecialSelector: aSelector.
	selector _ encoder encodeSelector: aSelector.
			rcvr == NodeSuper ifTrue: [encoder noteSuper].
	self pvtCheckForPvtSelector: encoder! !

!MessageNode methodsFor: 'testing' stamp: 'hg 8/31/2000 21:40'!
canCascade

	^(receiver == NodeSuper) not! !

!MessageNode methodsFor: 'testing' stamp: 'hg 8/31/2000 21:39'!
isComplex
	
	^arguments size > 2 or: [receiver isComplex]! !

!MessageNode methodsFor: 'macro transformations' stamp: 'hg 9/25/2000 20:22'!
toDoFromWhileWithInit: initStmt
	"Return nil, or a to:do: expression equivalent to this whileTrue:"
	| variable increment limit toDoBlock body test |
	(selector key == #whileTrue:
		and: [(initStmt isMemberOf: AssignmentNode) and:
				[initStmt variable isTemp]])
		ifFalse: [^ nil].
	body _ arguments last statements.
	variable _ initStmt variable.
	increment _ body last toDoIncrement: variable.
	(increment == nil or: [receiver statements size ~= 1])
		ifTrue: [^ nil].
	test _ receiver statements first.
	"Note: test chould really be checked that <= or >= comparison
	jibes with the sign of the (constant) increment"
	((test isKindOf: MessageNode)
		and: [(limit _ test toDoLimit: variable) notNil])
		ifFalse: [^ nil].
	toDoBlock _ BlockNode statements: body allButLast returns: false.
	toDoBlock arguments: (Array with: variable).
	^ MessageNode new
		receiver: initStmt value
		selector: (SelectorNode new key: #to:by:do: code: #macro)
		arguments: (Array with: limit with: increment with: toDoBlock)
		precedence: precedence! !

!MessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 20:10'!
emitForValue: stack on: strm

	receiver ~~ nil ifTrue: [receiver emitForValue: stack on: strm].
	arguments do: [:argument | argument emitForValue: stack on: strm].
	selector
		emit: stack
		args: arguments size
		on: strm
		super: receiver == NodeSuper.
	pc _ strm position! !

!MessageNode methodsFor: 'code generation' stamp: 'hg 8/31/2000 20:13'!
sizeForValue: encoder
	| total argSize |
	receiver == NodeSuper
		ifTrue: [selector _ selector copy "only necess for splOops"].
	total _ selector size: encoder args: arguments size super: receiver == NodeSuper.
	receiver == nil 
		ifFalse: [total _ total + (receiver sizeForValue: encoder)].
	sizes _ arguments collect: 
					[:arg | 
					argSize _ arg sizeForValue: encoder.
					total _ total + argSize.
					argSize].
	^total! !

!MessageNode methodsFor: 'printing' stamp: 'hg 8/31/2000 20:58'!
printOn: aStream indent: level

	| leadingKeyword |
	selector key first = $:
		ifTrue: [leadingKeyword _ selector key keywords first.
				aStream nextPutAll: leadingKeyword; space.
				self printReceiver: receiver on: aStream indent: level.
				self printKeywords: (selector key allButFirst: leadingKeyword size + 1) arguments: arguments
					on: aStream indent: level]
		ifFalse: [(aStream dialect = #SQ00 and: [selector key == #do:])
				ifTrue: ["Add prefix keyword"
						aStream withStyleFor: #prefixKeyword do: [aStream nextPutAll: 'Repeat '].
						self printParenReceiver: receiver on: aStream indent: level + 1.
						self printKeywords: selector key arguments: arguments
							on: aStream indent: level prefix: true]
				ifFalse: [self printReceiver: receiver on: aStream indent: level.
						self printKeywords: selector key arguments: arguments
							on: aStream indent: level]]! !


!MessageNode class methodsFor: 'class initialization' stamp: 'hg 8/31/2000 19:38'!
initialize		"MessageNode initialize"

	TransformedMessageNode initialize.
	self initializeSafeList! !


!Parser methodsFor: 'expression types' stamp: 'hg 9/1/2000 20:00'!
messagePart: level repeat: repeat
 
	| start receiver selector args precedence words keywordStart |
	[receiver _ parseNode.
	(hereType == #keyword and: [level >= 3])
		ifTrue: 
			[start _ self startOfNextToken.
			selector _ WriteStream on: (String new: 32).
			args _ OrderedCollection new.
			words _ OrderedCollection new.
			[hereType == #keyword]
				whileTrue: 
					[keywordStart _ self startOfNextToken + requestorOffset.
					selector nextPutAll: self advance.
					words addLast: (keywordStart to: self endOfLastToken + requestorOffset).
					self primaryExpression ifFalse: [^self expected: 'Argument'].
					self messagePart: 2 repeat: true.
					args addLast: parseNode].
			(Symbol hasInterned: selector contents ifTrue: [ :sym | selector _ sym])
				ifFalse: [ selector _ self correctSelector: selector contents
										wordIntervals: words
										exprInterval: (start to: self endOfLastToken)
										ifAbort: [ ^ self fail ] ].
			precedence _ 3]
		ifFalse: [((hereType == #binary or: [hereType == #verticalBar])
				and: [level >= 2])
				ifTrue: 
					[start _ self startOfNextToken.
					selector _ self advance asSymbol.
					self primaryExpression ifFalse: [^self expected: 'Argument'].
					self messagePart: 1 repeat: true.
					args _ Array with: parseNode.
					precedence _ 2]
				ifFalse: [hereType == #word
						ifTrue: 
							[start _ self startOfNextToken.
							selector _ self advance.
							args _ #().
							words _ OrderedCollection with: (start  + requestorOffset to: self endOfLastToken + requestorOffset).
							(Symbol hasInterned: selector ifTrue: [ :sym | selector _ sym])
								ifFalse: [ selector _ self correctSelector: selector
													wordIntervals: words
													exprInterval: (start to: self endOfLastToken)
													ifAbort: [ ^ self fail ] ].
							precedence _ 1]
						ifFalse: [^args notNil]]].
	parseNode _ encoder newMessageNode
				receiver: receiver
				selector: selector
				arguments: args
				precedence: precedence
				from: encoder
				sourceRange: (start to: self endOfLastToken).
	repeat]
		whileTrue: [].
	^true! !


!DialectParser methodsFor: 'as yet unclassified' stamp: 'hg 8/31/2000 20:22'!
messagePart: level repeat: repeat initialKeyword: kwdIfAny

	| start receiver selector args precedence words keywordStart |
	[receiver _ parseNode.
	(self matchKeyword and: [level >= 3])
		ifTrue: 
			[start _ self startOfNextToken.
			selector _ WriteStream on: (String new: 32).
			selector nextPutAll: kwdIfAny.
			args _ OrderedCollection new.
			words _ OrderedCollection new.
			[self matchKeyword]
				whileTrue: 
					[keywordStart _ self startOfNextToken + requestorOffset.
					selector nextPutAll: self advance , ':'.
					words addLast: (keywordStart to: hereMark + self previousTokenSize + requestorOffset).
					self primaryExpression ifFalse: [^ self expected: 'Argument'].
					args addLast: parseNode].
			(Symbol hasInterned: selector contents ifTrue: [ :sym | selector _ sym])
				ifFalse: [ selector _ self correctSelector: selector contents
										wordIntervals: words
										exprInterval: (start to: self endOfLastToken)
										ifAbort: [ ^ self fail ] ].
			precedence _ 3]
		ifFalse: [((hereType == #binary or: [hereType == #verticalBar])
				and: [level >= 2])
				ifTrue: 
					[start _ self startOfNextToken.
					selector _ self advance asSymbol.
					self primaryExpression ifFalse: [^self expected: 'Argument'].
					self messagePart: 1 repeat: true.
					args _ Array with: parseNode.
					precedence _ 2]
				ifFalse: [(hereType == #word
							and: [(#(leftParenthesis leftBracket leftBrace) includes: tokenType) not])
						ifTrue: 
							[start _ self startOfNextToken.
							selector _ self advance.
							args _ #().
							words _ OrderedCollection with: (start  + requestorOffset to: self endOfLastToken + requestorOffset).
							(Symbol hasInterned: selector ifTrue: [ :sym | selector _ sym])
								ifFalse: [ selector _ self correctSelector: selector
													wordIntervals: words
													exprInterval: (start to: self endOfLastToken)
													ifAbort: [ ^ self fail ] ].
							precedence _ 1]
						ifFalse: [^args notNil]]].
	parseNode _ encoder newMessageNode
				receiver: receiver
				selector: selector
				arguments: args
				precedence: precedence
				from: encoder
				sourceRange: (start to: self endOfLastToken).
	repeat]
		whileTrue: [].
	^true! !

MessageNode initialize!
MessageNode removeSelector: #checkBlock:as:from:!
MessageNode removeSelector: #emitCase:on:value:!
MessageNode removeSelector: #emitForEffect:on:!
MessageNode removeSelector: #emitIf:on:value:!
MessageNode removeSelector: #emitIfNil:on:value:!
MessageNode removeSelector: #emitToDo:on:value:!
MessageNode removeSelector: #emitWhile:on:value:!
MessageNode removeSelector: #printCaseOn:indent:!
MessageNode removeSelector: #printIfNil:indent:!
MessageNode removeSelector: #printIfNilNotNil:indent:!
MessageNode removeSelector: #printIfOn:indent:!
MessageNode removeSelector: #printToDoOn:indent:!
MessageNode removeSelector: #printWhileOn:indent:!
MessageNode removeSelector: #sizeCase:value:!
MessageNode removeSelector: #sizeForEffect:!
MessageNode removeSelector: #sizeIf:value:!
MessageNode removeSelector: #sizeIfNil:value:!
MessageNode removeSelector: #sizeToDo:value:!
MessageNode removeSelector: #sizeWhile:value:!
MessageNode removeSelector: #transform:!
MessageNode removeSelector: #transformAnd:!
MessageNode removeSelector: #transformBoolean:!
MessageNode removeSelector: #transformCase:!
MessageNode removeSelector: #transformIfFalse:!
MessageNode removeSelector: #transformIfFalseIfTrue:!
MessageNode removeSelector: #transformIfNil:!
MessageNode removeSelector: #transformIfNilIfNotNil:!
MessageNode removeSelector: #transformIfNotNilIfNil:!
MessageNode removeSelector: #transformIfTrue:!
MessageNode removeSelector: #transformIfTrueIfFalse:!
MessageNode removeSelector: #transformOr:!
MessageNode removeSelector: #transformToDo:!
MessageNode removeSelector: #transformWhile:!
-------------- next part --------------
'From Squeak2.9alpha of 8 July 2000 [latest update: #2447] on 26 September 2000 at 12:15:08 pm'!

!Compiler methodsFor: 'public access' stamp: 'hg 8/31/2000 20:41'!
parse: textOrStream in: aClass notifying: req
	"Compile the argument, textOrStream, with respect to the class, aClass, 
	and answer the MethodNode that is the root of the resulting parse tree. 
	Notify the argument, req, if an error occurs. The failBlock is defaulted to 
	an empty block."

	^ self parse: textOrStream in: aClass notifying: req dialect: false transformMessages: true! !


!Encoder methodsFor: 'code transformation' stamp: 'hg 9/1/2000 19:58'!
newMessageNode
	"this message decides what kind of nodes to build for messages,
	 in other words, whether the messages should be transformed or not during parsing.
	 instvar requestor contains ref to parser which holds setting for message transformation.
	 For backward compatibility, do transform unless I obtain explicit instructions not to do so."
 
	^(requestor notNil and: [(requestor respondsTo: #transformMessages) 
			and: [requestor transformMessages not]])
		ifTrue: [MessageNode new]
		ifFalse: [TransformedMessageNode new]! !

Compiler removeSelector: #parse:in:notifying:dialect:!
"Postscript:
Recompile the involved classes to generate optimized bytecodes."

#(Compiler Debugger DialectParser Encoder MessageNode Parser TransformedMessageNode)
	do: [:name | (Smalltalk at: name) compileAll]!



More information about the Squeak-dev mailing list