'From Cuis 2.6 of 10 August 2010 [latest update: #540] on 28 August 2010 at 11:54:54 am'!

!Decompiler commentStamp: 'nice 3/1/2010 19:56' prior: 0!
I decompile a method in three phases:
	Reverser: postfix byte codes -> prefix symbolic codes (nodes and atoms)
	Parser: prefix symbolic codes -> node tree (same as the compiler)
	Printer: node tree -> text (done by the nodes)
	

instance vars:

	constructor <DecompilerConstructor> an auxiliary knowing how to generate Abstract Syntax Tree (node tree)
	method <CompiledMethod> the method being decompiled
	instVars <Array of: String> the instance variables of the class implementing method
	tempVars <String | (OrderedCollection of: String)> hold the names of temporary variables (if known)
		NOTE: POLYMORPHISM WILL BE RESOLVED IN #initSymbols:
	constTable <Collection of: ParseNode> parse node associated with byte encoded constants (nil true false 0 1 -1 etc...)
	stack <OrderedCollection of: (ParseNode | String | Integer) > multipurpose...
	statements <OrderedCollection of: ParseNode> the statements of the method being decompiled 
	lastPc <Integer>
	exit <Integer>
	caseExits <OrderedCollection of: Integer> - stack of exit addresses that have been seen in the branches of caseOf:'s
	lastJumpPc <Integer>
	lastReturnPc <Integer>
	limit <Integer>
	hasValue <Boolean>
	blockStackBase <Integer>
	numLocaltemps <Integer | Symbol> - number of temps local to a block; also a flag indicating decompiling a block
	blockStartsToTempVars <Dictionary key: Integer value: (OrderedCollection of: String)>
	tempVarCount <Integer> number of temp vars used by the method!

!classDefinition: #BlockNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #BlockNode
	instanceVariableNames: 'arguments statements returns nArgsNode size remoteCopyNode temporaries optimized optimizedMessageNode actualScopeIfOptimized blockExtent remoteTempNode copiedValues closureCreationNode startOfLastStatement tempsMark '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #MessageNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #MessageNode
	instanceVariableNames: 'receiver selector precedence special arguments sizes equalNode caseErrorNode '
	classVariableNames: 'MacroEmitters MacroPrinters MacroSelectors MacroSizers MacroTransformers NewStyleMacroEmitters NewStyleMacroSizers StdTypers ThenFlag '
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #MethodNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #MethodNode
	instanceVariableNames: 'selectorOrFalse precedence arguments block primitive encoder temporaries properties sourceText localsPool locationCounter '
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!MethodNode commentStamp: 'eem 8/15/2010 10:49' prior: 0!
I am the root of the parse tree..

Instance Variables
	arguments:			<SequenceableCollection>
	block:				<BlockNode>
	encoder:			<BytecodeEncoder>
	localsPool:			<IdentitySet>
	locationCounter:	<Integer>
	precedence:		<Integer>
	primitive:			<Integer>
	properties:			<AdditionalMethodState|nil>
	selectorOrFalse:	<Object>
	sourceText:		<String|Text>
	temporaries:		<SequenceableCollection>

arguments
	- the collection of parsed or decompiled method arguments

block
	- the BlockNode holding the method's statements

encoder
	- the object that comprises the copiler's scope table, literal pool and back-end bytecode generator

localsPool
	- a set used to determine the set of copied values for each block in the method

locationCounter
	- an integer used to mark block scopes for the purposes of the closure transformation.  See BlockNode>>#analyseArguments:temporaries:rootNode:

precedence
	- the precedence of the method's selector (see Symbol>>precedence)

primitive
	- if non-zero this is the integer code of the method's primitive

properties
	- the object used to accumulate method properties (a.k.a. pragmas)

selectorOrFalse
	- the method's selector or false if this is a doit

sourceText
	- the source test from which the method was compiled

temporaries
	- the collection of parsed or decompiled method temporaries
!

!classDefinition: #UndeclaredVariableNode category: #'Compiler-ParseNodes'!
VariableNode subclass: #UndeclaredVariableNode
	instanceVariableNames: 'tag'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #VariableScopeFinder category: #'Compiler-Support'!
ParseNodeVisitor subclass: #VariableScopeFinder
	instanceVariableNames: 'theVariable'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!

!VariableScopeFinder commentStamp: 'eem 8/14/2010 19:45' prior: 0!
A VariableScopeFinder is used to find the minimum enclosing scope of a variable in a method.  This is used when auto-declaring temporaries to find the smallest enclosing block in which to declare the temp.

Instance Variables
	theVariable:		<VariableNode>

theVariable
	- the varable whose scope is to be determined
!


!BlockLocalTempCounter methodsFor: 'initialize-release' stamp: 'eem 9/26/2008 13:40'!
tempCountForBlockAt: pc in: method
	"Compute the number of local temporaries in a block.
	 If the block begins with a sequence of push: nil bytecodes then some of
	 These could be initializing local temps.  We can only reliably disambuguate
	 them from other uses of nil by parsing the stack and seeing what the offset
	 of the stack pointer is at the end of the block.

	 There are short-cuts.  The ones we take here are
		- if there is no sequence of push nils there can be no local temps
		- we follow forward jumps to shorten the amount of scanning"
	stackPointer := 0.
	scanner := InstructionStream new method: method pc: pc.
	scanner interpretNextInstructionFor: self.
	blockEnd isNil ifTrue:
		[self error: 'pc is not that of a block'].
	scanner nextByte = Encoder pushNilCode ifTrue:
		[joinOffsets := Dictionary new.
		 [scanner pc < blockEnd] whileTrue:
			[scanner interpretNextInstructionFor: self]].
	^stackPointer! !

!BlockLocalTempCounter methodsFor: 'initialize-release' stamp: 'eem 9/26/2008 13:41'!
testTempCountForBlockAt: startPc in: method
	"Compute the number of local temporaries in a block.
	 If the block begins with a sequence of push: nil bytecodes then some of
	 These could be initializing local temps.  We can only reliably disambuguate
	 them from other uses of nil by parsing the stack and seeing what the offset
	 of the stack pointer is at the end of the block.There are short-cuts.  The only
	 one we take here is
		- if there is no sequence of push nils there can be no local temps"

	| symbolicLines line prior thePc |
	symbolicLines := Dictionary new.
	method symbolicLinesDo:
		[:pc :lineForPC| symbolicLines at: pc put: lineForPC].
	stackPointer := 0.
	scanner := InstructionStream new method: method pc: startPc.
	scanner interpretNextInstructionFor: self.
	blockEnd isNil ifTrue:
		[self error: 'pc is not that of a block'].
	scanner nextByte = Encoder pushNilCode ifTrue:
		[joinOffsets := Dictionary new.
		 [scanner pc < blockEnd] whileTrue:
			[line := symbolicLines at: scanner pc.
			 prior := stackPointer.
			 thePc := scanner pc.
			 scanner interpretNextInstructionFor: self.
			 Transcript cr; print: prior; nextPutAll: '->'; print: stackPointer;  tab; print: thePc; tab; nextPutAll: line; flush]].
	^stackPointer! !


!CodeHolder methodsFor: 'message list' stamp: 'jmv 8/27/2010 18:28'!
sourceStringPrettifiedAndDiffed
	"Answer a copy of the source code for the selected message, transformed by diffing and pretty-printing exigencies"
	| class selector sourceString |
	class _ self selectedClassOrMetaClass.
	selector _ self selectedMessageName.
	(class isNil or: [ selector isNil ]) ifTrue: [ ^ 'missing' ].
	sourceString _ class
		ultimateSourceCodeAt: selector
		ifAbsent: [ ^ 'error' ].
	self
		validateMessageSource: sourceString
		forSelector: selector
		inClass: class.
	(self showingPrettyPrint or: [ self showingAnyKindOfPrettyDiffs ]) ifTrue: [
		sourceString _ class compilerClass new
			format: sourceString
			in: class
			notifying: nil ].
	self showingAnyKindOfDiffs ifTrue: [
		sourceString _ self diffFromPriorSourceFor: sourceString ].
	^ sourceString! !

