'From Cuis 1.0 of 21 August 2009 [latest update: #268] on 27 August 2009 at 1:16:39 pm'!

!ProtoObject methodsFor: 'testing' stamp: 'vb 4/15/2007 10:54'!
ifNil: nilBlock ifNotNil: ifNotNilBlock
	"Evaluate the block, unless I'm == nil (q.v.)"

	^ ifNotNilBlock valueWithPossibleArgs: {self}! !

!ProtoObject methodsFor: 'testing' stamp: 'jmv 8/27/2009 13:13'!
ifNotNil: ifNotNilBlock
	"Evaluate the block, unless I'm == nil (q.v.)"

	^ ifNotNilBlock valueWithPossibleArgs: {self}! !

!ProtoObject methodsFor: 'testing' stamp: 'vb 4/15/2007 10:55'!
ifNotNil: ifNotNilBlock ifNil: nilBlock 
	"If I got here, I am not nil, so evaluate the block ifNotNilBlock"

	^ ifNotNilBlock valueWithPossibleArgs: {self}! !

!MessageNode methodsFor: 'private' stamp: 'vb 4/16/2007 11:39'!
checkBlock: node as: nodeName from: encoder maxArgs: maxArgs
	"vb: #canBeSpecialArgument for blocks hardcodes 0 arguments as the requirement for special blocks. We work around that here by further checking the number of arguments for blocks.."

	node canBeSpecialArgument ifTrue: 
		[^node isMemberOf: BlockNode].
	(node isKindOf: BlockNode)
		ifTrue:
			[node numberOfArguments <= maxArgs
				ifTrue: [^true]
				ifFalse: [^encoder notify: '<- ', nodeName , ' of ' ,
					(MacroSelectors at: special) , ' has too many arguments']]
		ifFalse:
			[^encoder notify: '<- ', nodeName , ' of ' ,
					(MacroSelectors at: special) , ' must be a block or variable']! !


!MessageNode methodsFor: 'macro transformations' stamp: 'vb 4/16/2007 11:42'!
transformIfNil: encoder

	"vb: Removed the original transformBoolean: which amounds to a test we perform in each of the branches below."
	(MacroSelectors at: special) = #ifNotNil:
	ifTrue:
		[(self checkBlock: arguments first as: 'ifNotNil arg' from: encoder maxArgs: 1) 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]
! !

!MessageNode methodsFor: 'macro transformations' stamp: 'vb 4/16/2007 11:44'!
transformIfNilIfNotNil: encoder
	"vb: Changed to support one-argument ifNotNil: branch. In the 1-arg case we transform the receiver to
		(var := receiver)
	which is further transformed to
		(var := receiver) == nil ifTrue: .... ifFalse: ...
	This does not allow the block variable to shadow an existing temp, but it's no different from how to:do: is done."

	| ifNotNilArg blockVar |
	ifNotNilArg := arguments at: 2.
	((self checkBlock: (arguments at: 1) as: 'Nil arg' from: encoder)
		and: [self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder maxArgs: 1])
			ifFalse: [^false].
	ifNotNilArg numberOfArguments = 1 ifTrue:
		[blockVar := ifNotNilArg firstArgument.
		receiver := AssignmentNode new variable: blockVar value: receiver].
	selector _ SelectorNode new key: #ifTrue:ifFalse: code: #macro.
	receiver _ MessageNode new
		receiver: receiver
		selector: #==
		arguments: (Array with: NodeNil)
		precedence: 2
		from: encoder.
	^true! !

!MessageNode methodsFor: 'macro transformations' stamp: 'vb 4/16/2007 11:44'!
transformIfNotNilIfNil: encoder
	"vb: Changed to support one-argument ifNotNil: branch. In the 1-arg case we transform the receiver to
		(var := receiver)
	which is further transformed to
		(var := receiver) == nil ifTrue: .... ifFalse: ...
	This does not allow the block variable to shadow an existing temp, but it's no different from how to:do: is done."

	| ifNotNilArg blockVar |
	ifNotNilArg := arguments at: 1.
	((self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder maxArgs: 1)
		and: [self checkBlock: (arguments at: 2) as: 'Nil arg' from: encoder])
			ifFalse: [^false].
		
	ifNotNilArg numberOfArguments = 1 ifTrue:
		[blockVar := ifNotNilArg firstArgument.
		receiver := AssignmentNode new variable: blockVar value: receiver].
	selector _ SelectorNode new key: #ifTrue:ifFalse: code: #macro.
	receiver _ MessageNode new
		receiver: receiver
		selector: #==
		arguments: (Array with: NodeNil)
		precedence: 2
		from: encoder.
	arguments swap: 1 with: 2.
	^true
! !

!MessageNode methodsFor: 'code generation' stamp: 'vb 4/16/2007 11:40'!
emitIfNil: stack on: strm value: forValue
	"Emits both ifNil: and ifNotNil: code."
	"vb: The comment seems out of date; #ifNotNil: is expanded to #ifNil:ifNotNil: in 3.9 so this method only handles the ifNil: case."

	| theNode theSize ifNotNilSelector |
	theNode _ arguments first.
	theSize _ sizes at: 1.
	ifNotNilSelector _ #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 == ifNotNilSelector)
		dist: theSize 
		pop: stack 
		on: strm.
	pc _ strm position.
	forValue 
		ifTrue: 
			[strm nextPut: Pop. stack pop: 1.
			theNode emitForEvaluatedValue: stack on: strm]	
		ifFalse: [theNode emitForEvaluatedEffect: stack on: strm].! !

!MessageNode methodsFor: 'private' stamp: 'vb 4/15/2007 09:10'!
checkBlock: node as: nodeName from: encoder

	^self checkBlock: node as: nodeName from: encoder maxArgs: 0! !