!CodeHolder methodsFor: 'message list' stamp: 'jmv 8/27/2010 18:27'!
validateMessageSource: sourceString forSelector: aSelector inClass: theClass
	"Check whether there is evidence that method source is invalid"

	(theClass parserClass new parseSelector: sourceString asString) = aSelector
		ifFalse: [
			self inform: 'There may be a problem with your sources file!!

The source code for every method should (usually) start with the
method selector but this is not the case with this method!! You may
proceed with caution but it is recommended that you get a new source file.'].! !


!Compiler methodsFor: 'public access' stamp: 'Igor.Stasenko 12/20/2009 07:25'!
compiledMethodFor: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: logFlag
	"Compiles the sourceStream into a parse tree, then generates code
	 into a method, and answers it.  If receiver is not nil, then the text can
	 refer to instance variables of that receiver (the Inspector uses this).
	 If aContext is not nil, the text can refer to temporaries in that context
	 (the Debugger uses this). If aRequestor is not nil, then it will receive a 
	 notify:at: message before the attempt to evaluate is aborted."

	| methodNode method |
	class := (aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class.
	self from: textOrStream class: class context: aContext notifying: aRequestor.
	methodNode := self translate: sourceStream noPattern: true ifFail: [^failBlock value].
	method := self interactive ifTrue: [ 	methodNode generateWithTempNames ] 
		ifFalse: [methodNode generate].
		
	logFlag ifTrue:
		[SystemChangeNotifier uniqueInstance evaluated: sourceStream contents context: aContext].
	^method! !

!Compiler methodsFor: 'public access' stamp: 'eem 7/2/2010 09:54'!
evaluate: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: logFlag
	"Compiles the sourceStream into a parse tree, then generates code into
	 a method. If aContext is not nil, the text can refer to temporaries in that
	 context (the Debugger uses this). If aRequestor is not nil, then it will receive
	 a notify:at: message before the attempt to evaluate is aborted. Finally, the 
	 compiled method is invoked from here via withArgs:executeMethod:, hence
	 the system no longer creates Doit method litter on errors."

	| methodNode method value toLog itsSelection itsSelectionString |
	class := (aContext == nil ifTrue: [receiver] ifFalse: [aContext receiver]) class.
	self from: textOrStream class: class context: aContext notifying: aRequestor.
	methodNode := self translate: sourceStream noPattern: true ifFail: [^failBlock value].

	method := self interactive
				ifTrue: [methodNode generateWithTempNames]
				ifFalse: [methodNode generate].

	value := receiver
				withArgs: (context ifNil: [#()] ifNotNil: [{context}])
				executeMethod: method.

	logFlag ifTrue:
		[toLog := ((requestor respondsTo: #selection)  
			and:[(itsSelection := requestor selection) notNil
			and:[(itsSelectionString := itsSelection asString) isEmptyOrNil not]])
				ifTrue:[itsSelectionString]
				ifFalse:[sourceStream contents].
		SystemChangeNotifier uniqueInstance evaluated: toLog context: aContext].
	^ value! !

!Compiler methodsFor: 'public access' stamp: 'eem 8/14/2010 20:23'!
from: textOrStream class: aClass classified: aCategory context: aContext notifying: req

	sourceStream := (textOrStream isKindOf: PositionableStream)
						ifTrue: [textOrStream]
						ifFalse: [ReadStream on: textOrStream asString].
	class := aClass.
	context := aContext.
	requestor := req.
	category := aCategory
! !

!Compiler methodsFor: 'public access' stamp: 'eem 5/15/2008 15:11'!
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 from: textOrStream class: aClass context: nil notifying: req.
	^self parser
		parse: sourceStream
		class: class
		noPattern: false
		context: context
		notifying: requestor
		ifFail: []! !

!Compiler methodsFor: 'public access' stamp: 'md 2/20/2006 21:16'!
translate: aStream noPattern: noPattern ifFail: failBlock parser: parser
	| tree |
	tree := parser
			parse: aStream
			class: class
			noPattern: noPattern
			context: context
			notifying: requestor
			ifFail: [^ failBlock value].
	^ tree! !

!Compiler methodsFor: 'private' stamp: 'jmv 8/28/2010 10:47'!
translate: aStream noPattern: noPattern ifFail: failBlock
	^self parser
		sourceStreamGetter: sourceStreamGetter;			"Cuis specific. Do not remove!!"
		parse: aStream
		class: class
		category: category
		noPattern: noPattern
		context: context
		notifying: requestor
		ifFail: [^failBlock value]! !

!Compiler methodsFor: 'error handling' stamp: 'eem 9/25/2008 12:41'!
notify: aString at: location
	"Refer to the comment in Object|notify:."

	^requestor == nil
		ifTrue: [SyntaxErrorNotification
					inClass: class
					category: category
					withCode: 
						(sourceStream contents
							copyReplaceFrom: location
							to: location - 1
							with: aString)
					doitFlag: false
					errorMessage: aString
					location: location]
		ifFalse: [requestor
					notify: aString
					at: location
					in: sourceStream]! !


!Compiler class methodsFor: 'utilities' stamp: 'jmv 8/28/2010 09:18'!
recompileAll
	"Recompile all classes."

	Smalltalk forgetDoIts.
	Smalltalk allClasses do: [ :cls | cls compileAll] displayingProgress: 'Recompiling all classes'. 


! !


!Decompiler methodsFor: 'control' stamp: 'eem 5/29/2008 17:02'!
checkForClosureCopy: receiver arguments: arguments
	"We just saw a closureCopy:copiedValues: message. Check for and construct a following block."

	| savePc jump |
	receiver == constructor codeThisContext ifFalse: [^false].
	savePc := pc.
	(jump := self interpretJump) notNil ifFalse:
		[pc := savePc.
		 ^nil].
	"Definitely a block"
	self doClosureCopyCopiedValues: arguments last "<BraceNode>" elements
		numArgs: arguments first key
		blockSize: jump.
	^true! !

!Decompiler methodsFor: 'control' stamp: 'jmv 8/28/2010 11:42'!
doClosureCopyCopiedValues: blockCopiedValues numArgs: numArgs blockSize: blockSize
	| startpc savedTemps savedTempVarCount savedNumLocalTemps
	  jump blockArgs blockTemps blockTempsOffset block |
	savedTemps := tempVars.
	savedTempVarCount := tempVarCount.
	savedNumLocalTemps := numLocalTemps.
	jump := blockSize + (startpc := pc).
	numLocalTemps := BlockLocalTempCounter tempCountForBlockAt: pc - 4 in: method.
	blockTempsOffset := numArgs + blockCopiedValues size.
	(blockStartsToTempVars notNil "implies we were intialized with temp names."
	 and: [blockStartsToTempVars includesKey: pc])
		ifTrue:
			[tempVars := blockStartsToTempVars at: pc]
		ifFalse:
			[blockArgs := (1 to: numArgs) collect:
							[:i| (constructor
									codeTemp: i - 1
									named: 'arg', (tempVarCount + i) printString)
								  beBlockArg].
			blockTemps := (1 to: numLocalTemps) collect:
							[:i| constructor
									codeTemp: i + blockTempsOffset - 1
									named: 'temp', (tempVarCount + i + numArgs) printString].
			tempVars := blockArgs, blockCopiedValues, blockTemps].
	numLocalTemps timesRepeat:
		[self interpretNextInstructionFor: self.
		 stack removeLast].
	tempVarCount := tempVarCount + numArgs + numLocalTemps.
	block := self blockTo: jump.
	stack addLast: ((constructor
						codeArguments: (tempVars copyFrom: 1 to: numArgs)
						temps: (tempVars copyFrom: blockTempsOffset + 1 to: blockTempsOffset + numLocalTemps)
						block: block)
							pc: startpc;
							yourself).
	tempVars := savedTemps.
	tempVarCount := savedTempVarCount.
	numLocalTemps := savedNumLocalTemps! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'jmv 8/28/2010 11:43'!
popIntoTemporaryVariable: offset
	| maybeTVTag tempVector start |
	maybeTVTag := stack last.
	((maybeTVTag isMemberOf: Association)
	 and: [maybeTVTag key == #pushNewArray]) ifTrue:
		[blockStartsToTempVars notNil "implies we were intialized with temp names."
			ifTrue: "Use the provided temps"
				[self assert: ((tempVector := tempVars at: offset + 1 ifAbsent: [ParseNode basicNew]) isTemp
							 and: [tempVector isIndirectTempVector
							 and: [tempVector remoteTemps size = maybeTVTag value size]])]
			ifFalse: "Synthesize some remote temps"
				[tempVector := maybeTVTag value.
				 offset + 1 <= tempVars size
					ifTrue:
						[start := 2.
						 tempVector at: 1 put: (tempVars at: offset + 1)]
					ifFalse:
						[tempVars := (Array new: offset + 1)
										replaceFrom: 1
										to: tempVars size
										with: tempVars.
						start := 1].
				 start to: tempVector size do:
					[:i|
					tempVector
						at: i
						put: (constructor
								codeTemp: numLocalTemps + offset + i - 1
								named: 'temp', (tempVarCount + i) printString)].
				tempVars at: offset + 1 put: (constructor codeRemoteTemp: offset + 1 remoteTemps: tempVector)].
		 tempVarCount := tempVarCount + maybeTVTag value size.
		 stack removeLast.
		 ^self].
	self pushTemporaryVariable: offset; doStore: statements! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 8/12/2010 13:51'!
pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
	| copiedValues |
	self sawClosureBytecode.
	copiedValues := ((1 to: numCopied) collect: [:ign| stack removeLast]) reversed.
	self doClosureCopyCopiedValues: copiedValues numArgs: numArgs blockSize: blockSize! !

!Decompiler methodsFor: 'instruction decoding'!
pushConstant: value

	| node |
	node := value == true ifTrue: [constTable at: 2]
		ifFalse: [value == false ifTrue: [constTable at: 3]
		ifFalse: [value == nil ifTrue: [constTable at: 4]
		ifFalse: [constructor codeAnyLiteral: value]]].
	stack addLast: node! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'nk 2/20/2004 11:56'!
pushReceiverVariable: offset

	| var |
	(var := instVars at: offset + 1 ifAbsent: []) == nil
		ifTrue:
			["Not set up yet"
			var := constructor codeInst: offset.
			instVars size < (offset + 1) ifTrue: [
				instVars := (Array new: offset + 1)
					replaceFrom: 1 to: instVars size with: instVars; yourself ].
			instVars at: offset + 1 put: var].
	stack addLast: var! !

!Decompiler methodsFor: 'private' stamp: 'eem 9/5/2008 18:41'!
convertToDoLoop
	"If statements contains the pattern
		var := startExpr.
		[var <= limit] whileTrue: [...statements... var := var + incConst]
	then replace this by
		startExpr to: limit by: incConst do: [:var | ...statements...]"
	| initStmt toDoStmt limitStmt |
	statements size < 2 ifTrue: [^ self].
	initStmt := statements at: statements size-1.
	(toDoStmt := statements last toDoFromWhileWithInit: initStmt)
		== nil ifTrue: [^ self].
	initStmt variable scope: -1.  "Flag arg as block temp"
	statements removeLast; removeLast; addLast: toDoStmt.

	"Attempt further conversion of the pattern
		limitVar := limitExpr.
		startExpr to: limitVar by: incConst do: [:var | ...statements...]
	to
		startExpr to: limitExpr by: incConst do: [:var | ...statements...]"
	statements size < 2 ifTrue: [^ self].
	limitStmt := statements at: statements size-1.
	((limitStmt isMemberOf: AssignmentNode)
		and: [limitStmt variable isTemp
		and: [limitStmt variable == toDoStmt arguments first
		and: [self blockScopeRefersOnlyOnceToTemp: limitStmt variable fieldOffset]]])
		ifFalse: [^ self].
	toDoStmt arguments at: 1 put: limitStmt value.
	limitStmt variable scope: -2.  "Flag limit var so it won't print"
	statements removeLast; removeLast; addLast: toDoStmt.

! !

!Decompiler methodsFor: 'public access' stamp: 'eem 8/12/2010 13:46'!
decompileBlock: aBlock 
	"Decompile aBlock, returning the result as a BlockNode.  
	Show temp names from source if available."
	"Decompiler new decompileBlock: [3 + 4]"
	| startpc end homeClass blockNode methodNode home |
	(home := aBlock home) ifNil: [^ nil].
	method := home method.
	(homeClass := home methodClass) == #unknown ifTrue: [^ nil].
	aBlock isClosure ifTrue:
		[(methodNode := method decompileWithTemps)
			ifNil: [^nil]
			ifNotNil: [methodNode nodesDo: [:node| node pc = aBlock startpc ifTrue: [^node]]].
		 ^self error: 'cannot find block node matching aBlock'].
	constructor := self constructorForMethod: aBlock method.
	
	self withTempNames: method methodNode tempNames.

	self initSymbols: homeClass.
	startpc := aBlock startpc.
	end := aBlock endPC.
	stack := OrderedCollection new: method frameSize.
	caseExits := OrderedCollection new.
	statements := OrderedCollection new: 20.
	super method: method pc: startpc - 5.
	blockNode := self blockTo: end.
	stack isEmpty ifFalse: [self error: 'stack not empty'].
	^blockNode statements first! !

!Decompiler methodsFor: 'initialize-release' stamp: 'jmv 8/28/2010 11:12'!
initSymbols: aClass
	"Somewhat simplified for Cuis"
	| argCount |
	constructor method: method class: aClass literals: method literals.
	constTable _ constructor codeConstants.
	instVars _ Array new: aClass instSize.
	tempVarCount _ method numTemps.
	argCount _ method numArgs.
	"(tempVars isNil
	 and: [method holdsTempNames]) ifTrue:
		[tempVars := method tempNamesString]."
	tempVars isString
		ifTrue:
			[blockStartsToTempVars _ self mapFromBlockStartsIn: method
											toTempVarsFrom: tempVars
											constructor: constructor.
			 tempVars _ blockStartsToTempVars at: method initialPC]
		ifFalse:
			[| namedTemps |
			namedTemps _ tempVars ifNil: [(1 to: tempVarCount) collect: [ :i | 
					(i <= argCount ifTrue: ['arg'] ifFalse: ['temp']), i printString]].
			tempVars _ (1 to: tempVarCount) collect:
							[:i | i <= namedTemps size
								ifTrue: [constructor codeTemp: i - 1 named: (namedTemps at: i)]
								ifFalse: [constructor codeTemp: i - 1]]].
	1 to: method numArgs do:
		[:i|
		(tempVars at: i)
			beMethodArg]! !

!Decompiler methodsFor: 'initialize-release' stamp: 'nice 10/21/2009 00:29'!
mapFromBlockStartsIn: aMethod toTempVarsFrom: schematicTempNamesString constructor: aDecompilerConstructor
	| map |
	map := aMethod
				mapFromBlockKeys: aMethod startpcsToBlockExtents keys asArray sort
				toSchematicTemps: schematicTempNamesString.
	map keysAndValuesDo:
		[:startpc :tempNameTupleVector|
		tempNameTupleVector isEmpty ifFalse:
			[| subMap numTemps tempVector |
			subMap := Dictionary new.
			"Find how many temp slots there are (direct & indirect temp vectors)
			 and for each indirect temp vector find how big it is."
			tempNameTupleVector do:
				[:tuple|
				tuple last isArray
					ifTrue:
						[subMap at: tuple last first put: tuple last last.
						 numTemps := tuple last first]
					ifFalse:
						[numTemps := tuple last]].
			"create the temp vector for this scope level."
			tempVector := Array new: numTemps.
			"fill it in with any indirect temp vectors"
			subMap keysAndValuesDo:
				[:index :size|
				tempVector at: index put: (Array new: size)].
			"fill it in with temp nodes."
			tempNameTupleVector do:
				[:tuple| | itv |
				tuple last isArray
					ifTrue:
						[itv := tempVector at: tuple last first.
						 itv at: tuple last last
							put: (aDecompilerConstructor
									codeTemp: tuple last last - 1
									named: tuple first)]
					ifFalse:
						[tempVector
							at: tuple last
							put: (aDecompilerConstructor
									codeTemp: tuple last - 1
									named: tuple first)]].
			"replace any indirect temp vectors with proper RemoteTempVectorNodes"
			subMap keysAndValuesDo:
				[:index :size|
				tempVector
					at: index
					put: (aDecompilerConstructor
							codeRemoteTemp: index
							remoteTemps: (tempVector at: index))].
			"and update the entry in the map"
			map at: startpc put: tempVector]].
	^map! !


!Dictionary methodsFor: '*Compiler' stamp: 'ul 1/25/2010 18:57'!
bindingOf: varName

	^self associationAt: varName ifAbsent: nil! !


!Exception methodsFor: 'handling' stamp: 'ar 2/13/2010 15:20'!
resume
	"Return from the message that signaled the receiver."

	self resume: self defaultResumeValue! !

!Exception methodsFor: 'defaults' stamp: 'ar 2/13/2010 15:20'!
defaultResumeValue
	"Answer the value that by default should be returned if the exception is resumed"
	^nil! !


!ParseNode methodsFor: 'printing' stamp: 'eem 9/5/2009 11:27'!
printCommentOn: aStream indent: indent 
	| thisComment |
	self comment == nil ifTrue: [^ self].
	1 to: self comment size
	   do: [:index |
		index > 1 ifTrue: [aStream crtab: indent].
		aStream nextPut: $".
		thisComment := self comment at: index.
		self printSingleComment: thisComment
			on: aStream
			indent: indent.
		aStream nextPut: $"]! !


!AssignmentNode methodsFor: 'printing' stamp: 'jmv 8/27/2010 20:06'!
printWithClosureAnalysisOn: aStream indent: level 
	variable printWithClosureAnalysisOn: aStream indent: level.
	aStream nextPutAll: ' _ '.
	value printWithClosureAnalysisOn: aStream indent: level! !


!BlockNode methodsFor: 'code generation (closures)' stamp: 'nice 3/2/2010 00:58'!
addRemoteTemp: aTempVariableNode rootNode: rootNode "<MethodNode>"
	"Add aTempVariableNode to my actualScope's sequence of
	 remote temps.  If I am an optimized block then the actual
	 scope is my actualScopeIfOptimized, otherwise it is myself."
	remoteTempNode == nil ifTrue:
		[remoteTempNode := RemoteTempVectorNode new
								name: self remoteTempNodeName
								index: arguments size + temporaries size
								type: LdTempType
								scope: 0.
		 actualScopeIfOptimized
			ifNil:
				[self addTempNode: remoteTempNode.
				 remoteTempNode definingScope: self]
			ifNotNil: [actualScopeIfOptimized addHoistedTemps: { remoteTempNode }]].
	remoteTempNode addRemoteTemp: aTempVariableNode encoder: rootNode encoder.
	"use remove:ifAbsent: because the deferred analysis for optimized
	 loops can result in the temp has already been hoised into the root."
	self removeTempNode: aTempVariableNode ifAbsent: [
		self actualScope removeTempNode: aTempVariableNode ifAbsent: ["should not happen"]].
	^remoteTempNode! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'nice 8/19/2010 16:31'!
computeCopiedValues: rootNode
	| referencedValues |
	referencedValues := rootNode referencedValuesWithinBlockExtent: blockExtent.
	^(referencedValues reject: [:temp| temp isDefinedWithinBlockExtent: blockExtent])
		asArray sort: ParseNode tempSortBlock! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 7/24/2009 18:56'!
ifHasRemoteTempNodeEnsureInitializationStatementExists: rootNode
	"If a remoteTempNode has been added ensure a statement exists to initialize it."
	remoteTempNode ~~ nil ifTrue:
		[(statements notEmpty
		  and: [statements first isAssignmentNode
		  and: [statements first variable isTemp
		  and: [statements first variable isIndirectTempVector]]])
			ifTrue: "If this is a decompiled tree, or if a temporary has been added later in
					the analysis then there already is a temp vector initialization node."
				[(statements first variable ~~ remoteTempNode) ifTrue:
					[statements first variable become: remoteTempNode].
				 statements first value numElements: remoteTempNode remoteTemps size]
			ifFalse:
				[statements addFirst: (remoteTempNode nodeToInitialize: rootNode encoder)]].! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 8/13/2010 15:44'!
tempsMark
	^tempsMark! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 8/13/2010 15:44'!
tempsMark: anInteger
	tempsMark := anInteger! !

!BlockNode methodsFor: 'testing' stamp: 'eem 7/17/2008 12:20'!
generateAsClosure
	"Answer if we're compiling under the closure regime.  If blockExtent has been set by
	analyseTempsWithin:rootNode: et al then we're compiling under the closure regime."
	^blockExtent ~~ nil! !

!BlockNode methodsFor: 'printing' stamp: 'jmv 8/28/2010 11:11'!
decompileText
	"Answer a text description of the parse tree whose root is the receiver."
	"Don't have ColoredCodeStrean in Cuis"
	^ TextStream contents: [:strm | self printOn: strm indent: 0]
! !


!CascadeNode methodsFor: 'code generation' stamp: 'eem 5/15/2008 09:39'!
sizeCodeForValue: encoder
	| size |
	size := (receiver sizeCodeForValue: encoder)
			 + (messages size - 1 * (encoder sizeDup + encoder sizePop)).
	messages do: [:aMessage | size := size + (aMessage sizeCodeForValue: encoder)].
	^size! !


!DecompilerConstructorForClosures methodsFor: 'constructor' stamp: 'eem 8/15/2010 16:56'!
codeMethod: selector block: block tempVars: vars primitive: primitive class: class

	| blockNode selectorNode visibleTemps invisibleTemps arguments temporaries |
	selectorNode := self codeSelector: selector code: nil.
	tempVars := vars.
	visibleTemps := OrderedCollection new.
	invisibleTemps := OrderedCollection new.
	tempVars do: [:t|
				   ((t isIndirectTempVector or: [t scope >= 0])
						ifTrue: [visibleTemps]
						ifFalse: [invisibleTemps]) addLast: t].
	arguments := visibleTemps copyFrom: 1 to: nArgs.
	temporaries := visibleTemps copyFrom: nArgs + 1 to: visibleTemps size.
	block
		arguments: arguments;
		temporaries: temporaries.
	blockNode := MethodNode new
		selector: selectorNode
		arguments: arguments
		precedence: selector precedence
		temporaries: temporaries
		block: block
		encoder: (EncoderForV3PlusClosures new initScopeAndLiteralTables
					temps: visibleTemps, invisibleTemps
					literals: literalValues
					class: class)
		primitive: primitive
		properties: method properties copy.
	blockNode properties method: blockNode.
	^blockNode! !


!Encoder methodsFor: 'results' stamp: 'eem 5/27/2009 09:25'!
associationForClass
	| assoc |
	assoc := self environment associationAt: class name ifAbsent: [nil].
	^assoc value == class
		ifTrue: [assoc]
		ifFalse: [Association new value: class]! !

!Encoder methodsFor: 'results' stamp: 'eem 8/13/2010 16:51'!
undeclaredTemps 
	^(scopeTable select: [:var | var isVariableNode and: [var isUndeclared]]) values! !

!Encoder methodsFor: 'temps' stamp: 'eem 12/1/2008 12:07'!
fixTemp: name
	| node |
	node := scopeTable at: name ifAbsent: [].
	node class ~~ TempVariableNode ifTrue:
		[self error: 'can only fix a floating temp var'].
	node index: nTemps.
	nTemps := nTemps + 1.
	^node! !

!Encoder methodsFor: 'temps' stamp: 'eem 7/13/2007 14:13'!
floatTemp: node
	(node ~~ (scopeTable at: node name ifAbsent: [])
	or: [node class ~~ TempVariableNode
	or: [node code ~= (node code: nTemps - 1 type: LdTempType)]]) ifTrue:
		[self error: 'can only float the last allocated temp var'].
	nTemps := nTemps - 1! !

!Encoder methodsFor: 'temps' stamp: 'eem 8/14/2010 19:35'!
newUndeclaredTemp: name
	^UndeclaredVariableNode new name: name! !

!Encoder methodsFor: 'encoding' stamp: 'jmv 8/28/2010 11:09'!
encodeSelector: aSelector
	"Don't call it 'selector'. It would be shadowed."
	^self
		name: aSelector
		key: aSelector
		class: SelectorNode
		type: SendType
		set: selectorSet! !

!Encoder methodsFor: 'encoding' stamp: 'eem 8/15/2010 08:29'!
lookupVariable: name ifAbsent: aBlock
	"Answer the binding of name in the scope table or aBlock's vaue if none.
	 Do not bind and do not lookup in pools.  Used for correction, explanation etc"
	^scopeTable at: name ifAbsent: aBlock! !

!Encoder methodsFor: 'private' stamp: 'eem 8/13/2010 16:06'!
bindUndeclaredTemp: name
	^scopeTable at: name put: (self newUndeclaredTemp: name)! !

!Encoder methodsFor: 'private' stamp: 'ar 3/4/2010 23:39'!
interactive
	"Answer true if compilation is interactive"

	^requestor interactive! !

!Encoder methodsFor: 'private' stamp: 'Lukas Renggli 11/2/2009 00:29'!
name: name key: key class: leafNodeClass type: type set: dict 
	^dict at: key
		ifAbsentPut: 
			[leafNodeClass new 
				name: name
				key: key
				index: nil
				type: type]! !

!Encoder methodsFor: 'initialize-release' stamp: 'jmv 8/28/2010 11:17'!
init: aClass context: aContext notifying: req
	requestor := req.
	class := aClass.
	nTemps := 0.
	supered := false.
	self initScopeAndLiteralTables.
	"No Tweak Fields in Cuis"
	class variablesAndOffsetsDo: [ :variable "<String>" :offset "<Integer>" |
		scopeTable
			at: variable
			put: (offset >= 0
					ifTrue: [InstanceVariableNode new
								name: variable index: offset]
					ifFalse: [MaybeContextInstanceVariableNode new
								name: variable index: offset negated])].
	aContext ifNotNil: [
		| homeNode |
		homeNode := self bindTemp: self doItInContextName.
		"0th temp = aContext passed as arg"
		aContext tempNames withIndexDo: [ :variable :index |
			scopeTable
				at: variable
				put: (MessageAsTempNode new
						receiver: homeNode
						selector: #namedTempAt:
						arguments: (Array with: (self encodeLiteral: index))
						precedence: 3
						from: self)]].
	sourceRanges := Dictionary new: 32.
	globalSourceRanges := OrderedCollection new: 32! !

!Encoder methodsFor: 'error handling'!
notify: string
	"Put a separate notifier on top of the requestor's window"
	| req |
	requestor == nil
		ifFalse: 
			[req := requestor.
			self release.
			req notify: string].
	^false! !

!Encoder methodsFor: 'error handling'!
notify: string at: location

	| req |
	requestor == nil
		ifFalse: 
			[req := requestor.
			self release.
			req notify: string at: location].
	^false! !


!BytecodeEncoder methodsFor: 'temps' stamp: 'eem 9/8/2008 18:24'!
bindBlockArg: name within: aBlockNode
	"Read the comment in the superclass's method.
	 If we have closures we should check the argument
	 count against the block, not the method.

	(Note that this isn't entirely adequate either since optimized blocks
	 will slip through the cracks (their arguments (i.e. ifNotNil: [:expr|)
	 are charged against their enclosing block, not themselves))."
	| nArgs |
	self supportsClosureOpcodes ifFalse:
		[^super bindBlockArg: name within: aBlockNode].
	(nArgs := aBlockNode nArgsSlot) isNil ifTrue:
		[aBlockNode nArgsSlot: (nArgs := 0)].
	nArgs  >= 15 ifTrue:
		[^self notify: 'Too many arguments'].
	aBlockNode nArgsSlot: nArgs + 1.
	^(self bindTemp: name)
		beBlockArg;
		nowHasDef;
		nowHasRef;
		yourself! !

!BytecodeEncoder methodsFor: 'temps' stamp: 'eem 5/30/2008 14:35'!
bindBlockTemp: name within: aBlockNode
	"Read the comment in the superclass's bindBlockArg:within: method.
	 If we have closures we should check the argument
	 count against the block, not the method.

	(Note that this isn't entirely adequate either since optimized blocks
	 will slip through the cracks (their arguments (i.e. ifNotNil: [:expr|)
	 are charged against their enclosing block, not themselves))."
	| nArgs |
	self supportsClosureOpcodes ifFalse:
		[^super bindBlockTemp: name within: aBlockNode].
	(nArgs := aBlockNode nArgsSlot) isNil ifTrue:
		[aBlockNode nArgsSlot: (nArgs := 0)].
	nArgs >= (CompiledMethod fullFrameSize - 1) ifTrue:
		[^self notify: 'Too many temporaries'].
	aBlockNode nArgsSlot: nArgs + 1.
	^self bindTemp: name! !

!BytecodeEncoder methodsFor: 'temps' stamp: 'jmv 8/28/2010 10:56'!
blockExtentsToTempsMap
	"Answer a Dictionary of blockExtent to temp locations for the current method.
	 This is used by the debugger to locate temp vars in contexts.  A temp map
	 entry is a pair of the temp's name and its index, where an index is either an
	 integer for a normal temp or a pair of the index of the indirect temp vector
	 containing  the temp and the index of the temp in its indirect temp vector."
	| blockExtentsToTempsMap |
	blockExtentsToLocals ifNil:
		[^nil].
	blockExtentsToTempsMap := Dictionary new.
	blockExtentsToLocals keysAndValuesDo:
		[:blockExtent :locals|
		blockExtentsToTempsMap
			at: blockExtent
			put: (Array streamContents:
					[:strm|		"Do not call it stream, it would be shadowed"
					locals withIndexDo:
						[:local :index|
						local isIndirectTempVector
							ifTrue: [local remoteTemps withIndexDo:
										[:remoteLocal :innerIndex| strm nextPut: { remoteLocal key. { index. innerIndex } }]]
							ifFalse: [strm nextPut: { local key. index }]]])].
	^blockExtentsToTempsMap! !


!LeafNode methodsFor: 'private' stamp: 'jmv 8/28/2010 11:18'!
code: idx type: type
	"Warning: index would be shadowed"
	idx ifNil: [
		^type negated].
	(CodeLimits at: type) > idx 
		ifTrue: [^(CodeBases at: type) + idx].
	^type * 256 + idx! !


!LiteralNode methodsFor: 'printing' stamp: 'eem 5/6/2008 14:46'!
printOn: aStream indent: level

	key isVariableBinding
		ifTrue:
			[key key isNil
				ifTrue:
					[aStream nextPutAll: '###'; nextPutAll: key value soleInstance name]
				ifFalse:
					[aStream nextPutAll: '##'; nextPutAll: key key]]
		ifFalse:
			[key storeOn: aStream]! !

!LiteralNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: aStream indent: level

	key isVariableBinding
		ifTrue:
			[key key isNil
				ifTrue:
					[aStream nextPutAll: '###'; nextPutAll: key value soleInstance name]
				ifFalse:
					[aStream nextPutAll: '##'; nextPutAll: key key]]
		ifFalse:
			[key storeOn: aStream]! !


!MessageNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2009 11:58'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	"Assignments within optimized loops are tricky.  Because a loop repeats a
	 write to a temporary in an optimized loop effectively occurs after the loop.
	 To handle this collect the set of temps assigned to in optimized loops and
	 add extra writes after traversing the optimized loop constituents."
	| writtenToTemps |
	self isOptimizedLoop ifTrue:
		[{ receiver }, arguments do:
			[:node|
			(node notNil and: [node isBlockNode and: [node optimized]]) ifTrue:
				[assignmentPools at: node put: Set new]]].
	"receiver is nil in cascades"
	receiver == nil ifFalse:
		[receiver analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools].
	arguments do:
		[:node|
		node == nil ifFalse: "last argument of optimized to:do: can be nil"
			[node analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools]].
	"Add assignments representing subsequent iterations
	 and redo the closure analysis for the written-to temps."
	self isOptimizedLoop ifTrue:
		[writtenToTemps := Set new.
		 { receiver }, arguments do:
			[:node|
			(node notNil and: [node isBlockNode and: [node optimized]]) ifTrue:
				[(assignmentPools removeKey: node) do:
					[:temp|
					temp isBlockArg ifFalse: "ignore added assignments to to:do: loop args"
						[writtenToTemps add: temp.
						 temp addWriteWithin: node at: rootNode locationCounter]]]].
		 writtenToTemps isEmpty ifFalse:
			[(writtenToTemps asSortedCollection: ParseNode tempSortBlock) do:
				[:each| each analyseClosure: rootNode].
			 (writtenToTemps collect: [:each| each definingScope]) do:
				[:blockNode|
				blockNode ifHasRemoteTempNodeEnsureInitializationStatementExists: rootNode]]]! !

!MessageNode methodsFor: 'code generation' stamp: 'eem 8/15/2010 10:23'!
emitCodeForEffect: stack encoder: encoder
	"For #ifTrue:ifFalse: and #whileTrue: / #whileFalse: style messages, the pc is set to the jump instruction, so that mustBeBoolean exceptions can be shown correctly."
	special > 0
		ifTrue: 
			[pc := 0.
			self perform: (MacroEmitters at: special) with: stack with: encoder with: false]
		ifFalse: 
			[super emitCodeForEffect: stack encoder: encoder]! !

!MessageNode methodsFor: 'code generation' stamp: 'eem 5/14/2008 16:31'!
emitCodeForToDo: stack encoder: encoder 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 emitCodeForEffect: stack encoder: encoder].
	initStmt emitCodeForEffect: stack encoder: encoder.
	test emitCodeForValue: stack encoder: encoder.
	self emitCodeForBranchOn: false dist: blockSize pop: stack encoder: encoder.
	pc := encoder methodStreamPosition.
	block emitCodeForEvaluatedEffect: stack encoder: encoder.
	incStmt emitCodeForEffect: stack encoder: encoder.
	self emitCodeForJump: 0 - loopSize encoder: encoder.
	forValue ifTrue: [encoder genPushSpecialLiteral: nil. stack push: 1]! !

!MessageNode methodsFor: 'code generation' stamp: 'eem 8/15/2010 10:23'!
emitCodeForValue: stack encoder: encoder
	"For #ifTrue:ifFalse: and #whileTrue: / #whileFalse: style messages, the pc is set to the jump instruction, so that mustBeBoolean exceptions can be shown correctly."
	special > 0
		ifTrue: 
			[pc := 0.
			self perform: (MacroEmitters at: special) with: stack with: encoder with: true]
		ifFalse: 
			[receiver ~~ nil ifTrue: [receiver emitCodeForValue: stack encoder: encoder].
			arguments do: [:argument | argument emitCodeForValue: stack encoder: encoder].
			pc := encoder methodStreamPosition + 1. "debug pc is first byte of the send, i.e. the next byte".
			selector
				emitCode: stack
				args: arguments size
				encoder: encoder
				super: receiver == NodeSuper]! !

!MessageNode methodsFor: 'code generation' stamp: 'nice 12/27/2009 03:11'!
sizeCodeForCase: encoder value: forValue

	| braceNode sizeIndex elseSize allReturn |
	forValue not ifTrue:
		[^super sizeCodeForEffect: encoder].
	equalNode := encoder encodeSelector: #=.
	braceNode := arguments first.
	sizes := Array new: 2 * braceNode numElements.
	sizeIndex := sizes size.
	elseSize := arguments size = 2
		ifTrue:
			[arguments last sizeCodeForEvaluatedValue: encoder] "otherwise: [...]"
		ifFalse:
			[caseErrorNode := encoder encodeSelector: #caseError.
			 (NodeSelf sizeCodeForValue: encoder)
			 + (caseErrorNode sizeCode: encoder args: 0 super: false)]. "self caseError"
	"There must be at least one branch around the otherwise/caseError
	  so the decompiler can identify the end of the otherwise/caseError."
	allReturn := true. "assume every case ends with a return"
	braceNode casesForwardDo:
		[:keyNode :valueNode :last |
		valueNode returns ifFalse: [allReturn := false]].
	braceNode casesReverseDo:
		[:keyNode :valueNode :last | | thenSize |
		sizes at: sizeIndex put: elseSize.
		thenSize := valueNode sizeCodeForEvaluatedValue: encoder.
		last ifFalse: [thenSize := thenSize + encoder sizePop].
		valueNode returns ifFalse: [thenSize := thenSize + (self sizeCode: encoder forJump: elseSize)].
		(last and: [allReturn]) ifTrue: [thenSize := thenSize + (self sizeCode: encoder forJump: elseSize)].
		sizes at: sizeIndex-1 put: thenSize.
		last ifFalse: [elseSize := elseSize + encoder sizeDup].
		elseSize := elseSize
					+ (keyNode sizeCodeForEvaluatedValue: encoder)
					+ (equalNode sizeCode: encoder args: 1 super: false)
					+ (self sizeCode: encoder forBranchOn: false dist: thenSize)
					+ thenSize.
		sizeIndex := sizeIndex - 2].
	^(receiver sizeCodeForValue: encoder) + elseSize! !

!MessageNode methodsFor: 'code generation' stamp: 'eem 8/15/2010 10:22'!
sizeCodeForEffect: encoder

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

!MessageNode methodsFor: 'code generation' stamp: 'eem 5/19/2008 15:09'!
sizeCodeForToDo: encoder value: forValue 
	" var := rcvr. L1: [var <= arg1] Bfp(L2) [block body. var := var + inc] Jmp(L1) L2: "
	| loopSize initStmt test block incStmt blockSize initSize limitInit |
	block := arguments at: 3.
	initStmt := arguments at: 4.
	test := arguments at: 5.
	incStmt := arguments at: 6.
	limitInit := arguments at: 7.
	initSize := initStmt sizeCodeForEffect: encoder.
	limitInit == nil ifFalse:
		[initSize := initSize + (limitInit sizeCodeForEffect: encoder)].
	blockSize := (block sizeCodeForEvaluatedEffect: encoder)
			+ (incStmt sizeCodeForEffect: encoder)
			+ (encoder sizeJumpLong: -1).
	loopSize := (test sizeCodeForValue: encoder)
			+ (self sizeCode: encoder forBranchOn: false dist: blockSize)
			+ blockSize.
	sizes := Array with: blockSize with: loopSize.
	^initSize
	+ loopSize
	+ (forValue ifTrue: [encoder sizePushSpecialLiteral: nil] ifFalse: [0])! !

!MessageNode methodsFor: 'code generation' stamp: 'eem 8/15/2010 10:22'!
sizeCodeForValue: encoder
	| total |
	special > 0 
		ifTrue: [^self perform: (MacroSizers at: special) with: encoder with: true].
	receiver == NodeSuper
		ifTrue: [selector := selector copy "only necess for splOops"].
	total := selector sizeCode: encoder args: arguments size super: receiver == NodeSuper.
	receiver == nil 
		ifFalse: [total := total + (receiver sizeCodeForValue: encoder)].
	sizes := arguments collect: 
					[:arg | | argSize | 
					argSize := arg sizeCodeForValue: encoder.
					total := total + argSize.
					argSize].
	^total! !

!MessageNode methodsFor: 'initialize-release' stamp: 'eem 5/10/2008 12:10'!
receiver: rcvr selector: aSelector arguments: args precedence: p from: encoder 
	"Compile."

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


!MessageNode class methodsFor: 'class initialization' stamp: 'eem 8/15/2010 10:22'!
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:).
	MacroTransformers := 
		#(	transformIfTrue: transformIfFalse: transformIfTrueIfFalse: transformIfFalseIfTrue:
			transformAnd: transformOr:
			transformWhile: transformWhile: transformWhile: transformWhile:
			transformToDo: transformToDo:
			transformCase: transformCase:
			transformIfNil: transformIfNil:  transformIfNilIfNotNil: transformIfNotNilIfNil:).
	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:).
	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:).
	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:)! !


!MethodNode methodsFor: 'converting' stamp: 'eem 7/18/2008 06:37'!
asColorizedSmalltalk80Text
	"Answer a colorized Smalltalk-80-syntax string description of the parse tree whose root is the receiver."

	| printText |
	printText := self printString asText.
	^(Smalltalk at: #SHTextStylerST80 ifAbsent: [nil])
		ifNotNil: [:stylerClass| stylerClass new styledTextFor: printText]
		ifNil: [printText]! !

!MethodNode methodsFor: 'converting' stamp: 'ar 4/17/2010 16:50'!
decompileString 
	"Answer a string description of the parse tree whose root is the receiver."

	^self fullPrintString
! !

!MethodNode methodsFor: 'code generation' stamp: 'eem 7/14/2010 11:28'!
generate: trailer 
	"The receiver is the root of a parse tree. Answer a CompiledMethod.
	 The argument, trailer, is arbitrary but is typically either the reference
	 to the source code that is stored with every CompiledMethod, or an
	 encoding of the method's temporary names."

	| primErrNode blkSize nLits literals stack method |
	self generate: trailer ifQuick:
			[:m |
			  m	literalAt: 2 put: encoder associationForClass;
				properties: properties.
			^m].
	primErrNode := self primitiveErrorVariableName ifNotNil:
						[encoder fixTemp: self primitiveErrorVariableName].
	encoder supportsClosureOpcodes ifTrue:
		[self ensureClosureAnalysisDone.
		 encoder rootNode: self. "this is for BlockNode>>sizeCodeForClosureValue:"].
	blkSize := (block sizeCodeForEvaluatedValue: encoder)
				+ (primErrNode
					ifNil: [0]
					ifNotNil: [primErrNode sizeCodeForStore: encoder "The VM relies on storeIntoTemp: (129)"]).
	method := CompiledMethod
				newBytes: blkSize
				trailerBytes: trailer 
				nArgs: arguments size
				nTemps: (encoder supportsClosureOpcodes
							ifTrue: [| locals |
									locals := arguments,
											  temporaries,
											  (primErrNode
												ifNil: [#()]
												ifNotNil: [{primErrNode}]).
									encoder
										noteBlockExtent: block blockExtent
										hasLocals: locals.
									locals size]
							ifFalse: [encoder maxTemp])
				nStack: 0
				nLits: (nLits := (literals := encoder allLiterals) size)
				primitive: primitive.
	nLits > 255 ifTrue:
		[^self error: 'Too many literals referenced'].
	1 to: nLits do: [:lit | method literalAt: lit put: (literals at: lit)].
	encoder streamToMethod: method.
	stack := ParseStack new init.
	primErrNode ifNotNil: [primErrNode emitCodeForStore: stack encoder: encoder].
	stack position: method numTemps.
	block emitCodeForEvaluatedValue: stack encoder: encoder.
	stack position ~= (method numTemps + 1) ifTrue:
		[^self error: 'Compiler stack discrepancy'].
	encoder methodStreamPosition ~= (method size - trailer size) ifTrue:
		[^self error: 'Compiler code size discrepancy'].
	method needsFrameSize: stack size - method numTemps.
	method properties: properties.
	^method! !

!MethodNode methodsFor: 'code generation' stamp: 'jmv 8/28/2010 10:04'!
generateWithTempNames
	"Should adopt at least a reduced version of method trailers it seems...
	Otherwise, perhaps, decide not to store any trail... Consequences?"
	^ self generate copyWithTempsFromMethodNode: self.! !

!MethodNode methodsFor: 'code generation' stamp: 'eem 11/29/2008 18:53'!
properties
	^properties! !

!MethodNode methodsFor: 'printing' stamp: 'eem 8/15/2010 10:36'!
printWithClosureAnalysisOn: aStream 
	self ensureClosureAnalysisDone.
	precedence = 1
		ifTrue: 
			[(self selector includesSubString: '()/')
				ifTrue: [aStream nextPutAll: (self selector copyUpTo: $)).
						arguments
							do: [:arg| aStream nextPutAll: arg key]
							separatedBy: [aStream nextPutAll: ', '].
						aStream nextPut: $)]
				ifFalse: [aStream nextPutAll: self selector]]  "no node for method selector"
		ifFalse: 
			[self selector keywords with: arguments do: 
				[:kwd :arg | 
				aStream nextPutAll: kwd; space.
				arg printDefinitionForClosureAnalysisOn: aStream.
				aStream space]].
	comment == nil ifFalse: 
			[aStream crtab: 1.
			 self printCommentOn: aStream indent: 1].
	temporaries size > 0 ifTrue: 
			[aStream crtab: 1; nextPut: $|.
			temporaries do: [:temp | 
				aStream space.
				temp printDefinitionForClosureAnalysisOn: aStream].
			aStream space; nextPut: $|].
	primitive > 0 ifTrue:
		[(primitive between: 255 and: 519) ifFalse:  "Dont decompile quick prims  e.g, ^ self or ^instVar"
			[aStream crtab: 1.
			 self printPrimitiveOn: aStream]].
	self printPropertiesOn: aStream.
	self printPragmasOn: aStream.
	aStream crtab: 1.
	block printWithClosureAnalysisStatementsOn: aStream indent: 0! !

!MethodNode methodsFor: 'source mapping' stamp: 'Igor.Stasenko 12/20/2009 03:54'!
rawSourceRangesAndMethodDo: aBinaryBlock
	"Evaluate aBinaryBlock with the rawSourceRanges and method generated from the receiver."

	| methNode method |
	methNode := encoder classEncoding parserClass new
					encoderClass: encoder class;
					parse: (sourceText "If no source, use decompile string as source to map from"
							ifNil: [self decompileString]
							ifNotNil: [sourceText])
					class: self methodClass.
	method := methNode generate.  "set bytecodes to map to"
	^aBinaryBlock
		value: methNode encoder rawSourceRanges
		value: method! !

!MethodNode methodsFor: 'debugger support' stamp: 'Igor.Stasenko 12/20/2009 03:59'!
blockExtentsToTempsMap
	"Answer a Dictionary of blockExtent to temp locations for the current method.
	 This is used by the debugger to locate temp vars in contexts.  A temp map
	 entry is a pair of the temp's name and its index, where an index is either an
	 integer for a normal temp or a pair of the index of the indirect temp vector
	 containing  the temp and the index of the temp in its indirect temp vector."

	^encoder blockExtentsToTempsMap ifNil:
		[| methNode |
		methNode := encoder classEncoding parserClass new
						encoderClass: encoder class;
						parse: (sourceText ifNil: [self decompileString])
						class: self methodClass.
		"As a side effect generate: creates data needed for the map."
		methNode generate.
		methNode encoder blockExtentsToTempsMap]! !

!MethodNode methodsFor: 'debugger support' stamp: 'eem 7/1/2009 13:45'!
hasGeneratedMethod
	^encoder hasGeneratedMethod! !

!MethodNode methodsFor: 'debugger support' stamp: 'Igor.Stasenko 12/20/2009 03:58'!
schematicTempNamesString
	"Answer the temp names for the current method node in a form that captures
	 temp structure.  The temps at each method and block scope level occur
	 space-separated, with any indirect temps enclosed in parentheses.  Each block
	 level is enclosed in square brackets.  e.g.
		'method level temps (indirect temp)[block args and temps (indirect)]'
	 This representation can be reconstituted into a blockExtentsToTempsMap
	 by a CompiledMethod that has been copied with the schematicTempNamesString."
	encoder hasGeneratedMethod ifFalse:
		["create the encoder's blockExtentsToLoals map, except if the method is quick
		  in which case it has no temps."
		(self generate) isQuick ifTrue:
			[^'']].
	^encoder schematicTempNamesString! !

!MethodNode methodsFor: 'code generation (closures)' stamp: 'eem 5/29/2008 15:27'!
addLocalsToPool: locals "<Set of: TempVariableNode>"
	localsPool isNil ifTrue:
		[localsPool := IdentitySet new].
	localsPool addAll: locals! !

!MethodNode methodsFor: 'code generation (closures)' stamp: 'eem 7/24/2008 10:04'!
ensureClosureAnalysisDone
	block blockExtent ifNil:
		[temporaries := block analyseArguments: arguments temporaries: temporaries rootNode: self]! !

!MethodNode methodsFor: 'code generation (closures)' stamp: 'eem 5/20/2008 13:43'!
locationCounter
	^locationCounter! !

!MethodNode methodsFor: 'code generation (closures)' stamp: 'eem 5/30/2008 11:27'!
noteBlockEntry: aBlock
	"Evaluate aBlock with the numbering for the block entry."
	locationCounter isNil ifTrue:
		[locationCounter := -1].
	aBlock value: locationCounter + 1.
	locationCounter := locationCounter + 2! !

!MethodNode methodsFor: 'code generation (closures)' stamp: 'eem 6/2/2008 12:12'!
noteBlockExit: aBlock
	"Evaluate aBlock with the numbering for the block exit."
	aBlock value: locationCounter + 1.
	locationCounter := locationCounter + 2! !

!MethodNode methodsFor: 'code generation (closures)' stamp: 'eem 5/29/2008 16:07'!
referencedValuesWithinBlockExtent: anInterval 
	^(localsPool select:
		[:temp|
		 temp isReferencedWithinBlockExtent: anInterval]) collect:
			[:temp|
			temp isRemote ifTrue: [temp remoteNode] ifFalse: [temp]]! !


!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 8/13/2010 16:50'!
visitUndeclaredVariableNode: aVariableNode! !


!Scanner methodsFor: 'expression types' stamp: 'eem 7/2/2010 10:07'!
scanAllTokenPositionsInto: aBlock
	"Evaluate aBlock with the start and end positions of all separate non-white-space tokens, including comments."

	| lastMark |
	lastMark := 1.
	[currentComment notNil ifTrue:
		[currentComment do:
			[:cmnt| | idx |
			 idx := source originalContents indexOfSubCollection: cmnt startingAt: lastMark.
			 (idx > 0 and: [idx < mark]) ifTrue:
				[aBlock value: idx - 1 value: (lastMark := idx + cmnt size)]].
		 currentComment := nil].
	mark notNil ifTrue:
		[(token == #- 
		  and: [(self typeTableAt: hereChar) = #xDigit]) ifTrue:
			[| savedMark |
			 savedMark := mark.
			 self scanToken.
			 token := token negated.
			 mark := savedMark].
		"Compensate for the fact that the parser uses two character lookahead.  Normally we must
		  remove the extra two characters.  But this mustn't happen for the last token at the end of stream."
		 aBlock
			value: mark
			value: (source atEnd
					ifTrue: [tokenType := #doIt. "to cause an immediate ^self" source position]
					ifFalse: [source position - 2])].
	 (tokenType = #rightParenthesis
	  or: [tokenType == #doIt]) ifTrue:
		[^self].
	tokenType = #leftParenthesis
		ifTrue: 
			[self scanToken; scanAllTokenPositionsInto: aBlock]
		ifFalse: 
			[(tokenType = #word or: [tokenType = #keyword or: [tokenType = #colon]])
				ifTrue: 
					[self scanLitWord.
					 token = #true ifTrue: [token := true].
					 token = #false ifTrue: [token := false].
					 token = #nil ifTrue: [token := nil]]
				ifFalse:
					[(token == #- 
					  and: [(self typeTableAt: hereChar) = #xDigit])
						ifTrue: 
							[self scanToken.
							 token := token negated]]].
		self scanToken.
	true] whileTrue! !

!Scanner methodsFor: 'error handling' stamp: 'nice 2/25/2010 02:56'!
notify: string at: posiiton
	"Parser compatible message"
	 
	^self notify: string ! !

!Scanner methodsFor: 'initialize-release' stamp: 'jmv 8/28/2010 11:30'!
initScannerForTokenization
	"Don't raise xIllegal when enocuntering an _"
	"Simpler implementation for Cuis"
	isForTokenization _ true! !

!Scanner methodsFor: 'multi-character scans' stamp: 'ar 3/26/2004 15:45'!
xDoubleQuote
    "Collect a comment."
    "wod 1/10/98: Allow 'empty' comments by testing the first character
for $"" rather than blindly adding it to the comment being collected."
    | aStream stopChar |
    stopChar := 30 asCharacter.
    aStream := WriteStream on: (String new: 200).
    self step.
    [hereChar == $"]
        whileFalse:
            [(hereChar == stopChar and: [source atEnd])
                ifTrue: [^self offEnd: 'Unmatched comment quote'].
            aStream nextPut: self step.].
    self step.
    currentComment == nil
        ifTrue: [currentComment := OrderedCollection with: aStream
contents]
        ifFalse: [currentComment add: aStream contents].
    self scanToken! !

!Scanner methodsFor: 'multi-character scans' stamp: 'jmv 8/27/2010 18:47'!
xIllegal
	"An illegal character was encountered"
	self notify: 'Illegal character (char code ' , hereChar asciiValue printString, hereChar asciiValue hex , ')' at: mark! !


!Parser methodsFor: 'private'!
addComment

	parseNode ~~ nil
		ifTrue: 
			[parseNode comment: currentComment.
			currentComment := nil]! !

!Parser methodsFor: 'private' stamp: 'jmv 8/28/2010 11:24'!
init: sourceStream notifying: req failBlock: aBlock

	requestor := req.
	failBlock := aBlock.
	requestorOffset := 0.
	"Hey, don't call super with a different selector!!"
	self scan: sourceStream.
	prevMark := hereMark := mark.
	self advance! !

!Parser methodsFor: 'error handling' stamp: 'nice 2/26/2010 00:21'!
fail

	| exitBlock |
	(encoder == nil or: [encoder == self])
		ifFalse: [encoder release. encoder := nil]. "break cycle"
	exitBlock := failBlock.
	failBlock := nil.
	^exitBlock value! !

!Parser methodsFor: 'error handling' stamp: 'jmv 8/28/2010 11:26'!
interactive
	"Answer true if compilation is interactive"

	^ requestor notNil and: [(requestor isKindOf: SyntaxError) not]! !

!Parser methodsFor: 'error handling' stamp: 'di 2/9/1999 15:43'!
offEnd: aString 
	"Notify a problem beyond 'here' (in lookAhead token). Don't be offEnded!!"

	requestorOffset == nil
		ifTrue: [^ self notify: aString at: mark]
		ifFalse: [^ self notify: aString at: mark + requestorOffset]
! !

!Parser methodsFor: 'primitives' stamp: 'ar 5/24/2010 20:41'!
externalFunctionDeclaration
	"Parse the function declaration for a call to an external library."
	| descriptorClass callType retType externalName args argType module |
	descriptorClass := Smalltalk at: #ExternalFunction ifAbsent:[nil].
	descriptorClass == nil ifTrue:[^false].
	callType := descriptorClass callingConventionFor: here.
	callType == nil ifTrue:[^false].
	"Parse return type"
	self advance.
	retType := self externalType: descriptorClass.
	retType == nil ifTrue:[^self expected:'return type'].
	"Parse function name or index"
	externalName := here.
	(self match: #string) 
		ifTrue:[externalName := externalName asSymbol]
		ifFalse:[(self match:#number) ifFalse:[^self expected:'function name or index']].
	(self matchToken: #'(') ifFalse:[^self expected:'argument list'].
	args := WriteStream on: Array new.
	[here == #')'] whileFalse:[
		argType := self externalType: descriptorClass.
		argType == nil ifTrue:[^self expected:'argument'].
		argType isVoid & argType isPointerType not ifFalse:[args nextPut: argType].
	].
	(args position = self properties selector numArgs) ifFalse:[
		^self expected: 'Matching number of arguments'
	].
	(self matchToken:#')') ifFalse:[^self expected:')'].
	(self matchToken: 'module:') ifTrue:[
		module := here.
		(self match: #string) ifFalse:[^self expected: 'String'].
		module := module asSymbol].
	Smalltalk at: #ExternalLibraryFunction ifPresent:[:xfn| | fn |
		fn := xfn name: externalName 
				module: module 
				callType: callType
				returnType: retType
				argumentTypes: args contents.
		self allocateLiteral: fn.
	].
	self addPragma: (Pragma keyword: #primitive: arguments: #(120)).
	^true! !

!Parser methodsFor: 'primitives' stamp: 'ar 12/2/1999 16:49'!
externalType: descriptorClass
	"Parse an return an external type"
	| xType |
	xType := descriptorClass atomicTypeNamed: here.
	xType == nil ifTrue:["Look up from class scope"
		Symbol hasInterned: here ifTrue:[:sym|
			xType := descriptorClass structTypeNamed: sym]].
	xType == nil ifTrue:[
		"Raise an error if user is there"
		self interactive ifTrue:[^nil].
		"otherwise go over it silently"
		xType := descriptorClass forceTypeNamed: here].
	self advance.
	(self matchToken:#*)
		ifTrue:[^xType asPointerType]
		ifFalse:[^xType]! !

!Parser methodsFor: 'expression types' stamp: 'eem 8/13/2010 16:48'!
method: doit context: ctxt 
	" pattern [ | temporaries ] block => MethodNode."

	| sap blk prim temps messageComment methodNode |
	sap := self pattern: doit inContext: ctxt.
	"sap={selector, arguments, precedence}"
	self properties selector: (sap at: 1).
	encoder selector: (sap at: 1).
	(sap at: 2) do: [:argNode | argNode beMethodArg].
	doit ifFalse: [self pragmaSequence].
	temps := self temporaries.
	messageComment := currentComment.
	currentComment := nil.
	doit ifFalse: [self pragmaSequence].
	prim := self pragmaPrimitives.
	self statements: #() innerBlock: doit.
	blk := parseNode.
	doit ifTrue: [blk returnLast]
		ifFalse: [blk returnSelfIfNoOther: encoder].
	hereType == #doIt ifFalse: [^self expected: 'Nothing more'].
	methodNode := self newMethodNode comment: messageComment.
	methodNode
		selector: (sap at: 1)
		arguments: (sap at: 2)
		precedence: (sap at: 3)
		temporaries: temps
		block: blk
		encoder: encoder
		primitive: prim
		properties: properties.
	self interactive ifTrue:
		[self declareUndeclaredTemps: methodNode.
		 self removeUnusedTemps].
	^methodNode! !

!Parser methodsFor: 'expression types' stamp: 'eem 7/16/2008 11:05'!
pattern: fromDoit inContext: ctxt
	" unarySelector | binarySelector arg | keyword arg {keyword arg} =>
	{selector, arguments, precedence}."
	| args selector |
	doitFlag := fromDoit.
	fromDoit ifTrue:
		[^ctxt == nil
			ifTrue: [{#DoIt. {}. 1}]
			ifFalse: [{#DoItIn:. {encoder encodeVariable: encoder doItInContextName}. 3}]].

	hereType == #word ifTrue: [^ {self advance asSymbol. {}. 1}].

	(hereType == #binary or: [hereType == #verticalBar]) ifTrue: 
		[selector := self advance asSymbol.
		args := Array with: (encoder bindArg: self argumentName).
		^ {selector. args. 2}].

	hereType == #keyword ifTrue: 
		[selector := WriteStream on: (String new: 32).
		args := OrderedCollection new.
		[hereType == #keyword] whileTrue:[
			selector nextPutAll: self advance.
			args addLast: (encoder bindArg: self argumentName).
		].
		^ {selector contents asSymbol. args. 3}].
	hereType == #positionalMessage ifTrue:[
		args := OrderedCollection new.
		selector := self advance.
		hereType == #rightParenthesis ifTrue:[self advance. ^{(selector,'/0') asSymbol. args. 1}].
		[
			args addLast: (encoder bindArg: self argumentName).
			hereType == #rightParenthesis ifTrue:[
				self advance. 
				selector := (selector,'/', args size printString) asSymbol.
				^{selector. args. 1}].
			here == #, ifFalse:[self expected: 'comma'].
			self advance.
		] repeat.
	].
	^self expected: 'Message pattern'! !

!Parser methodsFor: 'expression types' stamp: 'jmv 8/28/2010 11:28'!
statements: argNodes innerBlock: inner blockNode: theBlockNode

	| stmts returns start |
	"give initial comment to block, since others trail statements"
	theBlockNode comment: currentComment.
	"Very important. Nil the comment, to avoid printing comments multiple times when pretty-printing"
	currentComment _ nil.
	stmts := OrderedCollection new.
	returns := false.
	hereType ~~ #rightBracket ifTrue:
		[[theBlockNode startOfLastStatement: (start := self startOfNextToken).
		  (returns := self matchReturn)
			ifTrue: 
				[self expression ifFalse:
					[^self expected: 'Expression to return'].
				 self addComment.
				 stmts addLast: (parseNode isReturningIf
								ifTrue: [parseNode]
								ifFalse: [ReturnNode new
											expr: parseNode
											encoder: encoder
											sourceRange: (start to: self endOfLastToken)])]
			ifFalse: 
				[self expression
					ifTrue: 
						[self addComment.
						 stmts addLast: parseNode]
					ifFalse: 
						[self addComment.
						 stmts size = 0 ifTrue: 
							[stmts addLast: 
								(encoder encodeVariable:
									(inner ifTrue: ['nil'] ifFalse: ['self']))]]].
		  returns ifTrue: 
			[self match: #period.
			 (hereType == #rightBracket or: [hereType == #doIt]) ifFalse:
				[^self expected: 'End of block']].
		  returns not and: [self match: #period]] whileTrue].
	theBlockNode
		arguments: argNodes
		statements: stmts
		returns: returns
		from: encoder.
	parseNode := theBlockNode.
	^true! !

!Parser methodsFor: 'expression types' stamp: 'eem 8/13/2010 10:35'!
temporaries
	" [ '|' (variable)* '|' ]"
	| vars theActualText |
	(self match: #verticalBar) ifFalse: 
		["no temps"
		doitFlag ifTrue:
			[tempsMark := self interactive
								ifTrue: [requestor selectionInterval first]
								ifFalse: [1].
			^ #()].
		tempsMark := hereMark	"formerly --> prevMark + prevToken".
		tempsMark > 0 ifTrue:
			[theActualText := source contents.
			[tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]]
				whileTrue: [tempsMark := tempsMark + 1]].
			^ #()].
	vars := OrderedCollection new.
	[hereType == #word]
		whileTrue: [vars addLast: (encoder bindTemp: self advance)].
	(self match: #verticalBar) ifTrue: 
		[tempsMark := prevMark.
		^ vars].
	^ self expected: 'Vertical bar'
! !

!Parser methodsFor: 'expression types' stamp: 'eem 8/13/2010 10:35'!
temporariesIn: methodSelector
	" [ '|' (variable)* '|' ]"
	| vars theActualText |
	(self match: #verticalBar) ifFalse: 
		["no temps"
		doitFlag ifTrue:
			[tempsMark := self interactive
								ifTrue: [requestor selectionInterval first]
								ifFalse: [1].
			^ #()].
		tempsMark := hereMark	"formerly --> prevMark + prevToken".
		tempsMark > 0 ifTrue:
			[theActualText := source contents.
			[tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]]
				whileTrue: [tempsMark := tempsMark + 1]].
			^ #()].
	vars := OrderedCollection new.
	[hereType == #word]
		whileTrue: [vars addLast: (encoder bindTemp: self advance in: methodSelector)].
	(self match: #verticalBar) ifTrue: 
		[tempsMark := prevMark.
		^ vars].
	^ self expected: 'Vertical bar'! !

!Parser methodsFor: 'expression types' stamp: 'eem 8/13/2010 15:57'!
temporaryBlockVariablesFor: aBlockNode
	"Scan and answer temporary block variables."

	| variables |
	(self match: #verticalBar) ifFalse:
		"There are't any temporary variables."
		[aBlockNode tempsMark: prevMark + requestorOffset.
		 ^#()].

	variables := OrderedCollection new.
	[hereType == #word] whileTrue:
		[variables addLast: (encoder bindBlockTemp: self advance within: aBlockNode)].
	(self match: #verticalBar) ifFalse:
		[^self expected: 'Vertical bar'].
	aBlockNode tempsMark: prevMark + requestorOffset.
	^variables! !

!Parser methodsFor: 'error correction' stamp: 'jmv 8/28/2010 10:36'!
declareClassVar: name
	| sym class |
	sym := name asSymbol.
	class := encoder classEncoding.
	class := class theNonMetaClass.		"not the metaclass"
	class addClassVarName: name.
	"Not needed in Cuis"
	"Smalltalk logChange: class definition."
	^ encoder global: (class classPool associationAt: sym)
			name: sym! !

!Parser methodsFor: 'error correction' stamp: 'jmv 8/28/2010 10:36'!
declareInstVar: name
	"Declare an instance variable.  Since the variable will get added after any existing
	 inst vars its index is the instSize."
	encoder classEncoding addInstVarName: name.
	"Not needed in Cuis"
	"Smalltalk logChange: encoder classEncoding definition."
	^InstanceVariableNode new name: name index: encoder classEncoding instSize
		! !

!Parser methodsFor: 'error correction' stamp: 'eem 8/17/2010 16:35'!
declareTemp: name at: levelTag
	"Defer declaring the temp until the parse has completed.  This allows
	 the parser to declare the temp in the minimum enclosing block instead
	 of always at method level.  See Parser>>declareUndeclaredTemps:"
	^(encoder bindUndeclaredTemp: name)
		tag: levelTag;
		yourself! !

!Parser methodsFor: 'error correction' stamp: 'eem 8/14/2010 19:34'!
declareTempAndPaste: name
	"Defer declaring the temp until the parse has completed.  This allows
	 the parser to declare the temp in the minimum enclosing block instead
	 of always at method level.  See Parser>>declareUndeclaredTemps:"
	^encoder bindUndeclaredTemp: name! !

!Parser methodsFor: 'error correction' stamp: 'eem 8/17/2010 16:37'!
declareUndeclaredTemps: methodNode
	"Declare any undeclared temps, declaring them at the smallest enclosing scope."

	| undeclared userSelection blocksToVars |
	(undeclared := encoder undeclaredTemps) isEmpty ifTrue:
		[^self].
	userSelection := requestor selectionInterval.
	blocksToVars := IdentityDictionary new.
	undeclared do:
		[:var|
		(blocksToVars
			at: (var tag == #method
					ifTrue: [methodNode block]
					ifFalse: [methodNode accept: (VariableScopeFinder new ofVariable: var)])
			ifAbsentPut: [SortedCollection new]) add: var name].
	(blocksToVars removeKey: methodNode block ifAbsent: []) ifNotNil:
		[:rootVars|
		rootVars do: [:varName| self pasteTempAtMethodLevel: varName]].
	(blocksToVars keys sorted: [:a :b| a tempsMark < b tempsMark]) do:
		[:block| | decl |
		decl := (blocksToVars at: block) reduce: [:a :b| a, ' ', b].
		block temporaries isEmpty
			ifTrue:
				[self substituteWord: ' | ', decl, ' |'
					wordInterval: (block tempsMark + 1 to: block tempsMark)
					offset: requestorOffset]
			ifFalse:
				[self substituteWord: decl, ' '
					wordInterval: (block tempsMark to: block tempsMark - 1)
					offset: requestorOffset]].
	requestor selectInvisiblyFrom: userSelection first to: userSelection last + requestorOffset.
	ReparseAfterSourceEditing signal! !

!Parser methodsFor: 'error correction' stamp: 'eem 8/13/2010 19:34'!
pasteTempAtMethodLevel: name
	| insertion delta theTextString characterBeforeMark |

	theTextString := requestor text string.
	characterBeforeMark := theTextString at: tempsMark-1 ifAbsent: [$ ].
	(theTextString at: tempsMark) = $| ifTrue: [
  		"Paste it before the second vertical bar"
		insertion := name, ' '.
		characterBeforeMark isSeparator ifFalse: [insertion := ' ', insertion].
		delta := 0.
	] ifFalse: [
		"No bars - insert some with CR, tab"
		insertion := '| ' , name , ' |',String cr.
		delta := 2.	"the bar and CR"
		characterBeforeMark = Character tab ifTrue: [
			insertion := insertion , String tab.
			delta := delta + 1.	"the tab"
		].
	].
	tempsMark := tempsMark +
		(self substituteWord: insertion
			wordInterval: (tempsMark to: tempsMark-1)
			offset: 0) - delta! !

!Parser methodsFor: 'error correction' stamp: 'jmv 8/28/2010 10:40'!
removeUnusedTemps
	"Scan for unused temp names, and prompt the user about the prospect of removing each one found"

	| str madeChanges | 
	madeChanges := false.
	str := requestor text asString.
	((tempsMark between: 1 and: str size)
		and: [(str at: tempsMark) = $|]) ifFalse: [^ self].
	encoder unusedTempNames do:
		[:temp | | start end |
		(UnusedVariable name: temp) ifTrue:
			[(encoder lookupVariable: temp ifAbsent: []) isUndefTemp
				ifTrue:
					[end := tempsMark.
					["Beginning at right temp marker..."
					start := end - temp size + 1.
					end < temp size or: [temp = (str copyFrom: start to: end)
							"In Cuis, we chose to use 'tokenish not' and not 'isSeparator'"
							and: [(str at: start-1) tokenish not & (str at: end+1) tokenish not]]]
						whileFalse:
							["Search left for the unused temp"
							end := requestor nextTokenFrom: end direction: -1].
					end < temp size ifFalse:
						[(str at: start-1) = $  ifTrue: [start := start-1].
						requestor correctFrom: start to: end with: ''.
						str := str copyReplaceFrom: start to: end with: ''. 
						madeChanges := true.
						tempsMark := tempsMark - (end-start+1)]]
				ifFalse:
					[self inform:
'You''ll first have to remove the\statement where it''s stored into' withCRs]]].
	madeChanges ifTrue: [ReparseAfterSourceEditing signal]! !

!Parser methodsFor: 'error correction' stamp: 'eem 8/14/2010 10:32'!
substituteWord: correctWord wordInterval: spot offset: o
	"Substitute the correctSelector into the (presumed interactive) receiver.
	 Update requestorOffset based on the delta size and answer the updated offset."

	requestor correctFrom: spot first + o to: spot last + o with: correctWord.
	requestorOffset := requestorOffset + correctWord size - spot size.
	^o + correctWord size - spot size! !

!Parser methodsFor: 'public access' stamp: 'eem 6/19/2008 09:38'!
encoder
	encoder isNil ifTrue:
		[encoder := EncoderForV3PlusClosures new].
	^encoder! !

!Parser methodsFor: 'public access' stamp: 'eem 5/14/2008 15:24'!
encoderClass: anEncoderClass
	encoder notNil ifTrue:
		[self error: 'encoder already set'].
	encoder := anEncoderClass new! !

!Parser methodsFor: 'public access' stamp: 'jmv 8/28/2010 10:50'!
parse: sourceStream class: class category: aCategory noPattern: noPattern context: ctxt notifying: req ifFail: aBlock 
	"Answer a MethodNode for the argument, sourceStream, that is the root of
	 a parse tree. Parsing is done with respect to the argument, class, to find
	 instance, class, and pool variables; and with respect to the argument,
	 ctxt, to find temporary variables. Errors in parsing are reported to the
	 argument, req, if not nil; otherwise aBlock is evaluated. The argument
	 noPattern is a Boolean that is true if the the sourceStream does not
	 contain a method header (i.e., for DoIts)."

	| methNode repeatNeeded myStream s p |
	category := aCategory.
	myStream := sourceStream.
	[repeatNeeded := false.
	 p := myStream position.
	 s := myStream upToEnd.
	 myStream position: p.
	 self encoder init: class context: ctxt notifying: self.
	 self init: myStream notifying: req failBlock: [^ aBlock value].
	 doitFlag := noPattern.
	 failBlock:= aBlock.
	 [methNode := self
					method: noPattern
					context: ctxt] 
		on: ReparseAfterSourceEditing 
		do:	[ :ex |
			repeatNeeded := true.
			myStream _ sourceStreamGetter notNil				"Cuis specific. Do not remove!!"
				ifTrue: [ requestor perform: sourceStreamGetter ]
				ifFalse: [ReadStream on: requestor text string]].
	 repeatNeeded] whileTrue:
		[encoder := self encoder class new].
	methNode sourceText: s.
	^methNode! !

!Parser methodsFor: 'public access' stamp: 'eem 5/6/2008 13:42'!
parseArgsAndTemps: aString notifying: req 
        "Parse the argument, aString, notifying req if an error occurs. Otherwise, 
        answer a two-element Array containing Arrays of strings (the argument 
        names and temporary variable names)."

        aString == nil ifTrue: [^#()].
        doitFlag := false.               "Don't really know if a doit or not!!"
        ^self initPattern: aString
                notifying: req
                return: [:pattern | (pattern at: 2) , (self temporariesIn: (pattern at: 1))]! !

!Parser methodsFor: 'public access'!
parseMethodComment: aString setPattern: aBlock
	"Answer the method comment for the argument, aString. Evaluate aBlock 
	with the message pattern in the form #(selector, arguments, precedence)."

	self
		initPattern: aString
		notifying: nil
		return: aBlock.
	currentComment==nil
		ifTrue:	[^OrderedCollection new]
		ifFalse:	[^currentComment]! !

!Parser methodsFor: 'public access' stamp: 'jmv 8/28/2010 10:47'!
sourceStreamGetter: aSymbol
	"Cuis specific. Do not remove!!"
	sourceStreamGetter _ aSymbol! !


!SelectorNode methodsFor: 'printing' stamp: 'eem 5/6/2008 14:50'!
printOn: aStream indent: level 
	aStream nextPutAll: (key == nil
							ifTrue: ['<key==nil>']
							ifFalse: [key])! !

!SelectorNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: aStream indent: level 
	aStream nextPutAll: (key == nil
							ifTrue: ['<key==nil>']
							ifFalse: [key])! !


!SmalltalkEditor methodsFor: 'do-its' stamp: 'jmv 8/28/2010 10:48'!
compileSelectionFor: anObject in: evalContext
	| methodNode |
	methodNode _ [
	Compiler new
		sourceStreamGetter: #selectionAsStream;		"Cuis specific. Do not remove!!"
		
		compileNoPattern: self selectionAsStream
		in: anObject class
		context: evalContext
		notifying: self
		ifFail: [ ^ nil ]]
		on: OutOfScopeNotification
		do: [ :ex |
			ex resume: true ].
	^ methodNode generateWithTempNames.! !

!SmalltalkEditor methodsFor: 'do-its' stamp: 'jmv 8/28/2010 10:48'!
evaluateSelection
	"Treat the current selection as an expression; evaluate it and return the result"
	| result rcvr ctxt |
	self lineSelectAndEmptyCheck: [^ ''].

	(model respondsTo: #doItReceiver) 
		ifTrue: [FakeClassPool adopt: model selectedClass.  "Include model pool vars if any"
				rcvr _ model doItReceiver.
				ctxt _ model doItContext]
		ifFalse: [rcvr _ ctxt _ nil].
	result _ [
		rcvr class evaluatorClass new
			sourceStreamGetter: #selectionAsStream;		"Cuis specific. Do not remove!!"
			evaluate: self selectionAsStream
			in: ctxt
			to: rcvr
			notifying: self
			ifFail: [FakeClassPool adopt: nil. ^ #failedDoit]
			logged: true.
	] 
		on: OutOfScopeNotification 
		do: [ :ex | ex resume: true].
	FakeClassPool adopt: nil.
	^ result! !


!SystemDictionary methodsFor: 'browsing' stamp: 'dtl 8/1/2010 10:12'!
browseMyChanges
	"Browse only the changes (in the changes file) by the current author.
	Smalltalk browseMyChanges
	"
	self browseAllSelect: [ :method |
       method fileIndex > 1 "only look at changes file"
               and: [ method timeStamp beginsWith: Utilities authorInitials ]]! !

!SystemDictionary methodsFor: 'system attributes' stamp: 'eem 7/22/2010 17:44'!
flagInterpretedMethods: aBoolean
	"The Cog VM can be instructed to set the flag bit of CompiledMethods that
	 it executes but will only interpret.  This can be used e.g. to profile startup.
	 See CompiledMethod>>#flag & CompiledMethod>>#clearFlag.  
	 This flag persists across snapshots, stored in the image header."

	self vmParameterAt: 48 put: ((self vmParameterAt: 48) bitClear: 2) + (aBoolean ifTrue: [2] ifFalse: [0])! !

!SystemDictionary methodsFor: 'system attributes' stamp: 'eem 7/22/2010 17:23'!
processHasThreadIdInstVar: aBoolean
	"The threaded VM needs to know if the 4th inst var of Process
	 is threadId which it uses to control process-to-thread binding.
	 This flag persists across snapshots, stored in the image header."
	aBoolean ifTrue: [self assert: (Process instVarNames at: 4) ='threadId'].
	self vmParameterAt: 48 put: ((self vmParameterAt: 48) bitClear: 1) + (aBoolean ifTrue: [1] ifFalse: [0])! !

!SystemDictionary methodsFor: 'system attributes' stamp: 'eem 7/22/2010 17:51'!
processPreemptionYields
	"Answer whether the VM causes a process to yield on process preemption,
	 i.e. to put a preempted process at the back of its run queue.  If the parameter
	 is unavailable (non-Cog VMs) or bit 2 (4) is 0 then preemption yields."

	^(([self vmParameterAt: 48]
			on: Error
			do: [:ex| ^true]) allMask: 4) not! !

!SystemDictionary methodsFor: 'system attributes' stamp: 'eem 7/22/2010 17:26'!
processPreemptionYields: aBoolean
	"The Cog VM can be instructed not to yield on process preemption,
	 i.e. not to put a preempted process at the back of its run queue.  By
	 default preempting a process causes it to yield (Blue Book semantics)
	 which can have unfortunate effects.
	 This flag persists across snapshots, stored in the image header."

	self vmParameterAt: 48 put: ((self vmParameterAt: 48) bitClear: 4) + (aBoolean ifTrue: [0] ifFalse: [4])! !


!UndeclaredVariable methodsFor: 'as yet unclassified' stamp: 'eem 8/17/2010 16:35'!
openMenuIn: aBlock 
	| alternatives labels actions lines caption choice |
	alternatives := parser possibleVariablesFor: name.
	labels := OrderedCollection new.
	actions := OrderedCollection new.
	lines := OrderedCollection new.
	name first isLowercase 
		ifTrue: 
			[labels add: 'declare method temp'.
			actions add: [parser declareTemp: name at: #method].
			labels add: 'declare block-local temp'.
			actions add: [parser declareTemp: name at: #block].
			labels add: 'declare instance'.
			actions add: [parser declareInstVar: name]]
		ifFalse: 
			[labels add: 'define new class'.
			actions add: [parser defineClass: name].
			labels add: 'declare global'.
			actions add: [parser declareGlobal: name].
			parser canDeclareClassVariable 
				ifTrue: 
					[labels add: 'declare class variable'.
					actions add: [parser declareClassVar: name]]].
	lines add: labels size.
	alternatives do: 
		[:each | 
		labels add: each.
		actions add: [parser substituteVariable: each atInterval: interval]].
	lines add: labels size.
	labels add: 'cancel'.
	caption := 'Unknown variable: ' , name , ' please correct, or cancel:'.
	choice := aBlock value: labels value: lines value: caption.
	self resume: (actions at: choice ifAbsent: [nil])! !


!UndeclaredVariableWarning methodsFor: 'initialize-release' stamp: 'ar 2/13/2010 15:21'!
defaultResumeValue
	"Answer the value that by default should be returned if the exception is resumed"
	^true! !


!VariableNode methodsFor: 'testing' stamp: 'eem 8/13/2010 15:34'!
isUndeclared
	^false! !

!VariableNode methodsFor: 'tiles' stamp: 'jmv 8/28/2010 10:57'!
variableGetterBlockIn: aContext

	| temps idx ivars |
	"Do not call it index, it would be shadowed"
	(self type = 4 and: [self key isVariableBinding]) ifTrue: [
		^[self key value]
	].
	aContext ifNil: [^nil].
	self isSelfPseudoVariable ifTrue: [^[aContext receiver]].
	self type = 1 ifTrue: [
		ivars := aContext receiver class allInstVarNames.
		idx := ivars indexOf: self name ifAbsent: [^nil].
		^[aContext receiver instVarAt: idx]
	].
	self type = 2 ifTrue: [
		temps := aContext tempNames.
		idx := temps indexOf: self name ifAbsent: [^nil].
		^[aContext tempAt: idx]
	].
	^nil
! !


!LiteralVariableNode methodsFor: 'code generation' stamp: 'nice 7/23/2010 23:17'!
emitCodeForValue: stack encoder: encoder
	^readNode
		ifNil: [stack push: 1.
			encoder genPushLiteralVar: index]
		ifNotNil: [readNode emitCodeForValue: stack encoder: encoder]! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'nice 8/17/2010 22:26'!
sizeCodeForLoad: encoder
	self reserve: encoder.
	^(key isVariableBinding and: [key isSpecialWriteBinding])
		ifTrue: [encoder sizePushLiteral: index]
		ifFalse: [0]! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'nice 8/17/2010 22:27'!
sizeCodeForStore: encoder
	self reserve: encoder.
	(key isVariableBinding and: [key isSpecialWriteBinding]) ifFalse:
		[^encoder sizeStoreLiteralVar: index].
	code < 0 ifTrue:
		[self flag: #dubious.
		 self code: (self code: self index type: LdLitType)].
	"THIS IS WRONG!!!! THE VALUE IS LOST FROM THE STACK!!!!
	 The various value: methods on Association ReadOnlyVariableBinding
	 etc _do not_ return the value assigned; they return the receiver."
	"Should generate something more like
		push expr
		push lit
		push temp (index of expr)
		send value:
		pop"
	self flag: #bogus.
	writeNode := encoder encodeSelector: #value:.
	^writeNode sizeCode: encoder args: 1 super: false! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'nice 7/23/2010 23:58'!
sizeCodeForValue: encoder
	self reserve: encoder.
	(key isVariableBinding and: [key isSpecialReadBinding]) 
		ifFalse:
			[^encoder sizePushLiteralVar: index].
	readNode := MessageNode new 
		receiver: (encoder encodeLiteral: key)
		selector: (encoder encodeSelector: #value)
		arguments: #()
		precedence: #value precedence.
	^readNode sizeCodeForValue: encoder! !


!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 5/20/2008 18:07'!
isReferencedWithinBlockExtent: anInterval 
	readingScopes ~~ nil ifTrue:
		[readingScopes do:
			[:set "<Set of <Integer>>"|
			set do:
				[:location|
				 (anInterval rangeIncludes: location) ifTrue:
					[^true]]]].
	writingScopes ~~ nil ifTrue:
		[writingScopes do:
			[:set "<Set of <Integer>>"|
			set do:
				[:location|
				 (anInterval rangeIncludes: location) ifTrue:
					[^true]]]].
	^false! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 5/20/2008 18:01'!
referenceScopesAndIndicesDo: aBinaryBlock
	"Evaluate aBinaryBlock with all read or write scopes and locations.
	 This is used to copy the reference information into RemoteTempVectorNodes"
	readingScopes ~~ nil ifTrue:
		[readingScopes keysAndValuesDo:
			[:scopeBlock "<BlockNode>" :set "<Set of <Integer>>"|
			set do: [:location| aBinaryBlock value: scopeBlock value: location]]].
	writingScopes ~~ nil ifTrue:
		[writingScopes keysAndValuesDo:
			[:scopeBlock "<BlockNode>" :set "<Set of <Integer>>"|
			set do: [:location| aBinaryBlock value: scopeBlock value: location]]]! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 8/14/2010 11:02'!
isDeclaredAtMethodLevel
	"For the explainer."
	^scope = 0! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 16:22'!
emitCodeForLoad: stack encoder: encoder
	remoteNode ~~ nil ifTrue:
		[remoteNode emitCodeForLoadFor: self stack: stack encoder: encoder]! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 14:53'!
emitCodeForStore: stack encoder: encoder
	remoteNode ~~ nil ifTrue:
		[^remoteNode emitCodeForStoreInto: self stack: stack encoder: encoder].
	encoder genStoreTemp: index! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 14:54'!
emitCodeForStorePop: stack encoder: encoder
	remoteNode ~~ nil ifTrue:
		[^remoteNode emitCodeForStorePopInto: self stack: stack encoder: encoder].
	encoder genStorePopTemp: index.
	stack pop: 1! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 14:53'!
emitCodeForValue: stack encoder: encoder
	remoteNode ~~ nil ifTrue:
		[^remoteNode emitCodeForValueOf: self stack: stack encoder: encoder].
	encoder genPushTemp: index.
	stack push: 1! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 16:23'!
sizeCodeForLoad: encoder
	^remoteNode isNil
		ifTrue: [0]
		ifFalse: [remoteNode sizeCodeForLoadFor: self encoder: encoder]! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 14:52'!
sizeCodeForStore: encoder
	remoteNode ~~ nil ifTrue:
		[^remoteNode sizeCodeForStoreInto: self encoder: encoder].
	self reserve: encoder.
	^encoder sizeStoreTemp: index! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 14:52'!
sizeCodeForStorePop: encoder
	remoteNode ~~ nil ifTrue:
		[^remoteNode sizeCodeForStorePopInto: self encoder: encoder].
	self reserve: encoder.
	^encoder sizeStorePopTemp: index! !

!TempVariableNode methodsFor: 'code generation' stamp: 'eem 5/20/2008 14:51'!
sizeCodeForValue: encoder
	remoteNode ~~ nil ifTrue:
		[^remoteNode sizeCodeForValueOf: self encoder: encoder].
	self reserve: encoder.
	^encoder sizePushTemp: index! !


!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/29/2008 16:19'!
addRemoteTemp: aTempVariableNode encoder: encoder
	remoteTemps isNil ifTrue:
		[remoteTemps := OrderedCollection new].
	remoteTemps addLast: aTempVariableNode.
	aTempVariableNode referenceScopesAndIndicesDo:
		[:scopeBlock "<BlockNode>" :location "<Integer>"|
		 self addReadWithin: scopeBlock at: location].
	encoder supportsClosureOpcodes ifFalse:
		[encoder encodeLiteral: remoteTemps size.
		 readNode := encoder encodeSelector: #at:.
		 writeNode := encoder encodeSelector: #at:put:]! !

!RemoteTempVectorNode methodsFor: 'printing' stamp: 'eem 7/23/2008 21:21'!
printDefinitionForClosureAnalysisOn: aStream 
	| refs |
	aStream
		nextPut: ${;
		nextPutAll: key.
	definingScope ifNotNil: [definingScope blockExtent ifNotNil: [:be| aStream nextPutAll: ' d@'; print: be first]].
	readingScopes notNil ifTrue:
		[refs := Set new.
		readingScopes do: [:elems| refs addAll: elems].
		refs asSortedCollection do: [:read| aStream nextPutAll: ' r@'; print: read]].
	remoteTemps
		do: [:rt| rt printDefinitionForClosureAnalysisOn: aStream]
		separatedBy: [aStream nextPut: $,; space].
	aStream nextPut: $}! !


!UndeclaredVariableNode methodsFor: 'visiting' stamp: 'eem 8/13/2010 16:51'!
accept: aVisitor
	^aVisitor visitUndeclaredVariableNode: self! !

!UndeclaredVariableNode methodsFor: 'testing' stamp: 'eem 8/13/2010 15:34'!
isUndeclared
	^true! !

!UndeclaredVariableNode methodsFor: 'accessing' stamp: 'eem 8/17/2010 16:30'!
tag
	"Tag can be whatever one wants it to be; used by Parser to tag
	  undeclared temps with the user's desired declaration level."

	^tag! !

!UndeclaredVariableNode methodsFor: 'accessing' stamp: 'eem 8/17/2010 16:30'!
tag: anObject
	"Tag can be whatever one wants it to be; used by Parser to tag
	  undeclared temps with the user's desired declaration level."

	tag := anObject! !


!VariableScopeFinder methodsFor: 'private' stamp: 'eem 8/12/2010 16:50'!
enclosingNodeFor: enumerator of: rootNode
	"Answer the minimum enclosing root node for aVariabe or nil if none.
	 If the variable is accessed in more than one subnode then the rootNode is the
	 enclosing node, otherwise it is which ever single subnode node that includes it, if any.
	 enumerator applies its argument to all relevant subnodes of rootNode."
	| enclosingNodeOrNil |
	enclosingNodeOrNil := nil.
	enumerator value:
		[:subnode|
		(subnode accept: self) ifNotNil:
			[:enclosingNode|
			enclosingNodeOrNil := enclosingNodeOrNil
										ifNil: [enclosingNode]
										ifNotNil: [rootNode]]].
	^enclosingNodeOrNil! !

!VariableScopeFinder methodsFor: 'initialize-release' stamp: 'eem 8/12/2010 16:18'!
ofVariable: aVariableNode
	theVariable := aVariableNode! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 16:51'!
visitAssignmentNode: anAssignmentNode
	"Answer the minimum enclosing node for aVariabe or nil if none.
	 If the variable is accessed in more than one subexpression then anAssignmentNode
	 is the enclosing node, otherwise it is which ever single node that includes it, if any."
	^self
		enclosingNodeFor: [:aBlock|
							aBlock
								value: anAssignmentNode value;
								value: anAssignmentNode variable]
		of: anAssignmentNode! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 16:52'!
visitBlockNode: aBlockNode
	"Answer the minimum enclosing node for aVariabe or nil if none.
	 If the variable is accessed in more than one statement then aBlockNode is the
	 enclosing node, otherwise it is which ever single block node that includes it, if any."
	^(self enclosingNodeFor: [:aBlock| aBlockNode statements do: aBlock] of: aBlockNode) ifNotNil:
		[:aNode|
		aNode isBlockNode ifTrue: [aNode] ifFalse: [aBlockNode]]! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 16:52'!
visitBraceNode: aBraceNode
	"Answer the minimum enclosing node for aVariabe or nil if none.
	 If the variable is accessed in more than one subexpression then aBraceNode
	 is the enclosing node, otherwise it is which ever single node that includes it, if any."
	^self
		enclosingNodeFor: [:aBlock| aBraceNode elements do: aBlock]
		of: aBraceNode! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/16/2010 18:02'!
visitCascadeNode: aCascadeNode
	"Answer the minimum enclosing node for aVariabe or nil if none.
	 If the variable is accessed in more than one subexpression then aMessageNode is the
	 enclosing node, otherwise it is which ever single node that includes it, if any."
	^self
		enclosingNodeFor: [:aBlock|
							aBlock value: aCascadeNode receiver.
							aCascadeNode messages do:
								[:msg| msg argumentsInEvaluationOrder do: aBlock]]
		of: aCascadeNode! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitCommentNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitFieldNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 16:55'!
visitFutureNode: aFutureNode
	^aFutureNode receiver accept: self! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitInstanceVariableNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitLiteralNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 19:03'!
visitLiteralVariableNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 17:07'!
visitMessageNode: aMessageNode
	"Answer the minimum enclosing node for aVariabe or nil if none.
	 If the variable is accessed in more than one subexpression then aMessageNode is the
	 enclosing node, otherwise it is which ever single node that includes it, if any."
	^self
		enclosingNodeFor: [:aBlock|
							aBlock value: aMessageNode receiver.
							aMessageNode argumentsInEvaluationOrder do: aBlock]
		of: aMessageNode! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 17:00'!
visitMethodNode: aMethodNode
	^aMethodNode block accept: self! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitNewArrayNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitRemoteTempVectorNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 17:01'!
visitReturnNode: aReturnNode
	^aReturnNode expr accept: self! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitSelectorNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 18:43'!
visitTempVariableNode: aNode
	^nil! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/13/2010 16:50'!
visitUndeclaredVariableNode: aVariableNode
	^theVariable name = aVariableNode name ifTrue: [theVariable]! !

!VariableScopeFinder methodsFor: 'visiting' stamp: 'eem 8/12/2010 19:06'!
visitVariableNode: aVariableNode
	^nil! !

Parser removeSelector: #parseParameterNames:!
BytecodeAgnosticMethodNode removeSelector: #addLocalsToPool:!
BytecodeAgnosticMethodNode removeSelector: #blockExtentsToTempsMap!
BytecodeAgnosticMethodNode removeSelector: #ensureClosureAnalysisDone!
BytecodeAgnosticMethodNode removeSelector: #generate:!
BytecodeAgnosticMethodNode removeSelector: #hasGeneratedMethod!
BytecodeAgnosticMethodNode removeSelector: #locationCounter!
BytecodeAgnosticMethodNode removeSelector: #noteBlockEntry:!
BytecodeAgnosticMethodNode removeSelector: #noteBlockExit:!
BytecodeAgnosticMethodNode removeSelector: #printWithClosureAnalysisOn:!
BytecodeAgnosticMethodNode removeSelector: #referencedValuesWithinBlockExtent:!
BytecodeAgnosticMethodNode removeSelector: #schematicTempNamesString!
!classDefinition: #BytecodeAgnosticMethodNode category: #'Compiler-ParseNodes'!
MethodNode subclass: #BytecodeAgnosticMethodNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #MethodNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #MethodNode
	instanceVariableNames: 'selectorOrFalse precedence arguments block primitive encoder temporaries properties sourceText locationCounter localsPool'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
MessageNode initialize!
!classDefinition: #MessageNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #MessageNode
	instanceVariableNames: 'receiver selector precedence special arguments sizes equalNode caseErrorNode'
	classVariableNames: 'MacroEmitters MacroPrinters MacroSelectors MacroSizers MacroTransformers StdTypers ThenFlag'
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
BytecodeEncoder removeSelector: #methodNodeClass!
!classDefinition: #BlockNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #BlockNode
	instanceVariableNames: 'arguments statements returns nArgsNode size remoteCopyNode temporaries optimized optimizedMessageNode actualScopeIfOptimized blockExtent remoteTempNode copiedValues closureCreationNode startOfLastStatement tempsMark'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
CodeHolder removeSelector: #validateMessageSource:forSelector:!
Behavior removeSelector: #formalParametersAt:!
