'From Cuis 1.0 of 28 November 2009 [latest update: #337] on 7 December 2009 at 10:58:58 pm'!
!classDefinition: #ArrayLiteralTest category: #'Compiler-Tests'!
TestCase subclass: #ArrayLiteralTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!
!classDefinition: #BlockLocalTempCounter category: #'Compiler-Support'!
InstructionClient subclass: #BlockLocalTempCounter
	instanceVariableNames: 'stackPointer scanner blockEnd joinOffsets'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!

!BlockLocalTempCounter commentStamp: '<historical>' prior: 0!
I am a support class for the decompiler that is used to find the number of local temps in a block by finding out what the stack offset is at the end of a block.!

!classDefinition: #ClosureCompilerTest category: #'Compiler-Tests'!
TestCase subclass: #ClosureCompilerTest
	instanceVariableNames: ''
	classVariableNames: 'CmpRR CogRTLOpcodes Jump MoveCqR Nop'
	poolDictionaries: ''
	category: 'Compiler-Tests'!
!classDefinition: #ClosureTests category: #'Compiler-Tests'!
TestCase subclass: #ClosureTests
	instanceVariableNames: 'collection'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!
!classDefinition: #ColoredCodeStream category: #'Compiler-Kernel'!
TextStream subclass: #ColoredCodeStream
	instanceVariableNames: 'dialect colorTable'
	classVariableNames: 'ST80ColorTable'
	poolDictionaries: ''
	category: 'Compiler-Kernel'!
!classDefinition: #CompiledMethodWithNode category: #'Compiler-Support'!
Object subclass: #CompiledMethodWithNode
	instanceVariableNames: 'node method'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!
!classDefinition: #Compiler category: #'Compiler-Kernel'!
Object subclass: #Compiler
	instanceVariableNames: 'sourceStream requestor class category context parser'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!Compiler commentStamp: '<historical>' prior: 0!
The compiler accepts Smalltalk source code and compiles it with respect to a given class. The user of the compiler supplies a context so that temporary variables are accessible during compilation. If there is an error, a requestor (usually a kind of StringHolderController) is sent the message notify:at:in: so that the error message can be displayed. If there is no error, then the result of compilation is a MethodNode, which is the root of a parse tree whose nodes are kinds of ParseNodes. The parse tree can be sent messages to (1) generate code for a CompiledMethod (this is done for compiling methods or evaluating expressions); (2) pretty-print the code (for formatting); or (3) produce a map from object code back to source code (used by debugger program-counter selection). See also Parser, Encoder, ParseNode.!

!classDefinition: #CompilerExceptionsTest category: #'Compiler-Tests'!
TestCase subclass: #CompilerExceptionsTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!
!classDefinition: #CompilerTest category: #'Compiler-Tests'!
TestCase subclass: #CompilerTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!

!CompilerTest commentStamp: 'nice 12/3/2007 22:15' prior: 0!
CompilerTest is a holder for SUnit test of Compiler!

!classDefinition: #ContextCompilationTest category: #'Compiler-Tests'!
TestCase subclass: #ContextCompilationTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!
!classDefinition: #Decompiler category: #'Compiler-Kernel'!
InstructionStream subclass: #Decompiler
	instanceVariableNames: 'constructor method instVars tempVars constTable stack statements lastPc exit caseExits lastJumpPc lastReturnPc limit hasValue blockStackBase numLocalTemps blockStartsToTempVars tempVarCount'
	classVariableNames: 'ArgumentFlag CascadeFlag CaseFlag IfNilFlag'
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!Decompiler commentStamp: '<historical>' 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
	method
	instVars
	tempVars
	constTable
	stack
	statements
	lastPc
	exit
	caseExits	- stack of exit addresses that have been seen in the branches of caseOf:'s
	lastJumpPc
	lastReturnPc
	limit
	hasValue
	blockStackBase
	numLocaltemps - number of temps local to a block; also a flag indicating decompiling a block!

!classDefinition: #DecompilerTests category: #'Compiler-Tests'!
TestCase subclass: #DecompilerTests
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!

!DecompilerTests commentStamp: 'sd 9/26/2004 13:24' prior: 0!
Apparently the decompiler does not really work totally.
Here are a bunch of methods that can help improving the decompiler:
	- blockingClasses return class for which it is impossible to decompile methods 
	- failures are problems that lead to a DNU
	- decompilerDiscrepancies are the results of running decompileTestHelper..as you see the pattern 	
	is quite present.!

!classDefinition: #DecompilerTestFailuresCollector category: #'Compiler-Tests'!
DecompilerTests subclass: #DecompilerTestFailuresCollector
	instanceVariableNames: 'failures'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!

!DecompilerTestFailuresCollector commentStamp: '<historical>' prior: 0!
(| dtfc |
dtfc := DecompilerTestFailuresCollector new.
(dtfc class superclass organization listAtCategoryNamed: #tests) do:
	[:s| dtfc perform: s].
dtfc failures)

(Transcript nextPut: ${.
self do: [:mr| Transcript print: mr actualClass; nextPut: $.; space; store: mr methodSymbol; nextPut: $.; cr; flush].
Transcript nextPut: $}; flush)

eem 7/1/2009 16:13
{AdditionalMethodState. #keysAndValuesDo:.
AdditionalMethodState. #propertyKeysAndValuesDo:.
AdditionalMethodState. #at:ifAbsent:.
AdditionalMethodState. #removeKey:ifAbsent:.
AdditionalMethodState. #at:ifAbsentPut:.
AdditionalMethodState. #setMethod:.
AdditionalMethodState. #at:put:.
AdditionalMethodState. #pragmas.
AdditionalMethodState. #includesProperty:.
AdditionalMethodState. #properties.
AdditionalMethodState. #hasLiteralSuchThat:.
AdditionalMethodState. #propertyValueAt:ifAbsent:.
AdditionalMethodState. #hasLiteralThorough:.
Array. #hasLiteralSuchThat:.
BitBltSimulation. #initDither8Lookup.
BlockNode. #sizeCodeExceptLast:.
BlockNode. #emitCodeExceptLast:encoder:.
Categorizer. #changeFromCategorySpecs:.
Categorizer. #elementCategoryDict.
CColorPicker. #colors:.
CCustomDrawListCostume. #drawListOn:in:.
ChangeList. #browseCurrentVersionsOfSelections.
ClosureTests. #testToDoInsideTemp.
Cogit. #computeMaximumSizes.
Cogit. #outputInstructionsAt:.
Cogit. #generateMapAt:start:.
CogVMSimulator. #printFrameThing:at:.
CogVMSimulator. #str:n:cmp:.
CoInterpreter. #validStackPageBaseFrames.
CoInterpreter. #markAndTraceTraceLog.
CoInterpreter. #mapTraceLog.
CoInterpreter. #checkStackIntegrity.
CoInterpreter. #mapStackPages.
CoInterpreter. #updateStackZoneReferencesToCompiledCodePreCompaction.
CoInterpreter. #ceActivateFailingPrimitiveMethod:.
CoInterpreterStackPages. #initializeStack:numSlots:pageSize:stackLimitOffset:stackPageHeadroom:.
CompiledMethod. #=.
CompiledMethod. #getPreambleFrom:at:.
CompiledMethod. #hasLiteralThorough:.
CompiledMethod. #hasLiteralSuchThat:.
CPopUpMenuCostume. #drawMenu:on:in:.
CroquetParticipant. #dropFiles:.
CTextParagraph. #selectionRectsFrom:to:.
CWheelWidgetCostume. #drawOn:in:.
Dictionary. #scanFor:.
Float. #printPaddedWith:to:.
FMSound. #mixSampleCount:into:startingAt:leftVol:rightVol:.
Form. #transformColors:.
FTPClient. #getDataInto:.
GIFReadWriter. #nextImageWithPlugin.
GraphMorph. #drawDataOn:.
GZipReadStream. #on:from:to:.
HTTPServiceDispatcher. #errorReportFor:stack:on:.
HttpUrl. #checkAuthorization:retry:.
Integer. #benchSwitch:.
Interpreter. #primitiveClosureValueWithArgs.
Interpreter. #primitivePerformAt:.
Interpreter. #primitiveDoPrimitiveWithArgs.
Interpreter. #primitiveNewMethod.
InterpreterStackPages. #initializeStack:numSlots:pageSize:stackLimitOffset:stackPageHeadroom:.
JPEGReadWriter. #decodeBlockInto:component:dcTable:acTable:.
KeyedIdentitySet. #scanFor:.
KeyedSet. #scanFor:.
LargeIntegersPlugin. #isNormalized:.
LargeIntegersPlugin. #cBytesCopyFrom:to:len:.
LargeIntegersPlugin. #cDigitMultiply:len:with:len:into:.
LiteralDictionary. #scanFor:.
LoopedSampledSound. #mixSampleCount:into:startingAt:leftVol:rightVol:.
MethodDictionary. #scanFor:.
MP4BoxInfoParser. #parseMP4BoxOutput:.
MP4BoxNHMLTrack. #computeDTSDeltas.
MultiByteBinaryOrTextStream. #next:.
MultiByteFileStream. #next:.
MViewPane. #reconstructEnabledDocuments.
MViewPane. #reconstructOpenDocuments.
MViewPane. #reconstructSelectionList.
NewParagraph. #selectionRectsFrom:to:.
Object. #instanceFields.
OldSocket. #getResponseNoLF.
PasteUpMorph. #dropFiles:.
PlotMorphGrid. #bestStep:.
PluckedSound. #reset.
PluggableDictionary. #scanFor:.
PluggableSet. #scanFor:.
PluggableTabButtonMorph. #calculateArcLengths.
PluggableTabButtonMorph. #drawTabOn:.
PNGReadWriter. #copyPixelsGray:.
PNMReadWriter. #readPlainRGB.
PNMReadWriter. #readBWreverse:.
PNMReadWriter. #nextPutRGB:.
PNMReadWriter. #nextPutBW:reverse:.
PopUpMenu. #readKeyboard.
QFloorFan. #initialize.
QMinimalForum. #demoDesksUnused.
QNetVidReorderingBuffer. #popFramesForCTS:.
QNetVidTrackStreamer. #sampleIndexWithCTS:.
QServiceProvider. #statusReport.
QServicesPane. #forumMenuInto:.
QUserListItem. #drawOn:in:.
QVMProfiler. #computeHistograms:.
QVMProfiler. #selectSymbolsInRange.
QwaqParticipantUI. #onDropFiles:.
RelativeInstructionPrinter. #print:.
RemoteHandMorph. #appendNewDataToReceiveBuffer.
SchizophrenicClosureFormatStackInterpreter. #primitiveClosureValueWithArgs.
Set. #do:.
Set. #scanFor:.
SHParserST80. #isBinary.
ShootoutMall. #processVisitors.
ShortIntegerArray. #writeOn:.
SparseLargeArray. #analyzeSpaceSaving.
StackInterpreter. #validStackPageBaseFrames.
StackInterpreter. #divorceAllFrames.
StackInterpreter. #checkStackIntegrity.
StackInterpreter. #primitiveDoPrimitiveWithArgs.
StackInterpreter. #reverseDisplayFrom:to:.
StackInterpreter. #printOop:.
StackInterpreter. #mapStackPages.
StackInterpreter. #primitiveNewMethod.
StackInterpreter. #primitiveClosureValueWithArgs.
StrikeFontSet. #displayStringR2L:on:from:to:at:kern:.
String. #howManyMatch:.
Text. #asHtmlFragmentTextStyle:useBreaks:.
TextURL. #actOnClickFor:.
TFractalTerrain. #heightAt:.
TFractalTerrain. #makeFaces.
TFractalTerrain. #makeVertices.
TFractalTerrain. #makeTextureUV.
TFractalTerrain. #makeVertexNormals.
TFrame. #computeUnionSphere.
TMethod. #emitCCommentOn:.
TRFBStreamOutput. #handleRequest:.
TTCFontReader. #processCharacterMappingTable:.
TTContourConstruction. #segmentsDo:.
TTensor. #projectionIntegrate:.
TTFontReader. #processHorizontalMetricsTable:length:.
TTFontReader. #processCharacterMappingTable:.
TWaves. #step.
Vector. #copyFrom:.
Vector. #asVector3.
VectorColor. #copyFrom:.
WeakKeyDictionary. #scanForNil:.
WeakKeyDictionary. #scanFor:.
WeakSet. #scanFor:.
WeakSet. #scanForLoadedSymbol:.
}!

!classDefinition: #LiteralDictionary category: #'Compiler-Support'!
Dictionary subclass: #LiteralDictionary
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!

!LiteralDictionary commentStamp: '<historical>' prior: 0!
A LiteralDictionary, like an IdentityDictionary, has a special test for equality.  In this case it is simple equality between objects of like class.  This allows equal Float or String literals to be shared without the possibility of erroneously sharing, say, 1 and 1.0!

!classDefinition: #MirrorPrimitiveTests category: #'Compiler-Tests'!
TestCase subclass: #MirrorPrimitiveTests
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!
!classDefinition: #ParseNode category: #'Compiler-ParseNodes'!
Object subclass: #ParseNode
	instanceVariableNames: 'comment pc'
	classVariableNames: 'Bfp BtpLong CodeBases CodeLimits DblExtDoAll Dup EndMethod EndRemote Jmp JmpLimit JmpLong LdFalse LdInstLong LdInstType LdLitIndType LdLitType LdMinus1 LdNil LdSelf LdSuper LdTempType LdThisContext LdTrue LoadLong LongLongDoAll NodeFalse NodeNil NodeSelf NodeSuper NodeThisContext NodeTrue Pop Send SendLimit SendLong SendLong2 SendPlus SendType ShortStoP StdLiterals StdSelectors StdVariables Store StorePop'
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!ParseNode commentStamp: '<historical>' prior: 0!
This superclass of most compiler/decompiler classes declares common class variables, default messages, and the code emitters for jumps. Some of the class variables are initialized here; the rest are initialized in class VariableNode.!

!classDefinition: #AssignmentNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #AssignmentNode
	instanceVariableNames: 'variable value'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!AssignmentNode commentStamp: '<historical>' prior: 0!
AssignmentNode comment: 'I represent a (var_expr) construct.'!

!classDefinition: #BlockArgsNode category: #'Compiler-Syntax'!
ParseNode subclass: #BlockArgsNode
	instanceVariableNames: 'temporaries'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Syntax'!
!classDefinition: #BlockNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #BlockNode
	instanceVariableNames: 'arguments statements returns nArgsNode size remoteCopyNode temporaries optimized actualScopeIfOptimized blockExtent remoteTempNode copiedValues closureCreationNode startOfLastStatement'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!BlockNode commentStamp: '<historical>' prior: 0!
I represent a bracketed block with 0 or more arguments and 1 or more statements. If I am initialized with no statements, I create one. I have a flag to tell whether my last statement returns a value from the enclosing method. My last three fields remember data needed for code generation. I can emit for value in the usual way, in which case I create a literal method (actually a context remotely copied) to be evaluated by sending it value: at run time. Or I can emit code to be evaluated in line; this only happens at the top level of a method and in conditionals and while-loops, none of which have arguments.!

!classDefinition: #BraceNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #BraceNode
	instanceVariableNames: 'elements sourceLocations emitNode'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!BraceNode commentStamp: '<historical>' prior: 0!
Used for compiling and decompiling brace constructs.

These now compile into either a fast short form for 4 elements or less:
	Array braceWith: a with: b ... 
or a long form of indefinfite length:
	(Array braceStream: N) nextPut: a; nextPut: b; ...; braceArray.

The erstwhile brace assignment form is no longer supported.!

!classDefinition: #CascadeNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #CascadeNode
	instanceVariableNames: 'receiver messages'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!CascadeNode commentStamp: '<historical>' prior: 0!
The first message has the common receiver, the rest have receiver == nil, which signifies cascading.!

!classDefinition: #CommentNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #CommentNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #DecompilerConstructor category: #'Compiler-Support'!
ParseNode subclass: #DecompilerConstructor
	instanceVariableNames: 'method instVars nArgs literalValues tempVars'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!

!DecompilerConstructor commentStamp: '<historical>' prior: 0!
I construct the node tree for a Decompiler.!

!classDefinition: #DecompilerConstructorForClosures category: #'Compiler-Support'!
DecompilerConstructor subclass: #DecompilerConstructorForClosures
	instanceVariableNames: 'tempNameCounter'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!
!classDefinition: #Encoder category: #'Compiler-Kernel'!
ParseNode subclass: #Encoder
	instanceVariableNames: 'scopeTable nTemps supered requestor class selector literalStream selectorSet litIndSet litSet sourceRanges globalSourceRanges addedSelectorAndMethodClassLiterals'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!Encoder commentStamp: '<historical>' prior: 0!
I encode names and literals into tree nodes with byte codes for the compiler. Byte codes for literals are not assigned until the tree-sizing pass of the compiler, because only then is it known which literals are actually needed. I also keep track of sourceCode ranges during parsing and code generation so I can provide an inverse map for the debugger.!

!classDefinition: #BytecodeEncoder category: #'Compiler-Kernel'!
Encoder subclass: #BytecodeEncoder
	instanceVariableNames: 'stream position rootNode blockExtentsToLocals'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!BytecodeEncoder commentStamp: '<historical>' prior: 0!
I am an abstract superclass for different bytecode set encoders.  Subclasses inherit the literal management of Encoder and encapsulate the mapping of opcodes to specific bytecodes.!

!classDefinition: #EncoderForLongFormV3 category: #'Compiler-Kernel'!
BytecodeEncoder subclass: #EncoderForLongFormV3
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!EncoderForLongFormV3 commentStamp: '<historical>' prior: 0!
I am an alternate to EncoderForV3 that tries to use thje longest forms of bytecodes possible so as to avoid using as many bytecode as possible to allow for the unused portions of the bytecode set this makes available to be reassigned.



I do not use the following ranges

0 through 111

	   0- 15 	0000iiii 	Push Receiver Variable #iiii

	  16- 31 	0001iiii 	Push Temporary Location #iiii

	  32- 63 	001iiiii 		Push Literal Constant #iiiii

	  64- 95 	010iiiii 		Push Literal Variable #iiiii

	  96-103 	01100iii 	Pop and Store Receiver Variable #iii

	104-111 	01101iii 	Pop and Store Temporary Location #iii

138-159

	138-143 				Unused.

	144-151 	10010iii 	Jump iii + 1 (i.e., 1 through 8).

	152-159 	10011iii 	Pop and Jump 0n False iii +1 (i.e., 1 through 8).

176-255

	176-191 	1011iiii 	Send Arithmetic Message #iiii

	192-207 	1100iiii 	Send Special Message #iiii

	208-223 	1101iiii 	Send Literal Selector #iiii With No Arguments

	224-239 	1110iiii 	Send Literal Selector #iiii With 1 Argument

	240-255 	1111iiii 	Send Literal Selector #iiii With 2 Arguments

= 112 + (160 - 138) + (256 - 176) =  214, or 84% of the bytecodes!

!classDefinition: #EncoderForLongFormV3PlusClosures category: #'Compiler-Kernel'!
EncoderForLongFormV3 subclass: #EncoderForLongFormV3PlusClosures
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!EncoderForLongFormV3PlusClosures commentStamp: '<historical>' prior: 0!
An encoder for the V3 bytecode set augmented with the following bytecodes that are part of the full closure implementation.
	138   10001010 jkkkkkkk		Push (Array new: kkkkkkk) (j = 0)
								or	Pop kkkkkkk elements into: (Array new: kkkkkkk) (j = 1)

	140   10001100 kkkkkkkk jjjjjjjj 	Push Temp At kkkkkkkk In Temp Vector At: jjjjjjjj
	141   10001101 kkkkkkkk jjjjjjjj 	Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj
	142   10001110 kkkkkkkk jjjjjjjj 	Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj
	143   10001111 llllkkkk jjjjjjjj iiiiiiii	Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii
This is an exact duplicate of EncoderForV3PlusClosures.
Could be a trait (or in Newspeak, a Mixin).
For now we impose upon you to synchronise any and all changes between these two classes.!

!classDefinition: #EncoderForV3 category: #'Compiler-Kernel'!
BytecodeEncoder subclass: #EncoderForV3
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!EncoderForV3 commentStamp: '<historical>' prior: 0!
I add behaviour to Encoder to size and emit bytecodes for the Squeak V3.x VM bytecode set.  The intention is for another subclass to restrict the range of bytecodes used to long forms only, allowing the bytecode set to be redefined by avoiding using the many short forms.  The short forms may then be reassigned.!

!classDefinition: #EncoderForV3PlusClosures category: #'Compiler-Kernel'!
EncoderForV3 subclass: #EncoderForV3PlusClosures
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!EncoderForV3PlusClosures commentStamp: '<historical>' prior: 0!
An encoder for the V3 bytecode set augmented with the following bytecodes that are part of the full closure implementation.
	138   10001010 jkkkkkkk		Push (Array new: kkkkkkk) (j = 0)
								or	Pop kkkkkkk elements into: (Array new: kkkkkkk) (j = 1)

	140   10001100 kkkkkkkk jjjjjjjj 	Push Temp At kkkkkkkk In Temp Vector At: jjjjjjjj
	141   10001101 kkkkkkkk jjjjjjjj 	Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj
	142   10001110 kkkkkkkk jjjjjjjj 	Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj
	143   10001111 llllkkkk jjjjjjjj iiiiiiii	Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii
This is an exact duplicate of EncoderForLongFormV3PlusClosures.
Could be a trait (or in Newspeak, a Mixin).
For now we impose upon you to synchronise any and all changes between these two classes.!

!classDefinition: #LeafNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #LeafNode
	instanceVariableNames: 'key code index'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!LeafNode commentStamp: '<historical>' prior: 0!
I represent a leaf node of the compiler parse tree. I am abstract.
	
Types (defined in class ParseNode):
	1 LdInstType (which uses class VariableNode)
	2 LdTempType (which uses class VariableNode)
	3 LdLitType (which uses class LiteralNode)
	4 LdLitIndType (which uses class VariableNode)
	5 SendType (which uses class SelectorNode).

Note that Squeak departs slightly from the Blue Book bytecode spec.

In order to allow access to more than 63 literals and instance variables,
bytecode 132 has been redefined as DoubleExtendedDoAnything:
		byte2				byte3			Operation
(hi 3 bits)  (lo 5 bits)
	0		nargs			lit index			Send Literal Message 0-255
	1		nargs			lit index			Super-Send Lit Msg 0-255
	2		ignored			rcvr index		Push Receiver Variable 0-255
	3		ignored			lit index			Push Literal Constant 0-255
	4		ignored			lit index			Push Literal Variable 0-255
	5		ignored			rcvr index		Store Receiver Variable 0-255
	6		ignored			rcvr index		Store-pop Receiver Variable 0-255
	7		ignored			lit index			Store Literal Variable 0-255

	This has allowed bytecode 134 also to be redefined as a second extended send
	that can access literals up to 64 for nargs up to 3 without needing three bytes.
	It is just like 131, except that the extension byte is aallllll instead of aaalllll,
	where aaa are bits of argument count, and lll are bits of literal index.!

!classDefinition: #LiteralNode category: #'Compiler-ParseNodes'!
LeafNode subclass: #LiteralNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!LiteralNode commentStamp: '<historical>' prior: 0!
I am a parse tree leaf representing a literal string or number.!

!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'!

!MessageNode commentStamp: '<historical>' prior: 0!
I represent a receiver and its message.
	
Precedence codes:
	1 unary
	2 binary
	3 keyword
	4 other
	
If special>0, I compile special code in-line instead of sending messages with literal methods as remotely copied contexts.!

!classDefinition: #MessageAsTempNode category: #'Compiler-ParseNodes'!
MessageNode subclass: #MessageAsTempNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!MessageAsTempNode commentStamp: '<historical>' prior: 0!
This node represents accesses to temporary variables for do-its in the debugger.  Since they execute in another context, they must send a message to the original context to access the value of the temporary variable in that context.!

!classDefinition: #MethodNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #MethodNode
	instanceVariableNames: 'selectorOrFalse precedence arguments block primitive encoder temporaries properties sourceText'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!MethodNode commentStamp: '<historical>' prior: 0!
I am the root of the parse tree.!

!classDefinition: #BytecodeAgnosticMethodNode category: #'Compiler-ParseNodes'!
MethodNode subclass: #BytecodeAgnosticMethodNode
	instanceVariableNames: 'locationCounter localsPool'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!BytecodeAgnosticMethodNode commentStamp: '<historical>' prior: 0!
I am a version of MethodNode that is able to work with different BytecodeEncoders, and is hence able to generate methods using different bytecode sets.!

!classDefinition: #MethodTempsNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #MethodTempsNode
	instanceVariableNames: 'temporaries'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #NewArrayNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #NewArrayNode
	instanceVariableNames: 'numElements'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!NewArrayNode commentStamp: '<historical>' prior: 0!
I represent a node for the genPushNewArray: opcode.!

!classDefinition: #ParseNodeVisitor category: #'Compiler-Support'!
Object subclass: #ParseNodeVisitor
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!

!ParseNodeVisitor commentStamp: '<historical>' prior: 0!
I am an abstract superclass for ParseNode visitors that functions as a null visitor.  Here's the code that defines my interface:

(SystemNavigation default allImplementorsOf: #accept: localTo: ParseNode) do:
	[:methodReference|
	methodReference compiledMethod messages do:
		[:sel|
		((sel beginsWith: 'visit')
		and: [sel numArgs = 1]) ifTrue:
			[ParseNodeVisitor
				compile: (String streamContents:
							[:str|
							str nextPutAll: sel;
								space;
								nextPut: $a.
							methodReference classSymbol first isVowel ifTrue:
								[str nextPut: $n].
							str nextPutAll: methodReference classSymbol])
				classified: 'visiting']]]!

!classDefinition: #ParseNodeEnumerator category: #'Compiler-Support'!
ParseNodeVisitor subclass: #ParseNodeEnumerator
	instanceVariableNames: 'theBlock'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!

!ParseNodeEnumerator commentStamp: '<historical>' prior: 0!
self superclass selectors do:
	[:s|
	self compile: (String streamContents:
		[:str| | arg |
		arg := 'a', (s allButFirst: 5) allButLast.
		str nextPutAll: s, ' ', arg; crtab;
			nextPutAll: 'theBlock value: '; nextPutAll: arg; nextPut: $.; crtab;
			nextPutAll: '^super '; nextPutAll: s, ' ', arg])]!

!classDefinition: #ParseStack category: #'Compiler-Support'!
Object subclass: #ParseStack
	instanceVariableNames: 'position length'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!

!ParseStack commentStamp: '<historical>' prior: 0!
I keep track of the current and high position of the stack that will be needed by code being compiled.!

!classDefinition: #ParserNotification category: #'Compiler-Exceptions'!
Notification subclass: #ParserNotification
	instanceVariableNames: 'name'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Exceptions'!
!classDefinition: #ReparseAfterSourceEditing category: #'Compiler-Support'!
Notification subclass: #ReparseAfterSourceEditing
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!
!classDefinition: #ReturnNode category: #'Compiler-ParseNodes'!
ParseNode subclass: #ReturnNode
	instanceVariableNames: 'expr'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!ReturnNode commentStamp: '<historical>' prior: 0!
I represent an expression of the form ^expr.!

!classDefinition: #Scanner category: #'Compiler-Kernel'!
Object subclass: #Scanner
	instanceVariableNames: 'source mark hereChar aheadChar token tokenType currentComment buffer typeTable'
	classVariableNames: 'TypeTable'
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!Scanner commentStamp: '<historical>' prior: 0!
I scan a string or text, picking out Smalltalk syntactic tokens. I look one character ahead. I put each token found into the instance variable, token, and its type (a Symbol) into the variable, tokenType. At the end of the input stream, I pretend to see an endless sequence of special characters called doits.!

!classDefinition: #Parser category: #'Compiler-Kernel'!
Scanner subclass: #Parser
	instanceVariableNames: 'here hereType hereMark hereEnd prevMark prevEnd encoder requestor parseNode failBlock requestorOffset tempsMark doitFlag properties category'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Kernel'!

!Parser commentStamp: '<historical>' prior: 0!
I parse Smalltalk syntax and create a MethodNode that is the root of the parse tree. I look one token ahead.!

!classDefinition: #ScannerTest category: #'Compiler-Tests'!
TestCase subclass: #ScannerTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Tests'!
!classDefinition: #SelectorNode category: #'Compiler-ParseNodes'!
LeafNode subclass: #SelectorNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!SelectorNode commentStamp: '<historical>' prior: 0!
I am a parse tree leaf representing a selector.!

!classDefinition: #KeyWordNode category: #'Compiler-Syntax'!
SelectorNode subclass: #KeyWordNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Syntax'!

!KeyWordNode commentStamp: '<historical>' prior: 0!
I am a part of a selector.   #at:put: is owned by a SelectorNode, and #put: within it is owned by a KeyWordNode.!

!classDefinition: #UndeclaredVariable category: #'Compiler-Exceptions'!
ParserNotification subclass: #UndeclaredVariable
	instanceVariableNames: 'parser interval'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Exceptions'!
!classDefinition: #UndeclaredVariableReference category: #'Compiler-Support'!
Notification subclass: #UndeclaredVariableReference
	instanceVariableNames: 'parser varName varStart varEnd'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!
!classDefinition: #UndeclaredVariableWarning category: #'Compiler-Support'!
Warning subclass: #UndeclaredVariableWarning
	instanceVariableNames: 'name selector class'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Support'!
!classDefinition: #UndefinedVariable category: #'Compiler-Exceptions'!
ParserNotification subclass: #UndefinedVariable
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Exceptions'!
!classDefinition: #UnknownSelector category: #'Compiler-Exceptions'!
ParserNotification subclass: #UnknownSelector
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Exceptions'!
!classDefinition: #UnusedVariable category: #'Compiler-Exceptions'!
ParserNotification subclass: #UnusedVariable
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-Exceptions'!
!classDefinition: #VariableNode category: #'Compiler-ParseNodes'!
LeafNode subclass: #VariableNode
	instanceVariableNames: 'name'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!VariableNode commentStamp: '<historical>' prior: 0!
I am a parse tree leaf representing a variable. Note that my name and key are different for pool variables: the key is the Object Reference.!

!classDefinition: #FieldNode category: #'Compiler-ParseNodes'!
VariableNode subclass: #FieldNode
	instanceVariableNames: 'fieldDef rcvrNode readNode writeNode'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!FieldNode commentStamp: '<historical>' prior: 0!
FileNode handles field access in Tweak, e.g. self fieldName := foo => self fieldName: foo.!

!classDefinition: #InstanceVariableNode category: #'Compiler-ParseNodes'!
VariableNode subclass: #InstanceVariableNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #LiteralVariableNode category: #'Compiler-ParseNodes'!
VariableNode subclass: #LiteralVariableNode
	instanceVariableNames: 'readNode writeNode'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!
!classDefinition: #MaybeContextInstanceVariableNode category: #'Compiler-ParseNodes'!
InstanceVariableNode subclass: #MaybeContextInstanceVariableNode
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!MaybeContextInstanceVariableNode commentStamp: '<historical>' prior: 0!
This class conspires to arrange that inst var access for contexts is done exclusively using the long-form instance variabl;e access bytecodes.  See InstructionStream class>>variablesAndOffsetsDo:.

A virtual machine can benefit in performance by organizing method and block activations using a  more conventional stack organization than by using first-class activation records (contexts).  But such a virtual machine is also cabable of hiding the stack and making it appear as if contexts are still used.  This means the system has better performance but still has all the benefits of first-class activation records.  To pull this off the VM needs to intercept any and all accesses to context objects so that it can make contexts function as proxy objects for stack frames.

Without help from the image such a virtual machine based on an interpreter would have to perform an expensive check on all instance variable accesses to determine if the instance variable was that of a context serving as a proxy for a stack frame.  A simple hack is to take advantage of the short and long forms of instance variable access bytecodes.  The BlueBook instruction set (and likely any bytecode set evolved from it) has short form bytecodes for fetching and storing the first few bytecodes (BlueBook fetch first 16, store first 8).  Contexts typically have at most 6 instance variables.  If we arrange to use the long-form bytecodes for all context inst var accesses then we only have to check for context inst var access in long-form bytecodes, and then only if the index is within the context inst var range.  This effectively makes the check free because on modern processors checking an index fetched from memory into a register against a constant costs far less than the memry read to fetch the index.!

!classDefinition: #TempVariableNode category: #'Compiler-ParseNodes'!
VariableNode subclass: #TempVariableNode
	instanceVariableNames: 'argType hasRefs hasDefs scope definingScope readingScopes writingScopes remoteNode'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!TempVariableNode commentStamp: '<historical>' prior: 0!
I am a parse tree leaf representing a temporary variable!

!classDefinition: #RemoteTempVectorNode category: #'Compiler-ParseNodes'!
TempVariableNode subclass: #RemoteTempVectorNode
	instanceVariableNames: 'remoteTemps readNode writeNode'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Compiler-ParseNodes'!

!RemoteTempVectorNode commentStamp: '<historical>' prior: 0!
I am a node for a vector of remote temps, created to share temps between closures when those temps are written to in closures other than their defining ones.!


!ArrayLiteralTest methodsFor: 'initialize-release' stamp: 'avi 2/16/2004 21:09'!
tearDown
	self class removeSelector: #array! !

!ArrayLiteralTest methodsFor: 'tests' stamp: 'avi 2/16/2004 21:08'!
testReservedIdentifiers
	self class compile: 'array ^ #(nil true false)'.
	self assert: self array = {nil. true. false}.! !

!ArrayLiteralTest methodsFor: 'tests' stamp: 'avi 2/16/2004 21:09'!
testSymbols
	self class compile: 'array ^ #(#nil #true #false #''nil'' #''true'' #''false'')'.
	self assert: self array = {#nil. #true. #false. #nil. #true. #false}.! !


!BlockClosure methodsFor: 'evaluating' stamp: 'jmv 12/7/2009 22:37'!
timeToRunWithoutGC
	"Answer the number of milliseconds taken to execute this block without GC time."

	^(Smalltalk vmParameterAt: 8) + 
		(Smalltalk vmParameterAt: 10) +
		self timeToRun -
		(Smalltalk vmParameterAt: 8) - 
		(Smalltalk vmParameterAt: 10)
! !


!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/26/2008 11:36'!
blockReturnTop
	"Return Top Of Stack bytecode."
	stackPointer := stackPointer - 1.
	scanner pc < blockEnd ifTrue:
		[self doJoin]! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:13'!
doDup
	"Duplicate Top Of Stack bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:17'!
doPop
	"Remove Top Of Stack bytecode."
	stackPointer := stackPointer - 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/26/2008 13:40'!
jump: offset
	"Unconditional Jump bytecode."
	offset > 0 ifTrue:
		[joinOffsets at: scanner pc + offset put: stackPointer.
		 self doJoin]! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/26/2008 13:40'!
jump: offset if: condition 
	"Conditional Jump bytecode."
	stackPointer := stackPointer - 1.
	offset > 0 ifTrue:
		[joinOffsets at: scanner pc + offset put: stackPointer]! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/26/2008 11:36'!
methodReturnConstant: value 
	"Return Constant bytecode."
	self doJoin! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/26/2008 11:36'!
methodReturnReceiver
	"Return Self bytecode."
	self doJoin! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/26/2008 11:36'!
methodReturnTop
	"Return Top Of Stack bytecode."
	stackPointer := stackPointer - 1.
	self doJoin! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:19'!
popIntoLiteralVariable: anAssociation 
	"Remove Top Of Stack And Store Into Literal Variable bytecode."
	stackPointer := stackPointer - 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:19'!
popIntoReceiverVariable: offset 
	"Remove Top Of Stack And Store Into Instance Variable bytecode."
	stackPointer := stackPointer - 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:19'!
popIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
	"Remove Top Of Stack And Store Into Offset of Temp Vector bytecode."
	stackPointer := stackPointer - 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:20'!
popIntoTemporaryVariable: offset 
	"Remove Top Of Stack And Store Into Temporary Variable bytecode."
	stackPointer := stackPointer - 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:20'!
pushActiveContext
	"Push Active Context On Top Of Its Own Stack bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:16'!
pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
	"Push Closure bytecode.  Either compute the end of the block if this is
	 the block we're analysing, or skip it, adjusting the stack as appropriate."
	blockEnd
		ifNil: [blockEnd := scanner pc + blockSize]
		ifNotNil:
			[stackPointer := stackPointer - numCopied + 1.
			 scanner pc: scanner pc + blockSize]! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:21'!
pushConsArrayWithElements: numElements
	"Push Cons Array of size numElements popping numElements items from the stack into the array bytecode."
	stackPointer := stackPointer - numElements + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:21'!
pushConstant: value
	"Push Constant, value, on Top Of Stack bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:22'!
pushLiteralVariable: anAssociation
	"Push Contents Of anAssociation On Top Of Stack bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:22'!
pushNewArrayOfSize: numElements 
	"Push New Array of size numElements bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:22'!
pushReceiver
	"Push Active Context's Receiver on Top Of Stack bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:23'!
pushReceiverVariable: offset
	"Push Contents Of the Receiver's Instance Variable Whose Index 
	is the argument, offset, On Top Of Stack bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:23'!
pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
	"Push Contents at Offset in Temp Vector bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:23'!
pushTemporaryVariable: offset
	"Push Contents Of Temporary Variable Whose Index Is the 
	argument, offset, On Top Of Stack bytecode."
	stackPointer := stackPointer + 1! !

!BlockLocalTempCounter methodsFor: 'instruction decoding' stamp: 'eem 9/23/2008 16:24'!
send: selector super: supered numArgs: numberArguments
	"Send Message With Selector, selector, bytecode. The argument, 
	supered, indicates whether the receiver of the message is specified with 
	'super' in the source method. The arguments of the message are found in 
	the top numArguments locations on the stack and the receiver just 
	below them."

	stackPointer := stackPointer - numberArguments! !

!BlockLocalTempCounter methodsFor: 'private' stamp: 'eem 9/26/2008 13:40'!
doJoin
	scanner pc < blockEnd ifTrue:
		[stackPointer := joinOffsets at: scanner pc]! !

!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! !


!BlockLocalTempCounter class methodsFor: 'instance creation' stamp: 'eem 9/23/2008 16:07'!
tempCountForBlockAt: pc in: method
	^self new tempCountForBlockAt: pc in: method! !


!ClosureCompilerTest methodsFor: 'source' stamp: 'eem 7/1/2009 10:51'!
closureCases
	^#(
'| n |
n := 1.
^n + n'

'| i |
i := 0.
[i := i + 1.
 i <= 10] whileTrue.
^i'

'[:c :s| | mn |
mn := Compiler new
		compile: (c sourceCodeAt: s)
		in: c
		notifying: nil
		ifFail: [self halt].
mn generate: #(0 0 0 0).
{mn blockExtentsToTempsMap.
  mn encoder schematicTempNames}]
			value: AbstractInstructionTests
			value: #runBinaryConditionalJumps:'

'inject: thisValue into: binaryBlock
	| nextValue |
	nextValue := thisValue.
	self do: [:each | nextValue := binaryBlock value: nextValue value: each].
	^nextValue'

'runBinaryConditionalJumps: assertPrintBar
	"CogIA32CompilerTests new runBinaryConditionalJumps: false"
	| mask reg1 reg2 reg3 |
	mask := 1 << self processor bitsInWord - 1.
	self concreteCompilerClass dataRegistersWithAccessorsDo:
		[:n :get :set|
		n = 0 ifTrue: [reg1 := get].
		n = 1 ifTrue: [reg2 := set].
		n = 2 ifTrue: [reg3 := set]].
	#(	(JumpAbove > unsigned)			(JumpBelowOrEqual <= unsigned)
		(JumpBelow < unsigned)			(JumpAboveOrEqual >= unsigned)
		(JumpGreater > signed)			(JumpLessOrEqual <= signed)
		(JumpLess < signed)				(JumpGreaterOrEqual >= signed)
		(JumpZero = signed)				(JumpNonZero ~= signed)) do:
		[:triple|
		[:opName :relation :signednessOrResult| | opcode jumpNotTaken jumpTaken nop memory bogus |
		self resetGen.
		opcode := CogRTLOpcodes classPool at: opName.
		self gen: CmpRR operand: 2 operand: 1.
		jumpTaken := self gen: opcode.
		self gen: MoveCqR operand: 0 operand: 0.
		jumpNotTaken := self gen: Jump.
		jumpTaken jmpTarget: (self gen: MoveCqR operand: 1 operand: 0).
		jumpNotTaken jmpTarget: (nop := self gen: Nop).
		memory := self generateInstructions.
		bogus := false.
		self pairs: (-2 to: 2)  do:
			[:a :b| | taken |
			self processor
				reset;
				perform: reg2 with: a signedIntToLong;
				perform: reg3 with: b signedIntToLong.
			[self processor singleStepIn: memory.
			 self processor pc ~= nop address] whileTrue.
			taken := (self processor perform: reg1) = 1.
			assertPrintBar
				ifTrue:
					[self assert: taken = (signednessOrResult == #unsigned
											ifTrue: [(a bitAnd: mask) perform: relation with: (b bitAnd: mask)]
											ifFalse: [a perform: relation with: b])]
				ifFalse:
					[Transcript
						nextPutAll: reg2; nextPut: $(; print: a; nextPutAll: '') ''; nextPutAll: relation; space;
						nextPutAll: reg3; nextPut: $(; print: b; nextPutAll: '') = '';
						print: taken; cr; flush.
					 taken = (signednessOrResult == #unsigned
											ifTrue: [(a bitAnd: mask) perform: relation with: (b bitAnd: mask)]
											ifFalse: [a perform: relation with: b]) ifFalse:
						[bogus := true]]].
			 bogus ifTrue:
				[self processor printRegistersOn: Transcript.
				 Transcript show: (self processor disassembleInstructionAt: jumpTaken address In: memory); cr]]
					valueWithArguments: triple]'

'mapFromBlockStartsIn: aMethod toTempVarsFrom: schematicTempNamesString constructor: aDecompilerConstructor
	| map |
	map := aMethod
				mapFromBlockKeys: aMethod startpcsToBlockExtents keys asSortedCollection
				toSchematicTemps: schematicTempNamesString.
	map keysAndValuesDo:
		[:startpc :tempNameTupleVector| | subMap tempVector numTemps |
		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'

 'gnuifyFrom: inFileStream to: outFileStream

"convert interp.c to use GNU features"

	| inData beforeInterpret inInterpret inInterpretVars beforePrimitiveResponse inPrimitiveResponse |

	inData := inFileStream upToEnd withSqueakLineEndings.
	inFileStream close.

	"print a header"
	outFileStream
		nextPutAll: ''/* This file has been post-processed for GNU C */'';
		cr; cr; cr.

	beforeInterpret := true.    "whether we are before the beginning of interpret()"
	inInterpret := false.     "whether we are in the middle of interpret"
	inInterpretVars := false.    "whether we are in the variables of interpret"
	beforePrimitiveResponse := true.  "whether we are before the beginning of primitiveResponse()"
	inPrimitiveResponse := false.   "whether we are inside of primitiveResponse"
	''Gnuifying''
		displayProgressAt: Sensor cursorPoint
		from: 1 to: (inData occurrencesOf: Character cr)
		during:
			[:bar | | lineNumber |
			lineNumber := 0.
			inData linesDo:
				[ :inLine | | outLine extraOutLine caseLabel |
				bar value: (lineNumber := lineNumber + 1).
				outLine := inLine. 	"print out one line for each input line; by default, print out the line that was input, but some rules modify it"
				extraOutLine := nil.   "occasionally print a second output line..."
				beforeInterpret ifTrue: [
					inLine = ''#include "sq.h"'' ifTrue: [
						outLine := ''#include "sqGnu.h"'' ].
					inLine = ''interpret(void) {'' ifTrue: [
						"reached the beginning of interpret"
						beforeInterpret := false.
						inInterpret := true.
						inInterpretVars := true ] ]
				ifFalse: [
				inInterpretVars ifTrue: [
					(inLine findString: ''register struct foo * foo = &fum;'') > 0 ifTrue: [
						outLine := ''register struct foo * foo FOO_REG = &fum;'' ].
					(inLine findString: '' localIP;'') > 0 ifTrue: [
						outLine := ''    char* localIP IP_REG;'' ].
					(inLine findString: '' localFP;'') > 0 ifTrue: [
						outLine := ''    char* localFP FP_REG;'' ].
					(inLine findString: '' localSP;'') > 0 ifTrue: [
						outLine := ''    char* localSP SP_REG;'' ].
					(inLine findString: '' currentBytecode;'') > 0 ifTrue: [
						outLine := ''    sqInt currentBytecode CB_REG;'' ].
					inLine isEmpty ifTrue: [
						"reached end of variables"
						inInterpretVars := false.
						outLine := ''    JUMP_TABLE;''.
						extraOutLine := inLine ] ]
				ifFalse: [
				inInterpret ifTrue: [
					"working inside interpret(); translate the switch statement"
					(inLine beginsWith: ''		case '') ifTrue: [
						caseLabel := (inLine findTokens: ''	 :'') second.
						outLine := ''		CASE('', caseLabel, '')'' ].
					inLine = ''			break;'' ifTrue: [
						outLine := ''			BREAK;'' ].
					inLine = ''}'' ifTrue: [
						"all finished with interpret()"
						inInterpret := false ] ]
				ifFalse: [
				beforePrimitiveResponse ifTrue: [
					(inLine beginsWith: ''primitiveResponse('') ifTrue: [
						"into primitiveResponse we go"
						beforePrimitiveResponse := false.
						inPrimitiveResponse := true.
						extraOutLine := ''    PRIM_TABLE;'' ] ]
				ifFalse: [
				inPrimitiveResponse ifTrue: [
					inLine = ''	switch (primitiveIndex) {'' ifTrue: [
						extraOutLine := outLine.
						outLine := ''	PRIM_DISPATCH;'' ].
					inLine = ''	switch (GIV(primitiveIndex)) {'' ifTrue: [
						extraOutLine := outLine.
						outLine := ''	PRIM_DISPATCH;'' ].
					(inLine beginsWith: ''	case '') ifTrue: [
						caseLabel := (inLine findTokens: ''	 :'') second.
						outLine := ''	CASE('', caseLabel, '')'' ].
					inLine = ''}'' ifTrue: [
						inPrimitiveResponse := false ] ]
				] ] ] ].

				outFileStream nextPutAll: outLine; cr.
				extraOutLine ifNotNil: [
					outFileStream nextPutAll: extraOutLine; cr ]]].

	outFileStream close' )! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/24/2008 12:28'!
doTestDebuggerTempAccessWith: one with: two
	"Test debugger access for temps"
	| outerContext local1 remote1 |
	outerContext := thisContext.
	local1 := 3.
	remote1 := 1/2.
	self assert: (Compiler new evaluate: 'one' in: thisContext to: self) == one.
	self assert: (Compiler new evaluate: 'two' in: thisContext to: self) == two.
	self assert: (Compiler new evaluate: 'local1' in: thisContext to: self) == local1.
	self assert: (Compiler new evaluate: 'remote1' in: thisContext to: self) == remote1.
	Compiler new evaluate: 'local1 := -3.0' in: thisContext to: self.
	self assert: local1 = -3.0.
	(1 to: 2) do:
		[:i| | local2 r1 r2 r3 r4 |
		local2 := i * 3.
		remote1 := local2 / 7.
		self assert: thisContext ~~ outerContext.
		self assert: (r1 := Compiler new evaluate: 'one' in: thisContext to: self) == one.
		self assert: (r2 := Compiler new evaluate: 'two' in: thisContext to: self) == two.
		self assert: (r3 := Compiler new evaluate: 'i' in: thisContext to: self) == i.
		self assert: (r4 := Compiler new evaluate: 'local2' in: thisContext to: self) == local2.
		self assert: (r4 := Compiler new evaluate: 'remote1' in: thisContext to: self) == remote1.
		self assert: (r4 := Compiler new evaluate: 'remote1' in: outerContext to: self) == remote1.
		Compiler new evaluate: 'local2 := 15' in: thisContext to: self.
		self assert: local2 = 15.
		Compiler new evaluate: 'local1 := 25' in: thisContext to: self.
		self assert: local1 = 25.
		{ r1. r2. r3. r4 } "placate the compiler"].
	self assert: local1 = 25.
	self assert: remote1 = (6/7)! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 16:58'!
supportTestSourceRangeAccessForDecompiledInjectInto: method source: source
	"Test debugger source range selection for inject:into:"
	^self
		supportTestSourceRangeAccessForInjectInto: method
		source: source
		selectionSequence: #(	':= t1'
								'do: [:t4 | t3 := t2 value: t3 value: t4]'
								'value: t3 value: t4'
								':= t2 value: t3 value: t4'
								']'
								'value: t3 value: t4'
								':= t2 value: t3 value: t4'
								']'
								'^t3')! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 19:44'!
supportTestSourceRangeAccessForDecompiledNoBytecodeInjectInto: method source: source
	"Test debugger source range selection for inject:into:"
	^self
		supportTestSourceRangeAccessForInjectInto: method
		source: source
		selectionSequence: #(	'at: 1 put: t1'
								'do: [:t4 | t3 at: 1 put: (t2 value: (t3 at: 1) value: t4)]'
								'value: (t3 at: 1) value: t4'
								'at: 1 put: (t2 value: (t3 at: 1) value: t4)'
								']'
								'value: (t3 at: 1) value: t4'
								'at: 1 put: (t2 value: (t3 at: 1) value: t4)'
								']'
								'^t3 at: 1')! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 7/24/2009 20:53'!
supportTestSourceRangeAccessForInjectInto: method source: source
	"Test debugger source range selection for inject:into:"
	^self
		supportTestSourceRangeAccessForInjectInto: method
		source: source
		selectionSequence: #(	':= thisValue'
								'do: [:each | nextValue := binaryBlock value: nextValue value: each]'
								'value: nextValue value: each'
								':= binaryBlock value: nextValue value: each'
								'nextValue := binaryBlock value: nextValue value: each'
								'value: nextValue value: each'
								':= binaryBlock value: nextValue value: each'
								'nextValue := binaryBlock value: nextValue value: each'
								'^nextValue')! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 7/29/2008 17:16'!
supportTestSourceRangeAccessForInjectInto: method source: source selectionSequence: selections
	"Test debugger source range selection for inject:into:"
	| evaluationCount sourceMap debugTokenSequence debugCount |
	DebuggerMethodMap voidMapCache.
	evaluationCount := 0.
	sourceMap := method debuggerMap abstractSourceMap.
	debugTokenSequence := selections collect: [:string| Scanner new scanTokens: string].
	debugCount := 0.
	thisContext
		runSimulated: [(1 to: 2)
						withArgs:
							{	0.
								[:sum :each|
								 evaluationCount := evaluationCount + 1.
								 sum + each]}
						executeMethod: method]
		contextAtEachStep:
			[:ctxt| | range debugTokens |
			(ctxt method == method
			and: ["Exclude the send of #blockCopy: or #closureCopy:copiedValues: and braceWith:with:
				    to create the block, and the #new: and #at:'s for the indirect temp vector.
				   This for compilation without closure bytecodes. (Note that at:put:'s correspond to stores)"
				(ctxt willSend
					and: [(#(closureCopy:copiedValues: blockCopy: new: at: braceWith:with:) includes: ctxt selectorToSendOrSelf) not])
				"Exclude the store of the argument into the home context (for BlueBook blocks)
				 and the store of an indirection vector into an initial temp"
				or: [(ctxt willStore
					and: [(ctxt isBlock and: [ctxt pc = ctxt startpc]) not
					and: [(ctxt isBlock not
						and: [(method usesClosureBytecodes and: [ctxt abstractPC = 2])]) not]])
				or: [ctxt willReturn]]]) ifTrue:
				[debugTokens := debugTokenSequence at: (debugCount := debugCount + 1) ifAbsent: [#(bogusToken)].
				 self assert: (sourceMap includesKey: ctxt abstractPC).
				 range := sourceMap at: ctxt abstractPC ifAbsent: [(1 to: 0)].
				 self assert: (Scanner new scanTokens: (source copyFrom: range first to: range last)) = debugTokens]].
	self assert: evaluationCount = 2! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'nice 10/20/2009 20:10'!
testBlockNumbering
	"Test that the compiler and CompiledMethod agree on the block numbering of a substantial doit."
	"self new testBlockNumbering"
	| methodNode method tempRefs |
	methodNode :=
		Parser new
			encoderClass: EncoderForV3PlusClosures;
			parse: 'foo
					| numCopiedValuesCounts |
					numCopiedValuesCounts := Dictionary new.
					0 to: 32 do: [:i| numCopiedValuesCounts at: i put: 0].
					Transcript clear.
					Smalltalk allClasses remove: GeniePlugin; do:
						[:c|
						{c. c class} do:
							[:b|
							Transcript nextPut: b name first; endEntry.
							b selectorsAndMethodsDo:
								[:s :m| | pn |
								m isQuick not ifTrue:
									[pn := b parserClass new
												encoderClass: EncoderForV3PlusClosures;
												parse: (b sourceCodeAt: s)
												class: b.
									 pn generate: #(0 0 0 0).
									 [pn accept: nil]
										on: MessageNotUnderstood
										do: [:ex| | msg numCopied |
											msg := ex message.
											(msg selector == #visitBlockNode:
											 and: [(msg argument instVarNamed: ''optimized'') not]) ifTrue:
												[numCopied := (msg argument computeCopiedValues: pn) size.
												 numCopiedValuesCounts
													at: numCopied
													put: (numCopiedValuesCounts at: numCopied) + 1].
											msg setSelector: #==.
											ex resume: nil]]]]].
					numCopiedValuesCounts'
			class: Object.
	method := methodNode generate: #(0 0 0 0).
	tempRefs := methodNode encoder blockExtentsToTempsMap.
	self assert: tempRefs keys asSet = method startpcsToBlockExtents values asSet! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'nice 10/20/2009 20:10'!
testBlockNumberingForInjectInto
	"Test that the compiler and CompiledMethod agree on the block numbering of Collection>>inject:into:
	 and that temp names for inject:into: are recorded."
	"self new testBlockNumberingForInjectInto"
	| methodNode method tempRefs |
	methodNode := Parser new
						encoderClass: EncoderForV3PlusClosures;
						parse: (Collection sourceCodeAt: #inject:into:)
						class: Collection.
	method := methodNode generate: #(0 0 0 0).
	tempRefs := methodNode encoder blockExtentsToTempsMap.
	self assert: tempRefs keys asSet = method startpcsToBlockExtents values asSet.
	self assert: ((tempRefs includesKey: (0 to: 6))
				and: [(tempRefs at: (0 to: 6)) hasEqualElements: #(('thisValue' 1) ('binaryBlock' 2) ('nextValue' (3 1)))]).
	self assert: ((tempRefs includesKey: (2 to: 4))
				and: [(tempRefs at: (2 to: 4)) hasEqualElements: #(('each' 1) ('binaryBlock' 2) ('nextValue' (3 1)))])! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/24/2008 11:03'!
testDebuggerTempAccess
	self doTestDebuggerTempAccessWith: 1 with: 2! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 7/24/2009 21:12'!
testDecompiledDoitMethodTempNames
	"self new testDecompiledDoitMethodTempNames"
	"Test that a decompiled doit that has been copied with temps decompiles to the input"
	| removeComments |
	removeComments := [:n| n comment: nil].
	self closureCases do:
		[:source| | mns m mps mnps |
		"Need to compare an ungenerated tree with the generated method's methodNode
		 because generating code alters the tree when it introduces remote temp vectors."
		mns := #(first last) collect:
					[:ignored|
					source first isLetter
						ifTrue:
							[self class compilerClass new
								compile: source
								in: self class
								notifying: nil
								ifFail: [self error: 'compilation error']]
						ifFalse:
							[self class compilerClass new
								compileNoPattern: source
								in: self class
								context: nil
								notifying: nil
								ifFail: [self error: 'compilation error']]].
		m := (mns last generate: #(0 0 0 0)) copyWithTempsFromMethodNode: mns last.
		removeComments value: mns first.
		mns first nodesDo: removeComments.
		self assert: (mnps := mns first printString) = (mps := m methodNode printString)]! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 16:57'!
testInjectIntoDecompilations
	"Test various compilations decompile to the same code for a method sufficiently
	 simple that this is possible and sufficiently complex that the code generated
	 varies between the compilations."
	"self new testInjectIntoDecompilations"
	| source |
	source := (Collection sourceCodeAt: #inject:into:) asString.
	{ Encoder.
	   EncoderForV3. EncoderForLongFormV3.
	   EncoderForV3PlusClosures. EncoderForLongFormV3PlusClosures } do:
		[:encoderClass| | method |
		method := (Parser new
							encoderClass: encoderClass;
							parse: source
							class: Collection)
						generate: #(0 0 0 0).
		self assert: (Scanner new scanTokens: method decompileString)
					= #(inject: t1 into: t2
							| t3 |
							t3 ':=' t1 .
							self do: [ ':t4' | t3 ':=' t2 value: t3 value: t4 ] .
							^ t3)]! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 7/29/2008 17:17'!
testInjectIntoDecompiledDebugs
	"Test various debugs of the decompiled form debug correctly."
	"self new testInjectIntoDecompiledDebugs"
	| source |
	source := (Collection sourceCodeAt: #inject:into:) asString.
	{ Encoder.
	   EncoderForV3PlusClosures. EncoderForLongFormV3PlusClosures } do:
		[:encoderClass| | method |
		method := (Parser new
							encoderClass: encoderClass;
							parse: source
							class: Collection)
						generate: #(0 0 0 0).
		self supportTestSourceRangeAccessForDecompiledInjectInto: method source: method decompileString]! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 7/24/2009 11:51'!
testInlineBlockCollectionEM1
	| a1 b1 i1 a2 b2 i2 we wb |
	b1 := OrderedCollection new.
	i1 := 1.
	[a1 := i1.
	 i1 <= 3] whileTrue:
		[b1 add: [a1].
		i1 := i1 + 1].
	b1 := b1 asArray collect: [:b | b value].
	b2 := OrderedCollection new.
	i2 := 1.
	we := [a2 := i2. i2 <= 3].
	wb := [b2 add: [a2]. i2 := i2 + 1].
	we whileTrue: wb. "defeat optimization"
	b2 := b2 asArray collect: [:b | b value].
	self assert: b1 = b2! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 3/7/2009 11:25'!
testInlineBlockCollectionLR1
	"Test case from Lukas Renggli"
	| col |
	col := OrderedCollection new.
	1 to: 11 do: [ :each | col add: [ each ] ].
	self assert: (col collect: [ :each | each value ]) asArray = (1 to: 11) asArray! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 3/7/2009 11:39'!
testInlineBlockCollectionLR2
	"Test case from Lukas Renggli"
	| col |
	col := OrderedCollection new.
	1 to: 11 do: [ :each | #(1) do: [:ignored| col add: [ each ]] ].
	self assert: (col collect: [ :each | each value ]) asArray = (1 to: 11) asArray! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 3/9/2009 11:00'!
testInlineBlockCollectionLR3
	| col |
	col := OrderedCollection new.
	1 to: 11 do: [ :each | | i | i := each. col add: [ i ]. i := i + 1 ].
	self assert: (col collect: [ :each | each value ]) asArray = (2 to: 12) asArray! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 7/22/2009 16:55'!
testInlineBlockCollectionSD1
	| a1 b1 a2 b2 |
	b1 := OrderedCollection new.
	1 to: 3 do:
		[:i |
		a1 := i.
		b1 add: [a1]].
	b1 := b1 asArray collect: [:b | b value].
	b2 := OrderedCollection new.
	1 to: 3 do:
		[:i |
		a2 := i.
		b2 add: [a2]] yourself. "defeat optimization"
	b2 := b2 asArray collect: [:b | b value].
	self assert: b1 = b2! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'nice 10/23/2009 23:46'!
testMethodAndNodeTempNames
	"self new testMethodAndNodeTempNames"
	"Test that BytecodeAgnosticMethodNode>>blockExtentsToTempRefs answers the same
	 structure as CompiledMethod>>blockExtentsToTempRefs when the method has been
	 copied with the appropriate temps.  This tests whether doit methods are debuggable
	 since they carry their own temps."
	self closureCases do:
		[:source| | mn om m mbe obe |
		mn := source first isLetter
					ifTrue:
						[self class compilerClass new
							compile: source
							in: self class
							notifying: nil
							ifFail: [self error: 'compilation error']]
					ifFalse:
						[self class compilerClass new
							compileNoPattern: source
							in: self class
							context: nil
							notifying: nil
							ifFail: [self error: 'compilation error']].
		m := (om := mn generate: #(0 0 0 0)) copyWithTempsFromMethodNode: mn.
		self assert: m holdsTempNames.
		self assert: m endPC = om endPC.
		mbe := m blockExtentsToTempsMap.
		obe := mn blockExtentsToTempsMap.
		self assert: mbe keys asSet = obe keys asSet.
		(mbe keys intersection: obe keys) do:
			[:interval|
			self assert: (mbe at: interval) = (obe at: interval)]]! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 15:20'!
testSourceRangeAccessForBlueBookInjectInto
	"Test debugger source range selection for inject:into: for a version compiled with closures"
	"self new testSourceRangeAccessForBlueBookInjectInto"
	| source method |
	source := (Collection sourceCodeAt: #inject:into:) asString.
	method := (Parser new
						encoderClass: EncoderForV3;
						parse: source
						class: Collection)
					generate: (Collection compiledMethodAt: #inject:into:) trailer.
	self supportTestSourceRangeAccessForInjectInto: method source: source! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 15:20'!
testSourceRangeAccessForBlueBookLongFormInjectInto
	"Test debugger source range selection for inject:into: for a version compiled with closures"
	"self new testSourceRangeAccessForBlueBookLongFormInjectInto"
	| source method |
	source := (Collection sourceCodeAt: #inject:into:) asString.
	method := (Parser new
						encoderClass: EncoderForLongFormV3;
						parse: source
						class: Collection)
					generate: (Collection compiledMethodAt: #inject:into:) trailer.
	self supportTestSourceRangeAccessForInjectInto: method source: source! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 15:20'!
testSourceRangeAccessForClosureBytecodeInjectInto
	"Test debugger source range selection for inject:into: for a version compiled with closures"
	"self new testSourceRangeAccessForClosureBytecodeInjectInto"
	| source method |
	source := (Collection sourceCodeAt: #inject:into:) asString.
	method := (Parser new
						encoderClass: EncoderForV3PlusClosures;
						parse: source
						class: Collection)
					generate: (Collection compiledMethodAt: #inject:into:) trailer.
	self supportTestSourceRangeAccessForInjectInto: method source: source! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 15:20'!
testSourceRangeAccessForClosureLongFormBytecodeInjectInto
	"Test debugger source range selection for inject:into: for a version compiled with closures"
	"self new testSourceRangeAccessForClosureLongFormBytecodeInjectInto"
	| source method |
	source := (Collection sourceCodeAt: #inject:into:) asString.
	method := (Parser new
						encoderClass: EncoderForLongFormV3PlusClosures;
						parse: source
						class: Collection)
					generate: (Collection compiledMethodAt: #inject:into:) trailer.
	self supportTestSourceRangeAccessForInjectInto: method source: source! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/4/2008 11:40'!
testSourceRangeAccessForInjectInto
	"Test debugger source range selection for inject:into: for the current version of the method"
	"self new testSourceRangeAccessForInjectInto"
	self supportTestSourceRangeAccessForInjectInto: (Collection compiledMethodAt: #inject:into:)
		source: (Collection sourceCodeAt: #inject:into:) asString! !

!ClosureCompilerTest methodsFor: 'tests' stamp: 'eem 6/15/2008 11:26'!
testTempNameAccessForInjectInto
	"self new testTempNameAccessForInjectInto"
	| methodNode method evaluationCount block debuggerMap |
	methodNode := Parser new
						encoderClass: EncoderForV3PlusClosures;
						parse: (Collection sourceCodeAt: #inject:into:)
						class: Collection.
	method := methodNode generate: #(0 0 0 0).
	debuggerMap := DebuggerMethodMap forMethod: method methodNode: methodNode.
	evaluationCount := 0.
	block := [:prev :each| | theContext tempNames |
			evaluationCount := evaluationCount + 1.
			theContext := thisContext sender.
			tempNames := debuggerMap tempNamesForContext: theContext.
			self assert: (tempNames hasEqualElements: tempNames).
			#('thisValue' 'each' 'binaryBlock' 'nextValue')
				with: { 0. each. block. prev}
				do: [:tempName :value|
					self assert: (debuggerMap namedTempAt: (tempNames indexOf: tempName) in: theContext) == value.
					tempName ~= 'each' ifTrue:
						[self assert: (debuggerMap namedTempAt: (tempNames indexOf: tempName) in: theContext home) == value]]].
	(1 to: 10) withArgs: { 0. block } executeMethod: method.
	self assert: evaluationCount = 10! !


!ClosureCompilerTest class methodsFor: 'code examples' stamp: 'eem 5/20/2008 09:40'!
methodWithCopiedAndAssignedTemps
	| blk "0w" a "0w" b "0w" c "0w" t "0w" r1 "0w" r2 "0w" |
	a := 1. "1w"
	b := 2. "1w"
	c := 4. "1w"
	t := 0. "1w"
	blk "5w" := ["2" t  "3w" := t "3r" + a "3r" + b "3r" + c "3r" ] "4".
	r1 "5w" := blk "5r" value.
	b "5w" := -100.
	r2 "5w" := blk "5r" value.
	^r1 "5r" -> r2 "5r" -> t "5r"

	"a: main(read(),write(0,1)), block(read(3),write()) => copy; no writes follow read
	 b: main(read(),write(0,1,5)), block(read(3),write()) => remote; write follows contained read
	 blk: main(read(5),write(0,5)), block(read(),write()) => no copy in blocks < 5
	 c: main(read(),write(0,1)), block(read(3),write()) => copy; no writes follow read
	 r1: main(read(5),write(0,5)), block(read(),write()) => no copy in blocks < 5
	 r2: main(read(5),write(0,5)), block(read(),write()) => no copy in blocks < 5
	 t: main(read(5),write(0,1)), block(read(3),write(3)) => remote; read follows contained write"


	"(Parser new
		encoderClass: EncoderForV3;
		parse: (self class sourceCodeAt: #methodWithCopiedAndAssignedTemps)
		class: self class) generateUsingClosures: #(0 0 0 0)"! !

!ClosureCompilerTest class methodsFor: 'code examples' stamp: 'eem 5/19/2008 20:45'!
methodWithCopiedAndPostClosedOverAssignedTemps
	| blk a b c r1 r2 |
	a := 1.
	b := 2.
	c := 4.
	blk := [a + b + c].
	r1 := blk value.
	b := nil.
	r2 := blk value.
	r1 -> r2

	"(Parser new
		encoderClass: EncoderForV3;
		parse: (self class sourceCodeAt: #methodWithCopiedAndPostClosedOverAssignedTemps)
		class: self class) generateUsingClosures: #(0 0 0 0)"! !

!ClosureCompilerTest class methodsFor: 'code examples' stamp: 'eem 5/19/2008 20:10'!
methodWithCopiedTemps
	| a b c r |
	a := 1.
	b := 2.
	c := 4.
	r := [a + b + c] value.
	b := nil.
	r

	"Parser new
		parse: (self class sourceCodeAt: #methodWithCopiedTemps)
		class: self class"

	"(Parser new
		encoderClass: EncoderForV3;
		parse: (self class sourceCodeAt: #methodWithCopiedTemps)
		class: self class) generateUsingClosures: #(0 0 0 0)"! !

!ClosureCompilerTest class methodsFor: 'code examples' stamp: 'eem 5/19/2008 14:24'!
methodWithOptimizedBlocks
	| s c |
	s := self isNil
			ifTrue: [| a | a := 'isNil'. a]
			ifFalse: [| b | b := 'notNil'. b].
	c := String new: s size.
	1 to: s size do:
		[:i| c at: i put: (s at: i)].
	^c

	"Parser new
		parse: (self class sourceCodeAt: #methodWithOptimizedBlocks)
		class: self class"! !

!ClosureCompilerTest class methodsFor: 'code examples' stamp: 'eem 5/19/2008 14:24'!
methodWithOptimizedBlocksA
	| s c |
	s := self isNil
			ifTrue: [| a | a := 'isNil'. a]
			ifFalse: [| a | a := 'notNil'. a].
	c := String new: s size.
	1 to: s size do:
		[:i| c at: i put: (s at: i)].
	^c

	"Parser new
		parse: (self class sourceCodeAt: #methodWithOptimizedBlocksA)
		class: self class"! !

!ClosureCompilerTest class methodsFor: 'code examples' stamp: 'eem 5/19/2008 14:12'!
methodWithVariousTemps
	| classes total totalLength |
	classes := self withAllSuperclasses.
	total := totalLength := 0.
	classes do: [:class| | className |
		className := class name.
		total := total + 1.
		totalLength := totalLength + className size].
	^total -> totalLength

	"Parser new
		parse: (self class sourceCodeAt: #methodWithVariousTemps)
		class: self class"! !


!ClosureTests methodsFor: 'utilities' stamp: 'lr 3/9/2009 16:48'!
assertValues: anArray
	| values |
	values := collection collect: [ :each | each value ].
	self 
		assert: anArray asArray = values asArray
		description: 'Expected: ' , anArray asArray printString , 
			', but got ' , values asArray printString! !

!ClosureTests methodsFor: 'utilities' stamp: 'cwp 11/16/2009 08:12'!
evaluateCopyOf: aBlock
	aBlock copy value! !

!ClosureTests methodsFor: 'utilities' stamp: 'cwp 11/16/2009 08:12'!
methodWithNonLocalReturn
	self evaluateCopyOf: [^ self].
	self signalFailure: 'Should never reach here'! !

!ClosureTests methodsFor: 'testing' stamp: 'lr 3/11/2009 17:35'!
methodArgument: anObject
	^ [ anObject ]
	! !

!ClosureTests methodsFor: 'testing' stamp: 'lr 3/11/2009 17:33'!
testBlockArgument
	| block block1 block2 |
	block := [ :arg | | temp | temp := arg. [ temp ] ].
	block1 := block value: 1.
	block2 := block value: 2.
	self assert: block1 value = 1.
	self assert: block2 value = 2! !

!ClosureTests methodsFor: 'testing' stamp: 'lr 3/11/2009 17:33'!
testBlockTemp
	| block block1 block2 |
	block := [ :arg | [ arg ] ].
	block1 := block value: 1.
	block2 := block value: 2.
	self assert: block1 value = 1.
	self assert: block2 value = 2! !

!ClosureTests methodsFor: 'testing' stamp: 'cwp 11/16/2009 08:11'!
testCopyNonLocalReturn
	self
		shouldnt: [self methodWithNonLocalReturn]
		raise: Error! !

!ClosureTests methodsFor: 'testing' stamp: 'lr 3/11/2009 17:36'!
testMethodArgument
	| temp block |
	temp := 0.
	block := [ [ temp ] ].
	temp := 1.
	block := block value.
	temp := 2.
	self assert: block value = 2! !

!ClosureTests methodsFor: 'testing' stamp: 'lr 3/11/2009 17:36'!
testMethodTemp
	| block1 block2 |
	block1 := self methodArgument: 1.
	block2 := self methodArgument: 2.
	self assert: block1 value = 1.
	self assert: block2 value = 2! !

!ClosureTests methodsFor: 'running' stamp: 'lr 3/9/2009 16:48'!
setUp
	super setUp.
	collection := OrderedCollection new! !

!ClosureTests methodsFor: 'testing-todo' stamp: 'lr 3/10/2009 14:51'!
testToDoArgument
	1 to: 5 do: [ :index |
		collection add: [ index ] ].
	self assertValues: #(1 2 3 4 5)! !

!ClosureTests methodsFor: 'testing-todo' stamp: 'lr 3/10/2009 14:51'!
testToDoArgumentNotInlined
	| block |
	block := [ :index |
		collection add: [ index ] ].
	1 to: 5 do: block.
	self assertValues: #(1 2 3 4 5)! !

!ClosureTests methodsFor: 'testing-todo' stamp: 'lr 3/10/2009 14:51'!
testToDoInsideTemp
	1 to: 5 do: [ :index | 
		| temp | 
		temp := index. 
		collection add: [ temp ] ].
	self assertValues: #(1 2 3 4 5)! !

!ClosureTests methodsFor: 'testing-todo' stamp: 'lr 3/10/2009 14:51'!
testToDoInsideTempNotInlined
	| block |
	block := [ :index | 
		| temp | 
		temp := index. 
		collection add: [ temp ] ].
	1 to: 5 do: block.
	self assertValues: #(1 2 3 4 5)! !

!ClosureTests methodsFor: 'testing-todo' stamp: 'lr 3/10/2009 14:51'!
testToDoOutsideTemp
	| temp |
	1 to: 5 do: [ :index | 
		temp := index. 
		collection add: [ temp ] ].
	self assertValues: #(5 5 5 5 5)! !

!ClosureTests methodsFor: 'testing-todo' stamp: 'lr 3/10/2009 14:51'!
testToDoOutsideTempNotInlined
	| block temp |
	block := [ :index | 
		temp := index. 
		collection add: [ temp ] ].
	1 to: 5 do: block.
	self assertValues: #(5 5 5 5 5)! !

!ClosureTests methodsFor: 'testing-while' stamp: 'lr 3/10/2009 14:29'!
testWhileModificationAfter
	| index |
	index := 0.
	[ index < 5 ] whileTrue: [
		collection add: [ index ].
		index := index + 1 ].
	self assertValues: #(5 5 5 5 5)! !

!ClosureTests methodsFor: 'testing-while' stamp: 'lr 3/10/2009 14:29'!
testWhileModificationAfterNotInlined
	| index block |
	index := 0.
	block := [ 
		collection add: [ index ].
		index := index + 1 ].
	[ index < 5 ] whileTrue: block.
	self assertValues: #(5 5 5 5 5)! !

!ClosureTests methodsFor: 'testing-while' stamp: 'lr 3/10/2009 14:29'!
testWhileModificationBefore
	| index |
	index := 0.
	[ index < 5 ] whileTrue: [ 
		index := index + 1.
		collection add: [ index ] ].
	self assertValues: #(5 5 5 5 5)! !

!ClosureTests methodsFor: 'testing-while' stamp: 'lr 3/10/2009 14:29'!
testWhileModificationBeforeNotInlined
	| index block |
	index := 0.
	block := [ 
		index := index + 1.
		collection add: [ index ] ].
	[ index < 5 ] whileTrue: block.
	self assertValues: #(5 5 5 5 5)! !

!ClosureTests methodsFor: 'testing-while' stamp: 'lr 3/10/2009 14:52'!
testWhileWithTemp
	| index |
	index := 0.
	[ index < 5 ] whileTrue: [
		| temp |
		temp := index := index + 1.
		collection add: [ temp ] ].
	self assertValues: #(1 2 3 4 5)! !

!ClosureTests methodsFor: 'testing-while' stamp: 'lr 3/10/2009 14:53'!
testWhileWithTempNotInlined
	| index block |
	index := 0.
	block := [
		| temp |
		temp := index := index + 1.
		collection add: [ temp ] ].
	[ index < 5 ] whileTrue: block.
	self assertValues: #(1 2 3 4 5)! !


!ColoredCodeStream methodsFor: 'color/style' stamp: 'md 8/14/2005 17:33'!
colorTable
	"Answer the table to use to determine colors"

	^ colorTable ifNil: [colorTable := ST80ColorTable]! !

!ColoredCodeStream methodsFor: 'color/style' stamp: 'sw 5/20/2001 21:05'!
withColor: colorSymbol emphasis: emphasisSymbol do: aBlock
	"Evaluate the given block with the given color and style text attribute"

	^ self withAttributes: {TextColor color: (Color perform: colorSymbol).
							TextEmphasis perform: emphasisSymbol}
		do: aBlock! !

!ColoredCodeStream methodsFor: 'color/style' stamp: 'sw 5/20/2001 11:30'!
withStyleFor: elementType do: aBlock
	"Evaluate aBlock with appropriate emphasis and color for the given elementType"

	| colorAndStyle |
	colorAndStyle := self colorTable at: elementType.
	^ self withColor: colorAndStyle first emphasis: colorAndStyle second do: aBlock! !


!ColoredCodeStream class methodsFor: 'instance creation' stamp: 'md 8/15/2005 11:00'!
contents: blockWithArg 
	"Evaluate blockWithArg on a DialectStream of the given description"

	| stream |
	stream := self on: (Text new: 400).
	blockWithArg value: stream.
	^ stream contents! !

!ColoredCodeStream class methodsFor: 'class initialization' stamp: 'wiz 9/12/2005 00:41'!
initialize
	"Initialize the colors that characterize the ST80 dialect"

	ST80ColorTable := IdentityDictionary new.
	#(	(temporaryVariable blue italic)
		(methodArgument blue normal)
		(methodSelector black bold)
		(blockArgument red normal)
		(comment brown normal)
		(variable magenta normal)
		(literal	orange normal)
		(keyword darkGray bold)
		(prefixKeyword veryDarkGray bold)
		(setOrReturn black bold)) do:
			[:aTriplet |
				ST80ColorTable at: aTriplet first put: aTriplet allButFirst]

"ColoredCodeStream initialize"! !


!CompiledMethodWithNode methodsFor: 'accessing' stamp: 'NS 1/28/2004 09:03'!
method
	^ method! !

!CompiledMethodWithNode methodsFor: 'accessing' stamp: 'NS 1/28/2004 09:04'!
node
	^ node! !

!CompiledMethodWithNode methodsFor: 'accessing' stamp: 'NS 1/28/2004 09:04'!
selector
	^ self node selector! !

!CompiledMethodWithNode methodsFor: 'private' stamp: 'NS 1/28/2004 09:03'!
method: aCompiledMethod
	method := aCompiledMethod! !

!CompiledMethodWithNode methodsFor: 'private' stamp: 'NS 1/28/2004 09:04'!
node: aMethodNode
	node := aMethodNode! !


!CompiledMethodWithNode class methodsFor: 'instance creation' stamp: 'NS 1/28/2004 09:05'!
generateMethodFromNode: aMethodNode trailer: bytes
	^ self method: (aMethodNode generate: bytes) node: aMethodNode.! !

!CompiledMethodWithNode class methodsFor: 'instance creation' stamp: 'NS 1/28/2004 09:05'!
method: aCompiledMethod node: aMethodNode
	^ self new method: aCompiledMethod; node: aMethodNode.! !


!Compiler methodsFor: 'public access' stamp: 'md 2/28/2006 10:04'!
compile: textOrStream in: aClass classified: aCategory notifying: aRequestor ifFail: failBlock 
	"Answer a MethodNode for the argument, textOrStream. If the 
	MethodNode can not be created, notify the argument, aRequestor; if 
	aRequestor is nil, evaluate failBlock instead. The MethodNode is the root 
	of a parse tree. It can be told to generate a CompiledMethod to be 
	installed in the method dictionary of the argument, aClass."
	
	| methodNode |
	self from: textOrStream
		class: aClass
		classified: aCategory 
		context: nil
		notifying: aRequestor.
	methodNode := self translate: sourceStream noPattern: false ifFail: failBlock.
	methodNode encoder requestor: requestor.
	^methodNode.
! !

!Compiler methodsFor: 'public access' stamp: 'md 2/28/2006 10:45'!
compile: textOrStream in: aClass notifying: aRequestor ifFail: failBlock 
	^self compile: textOrStream in: aClass classified: nil notifying: aRequestor ifFail: failBlock ! !

!Compiler methodsFor: 'public access' stamp: 'vb 8/13/2001 23:11'!
compileNoPattern: textOrStream in: aClass context: aContext notifying: aRequestor ifFail: failBlock
	"Similar to #compile:in:notifying:ifFail:, but the compiled code is
	expected to be a do-it expression, with no message pattern."

	self from: textOrStream
		class: aClass
		context: aContext
		notifying: aRequestor.
	^self
		translate: sourceStream
		noPattern: true
		ifFail: failBlock! !

!Compiler methodsFor: 'public access' stamp: 'eem 9/4/2009 08:47'!
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 := methodNode generate: #(0 0 0 0).
	self interactive ifTrue:
		[method := method copyWithTempsFromMethodNode: methodNode].
	logFlag ifTrue:
		[SystemChangeNotifier uniqueInstance evaluated: sourceStream contents context: aContext].
	^method! !

!Compiler methodsFor: 'public access' stamp: 'sd 1/19/2004 20:58'!
evaluate: aString in: aContext to: aReceiver
	"evaluate aString in the given context, and return the result.  2/2/96 sw"
	| result |
	result := self
				evaluate: aString
				in: aContext
				to: aReceiver
				notifying: nil
				ifFail: [^ #failedDoit].
	^ result! !

!Compiler methodsFor: 'public access' stamp: 'NS 1/19/2004 09:05'!
evaluate: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock
	^ self evaluate: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: false.! !

!Compiler methodsFor: 'public access' stamp: 'eem 7/1/2009 13:53'!
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. This method is then installed in the receiver's class so that it 
	can be invoked. In other words, 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. Finally, the 
	compiled method is invoked from here as DoIt or (in the case of 
	evaluation in aContext) DoItIn:. The method is subsequently removed 
	from the class, but this will not get done if the invocation causes an 
	error which is terminated. Such garbage can be removed by executing: 
	Smalltalk allBehaviorsDo: [:cl | cl removeSelector: #DoIt; removeSelector: 
	#DoItIn:]."

	| 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 := methodNode generate: #(0 0 0 0).
	self interactive ifTrue:
		[method := method copyWithTempsFromMethodNode: methodNode].
	
	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: 'rss 8/23/2009 12:53'!
format: textOrStream in: aClass notifying: aRequestor
	"Compile a parse tree from the argument, textOrStream. Answer a string containing the original code, formatted nicely.  If aBoolean is true, then decorate the resulting text with color and hypertext actions"

	| aNode |
	self from: textOrStream
		class: aClass
		context: nil
		notifying: aRequestor.
	aNode := self format: sourceStream noPattern: false ifFail: [^ nil].

	"aSymbol == #colorPrint ifTrue:
		[^aNode asColorizedSmalltalk80Text]." "deprecating #colorPrint in favor of Shout --Ron Spengler"

	^aNode decompileString! !

!Compiler methodsFor: 'public access' stamp: 'sw 11/7/1999 00:11'!
format: textOrStream in: aClass notifying: aRequestor decorated: aBoolean
	"Compile a parse tree from the argument, textOrStream. Answer a string containing the original code, formatted nicely.  If aBoolean is true, then decorate the resulting text with color and hypertext actions"
	| aNode |
	self from: textOrStream
		class: aClass
		context: nil
		notifying: aRequestor.
	aNode := self format: sourceStream noPattern: false ifFail: [^ nil].
	^ aBoolean
		ifTrue: [aNode decompileText]
		ifFalse: [aNode decompileString]! !

!Compiler methodsFor: 'public access' stamp: 'ar 9/27/2005 19:20'!
from: textOrStream class: aClass classified: aCategory context: aContext notifying: req

	(textOrStream isKindOf: PositionableStream)
		ifTrue: [sourceStream  := textOrStream]
		ifFalse: [sourceStream  := 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: 'eem 5/15/2008 15:13'!
parser

	parser ifNil: [parser := self parserClass new].
	^parser! !

!Compiler methodsFor: 'public access' stamp: 'eem 5/15/2008 15:07'!
parser: aParser

	parser := aParser! !

!Compiler methodsFor: 'public access' stamp: 'eem 5/15/2008 15:05'!
parserClass

	^parser ifNil: [self class parserClass] ifNotNil: [parser class]! !

!Compiler methodsFor: 'public access' stamp: 'eem 5/15/2008 15:06'!
parserClass: aParserClass

	parser := aParserClass new! !

!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: 'eem 5/15/2008 15:10'!
format: aStream noPattern: noPattern ifFail: failBlock
	^self parser
		parse: aStream
		class: class
		noPattern: noPattern
		context: context
		notifying: requestor
		ifFail: [^failBlock value]! !

!Compiler methodsFor: 'private'!
from: textOrStream class: aClass context: aContext notifying: req

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

!Compiler methodsFor: 'private' stamp: 'stephaneducassse 11/5/2005 16:39'!
interactive
	"this version of the method is necessary to load code from MC else the interactive mode is one. 
	This method is really bad since it links the compiler package with the Tools
	one. The solution would be to have a real SyntaxError exception belonging to the 
	compiler package and not a subclass of StringHolder - sd Nov 2005"
	"the code submitted by PlusTools is ideally the one that should be used
	interactive

	      ^requestor ~~ nil "
	
	^ (requestor == nil or: [requestor isKindOf: SyntaxError]) not! !

!Compiler methodsFor: 'private' stamp: 'eem 5/15/2008 15:11'!
translate: aStream noPattern: noPattern ifFail: failBlock
	^self parser
		parse: aStream
		class: class
		category: category
		noPattern: noPattern
		context: context
		notifying: requestor
		ifFail: [^failBlock value]! !

!Compiler methodsFor: 'error handling'!
notify: aString 
	"Refer to the comment in Object|notify:."

	^self notify: aString at: sourceStream position + 1! !

!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: 'accessing' stamp: 'nk 8/30/2004 07:56'!
couldEvaluate: anObject
	"Answer true if anObject can be passed to my various #evaluate: methods."
	^anObject isString or: [ anObject isText or: [ anObject isStream ]]! !

!Compiler class methodsFor: 'accessing' stamp: 'md 3/1/2006 21:12'!
decompilerClass
	^Decompiler! !

!Compiler class methodsFor: 'accessing' stamp: 'eem 5/15/2008 15:12'!
new
	^ super new parser: self parserClass new! !

!Compiler class methodsFor: 'accessing' stamp: 'eem 5/13/2008 11:37'!
parserClass
	"Answer a parser class to use for parsing methods compiled by instances of the receiver."

	^Parser! !

!Compiler class methodsFor: 'evaluating' stamp: 'NS 1/19/2004 10:07'!
evaluate: textOrString 
	"See Compiler|evaluate:for:notifying:logged:. If a compilation error occurs, 
	a Syntax Error view is created rather than notifying any requestor. 
	Compilation is carried out with respect to nil, i.e., no object, and the 
	invocation is not logged."

	^self evaluate: textOrString for: nil logged: false! !

!Compiler class methodsFor: 'evaluating'!
evaluate: textOrString for: anObject logged: logFlag 
	"See Compiler|evaluate:for:notifying:logged:. If a compilation error occurs, 
	a Syntax Error view is created rather than notifying any requestor."

	^self evaluate: textOrString for: anObject notifying: nil logged: logFlag! !

!Compiler class methodsFor: 'evaluating' stamp: 'NS 1/19/2004 09:50'!
evaluate: textOrString for: anObject notifying: aController logged: logFlag
	"Compile and execute the argument, textOrString with respect to the class 
	of anObject. If a compilation error occurs, notify aController. If both 
	compilation and execution are successful then, if logFlag is true, log 
	(write) the text onto a system changes file so that it can be replayed if 
	necessary."

	^ self new
				evaluate: textOrString
				in: nil
				to: anObject
				notifying: aController
				ifFail: [^nil]
				logged: logFlag.! !

!Compiler class methodsFor: 'evaluating'!
evaluate: textOrString logged: logFlag 
	"See Compiler|evaluate:for:notifying:logged:. If a compilation error occurs, 
	a Syntax Error view is created rather than notifying any requestor. 
	Compilation is carried out with respect to nil, i.e., no object."

	^self evaluate: textOrString for: nil logged: logFlag! !

!Compiler class methodsFor: 'evaluating'!
evaluate: textOrString notifying: aController logged: logFlag 
	"See Compiler|evaluate:for:notifying:logged:. Compilation is carried out 
	with respect to nil, i.e., no object."

	^self evaluate: textOrString for: nil notifying: aController logged: logFlag! !

!Compiler class methodsFor: 'evaluating' stamp: 'rss 8/23/2009 12:53'!
format: textOrStream in: aClass notifying: aRequestor
	^self new format: textOrStream in: aClass notifying: aRequestor! !

!Compiler class methodsFor: 'evaluating' stamp: 'nk 2/23/2005 16:53'!
format: textOrStream in: aClass notifying: aRequestor decorated: aBoolean
	^self new format: textOrStream in: aClass notifying: aRequestor decorated: aBoolean! !

!Compiler class methodsFor: 'class initialization' stamp: 'ar 9/5/2009 22:18'!
initialize
	"For the benefit of MC running a required script in the proper order."
	"self recompileAll."! !

!Compiler class methodsFor: 'utilities' stamp: 'jmv 12/7/2009 22:58'!
recompileAll
	"Recompile all classes, starting with given name."

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


! !

!Compiler class methodsFor: 'utilities' stamp: 'sd 9/25/2004 15:07'!
recompileAllFrom: firstName 
	"Recompile all classes, starting with given name."

	Smalltalk forgetDoIts.
	Smalltalk allClassesDo: 
		[:class | class name >= firstName
			ifTrue: 
				[Transcript show: class name; cr.
				class compileAll]]

	"Compiler recompileAllFrom: 'AAABodyShop'."
! !


!CompilerExceptionsTest methodsFor: 'as yet unclassified' stamp: 'cwp 8/25/2009 20:27'!
griffle | goo |! !

!CompilerExceptionsTest methodsFor: 'emulating' stamp: 'cwp 8/25/2009 20:23'!
select
	! !

!CompilerExceptionsTest methodsFor: 'emulating' stamp: 'cwp 8/25/2009 20:23'!
selectFrom: start to: end 
	! !

!CompilerExceptionsTest methodsFor: 'emulating' stamp: 'cwp 8/25/2009 20:22'!
selectionInterval
	^ 1 to: 0! !

!CompilerExceptionsTest methodsFor: 'emulating' stamp: 'cwp 8/25/2009 20:26'!
text
	^ self unusedVariableSource! !

!CompilerExceptionsTest methodsFor: 'tests' stamp: 'cwp 8/25/2009 20:22'!
testUndeclaredVariable
	self 
		should: 
			[self class 
				compile: 'griffle ^ goo'
				notifying: self]
		raise: UndeclaredVariable! !

!CompilerExceptionsTest methodsFor: 'tests' stamp: 'cwp 8/25/2009 20:24'!
testUndefinedVariable
	self 
		should: 
			[self class 
				compile: 'griffle | goo | ^ goo'
				notifying: self]
		raise: UndefinedVariable! !

!CompilerExceptionsTest methodsFor: 'tests' stamp: 'cwp 8/25/2009 20:25'!
testUnknownSelector
	self 
		should: 
			[self class 
				compile: 'griffle self reallyHopeThisIsntImplementedAnywhere'
				notifying: self]
		raise: UnknownSelector! !

!CompilerExceptionsTest methodsFor: 'tests' stamp: 'cwp 8/25/2009 20:27'!
testUnusedVariable
	self 
		should: 
			[self class 
				compile: self unusedVariableSource
				notifying: self]
		raise: UnusedVariable! !

!CompilerExceptionsTest methodsFor: 'private' stamp: 'cwp 8/25/2009 20:28'!
unusedVariableSource
	^ 'griffle 
		| goo |
		^ nil'! !


!CompilerTest methodsFor: 'literals' stamp: 'nice 12/3/2007 22:20'!
testScaledDecimalLiterals
	"Equal ScaledDecimal with different scales should use different slots
	This is related to http://bugs.squeak.org/view.php?id=6797"
	
	"This correctly works when evaluated separately"
	self deny: (Compiler evaluate: '0.5s1') scale = (Compiler evaluate: '0.5s2') scale.
	
	"But not when evaluated together if literal reduction is too agressive"
	self deny: (Compiler evaluate: '0.5s1 scale =  0.5s2 scale').! !


!ContextCompilationTest methodsFor: 'tests' stamp: 'eem 6/19/2008 10:11'!
testVariablesAndOffsetsDo

	"ContextCompilationTest new testVariablesAndOffsetsDo"
	| contextClasses |
	contextClasses := ContextPart withAllSuperclasses, ContextPart allSubclasses asArray.
	contextClasses do:
		[:class|
		class variablesAndOffsetsDo:
			[:var :offset|
			self assert: offset < 0.
			self assert: (class instVarNameForIndex: offset negated) == var]].

	InstructionStream withAllSuperclasses, InstructionStream allSubclasses asArray do:
		[:class|
		(contextClasses includes: class) ifFalse:
			[class variablesAndOffsetsDo:
				[:var :offset|
				(InstructionStream instVarNames includes: var) ifFalse:
					[self assert: offset > 0.
					 self assert: (class instVarNameForIndex: offset) == var]]]]! !


!Decompiler methodsFor: 'control' stamp: 'tao 8/20/97 22:51'!
blockForCaseTo: end
	"Decompile a range of code as in statementsForCaseTo:, but return a block node."
	| exprs block oldBase |
	oldBase := blockStackBase.
	blockStackBase := stack size.
	exprs := self statementsForCaseTo: end.
	block := constructor codeBlock: exprs returns: lastReturnPc = lastPc.
	blockStackBase := oldBase.
	lastReturnPc := -1.  "So as not to mislead outer calls"
	^block! !

!Decompiler methodsFor: 'control'!
blockTo: end
	"Decompile a range of code as in statementsTo:, but return a block node."
	| exprs block oldBase |
	oldBase := blockStackBase.
	blockStackBase := stack size.
	exprs := self statementsTo: end.
	block := constructor codeBlock: exprs returns: lastReturnPc = lastPc.
	blockStackBase := oldBase.
	lastReturnPc := -1.  "So as not to mislead outer calls"
	^block! !

!Decompiler methodsFor: 'control' stamp: 'eem 5/29/2008 13:16'!
checkForBlock: receiver selector: selector arguments: arguments
	selector == #blockCopy: ifTrue:
		[^self checkForBlockCopy: receiver].
	self assert: selector == #closureCopy:copiedValues:.
	^self checkForClosureCopy: receiver arguments: arguments! !

!Decompiler methodsFor: 'control' stamp: 'eem 7/29/2008 17:42'!
checkForBlockCopy: receiver
	"We just saw a blockCopy: message. Check for a following block."

	| savePc jump args argPos block |
	receiver == constructor codeThisContext ifFalse: [^false].
	savePc := pc.
	(jump := self interpretJump) ifNil:
		[pc := savePc.  ^false].
	self sawBlueBookBlock.
	"Definitely a block"
	jump := jump + pc.
	argPos := statements size.
	[self willStorePop]
		whileTrue:
			[stack addLast: ArgumentFlag.  "Flag for doStore:"
			self interpretNextInstructionFor: self].
	args := Array new: statements size - argPos.
	1 to: args size do:  "Retrieve args"
		[:i | args at: i put: statements removeLast.
		(args at: i) scope: -1  "flag args as block temps"].
	block := self blockTo: jump.
	stack addLast: (constructor codeArguments: args block: block).
	^true! !

!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: 'eem 7/1/2009 14:37'!
doClosureCopyCopiedValues: blockCopiedValues numArgs: numArgs blockSize: blockSize
	| savedTemps savedTempVarCount savedNumLocalTemps
	  jump blockArgs blockTemps blockTempsOffset block |
	savedTemps := tempVars.
	savedTempVarCount := tempVarCount.
	savedNumLocalTemps := numLocalTemps.
	jump := blockSize + 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: 't', (tempVarCount + i) printString)
								  beBlockArg].
			blockTemps := (1 to: numLocalTemps) collect:
							[:i| constructor
									codeTemp: i + blockTempsOffset - 1
									named: 't', (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).
	tempVars := savedTemps.
	tempVarCount := savedTempVarCount.
	numLocalTemps := savedNumLocalTemps! !

!Decompiler methodsFor: 'control' stamp: 'ls 1/28/2004 13:29'!
statementsForCaseTo: end
	"Decompile the method from pc up to end and return an array of
	expressions. If at run time this block will leave a value on the stack,
	set hasValue to true. If the block ends with a jump or return, set exit
	to the destination of the jump, or the end of the method; otherwise, set
	exit = end. Leave pc = end.
	Note that stack initially contains a CaseFlag which will be removed by
	a subsequent Pop instruction, so adjust the StackPos accordingly."

	| blockPos stackPos |
	blockPos := statements size.
	stackPos := stack size - 1. "Adjust for CaseFlag"
	[pc < end]
		whileTrue:
			[lastPc := pc.  limit := end.  "for performs"
			self interpretNextInstructionFor: self].
	"If there is an additional item on the stack, it will be the value
	of this block."
	(hasValue := stack size > stackPos)
		ifTrue:
			[stack last == CaseFlag
				ifFalse: [ statements addLast: stack removeLast] ].
	lastJumpPc = lastPc ifFalse: [exit := pc].
	caseExits add: exit.
	^self popTo: blockPos! !

!Decompiler methodsFor: 'control'!
statementsTo: end
	"Decompile the method from pc up to end and return an array of
	expressions. If at run time this block will leave a value on the stack,
	set hasValue to true. If the block ends with a jump or return, set exit
	to the destination of the jump, or the end of the method; otherwise, set
	exit = end. Leave pc = end."

	| blockPos stackPos t |
	blockPos := statements size.
	stackPos := stack size.
	[pc < end]
		whileTrue:
			[lastPc := pc.  limit := end.  "for performs"
			self interpretNextInstructionFor: self].
	"If there is an additional item on the stack, it will be the value
	of this block."
	(hasValue := stack size > stackPos)
		ifTrue:
			[statements addLast: stack removeLast].
	lastJumpPc = lastPc ifFalse: [exit := pc].
	^self popTo: blockPos! !

!Decompiler methodsFor: 'instruction decoding'!
blockReturnTop
	"No action needed"! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 9/29/2008 15:02'!
case: dist
	"statements = keyStmts CascadeFlag keyValueBlock ... keyStmts"

	| nextCase thenJump stmtStream elements b node cases otherBlock myExits |
	nextCase := pc + dist.

	"Now add CascadeFlag & keyValueBlock to statements"
	statements addLast: stack removeLast.
	stack addLast: CaseFlag. "set for next pop"
	statements addLast: (self blockForCaseTo: nextCase).

	stack last == CaseFlag
		ifTrue: "Last case"
			["ensure jump is within block (in case thenExpr returns wierdly I guess)"
			stack removeLast. "get rid of CaseFlag"
			stmtStream := ReadStream on: (self popTo: stack removeLast).
			
			elements := OrderedCollection new.
			b := OrderedCollection new.
			[stmtStream atEnd] whileFalse:
				[(node := stmtStream next) == CascadeFlag
					ifTrue:
						[elements addLast: (constructor
							codeMessage: (constructor codeBlock: b returns: false)
							selector: (constructor codeSelector: #-> code: #macro)
							arguments: (Array with: stmtStream next)).
						 b := OrderedCollection new]
					ifFalse: [b addLast: node]].
			b size > 0 ifTrue: [self error: 'Bad cases'].
			cases := constructor codeBrace: elements.
			
			"try find the end of the case"
			myExits := caseExits removeLast: elements size.
			myExits := myExits reject: [ :e | e isNil or: [ e < 0 or: [ e > method endPC ] ] ].
			thenJump := myExits isEmpty
							ifTrue: [ nextCase ]
							ifFalse: [ myExits max ].
			
			otherBlock := self blockTo: thenJump.
			stack addLast:
				(constructor
					codeMessage: stack removeLast
					selector: (constructor codeSelector: #caseOf:otherwise: code: #macro)
					arguments: (Array with: cases with: otherBlock))].! !

!Decompiler methodsFor: 'instruction decoding'!
doDup

	stack last == CascadeFlag
		ifFalse:
			["Save position and mark cascade"
			stack addLast: statements size.
			stack addLast: CascadeFlag].
	stack addLast: CascadeFlag! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'di 2/5/2000 09:34'!
doPop

	stack isEmpty ifTrue:
		["Ignore pop in first leg of ifNil for value"
		^ self].
	stack last == CaseFlag
		ifTrue: [stack removeLast]
		ifFalse: [statements addLast: stack removeLast].! !

!Decompiler methodsFor: 'instruction decoding'!
doStore: stackOrBlock
	"Only called internally, not from InstructionStream. StackOrBlock is stack
	for store, statements for storePop."

	| var expr |
	var := stack removeLast.
	expr := stack removeLast.
	stackOrBlock addLast: (expr == ArgumentFlag
		ifTrue: [var]
		ifFalse: [constructor codeAssignTo: var value: expr])! !

!Decompiler methodsFor: 'instruction decoding'!
jump: dist

	exit := pc + dist.
	lastJumpPc := lastPc! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 7/1/2009 10:35'!
jump: dist if: condition

	| savePc sign elsePc elseStart end cond ifExpr thenBlock elseBlock
	  thenJump elseJump condHasValue isIfNil saveStack blockBody |
	stack last == CascadeFlag ifTrue: [^ self case: dist].
	elsePc := lastPc.
	elseStart := pc + dist.
	end := limit.
	"Check for bfp-jmp to invert condition.
	Don't be fooled by a loop with a null body."
	sign := condition.
	savePc := pc.
	self interpretJump ifNotNil:
		[:elseDist|
		 (elseDist >= 0 and: [elseStart = pc]) ifTrue:
			 [sign := sign not.  elseStart := pc + elseDist]].
	pc := savePc.
	ifExpr := stack removeLast.
	(isIfNil := stack size > 0 and: [stack last == IfNilFlag]) ifTrue:
		[stack removeLast].
	saveStack := stack.
	stack := OrderedCollection new.
	thenBlock := self blockTo: elseStart.
	condHasValue := hasValue or: [isIfNil].
	"ensure jump is within block (in case thenExpr returns)"
	thenJump := exit <= end ifTrue: [exit] ifFalse: [elseStart].
	"if jump goes back, then it's a loop"
	thenJump < elseStart
		ifTrue:
			["Must be a while loop...
			  thenJump will jump to the beginning of the while expr.  In the case of while's
			  with a block in the condition, the while expr should include more than just
			  the last expression: find all the statements needed by re-decompiling."
			stack := saveStack.
			pc := thenJump.
			blockBody := self statementsTo: elsePc.
			"discard unwanted statements from block"
			blockBody size - 1 timesRepeat: [statements removeLast].
			statements addLast:
				(constructor
					codeMessage: (constructor codeBlock: blockBody returns: false)
					selector: (constructor
								codeSelector: (sign
												ifTrue: [#whileFalse:]
												ifFalse: [#whileTrue:])
								code: #macro)
					arguments: { thenBlock }).
			pc := elseStart.
			self convertToDoLoop]
		ifFalse:
			["Must be a conditional..."
			elseBlock := self blockTo: thenJump.
			elseJump := exit.
			"if elseJump is backwards, it is not part of the elseExpr"
			elseJump < elsePc ifTrue:
				[pc := lastPc].
			cond := isIfNil
						ifTrue:
							[constructor
								codeMessage: ifExpr ifNilReceiver
								selector: (constructor
											codeSelector: (sign ifTrue: [#ifNotNil:] ifFalse: [#ifNil:])
											code: #macro)
								arguments: (Array with: thenBlock)]
						ifFalse:
							[constructor
								codeMessage: ifExpr
								selector: (constructor codeSelector: #ifTrue:ifFalse: code: #macro)
								arguments:	(sign
												ifTrue: [{elseBlock. thenBlock}]
												ifFalse: [{thenBlock. elseBlock}])].
			stack := saveStack.
			condHasValue
				ifTrue: [stack addLast: cond]
				ifFalse: [statements addLast: cond]]! !

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

	self pushConstant: value; methodReturnTop! !

!Decompiler methodsFor: 'instruction decoding'!
methodReturnReceiver

	self pushReceiver; methodReturnTop! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 9/26/2008 15:43'!
methodReturnTop
	| last |
	last := stack removeLast "test test" asReturnNode.
	stack size > blockStackBase  "get effect of elided pop before return"
		ifTrue: [statements addLast: stack removeLast].
	exit := pc.
	lastJumpPc := lastReturnPc := lastPc.
	statements addLast: last! !

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

	self pushLiteralVariable: value; doStore: statements! !

!Decompiler methodsFor: 'instruction decoding'!
popIntoReceiverVariable: offset

	self pushReceiverVariable: offset; doStore: statements! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 6/4/2008 14:44'!
popIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
	self sawClosureBytecode.
	self pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex; doStore: statements! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 8/4/2009 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: 't', (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'!
pushActiveContext

	stack addLast: constructor codeThisContext! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 9/5/2008 14:27'!
pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
	| copiedValues |
	self sawClosureBytecode.
	numCopied > 0
		ifTrue:
			[copiedValues := Array new: numCopied.
			 numLocalTemps == #decompileBlock: ifTrue: "Hack fake temps for copied values"
				[1 to: numCopied do: [:i| stack addLast: (constructor codeTemp: i - 1)]].
			 numCopied to: 1 by: -1 do:
				[:i|
				copiedValues at: i put: stack removeLast]]
		ifFalse:
			[copiedValues := #()].
	self doClosureCopyCopiedValues: copiedValues numArgs: numArgs blockSize: blockSize! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 6/4/2008 14:44'!
pushConsArrayWithElements: numElements 
	| array |
	self sawClosureBytecode.
	array := Array new: numElements.
	numElements to: 1 by: -1 do:
		[:i|
		array at: i put: stack removeLast].
	stack addLast: (constructor codeBrace: array)! !

!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'!
pushLiteralVariable: assoc

	stack addLast: (constructor codeAnyLitInd: assoc)! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 6/4/2008 14:45'!
pushNewArrayOfSize: size
	self sawClosureBytecode.
	stack addLast: #pushNewArray -> (Array new: size)! !

!Decompiler methodsFor: 'instruction decoding'!
pushReceiver

	stack addLast: (constTable at: 1)! !

!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: 'instruction decoding' stamp: 'eem 9/25/2008 09:48'!
pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
	self sawClosureBytecode.
	stack addLast: ((tempVars at: tempVectorIndex + 1) remoteTemps at: remoteTempIndex + 1)! !

!Decompiler methodsFor: 'instruction decoding'!
pushTemporaryVariable: offset

	stack addLast: (tempVars at: offset + 1)! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 9/29/2008 19:23'!
send: selector super: superFlag numArgs: numArgs

	| args rcvr selNode msgNode messages |
	args := Array new: numArgs.
	(numArgs to: 1 by: -1) do:
		[:i | args at: i put: stack removeLast].
	rcvr := stack removeLast.
	superFlag ifTrue: [rcvr := constructor codeSuper].
	((#(blockCopy: closureCopy:copiedValues:) includes: selector)
	  and: [self checkForBlock: rcvr selector: selector arguments: args]) ifFalse:
		[selNode := constructor codeAnySelector: selector.
		rcvr == CascadeFlag
			ifTrue:
				["May actually be a cascade or an ifNil: for value."
				self willJumpIfFalse
					ifTrue: "= generated by a case macro"
						[selector == #= ifTrue:
							[" = signals a case statement..."
							statements addLast: args first.
							stack addLast: rcvr. "restore CascadeFlag"
							^ self].
						selector == #== ifTrue:
							[" == signals an ifNil: for value..."
							stack removeLast; removeLast.
							rcvr := stack removeLast.
							stack addLast: IfNilFlag;
								addLast: (constructor
									codeMessage: rcvr
									selector: selNode
									arguments: args).
							^ self]]
					ifFalse:
						[(self willJumpIfTrue and: [selector == #==]) ifTrue:
							[" == signals an ifNotNil: for value..."
							stack removeLast; removeLast.
							rcvr := stack removeLast.
							stack addLast: IfNilFlag;
								addLast: (constructor
									codeMessage: rcvr
									selector: selNode
									arguments: args).
							^ self]].
				msgNode := constructor
								codeCascadedMessage: selNode
								arguments: args.
				stack last == CascadeFlag ifFalse:
					["Last message of a cascade"
					statements addLast: msgNode.
					messages := self popTo: stack removeLast.  "Depth saved by first dup"
					msgNode := constructor
									codeCascade: stack removeLast
									messages: messages]]
			ifFalse:
				[msgNode := constructor
							codeMessage: rcvr
							selector: selNode
							arguments: args].
		stack addLast: msgNode]! !

!Decompiler methodsFor: 'instruction decoding'!
storeIntoLiteralVariable: assoc

	self pushLiteralVariable: assoc; doStore: stack! !

!Decompiler methodsFor: 'instruction decoding'!
storeIntoReceiverVariable: offset

	self pushReceiverVariable: offset; doStore: stack! !

!Decompiler methodsFor: 'instruction decoding' stamp: 'eem 6/4/2008 14:45'!
storeIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
	self sawClosureBytecode.
	self pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex; doStore: stack! !

!Decompiler methodsFor: 'instruction decoding'!
storeIntoTemporaryVariable: offset

	self pushTemporaryVariable: offset; doStore: stack! !

!Decompiler methodsFor: 'private' stamp: 'eem 9/6/2008 08:45'!
blockScopeRefersOnlyOnceToTemp: offset
	| nRefs byteCode extension scanner scan |
	scanner := InstructionStream on: method.
	nRefs := 0.
	scan := offset <= 15
				ifTrue:
					[byteCode := 16 + offset.
					 [:instr |
					  instr = byteCode ifTrue:
						[nRefs := nRefs + 1].
					  nRefs > 1]]
				ifFalse:
					[extension := 64 + offset.
					 [:instr |
					  (instr = 128 and: [scanner followingByte = extension]) ifTrue:
						[nRefs := nRefs + 1].
					   nRefs > 1]].
	self scanBlockScopeFor: pc from: method initialPC to: method endPC with: scan scanner: scanner.
	^nRefs = 1! !

!Decompiler methodsFor: 'private' stamp: 'eem 10/20/2008 15:49'!
constructorForMethod: aMethod
	^(aMethod isBlueBookCompiled
		ifTrue: [DecompilerConstructor]
		ifFalse: [DecompilerConstructorForClosures]) new! !

!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: 'private' stamp: 'eem 5/13/2008 15:41'!
interpretNextInstructionFor: client

	| code varNames |

"Change false here will trace all state in Transcript."
true ifTrue: [^ super interpretNextInstructionFor: client].

	varNames := self class allInstVarNames.
	code := (self method at: pc) radix: 16.
	Transcript cr; cr; print: pc; space;
		nextPutAll: '<' , (code copyFrom: 4 to: code size), '>'.
	8 to: varNames size do:
		[:i | i <= 10 ifTrue: [Transcript cr]
				ifFalse: [Transcript space; space].
		Transcript nextPutAll: (varNames at: i);
				nextPutAll: ': '; print: (self instVarAt: i)].
	Transcript endEntry.
	^ super interpretNextInstructionFor: client! !

!Decompiler methodsFor: 'private' stamp: 'di 2/6/2000 10:55'!
methodRefersOnlyOnceToTemp: offset
	| nRefs byteCode extension scanner |
	nRefs := 0.
	offset <= 15
		ifTrue:
			[byteCode := 16 + offset.
			(InstructionStream on: method) scanFor:
				[:instr | instr = byteCode ifTrue: [nRefs := nRefs + 1].
				nRefs > 1]]
		ifFalse:
			[extension := 64 + offset.
			scanner := InstructionStream on: method.
			scanner scanFor:
				[:instr | (instr = 128 and: [scanner followingByte = extension])
							ifTrue: [nRefs := nRefs + 1].
				nRefs > 1]].
	^ nRefs = 1
! !

!Decompiler methodsFor: 'private'!
popTo: oldPos

	| t |
	t := Array new: statements size - oldPos.
	(t size to: 1 by: -1) do:
		[:i | t at: i put: statements removeLast].
	^t! !

!Decompiler methodsFor: 'private' stamp: 'di 12/26/1998 21:29'!
quickMethod
	| |
	method isReturnSpecial
		ifTrue: [^ constructor codeBlock:
				(Array with: (constTable at: method primitive - 255)) returns: true].
	method isReturnField
		ifTrue: [^ constructor codeBlock:
				(Array with: (constructor codeInst: method returnField)) returns: true].
	self error: 'improper short method'! !

!Decompiler methodsFor: 'private' stamp: 'eem 7/29/2008 17:41'!
sawBlueBookBlock
	constructor isForClosures ifTrue:
		[constructor primitiveChangeClassTo: DecompilerConstructor new]! !

!Decompiler methodsFor: 'private' stamp: 'eem 6/4/2008 14:43'!
sawClosureBytecode
	constructor isForClosures ifFalse:
		[constructor primitiveChangeClassTo: DecompilerConstructorForClosures new]! !

!Decompiler methodsFor: 'private' stamp: 'eem 9/6/2008 09:27'!
scanBlockScopeFor: refpc from: startpc to: endpc with: scan scanner: scanner
	| bsl maybeBlockSize |
	bsl := BlockStartLocator new.
	scanner pc: startpc.
	[scanner pc <= endpc] whileTrue:
		[refpc = scanner pc ifTrue:
			[scanner pc: startpc.
			 [scanner pc <= endpc] whileTrue:
				[(scan value: scanner firstByte) ifTrue:
					[^endpc].
				 (maybeBlockSize := scanner interpretNextInstructionFor: bsl) isInteger ifTrue:
					[scanner pc: scanner pc + maybeBlockSize]].
			   ^self].
		 (maybeBlockSize := scanner interpretNextInstructionFor: bsl) isInteger ifTrue:
			[refpc <= (scanner pc + maybeBlockSize)
				ifTrue: [^self scanBlockScopeFor: refpc from: scanner pc to: scanner pc + maybeBlockSize with: scan scanner: scanner]
				ifFalse: [scanner pc: scanner pc + maybeBlockSize]]]! !

!Decompiler methodsFor: 'public access'!
decompile: aSelector in: aClass 
	"See Decompiler|decompile:in:method:. The method is found by looking up 
	the message, aSelector, in the method dictionary of the class, aClass."

	^self
		decompile: aSelector
		in: aClass
		method: (aClass compiledMethodAt: aSelector)! !

!Decompiler methodsFor: 'public access' stamp: 'eem 10/20/2008 14:09'!
decompile: aSelector in: aClass method: aMethod
	"Answer a MethodNode that is the root of the parse tree for the 
	argument, aMethod, which is the CompiledMethod associated with the 
	message, aSelector. Variables are determined with respect to the 
	argument, aClass."

	^self
		decompile: aSelector
		in: aClass
		method: aMethod
		using: (self constructorForMethod: aMethod)! !

!Decompiler methodsFor: 'public access' stamp: 'eem 7/1/2009 14:45'!
decompile: aSelector in: aClass method: aMethod using: aConstructor

	| block node |
	constructor := aConstructor.
	method := aMethod.
	self initSymbols: aClass.  "create symbol tables"
	method isQuick
		ifTrue: [block := self quickMethod]
		ifFalse: 
			[stack := OrderedCollection new: method frameSize.
			caseExits := OrderedCollection new.
			statements := OrderedCollection new: 20.
			numLocalTemps := 0.
			super method: method pc: method initialPC.
			"skip primitive error code store if necessary"
			(method primitive ~= 0 and: [self willStore]) ifTrue:
				[pc := pc + 2.
				 tempVars := tempVars asOrderedCollection].
			block := self blockTo: method endPC + 1.
			stack isEmpty ifFalse: [self error: 'stack not empty']].
	node := constructor
				codeMethod: aSelector
				block: block
				tempVars: tempVars
				primitive: method primitive
				class: aClass.
	method primitive > 0 ifTrue:
		[node removeAndRenameLastTempIfErrorCode].
	^node! !

!Decompiler methodsFor: 'public access' stamp: 'tfel 9/15/2009 23:39'!
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 source |
	(home := aBlock home) ifNil: [^ nil].
	method := home method.
	(homeClass := home methodClass) == #unknown ifTrue: [^ nil].
	constructor := self constructorForMethod: aBlock method.
	method fileIndex ~~ 0 ifTrue: "got any source code?"
		[source := [method getSourceFromFile]
						on: Error
						do: [:ex | ^ nil].
		 methodNode := [homeClass compilerClass new
								parse: source
								in: homeClass
								notifying: nil]
							on: (Smalltalk classNamed: 'SyntaxErrorNotification')
							do: [:ex | ^ nil].
		 self withTempNames: methodNode schematicTempNamesString].
	self initSymbols: homeClass.
	startpc := aBlock startpc.
	end := aBlock isClosure
				ifTrue: [(method at: startpc - 2) * 256
					  + (method at: startpc - 1) + startpc - 1]
				ifFalse:
					[(method at: startpc - 2) \\ 16 - 4 * 256
					+ (method at: startpc - 1) + startpc - 1].
	stack := OrderedCollection new: method frameSize.
	caseExits := OrderedCollection new.
	statements := OrderedCollection new: 20.
	super
		method: method
		pc: (aBlock isClosure ifTrue: [startpc - 4] ifFalse: [startpc - 5]).
	aBlock isClosure ifTrue:
		[numLocalTemps := #decompileBlock: "Get pushClosureCopy... to hack fake temps for copied values"].
	blockNode := self blockTo: end.
	stack isEmpty ifFalse: [self error: 'stack not empty'].
	^blockNode statements first! !

!Decompiler methodsFor: 'public access'!
tempAt: offset
	"Needed by BraceConstructor<PopIntoTemporaryVariable"

	^tempVars at: offset + 1! !

!Decompiler methodsFor: 'initialize-release' stamp: 'eem 7/1/2009 14:45'!
initSymbols: aClass
	constructor method: method class: aClass literals: method literals.
	constTable := constructor codeConstants.
	instVars := Array new: aClass instSize.
	tempVarCount := method numTemps.
	"(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| 't', 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! !

!Decompiler methodsFor: 'initialize-release' stamp: 'eem 6/29/2009 09:41'!
withTempNames: tempNames "<Array|String>"
	"Optionally initialize the temp names to be used when decompiling.
	 For backward-copmpatibility, if tempNames is an Array it is a single
	 vector of temp names, probably for a blue-book-compiled method.
	 If tempNames is a string it is a schematic string that encodes the
	 layout of temp vars in the method and any closures/blocks within it.
	 Decoding encoded tempNames is done in decompile:in:method:using:
	 which has the method from which to derive blockStarts.
	 See e.g. BytecodeEncoder>>schematicTempNamesString for syntax."
	tempVars := tempNames! !


!Decompiler class methodsFor: 'class initialization' stamp: 'di 1/28/2000 22:21'!
initialize

	CascadeFlag := 'cascade'.  "A unique object"
	CaseFlag := 'case'. "Ditto"
	ArgumentFlag := 'argument'.  "Ditto"
	IfNilFlag := 'ifNil'.  "Ditto"

	"Decompiler initialize"! !

!Decompiler class methodsFor: 'testing' stamp: 'jmv 12/7/2009 22:38'!
recompileAllTest
	"[Decompiler recompileAllTest]"
	"decompile every method and compile it back; if the decompiler is correct then the system should keep running.  :)"
	
	Smalltalk allBehaviorsDo: [ :behavior |
		Utilities informUser: (behavior printString) during: [
			behavior selectors do: [ :sel |
				| decompiled ast compiled |
				decompiled := Decompiler new decompile: sel in: behavior.
				ast := Compiler new compile: decompiled in: behavior notifying: nil ifFail: [ self error: 'failed' ].
				compiled := ast generate: (behavior compiledMethodAt: sel) trailer.
				behavior addSelector: sel withMethod: compiled. ] ] ]! !


!DecompilerTests methodsFor: 'utilities' stamp: 'sd 9/25/2004 15:30'!
blockingClasses


	^ #(CompiledMethod)! !

!DecompilerTests methodsFor: 'utilities' stamp: 'eem 6/11/2009 17:24'!
checkDecompileMethod: oldMethod
	
	| cls selector oldMethodNode methodNode newMethod oldCodeString newCodeString |
	cls := oldMethod methodClass.
	selector := oldMethod selector.
	oldMethodNode := cls decompilerClass new
						decompile: selector
						in: cls
						method: oldMethod.
	[oldMethodNode properties includesKey: #warning] whileTrue:
		[oldMethodNode properties removeKey: #warning].
	oldCodeString := oldMethodNode decompileString.
	methodNode := [cls compilerClass new
						compile: oldCodeString
						in: cls
						notifying: nil
						ifFail: []]
						on: SyntaxErrorNotification
						do: [:ex|
							ex errorMessage = 'Cannot store into' ifTrue:
								[ex return: #badStore].
							ex pass].
	"Ignore cannot store into block arg errors; they're not our issue."
	methodNode ~~ #badStore ifTrue:
		[newMethod := methodNode generate: #(0 0 0 0).
		 newCodeString := (cls decompilerClass new
							decompile: selector
							in: cls
							method: newMethod) decompileString.
		 "(StringHolder new textContents:
			(TextDiffBuilder buildDisplayPatchFrom: oldCodeString to: newCodeString))
				openLabel: 'Decompilation Differences for ', cls name,'>>',selector"
		 "(StringHolder new textContents:
			(TextDiffBuilder buildDisplayPatchFrom: oldMethod abstractSymbolic to: newMethod abstractSymbolic))
				openLabel: 'Bytecode Differences for ', cls name,'>>',selector"
		 self assert: oldCodeString = newCodeString
			description: cls name asString, ' ', selector asString
			resumable: true]! !

!DecompilerTests methodsFor: 'utilities' stamp: 'nice 10/23/2009 22:49'!
decompileClassesSelect: aBlock
	
	(Smalltalk classNames select: aBlock) do:
		[:cn | | cls |
		cls := Smalltalk at: cn.
		Smalltalk garbageCollect.
		 Transcript cr; show: cn.
		 cls selectorsDo:
			[:selector | | methodNode oldMethod newMethod oldCodeString newCodeString |
			(self isFailure: cls sel: selector) ifFalse:
				[" to help making progress
					(self
						isStoredProblems: cls theNonMetaClass
						sel: selector
						meta: cls isMeta)
					ifFalse: [ "
				Transcript nextPut: $.; flush.
				self checkDecompileMethod: (cls compiledMethodAt: selector)]]]! !

!DecompilerTests methodsFor: 'utilities' stamp: 'eem 11/10/2008 15:30'!
decompilerFailures
	"here is the list of failures: DNU resulting in trying to decompile the following methods"

	^ #((BalloonEngineSimulation circleCosTable "-0.3826834323650903 => -0.38268343236509 or -0.3826834323650902")
		 (BalloonEngineSimulation circleSinTable "-0.3826834323650903 => -0.38268343236509 or -0.3826834323650902")
		 (GeniePlugin primSameClassAbsoluteStrokeDistanceMyPoints:otherPoints:myVectors:otherVectors:mySquaredLengths:otherSquaredLengths:myAngles:otherAngles:maxSizeAndReferenceFlag:rowBase:rowInsertRemove:rowInsertRemoveCount: "Cannot compile -- stack including temps is too deep")
		(QPickable2D pick:) "foo ifTrue: [^bar] ifFalse: [^baz]. ^huh?"
		(QUsersPane userEntryCompare:to:) "foo ifTrue: [^bar] ifFalse: [^baz]. ^huh?"
		(TShaderProgram vertexStrings) "foo ifTrue: []. => foo. => ."
		(TShaderProgram fragmentStrings) "foo ifTrue: []. => foo. => ."
		(TWindow zoomWindow:) "foo ifTrue: [^bar] ifFalse: [^baz]. ^huh?"

		"(PNMReadWriter nextImage) (Collection #ifEmpty:ifNotEmpty:) (Collection #ifEmpty:) (Collection #ifNotEmpty:ifEmpty:) (Text #alignmentAt:ifAbsent:) (ObjectWithDocumentation propertyAt:ifAbsent:)")! !

!DecompilerTests methodsFor: 'utilities' stamp: 'eem 11/10/2008 16:52'!
isFailure: cls sel: selector 
	"self new isKnowProblem: PNMReaderWriter sel: #nextImage"
	"#((PNMReadWriter nextImage)) includes: {PNMReadWriter
	name asSymbol . #nextImage}."
	^(#(#DoIt #DoItIn:) includes: selector)
	   or: [self decompilerFailures includes: {cls name asSymbol. selector}]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesAAtoAM
	self decompileClassesSelect: [:cn| cn first = $A and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesANtoAZ
	self decompileClassesSelect: [:cn| cn first = $A and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesBAtoBM
	self decompileClassesSelect: [:cn| cn first = $B and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesBNtoBZ
	self decompileClassesSelect: [:cn| cn first = $B and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesCAtoCM
	self decompileClassesSelect: [:cn| cn first = $C and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesCNtoCZ
	self decompileClassesSelect: [:cn| cn first = $C and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesDAtoDM
	self decompileClassesSelect: [:cn| cn first = $D and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesDNtoDZ
	self decompileClassesSelect: [:cn| cn first = $D and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesEAtoEM
	self decompileClassesSelect: [:cn| cn first = $E and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesENtoEZ
	self decompileClassesSelect: [:cn| cn first = $E and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesFAtoFM
	self decompileClassesSelect: [:cn| cn first = $F and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesFNtoFZ
	self decompileClassesSelect: [:cn| cn first = $F and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesGAtoGM
	self decompileClassesSelect: [:cn| cn first = $G and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesGNtoGZ
	self decompileClassesSelect: [:cn| cn first = $G and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesHAtoHM
	self decompileClassesSelect: [:cn| cn first = $H and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesHNtoHZ
	self decompileClassesSelect: [:cn| cn first = $H and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesIAtoIM
	self decompileClassesSelect: [:cn| cn first = $I and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesINtoIZ
	self decompileClassesSelect: [:cn| cn first = $I and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesJAtoJM
	self decompileClassesSelect: [:cn| cn first = $J and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesJNtoJZ
	self decompileClassesSelect: [:cn| cn first = $J and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesKAtoKM
	self decompileClassesSelect: [:cn| cn first = $K and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesKNtoKZ
	self decompileClassesSelect: [:cn| cn first = $K and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesLAtoLM
	self decompileClassesSelect: [:cn| cn first = $L and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesLNtoLZ
	self decompileClassesSelect: [:cn| cn first = $L and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesMAtoMM
	self decompileClassesSelect: [:cn| cn first = $M and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesMNtoMZ
	self decompileClassesSelect: [:cn| cn first = $M and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesNAtoNM
	self decompileClassesSelect: [:cn| cn first = $N and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesNNtoNZ
	self decompileClassesSelect: [:cn| cn first = $N and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesOAtoOM
	self decompileClassesSelect: [:cn| cn first = $O and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesONtoOZ
	self decompileClassesSelect: [:cn| cn first = $O and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesPAtoPM
	self decompileClassesSelect: [:cn| cn first = $P and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesPNtoPZ
	self decompileClassesSelect: [:cn| cn first = $P and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesQAtoQM
	self decompileClassesSelect: [:cn| cn first = $Q and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesQNtoQZ
	self decompileClassesSelect: [:cn| cn first = $Q and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesRAtoRM
	self decompileClassesSelect: [:cn| cn first = $R and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesRNtoRZ
	self decompileClassesSelect: [:cn| cn first = $R and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesSAtoSM
	self decompileClassesSelect: [:cn| cn first = $S and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesSNtoSZ
	self decompileClassesSelect: [:cn| cn first = $S and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesTAtoTM
	self decompileClassesSelect: [:cn| cn first = $T and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesTNtoTZ
	self decompileClassesSelect: [:cn| cn first = $T and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesUAtoUM
	self decompileClassesSelect: [:cn| cn first = $U and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesUNtoUZ
	self decompileClassesSelect: [:cn| cn first = $U and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesVAtoVM
	self decompileClassesSelect: [:cn| cn first = $V and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesVNtoVZ
	self decompileClassesSelect: [:cn| cn first = $V and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesWAtoWM
	self decompileClassesSelect: [:cn| cn first = $W and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesWNtoWZ
	self decompileClassesSelect: [:cn| cn first = $W and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesXAtoXM
	self decompileClassesSelect: [:cn| cn first = $X and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesXNtoXZ
	self decompileClassesSelect: [:cn| cn first = $X and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesYAtoYM
	self decompileClassesSelect: [:cn| cn first = $Y and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesYNtoYZ
	self decompileClassesSelect: [:cn| cn first = $Y and: [cn second asUppercase > $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesZAtoZM
	self decompileClassesSelect: [:cn| cn first = $Z and: [cn second asUppercase <= $M]]! !

!DecompilerTests methodsFor: 'tests' stamp: 'eem 9/23/2008 11:16'!
testDecompilerInClassesZNtoZZ
	self decompileClassesSelect: [:cn| cn first = $Z and: [cn second asUppercase > $M]]! !


!DecompilerTestFailuresCollector methodsFor: 'accessing' stamp: 'eem 11/10/2008 15:46'!
assert: aBoolean description: aString resumable: resumableBoolean 
	aBoolean ifFalse: 
		[failures isNil ifTrue:
			[failures := OrderedCollection new].
		 failures addLast: (thisContext sender tempAt: 1) methodReference]! !

!DecompilerTestFailuresCollector methodsFor: 'accessing' stamp: 'eem 11/10/2008 15:47'!
failures
	^failures! !


!Dictionary methodsFor: '*Compiler' stamp: 'ar 5/17/2003 14:07'!
bindingOf: varName
	^self associationAt: varName ifAbsent:[nil]! !

!Dictionary methodsFor: '*Compiler' stamp: 'ar 5/18/2003 20:33'!
bindingsDo: aBlock
	^self associationsDo: aBlock! !


!LiteralDictionary methodsFor: 'testing' stamp: 'nice 8/28/2008 19:26'!
literalEquality: x and: y
	"Check if two literals should be considered equal and reduced to a single literal.
	Delegate this task to the literal themselves, they are aware of their peculiarities and know how to behave."
	
	^ x literalEqual: y
! !

!LiteralDictionary methodsFor: 'as yet unclassified' stamp: 'ul 9/30/2009 14:22'!
scanFor: anObject
	"Scan the key array for the first slot containing either a nil (indicating an empty slot) or an element that matches anObject. Answer the index of that slot or raise an error if no slot is found. This method will be overridden in various subclasses that have different interpretations for matching elements."

	| index start |
	index := start := anObject hash \\ array size + 1.
	[ 
		| element |
		((element := array at: index) == nil or: [
			self literalEquality: element key and: anObject ])
				ifTrue: [ ^index ].
		(index := index \\ array size + 1) = start ] whileFalse.
	self errorNoFreeSpace! !


!MirrorPrimitiveTests methodsFor: 'tests' stamp: 'eem 5/8/2009 09:52'!
testMirrorAt
	| stackpBefore stackpAfter array byteArray |
	stackpBefore := thisContext stackPtr.
	array := { 1. 2. 3 }.
	byteArray := ByteArray with: 1 with: 2 with: 3.
	self assert: (thisContext object: array basicAt: 1) = 1.
	self assert: (thisContext object: byteArray basicAt: 2) = 2.
	thisContext object: array basicAt: 2 put: #two.
	self assert: array = #(1 #two 3).
	thisContext object: byteArray basicAt: 2 put: 222.
	self assert: byteArray asArray = #(1 222 3).
	stackpAfter := thisContext stackPtr.
	self assert: stackpBefore = stackpAfter. "Make sure primitives pop all their arguments"
	self should: [thisContext object: array basicAt: 4] raise: Error.
	self should: [thisContext object: byteArray basicAt: 0] raise: Error.
	self should: [thisContext object: byteArray basicAt: 1 put: -1] raise: Error! !

!MirrorPrimitiveTests methodsFor: 'tests' stamp: 'eem 4/8/2009 19:44'!
testMirrorClass
	| stackpBefore stackpAfter |
	stackpBefore := thisContext stackPtr.
	self assert: (thisContext objectClass: Array new) = Array.
	self assert: (thisContext objectClass: 1) = 1 class.
	self assert: (thisContext objectClass: ProtoObject new) = ProtoObject.
	stackpAfter := thisContext stackPtr.
	self assert: stackpBefore = stackpAfter "Make sure primitives pop all their arguments"! !

!MirrorPrimitiveTests methodsFor: 'tests' stamp: 'eem 5/8/2009 09:54'!
testMirrorEqEq
	| stackpBefore stackpAfter |
	stackpBefore := thisContext stackPtr.
	self assert: (thisContext object: Array new eqeq: Array new) == false.
	self assert: (thisContext object: Array eqeq: Array) == true.
	stackpAfter := thisContext stackPtr.
	self assert: stackpBefore = stackpAfter "Make sure primitives pop all their arguments"! !

!MirrorPrimitiveTests methodsFor: 'tests' stamp: 'eem 4/8/2009 22:45'!
testMirrorInstVarAt
	| stackpBefore stackpAfter array point |
	stackpBefore := thisContext stackPtr.
	array := { 1. 2. 3 }.
	point := Point x: 1 y: 2.
	self assert: (thisContext object: array instVarAt: 1) = 1.
	self assert: (thisContext object: point instVarAt: 2) = 2.
	thisContext object: array instVarAt: 2 put: #two.
	self assert: array = #(1 #two 3).
	thisContext object: point instVarAt: 1 put: 1/2.
	self assert: point = (Point x: 1 / 2 y: 2).
	stackpAfter := thisContext stackPtr.
	self assert: stackpBefore = stackpAfter. "Make sure primitives pop all their arguments"
	self should: [thisContext object: array instVarAt: 4] raise: Error.
	self should: [thisContext object: point instVarAt: 3] raise: Error! !

!MirrorPrimitiveTests methodsFor: 'tests' stamp: 'eem 5/12/2009 21:17'!
testMirrorPerform
	| stackpBefore stackpAfter anInterval |
	stackpBefore := thisContext stackPtr.
	anInterval := 1 to: 2.
	self assert: (thisContext object: anInterval perform:# species withArguments: #() inClass: Interval) == Array.
	self assert: (thisContext object: anInterval perform:# species withArguments: #() inClass: Interval superclass) == Interval.
	self should: [thisContext object: anInterval perform:# species withArguments: #() inClass: Point]
		raise: Error.
	self should: [thisContext object: anInterval perform:# species withArguments: OrderedCollection new inClass: Interval]
		raise: Error.
	stackpAfter := thisContext stackPtr.
	self assert: stackpBefore = stackpAfter "Make sure primitives pop all their arguments"! !

!MirrorPrimitiveTests methodsFor: 'tests' stamp: 'eem 4/8/2009 22:50'!
testMirrorSize
	| stackpBefore stackpAfter |
	stackpBefore := thisContext stackPtr.
	self assert: (thisContext objectSize: #(1 2 3)) = 3.
	self assert: (thisContext objectSize: '123') = 3.
	self assert: (thisContext objectSize: nil) = 0.
	self assert: (thisContext objectSize: 1) = 0.
	stackpAfter := thisContext stackPtr.
	self assert: stackpBefore = stackpAfter. "Make sure primitives pop all their arguments"! !


!ParseNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:36'!
accept: aVisitor
	^self subclassResponsibility! !

!ParseNode methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:44'!
nodesDo: aBlock
	self accept: (ParseNodeEnumerator ofBlock: aBlock)! !

!ParseNode methodsFor: 'tiles' stamp: 'RAA 8/24/1999 13:06'!
currentValueIn: aContext

	^nil! !

!ParseNode methodsFor: 'converting'!
asReturnNode

	^ReturnNode new expr: self! !

!ParseNode methodsFor: 'testing'!
assignmentCheck: encoder at: location
	"For messageNodes masquerading as variables for the debugger.
	For now we let this through - ie we allow stores ev
	into args.  Should check against numArgs, though."
	^ -1! !

!ParseNode methodsFor: 'testing'!
canBeSpecialArgument
	"Can I be an argument of (e.g.) ifTrue:?"

	^false! !

!ParseNode methodsFor: 'testing'!
canCascade

	^false! !

!ParseNode methodsFor: 'testing'!
isArg

	^false! !

!ParseNode methodsFor: 'testing' stamp: 'eem 6/16/2008 09:37'!
isAssignmentNode
	^false! !

!ParseNode methodsFor: 'testing' stamp: 'eem 9/25/2008 12:11'!
isBlockNode
	^false! !

!ParseNode methodsFor: 'testing'!
isComplex
	"Used for pretty printing to determine whether to start a new line"

	^false! !

!ParseNode methodsFor: 'testing'!
isConstantNumber  "Overridden in LiteralNode"
	^false! !

!ParseNode methodsFor: 'testing' stamp: 'md 1/20/2006 16:22'!
isDoIt
	"polymorphic with RBNodes; called by debugger"

	^ false! !

!ParseNode methodsFor: 'testing' stamp: 'eem 7/18/2008 16:22'!
isFutureNode
	^false! !

!ParseNode methodsFor: 'testing' stamp: 'ls 1/29/2004 21:11'!
isJust: node
	^false! !

!ParseNode methodsFor: 'testing' stamp: 'di 4/5/2000 11:14'!
isLiteral

	^ false! !

!ParseNode methodsFor: 'testing' stamp: 'md 7/27/2006 19:14'!
isMessage
	^false! !

!ParseNode methodsFor: 'testing'!
isMessage: selSymbol receiver: rcvrPred arguments: argsPred
	"See comment in MessageNode."

	^false! !

!ParseNode methodsFor: 'testing' stamp: 'ar 7/10/2009 22:42'!
isMessageNode
	^false! !

!ParseNode methodsFor: 'testing'!
isReturnSelf

	^false! !

!ParseNode methodsFor: 'testing'!
isReturningIf

	^false! !

!ParseNode methodsFor: 'testing' stamp: 'tk 8/2/1999 18:39'!
isSelfPseudoVariable	
	"Overridden in VariableNode."
	^false! !

!ParseNode methodsFor: 'testing'!
isSpecialConstant
	^ false! !

!ParseNode methodsFor: 'testing' stamp: 'di 10/12/1999 15:28'!
isTemp
	^ false! !

!ParseNode methodsFor: 'testing'!
isUndefTemp
	^ false! !

!ParseNode methodsFor: 'testing'!
isUnusedTemp
	^ false! !

!ParseNode methodsFor: 'testing' stamp: 'ar 11/19/2002 14:58'!
isVariableNode
	^false! !

!ParseNode methodsFor: 'testing'!
isVariableReference

	^false! !

!ParseNode methodsFor: 'testing'!
nowHasDef  "Ignored in all but VariableNode"! !

!ParseNode methodsFor: 'testing'!
nowHasRef  "Ignored in all but VariableNode"! !

!ParseNode methodsFor: 'testing'!
toDoIncrement: ignored
	"Only meant for Messages or Assignments - else return nil"
	^ nil! !

!ParseNode methodsFor: 'comment'!
comment

	^comment! !

!ParseNode methodsFor: 'comment'!
comment: newComment

	comment := newComment! !

!ParseNode methodsFor: 'code generation'!
emitBranchOn:
condition dist: dist pop: stack on: strm
	stack pop: 1.
	dist = 0 ifTrue: [^ strm nextPut: Pop].
	condition
		ifTrue: [self emitLong: dist code: BtpLong on: strm]
		ifFalse: [self emitShortOrLong: dist code: Bfp on: strm]! !

!ParseNode methodsFor: 'code generation'!
emitForEffect: stack on: strm

	self emitForValue: stack on: strm.
	strm nextPut: Pop.
	stack pop: 1! !

!ParseNode methodsFor: 'code generation'!
emitForReturn: stack on: strm

	self emitForValue: stack on: strm.
	strm nextPut: EndMethod! !

!ParseNode methodsFor: 'code generation'!
emitJump: dist on: strm

	dist = 0 ifFalse: [self emitShortOrLong: dist code: Jmp on: strm]! !

!ParseNode methodsFor: 'code generation'!
emitLong: dist code: longCode on: aStream 
	"Force a two-byte jump."
	| code distance |
	code := longCode.
	distance := dist.
	distance < 0
		ifTrue: 
			[distance := distance + 1024.
			code := code - 4]
		ifFalse: 
			[distance > 1023 ifTrue: [distance := -1]].
	distance < 0
		ifTrue: 
			[self error: 'A block compiles more than 1K bytes of code']
		ifFalse: 
			[aStream nextPut: distance // 256 + code.
			aStream nextPut: distance \\ 256]! !

!ParseNode methodsFor: 'code generation'!
emitShortOrLong: dist code: shortCode on: strm
	(1 <= dist and: [dist <= JmpLimit])
		ifTrue: [strm nextPut: shortCode + dist - 1]
		ifFalse: [self emitLong: dist code: shortCode + (JmpLong-Jmp) on: strm]! !

!ParseNode methodsFor: 'code generation' stamp: 'nk 7/10/2004 10:04'!
pc
	"Used by encoder source mapping."

	^pc ifNil: [ 0 ]
! !

!ParseNode methodsFor: 'code generation' stamp: 'eem 8/4/2008 13:57'!
pc: anInteger
	"Used by encoder source mapping."

	pc := anInteger! !

!ParseNode methodsFor: 'code generation'!
sizeBranchOn: condition dist: dist
	dist = 0 ifTrue: [^1].
	^ condition
		ifTrue: [2]  "Branch on true is always 2 bytes"
		ifFalse: [self sizeShortOrLong: dist]! !

!ParseNode methodsFor: 'code generation'!
sizeForEffect: encoder

	^(self sizeForValue: encoder) + 1! !

!ParseNode methodsFor: 'code generation'!
sizeForReturn: encoder

	^(self sizeForValue: encoder) + 1! !

!ParseNode methodsFor: 'code generation'!
sizeJump: dist

	dist = 0 ifTrue: [^0].
	^self sizeShortOrLong: dist! !

!ParseNode methodsFor: 'code generation'!
sizeShortOrLong: dist

	(1 <= dist and: [dist <= JmpLimit])
		ifTrue: [^1].
	^2! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForBlockValue: stack encoder: encoder
	"Generate code for evaluating the last statement in a block"
	^self emitCodeForValue: stack encoder: encoder! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:37'!
emitCodeForBranchOn: condition dist: dist pop: stack encoder: encoder
	stack pop: 1.
	dist = 0 ifTrue: [^encoder genPop].
	condition
		ifTrue: [encoder genBranchPopTrue: dist]
		ifFalse: [encoder genBranchPopFalse: dist]! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:38'!
emitCodeForEffect: stack encoder: encoder

	self emitCodeForValue: stack encoder: encoder.
	encoder genPop.
	stack pop: 1! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:39'!
emitCodeForJump: dist encoder: encoder

	dist = 0 ifFalse: [encoder genJump: dist]! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:38'!
emitCodeForReturn: stack encoder: encoder

	self emitCodeForValue: stack encoder: encoder.
	encoder genReturnTop! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:13'!
sizeCode: encoder forBranchOn: condition dist: dist
	dist = 0 ifTrue: [^encoder sizePop].
	^condition
		ifTrue: [encoder sizeBranchPopTrue: dist]
		ifFalse: [encoder sizeBranchPopFalse: dist]! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 09:52'!
sizeCode: encoder forJump: dist

	^dist = 0 ifTrue: [0] ifFalse: [encoder sizeJump: dist]! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForBlockValue: encoder
	"Answer the size for evaluating the last statement in a block"
	^self sizeCodeForValue: encoder! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:53'!
sizeCodeForEffect: encoder

	^(self sizeCodeForValue: encoder) + encoder sizePop! !

!ParseNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:57'!
sizeCodeForReturn: encoder

	^(self sizeCodeForValue: encoder) + encoder sizeReturnTop! !

!ParseNode methodsFor: 'encoding'!
encodeSelector: selector

	^nil! !

!ParseNode methodsFor: 'private' stamp: 'ls 1/29/2004 21:17'!
ifNilReceiver
	"assuming this object is the receiver of an ifNil:, what object is being asked about?"
	^self! !

!ParseNode methodsFor: 'private' stamp: 'sma 5/28/2000 10:47'!
nextWordFrom: aStream setCharacter: aBlock
	| outStream char |
	outStream := WriteStream on: (String new: 16).
	[(aStream peekFor: Character space) 
		or: [aStream peekFor: Character tab]] whileTrue.
	[aStream atEnd
		or:
			[char := aStream next.
			char = Character cr or: [char = Character space]]]
		whileFalse: [outStream nextPut: char].
	aBlock value: char.
	^ outStream contents! !

!ParseNode methodsFor: 'private' stamp: 'jmv 12/7/2009 22:40'!
printSingleComment: aString on: aStream indent: indent 
	"Print the comment string"
	
	aStream nextPutAll: aString! !

!ParseNode methodsFor: 'printing' stamp: 'tk 10/16/2000 13:57'!
nodePrintOn: aStrm indent: nn
	| var aaStrm myLine |
	"Show just the sub nodes and the code."

	(aaStrm := aStrm) ifNil: [aaStrm := WriteStream on: (String new: 500)].
	nn timesRepeat: [aaStrm tab].
	aaStrm nextPutAll: self class name; space.
	myLine := self printString copyWithout: Character cr.
	myLine := myLine copyFrom: 1 to: (myLine size min: 70).
	aaStrm nextPutAll: myLine; cr.
	1 to: self class instSize do: [:ii | 
		var := self instVarAt: ii.
		(var respondsTo: #asReturnNode) ifTrue: [var nodePrintOn: aaStrm indent: nn+1]].
	1 to: self class instSize do: [:ii | 
		var := self instVarAt: ii.
		(var isKindOf: SequenceableCollection) ifTrue: [
				var do: [:aNode | 
					(aNode respondsTo: #asReturnNode) ifTrue: [
						aNode nodePrintOn: aaStrm indent: nn+1]]]].
	^ aaStrm
! !

!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: $"]! !

!ParseNode methodsFor: 'printing' stamp: 'eem 5/6/2008 15:18'!
printOn: aStream 
	"Refer to the comment in Object|printOn:."

	aStream nextPut: ${.
	self printOn: aStream indent: 0.
	aStream nextPut: $}.! !

!ParseNode methodsFor: 'printing'!
printOn: aStream indent: anInteger 
	"If control gets here, avoid recursion loop."

	super printOn: aStream! !

!ParseNode methodsFor: 'printing'!
printOn: aStream indent: level precedence: p

	self printOn: aStream indent: level! !

!ParseNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:51'!
printWithClosureAnalysis

	^String streamContents: [:str| self printWithClosureAnalysisOn: str]! !

!ParseNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: aStream 
	"Refer to the comment in Object|printOn:."

	aStream nextPut: ${.
	self printWithClosureAnalysisOn: aStream indent: 0.
	aStream nextPut: $}.! !

!ParseNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: aStream indent: anInteger 
	"If control gets here, avoid recursion loop."

	super printWithClosureAnalysisOn: aStream! !

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

	self printWithClosureAnalysisOn: aStream indent: level! !

!ParseNode methodsFor: 'printing' stamp: 'ms 8/1/2006 16:47'!
shortPrintOn: aStream 
	self printOn: aStream indent: 0! !

!ParseNode methodsFor: 'code generation (closures)' stamp: 'eem 7/20/2009 09:54'!
optimizedBlockHoistTempsInto: scopeBlock "<BlockNode>" 
	"This is a No-op for all nodes except non-optimized BlockNodes."
	^self! !


!AssignmentNode methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:12'!
accept: aVisitor
	aVisitor visitAssignmentNode: self! !

!AssignmentNode methodsFor: 'code generation (closures)' stamp: 'eem 5/30/2008 09:37'!
analyseTempsWithin: scopeBlock "<BlockNode>"  rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	"N.B.  since assigment happens _after_ the value is evaluated the value is sent the message _first_."
	value analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools.
	variable beingAssignedToAnalyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools! !

!AssignmentNode methodsFor: 'code generation (new scheme)' stamp: 'eem 6/4/2008 11:27'!
emitCodeForEffect: stack encoder: encoder

	variable emitCodeForLoad: stack encoder: encoder.
	value emitCodeForValue: stack encoder: encoder.
	pc := encoder methodStreamPosition + 1. "debug pc is first byte of the store, i.e. the next byte".
	variable emitCodeForStorePop: stack encoder: encoder! !

!AssignmentNode methodsFor: 'code generation (new scheme)' stamp: 'eem 6/4/2008 11:27'!
emitCodeForValue: stack encoder: encoder

	variable emitCodeForLoad: stack encoder: encoder.
	value emitCodeForValue: stack encoder: encoder.
	pc := encoder methodStreamPosition + 1. "debug pc is first byte of the store, i.e. the next byte".
	variable emitCodeForStore: stack encoder: encoder! !

!AssignmentNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/20/2008 15:16'!
sizeCodeForEffect: encoder

	^(variable sizeCodeForLoad: encoder)
	+ (value sizeCodeForValue: encoder)
	+ (variable sizeCodeForStorePop: encoder)! !

!AssignmentNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/20/2008 15:16'!
sizeCodeForValue: encoder

	^(variable sizeCodeForLoad: encoder)
	+ (value sizeCodeForValue: encoder)
	+ (variable sizeCodeForStore: encoder)! !

!AssignmentNode methodsFor: 'code generation' stamp: 'eem 6/4/2008 11:26'!
emitForEffect: stack on: aStream

	variable emitLoad: stack on: aStream.
	value emitForValue: stack on: aStream.
	pc := aStream position + 1. "debug pc is first byte of the store".
	variable emitStorePop: stack on: aStream! !

!AssignmentNode methodsFor: 'code generation' stamp: 'eem 6/4/2008 11:26'!
emitForValue: stack on: aStream

	variable emitLoad: stack on: aStream.
	value emitForValue: stack on: aStream.
	pc := aStream position + 1. "debug pc is first byte of the store"
	variable emitStore: stack on: aStream! !

!AssignmentNode methodsFor: 'code generation'!
sizeForEffect: encoder

	^(value sizeForValue: encoder)
		+ (variable sizeForStorePop: encoder)! !

!AssignmentNode methodsFor: 'code generation'!
sizeForValue: encoder

	^(value sizeForValue: encoder)
		+ (variable sizeForStore: encoder)! !

!AssignmentNode methodsFor: 'testing' stamp: 'eem 6/16/2008 09:37'!
isAssignmentNode
	^true! !

!AssignmentNode methodsFor: 'printing' stamp: 'eem 5/6/2008 13:48'!
printOn: aStream indent: level 
	variable printOn: aStream indent: level.
	aStream nextPutAll: ' := '.
	value printOn: aStream indent: level + 2! !

!AssignmentNode methodsFor: 'printing' stamp: 'eem 5/9/2008 18:44'!
printOn: aStream indent: level precedence: p

	aStream nextPut: $(.
	self printOn: aStream indent: level.
	aStream nextPut: $)! !

!AssignmentNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: aStream indent: level 
	variable printWithClosureAnalysisOn: aStream indent: level.
	aStream nextPutAll: ' := '.
	value printWithClosureAnalysisOn: aStream indent: level + 2! !

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

	aStream nextPut: $(.
	self printWithClosureAnalysisOn: aStream indent: level.
	aStream nextPut: $)! !

!AssignmentNode methodsFor: 'initialize-release'!
toDoIncrement: var
	var = variable ifFalse: [^ nil].
	(value isMemberOf: MessageNode) 
		ifTrue: [^ value toDoIncrement: var]
		ifFalse: [^ nil]! !

!AssignmentNode methodsFor: 'initialize-release'!
value
	^ value! !

!AssignmentNode methodsFor: 'initialize-release'!
variable: aVariable value: expression

	variable := aVariable.
	value := expression! !

!AssignmentNode methodsFor: 'initialize-release' stamp: 'di 3/22/1999 12:00'!
variable: aVariable value: expression from: encoder

	(aVariable isMemberOf: MessageAsTempNode)
		ifTrue: ["Case of remote temp vars"
				^ aVariable store: expression from: encoder].
	variable := aVariable.
	value := expression! !

!AssignmentNode methodsFor: 'initialize-release' stamp: 'hmm 7/15/2001 21:17'!
variable: aVariable value: expression from: encoder sourceRange: range

	encoder noteSourceRange: range forNode: self.
	^self
		variable: aVariable
		value: expression
		from: encoder! !

!AssignmentNode methodsFor: 'equation translation'!
variable
	^variable! !


!BlockNode methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:13'!
accept: aVisitor
	aVisitor visitBlockNode: self! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 9/3/2009 12:55'!
actualScope
	"Answer the actual scope for the receiver.  If this is an unoptimized block then it is its
	 actual scope, but if this is an optimized block then the actual scope is some outer block."
	^actualScopeIfOptimized ifNil: [self]! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2009 11:42'!
addHoistedTemps: additionalTemporaries "<SequenceableCollection>"
	additionalTemporaries do:
		[:temp|
		temp definingScope ifNil:
			[temp definingScope: self]].
	temporaries := (temporaries isNil or: [temporaries isEmpty])
					ifTrue: [additionalTemporaries copy]
					ifFalse:
						[temporaries last isIndirectTempVector
							ifTrue: [temporaries allButLast, additionalTemporaries, { temporaries last }]
							ifFalse: [temporaries, additionalTemporaries]]! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 7/24/2009 16:43'!
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."
	temporaries isArray ifTrue:
		[temporaries := temporaries asOrderedCollection].
	remoteTempNode == nil ifTrue:
		[remoteTempNode := RemoteTempVectorNode new
								name: self remoteTempNodeName
								index: arguments size + temporaries size
								type: LdTempType
								scope: 0.
		 actualScopeIfOptimized
			ifNil:
				[temporaries addLast: 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."
	temporaries remove: aTempVariableNode ifAbsent: [].
	^remoteTempNode! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2009 13:29'!
analyseArguments: methodArguments temporaries: methodTemporaries rootNode: rootNode "<MethodNode>" "^<Sequence of: <TempVarNade>>"
	"Top level entry-point for analysing temps within the hierarchy of blocks in the receiver's method.
	 Answer the (possibly modified) sequence of temp vars.
	 Need to hoist temps out of macro-optimized blocks into their actual blocks.
	 Need to note reads and writes to temps from blocks other than their actual blocks to determine
	 whether blocks can be local (simple slots within a block/method context) or remote (slots in
	 indirection vectors that are shared between contexts by sharing indirection vectors).

	 The algorithm is based on numbering temporary reads and writes and block extents.
	 The index used for numbering starts at zero and is incremented on every block entry
	 and block exit.  So the following
		| a b blk r1 r2 t |
		a := 1. b := 2. t := 0.
		blk := [ | s | s := a + b. t := t + s].
		r1 := blk value.
		b := -100.
		r2 := blk value.
		r1 -> r2 -> t
	is numbered as
		method block 0 to: 6:
		| a b blk r1 r2 t |
		a w@1 := 1. b w@1 := 2. t w@1 := 0.
		blk w@5 := [entry@2 | s |
					 t  w@3 := t r@3 + a r@3 + b r@3
					] exit@4.
		r1 w@5 := blk r@5 value.
		b w@5 := nil.
		r2 w@5 := blk r@5 value.
		r1 r@5 -> r2 r@5 -> t r@5
	So:
		b and blk cannot be copied because for both there exists a write @5 that follows a
			read @4 within block 2 through 4
		t must be remote because there exists a write @3 within block (2 to: 4)
	Complications are introduced by optimized blocks.  In the following temp is written to
	after it is closed over by [ temp ] since the inlined block is executed more than once.
		| temp coll |
		coll := OrderedCollection new.
		1 to: 5 do: [ :index | 
			temp := index. 
			coll add: [ temp ] ].
		self assert: (coll collect: [:ea| ea value]) asArray = #(5 5 5 5 5)
	In the following i is local to the block and must be initialized each time around the loop
	but if the block is inlined it must be declared at method level.
		| col |
		col := OrderedCollection new.
		1 to: 3 do: [ :each | | i | i := each. col add: [ i ]. i := i + 1 ].
		self assert: (col collect: [ :each | each value ]) asArray = #(2 3 4)"
	self assert: (arguments isEmpty or: [arguments hasEqualElements: methodArguments]).
	arguments := methodArguments asArray. "won't change"
	self assert: (temporaries isNil or: [temporaries isEmpty or: [temporaries hasEqualElements: methodTemporaries]]).
	temporaries := OrderedCollection withAll: methodTemporaries.

	self assert: optimized not. "the top-level block should not be optimized."
	self analyseTempsWithin: self rootNode: rootNode assignmentPools: Dictionary new.

	"The top-level block needs to reindex temporaries since analysis may have rearranged them.
	 This happens when temps are made remote and/or a remote node is added."
	temporaries withIndexDo:
		[:temp :offsetPlusOne| temp index: arguments size + offsetPlusOne - 1].

	"Answer the (possibly modified) sequence of temps."
	^temporaries asArray! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2009 11:42'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	| effectiveScope blockStart |
	effectiveScope := optimized
						ifTrue: [actualScopeIfOptimized := scopeBlock]
						ifFalse: [self].

	arguments ifNotNil:
		[arguments do: [:temp| temp definingScope: self]].
	temporaries ifNotNil:
		[temporaries do: [:temp| temp definingScope: self]].

	optimized ifFalse: "if optimized this isn't an actual scope"
		[rootNode noteBlockEntry:
			[:entryNumber|
			 blockExtent := (blockStart := entryNumber) to: 0]].

	"Need to enumerate a copy because closure analysis can add a statement
	 via ifHasRemoteTempNodeEnsureInitializationStatementExists:."
	statements copy do:
		[:statement|
		 statement analyseTempsWithin: effectiveScope rootNode: rootNode assignmentPools: assignmentPools].

	optimized ifFalse: "if optimized this isn't an actual scope"
		[rootNode noteBlockExit:
			[:exitNumber|
			 blockExtent := blockStart to: exitNumber]].

	"Now that the analysis is done move any temps that need to be moved."
	self postNumberingProcessTempsWithin: effectiveScope rootNode: rootNode.

	"This is simply a nicety for compiler developers..."
	temporaries do:
		[:temp|
		(temp isIndirectTempVector and: [temp name includes: $?]) ifTrue:
			[temp name: temp definingScope remoteTempNodeName]]! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 5/20/2008 12:16'!
blockExtent "^<Interval>"
	^blockExtent! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2009 11:56'!
computeCopiedValues: rootNode
	| referencedValues |
	referencedValues := rootNode referencedValuesWithinBlockExtent: blockExtent.
	^((referencedValues reject: [:temp| temp isDefinedWithinBlockExtent: blockExtent])
		asSortedCollection: ParseNode tempSortBlock)
			asArray! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2008 14:10'!
constructClosureCreationNode: encoder
	copiedValues := self computeCopiedValues: encoder rootNode.
	encoder supportsClosureOpcodes ifTrue:
		[^self closureCreationNode].
	"Without the bytecode we can still get by."
	^MessageNode new
		receiver: (encoder encodeVariable: 'thisContext')
		selector: #closureCopy:copiedValues:
		arguments: (Array
						with: (encoder encodeLiteral: arguments size)
						with: (copiedValues isEmpty
								ifTrue: [NodeNil]
								ifFalse: [BraceNode new elements: copiedValues]))
		precedence: 3
		from: encoder! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2008 14:10'!
emitCodeForClosureValue: stack encoder: encoder
	"if not supportsClosureOpcodes closureCreationSupportNode is the
	 node for thisContext closureCopy: numArgs [ copiedValues: { values } ]"
	encoder supportsClosureOpcodes
		ifTrue:
			[copiedValues do:
				[:copiedValue| copiedValue emitCodeForValue: stack encoder: encoder].
			 closureCreationNode pc: encoder methodStreamPosition + 1.
			 encoder
				genPushClosureCopyNumCopiedValues: copiedValues size
				numArgs: arguments size
				jumpSize: size.
			 stack
				pop: copiedValues size;
				push: 1]
		ifFalse:
			[closureCreationNode emitCodeForValue: stack encoder: encoder.
			 encoder genJumpLong: size]. "Force a two byte jump."
	"Emit the body of the block"
	self emitCodeForEvaluatedClosureValue: stack encoder: encoder! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 9/12/2008 10:55'!
emitCodeForEvaluatedClosureValue: stack encoder: encoder
	| position |
	position := stack position.
	stack position: arguments size + copiedValues size.
	temporaries size timesRepeat:
		[NodeNil emitCodeForValue: stack encoder: encoder].
	self
		reindexingLocalsDo: [self emitCodeForEvaluatedValue: stack encoder: encoder]
		encoder: encoder.
	self returns ifFalse:
		[encoder genReturnTopToCaller.
		 pc := encoder methodStreamPosition].
	stack position: position! !

!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: 'code generation (closures)' stamp: 'eem 5/19/2008 17:12'!
noteOptimized
	optimized := true! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 7/20/2009 09:52'!
optimizedBlockHoistTempsInto: scopeBlock "<BlockNode>"
	"This is a No-op for all nodes except non-optimized BlockNodes."
	"Let's assume the special > 0 guard in MessageNode>>analyseTempsWithin:forValue:encoder: is correct.
	 Then we can simply hoist our temps up."
	self assert: (arguments isNil or: [arguments size <= 1]).
	(arguments notNil and: [arguments notEmpty]) ifTrue:
		[scopeBlock addHoistedTemps: arguments.
		arguments := #()].
	temporaries notEmpty ifTrue:
		[scopeBlock addHoistedTemps: temporaries.
		temporaries := #()]! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 7/24/2009 16:23'!
postNumberingProcessTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>"
	"A temp can be local (and copied) if it is not written to after it is captured.
	 A temp cannot be local if it is written to remotely.
	 Need to enumerate a copy of the temporaries because any temps becoming remote
	 will be removed from temporaries in analyseClosure: (and a single remote temp node
	 will get added)"
	temporaries copy do:
		[:each|
		each isIndirectTempVector ifFalse:
			[each analyseClosure: rootNode]].

	"If this is an optimized node we need to hoist temporaries up into the relevant block scope."
	optimized ifTrue:
		[self optimizedBlockHoistTempsInto: scopeBlock].

	"Now we may have added a remoteTempNode.  So we need a statement to initialize it."
	self ifHasRemoteTempNodeEnsureInitializationStatementExists: rootNode.

	"Now add all arguments and locals to the pool so that copiedValues can be computed during sizing."
	rootNode
		addLocalsToPool: arguments;
		addLocalsToPool: temporaries! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 6/2/2008 16:37'!
reindexingLocalsDo: aBlock encoder: encoderOrNil
	"Evaluate aBlock wih arguments, temporaries and copiedValues reindexed for
	 their positions within the receiver's block, restoring the correct indices afterwards.
	 If encoder is not nil remember the temps for this block's extent."
	| tempIndices result tempsToReindex |
	self assert: copiedValues notNil.
	tempsToReindex := arguments asArray, copiedValues, temporaries.
	tempIndices := tempsToReindex collect: [:temp| temp index].
	tempsToReindex withIndexDo:
		[:temp :newIndex| temp index: newIndex - 1. self assert: temp index + 1 = newIndex].
	encoderOrNil ifNotNil:
		[encoderOrNil noteBlockExtent: blockExtent hasLocals: tempsToReindex].
	result := aBlock ensure:
				["Horribly pragmatic hack.  The copiedValues will have completely
				  unrelated indices within the closure method and sub-method.
				  Avoiding the effort of rebinding temps in the inner scope simply
				  update the indices to their correct ones during the generation of
				  the closure method and restore the indices immedately there-after."
				 tempsToReindex with: tempIndices do:
					[:temp :oldIndex| temp index: oldIndex. self assert: temp index = oldIndex]].
	^result! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 7/22/2009 10:48'!
remoteTempNodeName
	"Answer a useful name for a RemoteTempVectorNode in the receiver."
	| prefix scope extent |
	prefix := actualScopeIfOptimized ifNil: ['<'] ifNotNil: [ '<...'].
	scope := self.
	[extent := scope blockExtent.
	 extent == nil
	 and: [scope actualScope ~~ scope]] whileTrue:
		[scope := scope actualScope].
	^extent
		ifNil: [prefix, '?-?>']
		ifNotNil:
			[prefix, extent first printString, '-',
				(extent last isZero
					ifTrue: ['?']
					ifFalse: [extent last printString]), '>']! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2008 14:11'!
sizeCodeForClosureValue: encoder
	"Compute the size for the creation of the block and its code."
	"If we have the closure bytecodes constructClosureCreationNode: will note
	 the copied values in the copiedValues inst var and answer #pushCopiedValues."
	closureCreationNode := self constructClosureCreationNode: encoder.
	"Remember size of body for emit time so we know the size of the jump around it."
	size := self sizeCodeForEvaluatedClosureValue: encoder.
	^encoder supportsClosureOpcodes
		ifTrue:
			[(copiedValues inject: 0 into: [:sum :node| sum + (node sizeCodeForValue: encoder)])
			 + (encoder sizePushClosureCopyNumCopiedValues: copiedValues size numArgs: arguments size jumpSize: size)
			 + size]
		ifFalse:
			["closureCreationSupportNode is send closureCopy:copiedValues:"
			(closureCreationNode sizeCodeForValue: encoder)
			 + (encoder sizeJumpLong: size)
			 + size]! !

!BlockNode methodsFor: 'code generation (closures)' stamp: 'eem 5/31/2008 14:31'!
sizeCodeForEvaluatedClosureValue: encoder
	"The closure value primitives push the arguments and the copied values.
	 The compiler guarantees that any copied values come before all local temps.
	 So on closure activation we only need to push nils for the remaining temporaries."
	^temporaries size * (NodeNil sizeCodeForValue: encoder)
	+ (self
		reindexingLocalsDo: [self sizeCodeForEvaluatedValue: encoder]
		encoder: nil "don't store temps yet")
	+ (self returns ifTrue: [0] ifFalse: [encoder sizeReturnTopToCaller])! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 6/2/2008 14:00'!
addArgument: aTempVariableNode
	temporaries := temporaries copyWith: aTempVariableNode! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 7/27/2008 15:57'!
arguments
	^arguments! !

!BlockNode methodsFor: 'accessing'!
arguments: argNodes 
	"Decompile."

	arguments := argNodes! !

!BlockNode methodsFor: 'accessing' stamp: 'tk 8/4/1999 22:53'!
block
	^ self! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 8/22/2008 10:01'!
closureCreationNode
	closureCreationNode ifNil:
		[closureCreationNode := LeafNode new
									key: #closureCreationNode
									code: nil].
	^closureCreationNode! !

!BlockNode methodsFor: 'accessing'!
firstArgument
	^ arguments first! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 5/30/2008 12:12'!
nArgsSlot
	"Private for the Encoder to use in bindArg"
	^nArgsNode! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 5/30/2008 12:12'!
nArgsSlot: anInteger
	"Private for the Encoder to use in bindArg"
	nArgsNode := anInteger! !

!BlockNode methodsFor: 'accessing'!
numberOfArguments

	^arguments size! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 7/24/2008 12:37'!
optimized
	^optimized! !

!BlockNode methodsFor: 'accessing'!
returnLast

	self returns
		ifFalse: 
			[returns := true.
			statements at: statements size put: statements last asReturnNode]! !

!BlockNode methodsFor: 'accessing' stamp: 'ar 11/17/2002 19:57'!
returnNilIfNoOther

	self returns
		ifFalse: 
			[statements last == NodeNil ifFalse: [statements add: NodeNil].
			self returnLast]! !

!BlockNode methodsFor: 'accessing' stamp: 'gk 4/6/2006 11:29'!
returnSelfIfNoOther: encoder

	self returns ifTrue:[^self].
	statements last == NodeSelf ifFalse: [
		statements := statements copyWith: (encoder encodeVariable: 'self').
	].
	self returnLast.
! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 8/4/2008 10:48'!
startOfLastStatement
	^startOfLastStatement! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 8/4/2008 10:50'!
startOfLastStatement: anInteger
	"Note the source index of the start of the last full statement.  The
	 last full statement is the value answered by a block and hence the
	 expression the debugger should display as the value of the block."
	startOfLastStatement := anInteger! !

!BlockNode methodsFor: 'accessing' stamp: 'eem 7/27/2008 15:57'!
temporaries
	^temporaries! !

!BlockNode methodsFor: 'accessing' stamp: 'sma 2/27/2000 22:37'!
temporaries: aCollection
	temporaries := aCollection! !

!BlockNode methodsFor: 'initialize-release' stamp: 'eem 5/20/2008 13:40'!
arguments: argNodes statements: statementsCollection returns: returnBool from: encoder
	"Compile."

	arguments := argNodes.
	statements := statementsCollection size > 0
				ifTrue: [statementsCollection]
				ifFalse: [argNodes size > 0
						ifTrue: [statementsCollection copyWith: arguments last]
						ifFalse: [Array with: NodeNil]].
	optimized := false.
	returns := returnBool! !

!BlockNode methodsFor: 'initialize-release' stamp: 'eem 8/4/2008 14:12'!
noteSourceRangeStart: start end: end encoder: encoder
	"Note two source ranges for this node.  One is for the debugger
	 and is of the last expression, the result of the block.  One is for
	 source analysis and is for the entire block."
	encoder
		noteSourceRange: (start to: end)
		forNode: self closureCreationNode.
	startOfLastStatement
		ifNil:
			[encoder
				noteSourceRange: (start to: end)
				forNode: self]
		ifNotNil:
			[encoder
				noteSourceRange: (startOfLastStatement to: end - 1)
				forNode: self]! !

!BlockNode methodsFor: 'initialize-release' stamp: 'eem 5/20/2008 13:40'!
statements: statementsCollection returns: returnBool 
	"Decompile."

	| returnLast |
	returnLast := returnBool.
	returns := false.
	statements := 
		(statementsCollection size > 1 
			and: [(statementsCollection at: statementsCollection size - 1) 
					isReturningIf])
				ifTrue: 
					[returnLast := false.
					statementsCollection allButLast]
				ifFalse: [statementsCollection size = 0
						ifTrue: [Array with: NodeNil]
						ifFalse: [statementsCollection]].
	arguments := #().
	temporaries := #().
	optimized := false.
	returnLast ifTrue: [self returnLast]! !

!BlockNode methodsFor: 'testing'!
canBeSpecialArgument
	"Can I be an argument of (e.g.) ifTrue:?"

	^arguments size = 0! !

!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: 'testing' stamp: 'eem 9/25/2008 12:10'!
isBlockNode
	^true! !

!BlockNode methodsFor: 'testing'!
isComplex

	^statements size > 1 or: [statements size = 1 and: [statements first isComplex]]! !

!BlockNode methodsFor: 'testing'!
isJust: node

	returns ifTrue: [^false].
	^statements size = 1 and: [statements first == node]! !

!BlockNode methodsFor: 'testing'!
isJustCaseError

	^ statements size = 1 and:
		[statements first
			isMessage: #caseError
			receiver: [:r | r==NodeSelf]
			arguments: nil]! !

!BlockNode methodsFor: 'testing'!
isQuick
	^ statements size = 1
		and: [statements first isVariableReference
				or: [statements first isSpecialConstant]]! !

!BlockNode methodsFor: 'testing'!
returns

	^returns or: [statements last isReturningIf]! !

!BlockNode methodsFor: 'code generation'!
code

	^statements first code! !

!BlockNode methodsFor: 'code generation' stamp: 'di 11/19/1999 19:32'!
emitExceptLast: stack on: aStream
	| nextToLast |
	nextToLast := statements size - 1.
	nextToLast < 1 ifTrue: [^ self].  "Only one statement"
	1 to: nextToLast do:
		[:i | (statements at: i) emitForEffect: stack on: aStream].
! !

!BlockNode methodsFor: 'code generation'!
emitForEvaluatedEffect: stack on: aStream

	self returns
		ifTrue: 
			[self emitForEvaluatedValue: stack on: aStream.
			stack pop: 1]
		ifFalse: 
			[self emitExceptLast: stack on: aStream.
			statements last emitForEffect: stack on: aStream]! !

!BlockNode methodsFor: 'code generation' stamp: 'di 11/19/1999 19:44'!
emitForEvaluatedValue: stack on: aStream
	self emitExceptLast: stack on: aStream.
	statements last emitForValue: stack on: aStream.
! !

!BlockNode methodsFor: 'code generation' stamp: 'hmm 7/17/2001 21:02'!
emitForValue: stack on: aStream

	aStream nextPut: LdThisContext.
	stack push: 1.
	nArgsNode emitForValue: stack on: aStream.
	remoteCopyNode
		emit: stack
		args: 1
		on: aStream.
	"Force a two byte jump."
	self emitLong: size code: JmpLong on: aStream.
	stack push: arguments size.
	arguments reverseDo: [:arg | arg emitStorePop: stack on: aStream].
	self emitForEvaluatedValue: stack on: aStream.
	self returns ifFalse: [
		aStream nextPut: EndRemote.
		pc := aStream position.
	].
	stack pop: 1! !

!BlockNode methodsFor: 'code generation' stamp: 'di 11/19/1999 19:33'!
sizeExceptLast: encoder
	| codeSize nextToLast |
	nextToLast := statements size - 1.
	nextToLast < 1 ifTrue: [^ 0]. "Only one statement"
	codeSize := 0.
	1 to: nextToLast do: 
		[:i | codeSize := codeSize + ((statements at: i) sizeForEffect: encoder)].
	^ codeSize! !

!BlockNode methodsFor: 'code generation'!
sizeForEvaluatedEffect: encoder

	self returns ifTrue: [^self sizeForEvaluatedValue: encoder].
	^(self sizeExceptLast: encoder)
		+ (statements last sizeForEffect: encoder)! !

!BlockNode methodsFor: 'code generation'!
sizeForEvaluatedValue: encoder

	^(self sizeExceptLast: encoder)
		+ (statements last sizeForValue: encoder)! !

!BlockNode methodsFor: 'code generation'!
sizeForValue: encoder
	nArgsNode := encoder encodeLiteral: arguments size.
	remoteCopyNode := encoder encodeSelector: #blockCopy:.
	size := (self sizeForEvaluatedValue: encoder)
				+ (self returns ifTrue: [0] ifFalse: [1]). "endBlock"
	arguments := arguments collect:  "Chance to prepare debugger remote temps"
				[:arg | arg asStorableNode: encoder].
	arguments do: [:arg | size := size + (arg sizeForStorePop: encoder)].
	^1 + (nArgsNode sizeForValue: encoder) 
		+ (remoteCopyNode size: encoder args: 1 super: false) + 2 + size! !

!BlockNode methodsFor: 'printing' stamp: 'md 2/22/2006 16:37'!
decompileString 
	"Answer a string description of the parse tree whose root is the receiver."

	^ self decompileText asString
! !

!BlockNode methodsFor: 'printing' stamp: 'md 2/22/2006 16:37'!
decompileText
	"Answer a text description of the parse tree whose root is the receiver."

	^ ColoredCodeStream contents: [:strm | self printOn: strm indent: 0]
! !

!BlockNode methodsFor: 'printing' stamp: 'eem 5/6/2008 14:28'!
printArgumentsOn: aStream indent: level
	arguments size = 0 ifTrue: [^ self].
	arguments do:
		[:arg | aStream nextPut: $:;  nextPutAll: arg key;  space].
	aStream nextPut: $|; space.
	"If >0 args and >1 statement, put all statements on separate lines"
	statements size > 1 ifTrue:
		[aStream crtab: level]! !

!BlockNode methodsFor: 'printing' stamp: 'eem 9/25/2008 12:48'!
printOn: aStream indent: level

	"statements size <= 1 ifFalse: [aStream crtab: level]."
	aStream nextPut: $[.
	self printArgumentsOn: aStream indent: level.
	(self printTemporaries: temporaries on: aStream doPrior: []) ifTrue:
		["If >0 temps and >1 statement, put all statements on separate lines"
		 statements size > 1
			ifTrue: [aStream crtab: level]
			ifFalse: [aStream space]].
	self printStatementsOn: aStream indent: level.
	aStream nextPut: $]! !

!BlockNode methodsFor: 'printing' stamp: 'eem 9/23/2008 15:05'!
printStatementsOn: aStream indent: levelOrZero
	| len shown thisStatement level |
	level := 1 max: levelOrZero.
	comment == nil
		ifFalse: 
			[self printCommentOn: aStream indent: level.
			aStream crtab: level].
	len := shown := statements size.
	(levelOrZero = 0 "top level" and: [statements last isReturnSelf])
		ifTrue: [shown := 1 max: shown - 1]
		ifFalse: ["should a trailing nil be printed or not? Not if it is an implicit result."
				(arguments size = 0
				and: [len >= 1
				and: [(statements at: len) == NodeNil
				and: [len = 1
					or: [len > 1
						and: [(statements at: len - 1) isMessageNode
						and: [(statements at: len - 1) isNilIf]]]]]])
					ifTrue: [shown := shown - 1]].
	1 to: shown do: 
		[:i | 
		thisStatement := statements at: i.
		thisStatement printOn: aStream indent: level.
		i < shown ifTrue: [aStream nextPut: $.; crtab: level].
		(thisStatement comment ~~ nil and: [thisStatement comment size > 0])
			ifTrue: 
				[i = shown ifTrue: [aStream crtab: level].
				thisStatement printCommentOn: aStream indent: level.
				i < shown ifTrue: [aStream crtab: level]]]! !

!BlockNode methodsFor: 'printing' stamp: 'eem 7/21/2009 13:12'!
printTemporaries: tempSequence on: aStream doPrior: aBlock
	"Print any in-scope temporaries.  If there are any evaluate aBlock
	 prior to printing.  Answer whether any temporaries were printed."
	| tempStream seen |
	tempSequence ifNil:
		[^false].
	tempStream := (String new: 16) writeStream.
	"This is for the decompiler which canmot work out which optimized block a particular temp is
	 local to and hence may produce diplicates as in
		expr ifTrue: [| aTemp | ...] ifFalse: [| aTemp | ...]"
	seen := Set new.
	tempSequence do:
		[:tempNode |
		tempNode isIndirectTempVector
			ifTrue:
				[tempNode remoteTemps do:
					[:tempVariableNode|
					 (tempVariableNode scope >= 0
					  and: [(seen includes: tempNode key) not]) ifTrue:
						[tempStream space; nextPutAll: (seen add: tempVariableNode key)]]]
			ifFalse:
				[(tempNode scope >= -1
				  and: ["This is for the decompiler which may create a block arg when converting
						a while into a to:do: but won't remove it form temporaries"
					   tempNode isBlockArg not
				  and: [(seen includes: tempNode key) not]]) ifTrue:
					[tempStream space; nextPutAll: (seen add: tempNode key)]]].
	tempStream position = 0 ifTrue:
		[^false].
	aBlock value.
	aStream nextPut: $|; nextPutAll: tempStream contents; space; nextPut: $|.
	^true! !

!BlockNode methodsFor: 'printing' stamp: 'eem 6/2/2008 12:06'!
printWithClosureAnalysisArgumentsOn: aStream indent: level
	arguments size = 0 ifTrue: [^self].
	arguments do:
		[:tempNode |
		 aStream space; nextPut: $:.
		 tempNode printDefinitionForClosureAnalysisOn: aStream].
	aStream nextPut: $|; space.
	"If >0 args and >1 statement, put all statements on separate lines"
	statements size > 1 ifTrue:
		[aStream crtab: level]! !

!BlockNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:53'!
printWithClosureAnalysisOn: aStream indent: level
	aStream nextPut: $[.
	blockExtent ifNotNil: [aStream print: blockExtent].
	self printWithClosureAnalysisArgumentsOn: aStream indent: level.
	self printWithClosureAnalysisTemporariesOn: aStream indent: level.
	self printWithClosureAnalysisStatementsOn: aStream indent: level.
	aStream nextPut: $]! !

!BlockNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:48'!
printWithClosureAnalysisStatementsOn: aStream indent: levelOrZero
	| len shown thisStatement level |
	level := 1 max: levelOrZero.
	comment == nil
		ifFalse: 
			[self printCommentOn: aStream indent: level.
			aStream crtab: level].
	len := shown := statements size.
	(levelOrZero = 0 "top level" and: [statements last isReturnSelf])
		ifTrue: [shown := 1 max: shown - 1]
		ifFalse: [(len = 1 and: [((statements at: 1) == NodeNil) & (arguments size = 0)])
					ifTrue: [shown := shown - 1]].
	1 to: shown do: 
		[:i | 
		thisStatement := statements at: i.
		thisStatement printWithClosureAnalysisOn: aStream indent: level.
		i < shown ifTrue: [aStream nextPut: $.; crtab: level].
		(thisStatement comment ~~ nil and: [thisStatement comment size > 0])
			ifTrue: 
				[i = shown ifTrue: [aStream crtab: level].
				thisStatement printCommentOn: aStream indent: level.
				i < shown ifTrue: [aStream crtab: level]]]! !

!BlockNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:54'!
printWithClosureAnalysisTemporariesOn: aStream indent: level

	(temporaries == nil or: [temporaries size = 0]) ifFalse:
		[aStream nextPut: $|.
		temporaries do: 
			[:tempNode |
			 aStream space.
			 tempNode printDefinitionForClosureAnalysisOn: aStream].
		aStream nextPutAll: ' | '.
		"If >0 args and >1 statement, put all statements on separate lines"
		statements size > 1 ifTrue: [aStream crtab: level]]! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 6/2/2008 13:29'!
emitCodeExceptLast: stack encoder: encoder
	| position nextToLast |
	position := stack position.
	nextToLast := statements size - 1.
	1 to: nextToLast do:
		[:i | | statement |
		statement := statements at: i.
		statement emitCodeForEffect: stack encoder: encoder.
		self assert: stack position = position].! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/21/2008 11:28'!
emitCodeForEvaluatedEffect: stack encoder: encoder
	| position |
	position := stack position.
	self returns
		ifTrue: 
			[self emitCodeForEvaluatedValue: stack encoder: encoder.
			stack pop: 1]
		ifFalse: 
			[self emitCodeExceptLast: stack encoder: encoder.
			statements last emitCodeForEffect: stack encoder: encoder].
	self assert: stack position = position! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/21/2008 11:36'!
emitCodeForEvaluatedValue: stack encoder: encoder
	| position |
	position := stack position.
	self emitCodeExceptLast: stack encoder: encoder.
	statements last emitCodeForBlockValue: stack encoder: encoder.
	self assert: stack position - 1 = position! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/20/2008 16:55'!
emitCodeForValue: stack encoder: encoder

	self generateAsClosure ifTrue:
		[^self emitCodeForClosureValue: stack encoder: encoder].
	encoder genPushThisContext.
	stack push: 1.
	nArgsNode emitCodeForValue: stack encoder: encoder.
	remoteCopyNode
		emitCode: stack
		args: 1
		encoder: encoder.
	"Force a two byte jump."
	encoder genJumpLong: size.
	stack push: arguments size.
	arguments reverseDo: [:arg | arg emitCodeForStorePop: stack encoder: encoder].
	self emitCodeForEvaluatedValue: stack encoder: encoder.
	self returns ifFalse:
		[encoder genReturnTopToCaller.
		pc := encoder methodStreamPosition].
	stack pop: 1! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/29/2008 15:21'!
sizeCodeExceptLast: encoder
	| codeSize |
	codeSize := 0.
	1 to: statements size - 1 do: 
		[:i | | statement |
		 statement := statements at: i.
		 codeSize := codeSize + (statement sizeCodeForEffect: encoder)].
	^codeSize! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:13'!
sizeCodeForEvaluatedEffect: encoder

	^self returns
		ifTrue: [self sizeCodeForEvaluatedValue: encoder]
		ifFalse: [(self sizeCodeExceptLast: encoder)
				+ (statements last sizeCodeForEffect: encoder)]! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForEvaluatedValue: encoder

	^(self sizeCodeExceptLast: encoder)
		+ (statements last sizeCodeForBlockValue: encoder)! !

!BlockNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/20/2008 16:55'!
sizeCodeForValue: encoder
	self generateAsClosure ifTrue:
		[^self sizeCodeForClosureValue: encoder].

	nArgsNode := encoder encodeLiteral: arguments size.
	remoteCopyNode := encoder encodeSelector: #blockCopy:.
	size := self sizeCodeForEvaluatedValue: encoder.
	self returns ifFalse:
		[size := size + encoder sizeReturnTopToCaller]. "endBlock"
	arguments := arguments collect:  "Chance to prepare debugger remote temps"
						[:arg | arg asStorableNode: encoder].
	arguments do: [:arg | size := size + (arg sizeCodeForStorePop: encoder)].
	^encoder sizePushThisContext
	 + (nArgsNode sizeCodeForValue: encoder) 
	 + (remoteCopyNode sizeCode: encoder args: 1 super: false)
	 + (encoder sizeJumpLong: size)
	 + size! !

!BlockNode methodsFor: 'equation translation'!
statements
	^statements! !

!BlockNode methodsFor: 'equation translation'!
statements: val
	statements := val! !


!BraceNode methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:14'!
accept: aVisitor
	aVisitor visitBraceNode: self! !

!BraceNode methodsFor: 'code generation (closures)' stamp: 'eem 7/20/2009 09:33'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	elements do:
		[:node|
		node analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools]! !

!BraceNode methodsFor: 'code generation (closures)' stamp: 'eem 5/21/2008 10:40'!
elements
	^elements! !

!BraceNode methodsFor: 'code generation (closures)' stamp: 'eem 5/30/2008 17:22'!
maxElementsForConsArray
	"Hack; we have no way of knowing how much stack space is available during sizing"
	^8! !

!BraceNode methodsFor: 'testing' stamp: 'eem 9/25/2008 14:48'!
blockAssociationCheck: encoder
	"If all elements are MessageNodes of the form [block]->[block], and there is at
	 least one element, answer true.
	 Otherwise, notify encoder of an error."

	elements size = 0
		ifTrue: [^encoder notify: 'At least one case required'].
	elements with: sourceLocations do:
			[:x :loc |
			(x 	isMessage: #->
				receiver:
					[:rcvr |
					rcvr isBlockNode and: [rcvr numberOfArguments = 0]]
				arguments:
					[:arg |
					arg isBlockNode and: [arg numberOfArguments = 0]])
			  ifFalse:
				[^encoder notify: 'Association between 0-argument blocks required' at: loc]].
	^true! !

!BraceNode methodsFor: 'testing'!
numElements

	^ elements size! !

!BraceNode methodsFor: 'enumerating'!
casesForwardDo: aBlock
	"For each case in forward order, evaluate aBlock with three arguments:
	 the key block, the value block, and whether it is the last case."

	| numCases case |
	1 to: (numCases := elements size) do:
		[:i |
		case := elements at: i.
		aBlock value: case receiver value: case arguments first value: i=numCases]! !

!BraceNode methodsFor: 'enumerating'!
casesReverseDo: aBlock
	"For each case in reverse order, evaluate aBlock with three arguments:
	 the key block, the value block, and whether it is the last case."

	| numCases case |
	(numCases := elements size) to: 1 by: -1 do:
		[:i |
		case := elements at: i.
		aBlock value: case receiver value: case arguments first value: i=numCases]! !

!BraceNode methodsFor: 'initialize-release'!
elements: collection
	"Decompile."

	elements := collection! !

!BraceNode methodsFor: 'initialize-release'!
elements: collection sourceLocations: locations
	"Compile."

	elements := collection.
	sourceLocations := locations! !

!BraceNode methodsFor: 'initialize-release' stamp: 'di 11/19/1999 11:06'!
matchBraceStreamReceiver: receiver messages: messages

	((receiver isMessage: #braceStream: receiver: nil arguments: [:arg | arg isConstantNumber])
		and: [messages last isMessage: #braceArray receiver: nil arguments: nil])
		ifFalse: [^ nil "no match"].

	"Appears to be a long form brace construct"
	self elements: (messages allButLast collect:
		[:msg | (msg isMessage: #nextPut: receiver: nil arguments: nil)
					ifFalse: [^ nil "not a brace element"].
		msg arguments first])! !

!BraceNode methodsFor: 'initialize-release' stamp: 'di 11/19/1999 11:19'!
matchBraceWithReceiver: receiver selector: selector arguments: arguments

	selector = (self selectorForShortForm: arguments size)
		ifFalse: [^ nil "no match"].

	"Appears to be a short form brace construct"
	self elements: arguments! !

!BraceNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/30/2008 17:40'!
emitCodeForValue: stack encoder: encoder

	(encoder supportsClosureOpcodes
		"Hack; we have no way of knowing how much stack space is available"
	 and: [elements size <= self maxElementsForConsArray]) ifTrue:
		[elements do: [:node| node emitCodeForValue: stack encoder: encoder].
		 encoder genPushConsArray: elements size.
		 stack
			pop: elements size;
			push: 1.
		 ^self].
	^emitNode emitCodeForValue: stack encoder: encoder! !

!BraceNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/30/2008 17:22'!
sizeCodeForValue: encoder

	(encoder supportsClosureOpcodes
		"Hack; we have no way of knowing how much stack space is available"
	 and: [elements size <= self maxElementsForConsArray]) ifTrue:
		[^(elements inject: 0 into: [:sum :node| sum + (node sizeCodeForValue: encoder)])
		  + (encoder sizePushConsArray: elements size)].
	emitNode := elements size <= 4
		ifTrue: ["Short form: Array braceWith: a with: b ... "
				MessageNode new
					receiver: (encoder encodeVariable: #Array)
					selector: (self selectorForShortForm: elements size)
					arguments: elements precedence: 3 from: encoder]
		ifFalse: ["Long form: (Array braceStream: N) nextPut: a; nextPut: b; ...; braceArray"
				CascadeNode new
					receiver: (MessageNode new
								receiver: (encoder encodeVariable: #Array)
								selector: #braceStream:
								arguments: (Array with: (encoder encodeLiteral: elements size))
								precedence: 3 from: encoder)
					messages: ((elements collect: [:elt | MessageNode new receiver: nil
														selector: #nextPut:
														arguments: (Array with: elt)
														precedence: 3 from: encoder])
								copyWith: (MessageNode new receiver: nil
														selector: #braceArray
														arguments: (Array new)
														precedence: 1 from: encoder))].
	^emitNode sizeCodeForValue: encoder! !

!BraceNode methodsFor: 'code generation' stamp: 'di 11/19/1999 08:58'!
emitForValue: stack on: aStream

	^ emitNode emitForValue: stack on: aStream! !

!BraceNode methodsFor: 'code generation' stamp: 'di 1/4/2000 11:24'!
selectorForShortForm: nElements

	nElements > 4 ifTrue: [^ nil].
	^ #(braceWithNone braceWith: braceWith:with:
			braceWith:with:with: braceWith:with:with:with:) at: nElements + 1! !

!BraceNode methodsFor: 'code generation' stamp: 'di 11/19/1999 11:13'!
sizeForValue: encoder

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

!BraceNode methodsFor: 'printing' stamp: 'di 11/19/1999 09:17'!
printOn: aStream indent: level

	aStream nextPut: ${.
	1 to: elements size do: 
		[:i | (elements at: i) printOn: aStream indent: level.
		i < elements size ifTrue: [aStream nextPutAll: '. ']].
	aStream nextPut: $}! !

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

	aStream nextPut: ${.
	1 to: elements size do: 
		[:i | (elements at: i) printWithClosureAnalysisOn: aStream indent: level.
		i < elements size ifTrue: [aStream nextPutAll: '. ']].
	aStream nextPut: $}! !


!CascadeNode methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:16'!
accept: aVisitor
	aVisitor visitCascadeNode: self! !

!CascadeNode methodsFor: 'code generation (closures)' stamp: 'eem 5/19/2008 20:26'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	{ receiver }, messages do:
		[:node| node analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools]! !

!CascadeNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 09:41'!
emitCodeForValue: stack encoder: encoder
	receiver emitCodeForValue: stack encoder: encoder.
	1 to: messages size - 1 do: 
		[:i | 
		encoder genDup.
		stack push: 1.
		(messages at: i) emitCodeForValue: stack encoder: encoder.
		encoder genPop.
		stack pop: 1].
	messages last emitCodeForValue: stack encoder: encoder! !

!CascadeNode methodsFor: 'code generation (new scheme)' 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! !

!CascadeNode methodsFor: 'code generation'!
emitForValue: stack on: aStream

	receiver emitForValue: stack on: aStream.
	1 to: messages size - 1 do: 
		[:i | 
		aStream nextPut: Dup.
		stack push: 1.
		(messages at: i) emitForValue: stack on: aStream.
		aStream nextPut: Pop.
		stack pop: 1].
	messages last emitForValue: stack on: aStream! !

!CascadeNode methodsFor: 'code generation'!
sizeForValue: encoder

	| size |
	size := (receiver sizeForValue: encoder) + (messages size - 1 * 2).
	messages do: [:aMessage | size := size + (aMessage sizeForValue: encoder)].
	^size! !

!CascadeNode methodsFor: 'accessing' stamp: 'eem 9/10/2008 15:15'!
messages
	^messages! !

!CascadeNode methodsFor: 'accessing' stamp: 'tk 10/22/2000 16:55'!
receiver
	^receiver! !

!CascadeNode methodsFor: 'printing'!
printOn: aStream indent: level
	self printOn: aStream indent: level precedence: 0! !

!CascadeNode methodsFor: 'printing' stamp: 'di 4/25/2000 19:17'!
printOn: aStream indent: level precedence: p 

	p > 0 ifTrue: [aStream nextPut: $(].
	messages first printReceiver: receiver on: aStream indent: level.
	1 to: messages size do: 
		[:i | (messages at: i) printOn: aStream indent: level.
		i < messages size ifTrue: 
				[aStream nextPut: $;.
				messages first precedence >= 2 ifTrue: [aStream crtab: level + 1]]].
	p > 0 ifTrue: [aStream nextPut: $)]! !

!CascadeNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: aStream indent: level
	self printWithClosureAnalysisOn: aStream indent: level precedence: 0! !

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

	p > 0 ifTrue: [aStream nextPut: $(].
	messages first printWithClosureAnalysisReceiver: receiver on: aStream indent: level.
	1 to: messages size do: 
		[:i | (messages at: i) printWithClosureAnalysisOn: aStream indent: level.
		i < messages size ifTrue: 
				[aStream nextPut: $;.
				messages first precedence >= 2 ifTrue: [aStream crtab: level + 1]]].
	p > 0 ifTrue: [aStream nextPut: $)]! !

!CascadeNode methodsFor: 'initialize-release'!
receiver: receivingObject messages: msgs
	" Transcript show: 'abc'; cr; show: 'def' "

	receiver := receivingObject.
	messages := msgs! !


!CommentNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:43'!
accept: aVisitor
	aVisitor visitCommentNode: self! !


!DecompilerConstructor methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:44'!
accept: aVisitor
	"I am not really a ParseNode.  Only here to access constants defined in parseNode."
	self shouldNotImplement! !

!DecompilerConstructor methodsFor: 'constructor'!
codeAnyLitInd: association

	^VariableNode new
		name: association key
		key: association
		index: 0
		type: LdLitIndType! !

!DecompilerConstructor methodsFor: 'constructor'!
codeAnyLiteral: value

	^LiteralNode new
		key: value
		index: 0
		type: LdLitType! !

!DecompilerConstructor methodsFor: 'constructor'!
codeAnySelector: selector

	^SelectorNode new
		key: selector
		index: 0
		type: SendType! !

!DecompilerConstructor methodsFor: 'constructor'!
codeArguments: args block: block

	^block arguments: args! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'eem 5/21/2008 13:28'!
codeArguments: args temps: temps block: block 
	block
		arguments: args;
		temporaries: temps.
	^block! !

!DecompilerConstructor methodsFor: 'constructor'!
codeAssignTo: variable value: expression

	^AssignmentNode new variable: variable value: expression! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'sma 3/3/2000 13:34'!
codeBlock: statements returns: returns
	^ BlockNode statements: statements returns: returns! !

!DecompilerConstructor methodsFor: 'constructor'!
codeBrace: elements

	^BraceNode new elements: elements! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'di 11/19/1999 11:06'!
codeCascade: receiver messages: messages

	^ (BraceNode new matchBraceStreamReceiver: receiver messages: messages)
		ifNil: [CascadeNode new receiver: receiver messages: messages]! !

!DecompilerConstructor methodsFor: 'constructor'!
codeCascadedMessage: selector arguments: arguments

	^self
		codeMessage: nil
		selector: selector
		arguments: arguments! !

!DecompilerConstructor methodsFor: 'constructor'!
codeConstants
	"Answer with an array of the objects representing self, true, false, nil,
	-1, 0, 1, 2."

	^(Array with: NodeSelf with: NodeTrue with: NodeFalse with: NodeNil)
		, ((-1 to: 2) collect: [:i | LiteralNode new key: i code: LdMinus1 + i + 1])! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'sma 3/3/2000 13:35'!
codeEmptyBlock
	^ BlockNode withJust: NodeNil! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'eem 8/21/2008 14:02'!
codeInst: index

	^InstanceVariableNode new
		name: (instVars at: index + 1 ifAbsent: ['unknown', index asString])
		index: index + 1! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'sma 2/5/2000 12:37'!
codeMessage: receiver selector: selector arguments: arguments
	| symbol node |
	symbol := selector key.
	(node := BraceNode new
			matchBraceWithReceiver: receiver
			selector: symbol
			arguments: arguments) ifNotNil: [^ node].
	(node := self decodeIfNilWithReceiver: receiver
			selector: symbol
			arguments: arguments) ifNotNil: [^ node].
	^ MessageNode new
			receiver: receiver selector: selector
			arguments: arguments
			precedence: symbol precedence! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'eem 9/23/2008 22:06'!
codeMethod: selector block: block tempVars: vars primitive: primitive class: class

	| node methodTemps arguments temporaries |
	node := self codeSelector: selector code: nil.
	tempVars := vars.
	methodTemps := tempVars select: [:t | t scope >= 0].
	arguments := methodTemps copyFrom: 1 to: nArgs.
	temporaries := methodTemps copyFrom: nArgs + 1 to: methodTemps size.
	block
		arguments: arguments;
		temporaries: temporaries.
	^MethodNode new
		selector: node
		arguments: arguments
		precedence: selector precedence
		temporaries: temporaries
		block: block
		encoder: (Encoder new initScopeAndLiteralTables
					temps: tempVars
					literals: literalValues
					class: class)
		primitive: primitive! !

!DecompilerConstructor methodsFor: 'constructor'!
codeSelector: sel code: code

	^SelectorNode new key: sel code: code! !

!DecompilerConstructor methodsFor: 'constructor'!
codeSuper

	^NodeSuper! !

!DecompilerConstructor methodsFor: 'constructor'!
codeTemp: index

	^ TempVariableNode new
		name: 't' , (index + 1) printString
		index: index
		type: LdTempType
		scope: 0! !

!DecompilerConstructor methodsFor: 'constructor'!
codeTemp: index named: tempName

	^ TempVariableNode new
		name: tempName
		index: index
		type: LdTempType
		scope: 0! !

!DecompilerConstructor methodsFor: 'constructor'!
codeThisContext

	^NodeThisContext! !

!DecompilerConstructor methodsFor: 'constructor' stamp: 'di 1/28/2000 21:23'!
decodeIfNilWithReceiver: receiver selector: selector arguments: arguments

	selector == #ifTrue:ifFalse:
		ifFalse: [^ nil].
	(receiver isMessage: #==
				receiver: nil
				arguments: [:argNode | argNode == NodeNil])
		ifFalse: [^ nil].
	^ (MessageNode new
			receiver: receiver
			selector: (SelectorNode new key: #ifTrue:ifFalse: code: #macro)
			arguments: arguments
			precedence: 3)
		noteSpecialSelector: #ifNil:ifNotNil:! !

!DecompilerConstructor methodsFor: 'testing' stamp: 'eem 6/4/2008 14:41'!
isForClosures
	^false! !

!DecompilerConstructor methodsFor: 'initialize-release'!
method: aMethod class: aClass literals: literals

	method := aMethod.
	instVars := aClass allInstVarNames.
	nArgs := method numArgs.
	literalValues := literals! !


!DecompilerConstructorForClosures methodsFor: 'constructor' stamp: 'eem 6/11/2009 17:04'!
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 := BytecodeAgnosticMethodNode 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! !

!DecompilerConstructorForClosures methodsFor: 'constructor' stamp: 'eem 10/20/2008 13:01'!
codeRemoteTemp: index remoteTemps: tempVector

	^(RemoteTempVectorNode new
		name: '_r', index printString
		index: index
		type: LdTempType
		scope: 0)
			remoteTemps: tempVector;
			yourself! !

!DecompilerConstructorForClosures methodsFor: 'testing' stamp: 'eem 6/4/2008 14:41'!
isForClosures
	^true! !


!Encoder methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:44'!
accept: aVisitor
	"I am not really a ParseNode.  Only here to access constants defined in parseNode."
	self shouldNotImplement! !

!Encoder methodsFor: 'results' stamp: 'bgf 3/12/2009 17:42'!
allLiterals
	((literalStream isKindOf: WriteStream)
	 and: [ (addedSelectorAndMethodClassLiterals ifNil: [ false ]) not]) ifTrue:
		[addedSelectorAndMethodClassLiterals := true.
		 self litIndex: nil.
		 self litIndex: self associationForClass].
	^literalStream contents

	"The funky ifNil: [false], even though the init method initializes addedSAMCL,
	 is simply so that Monticello can load and compile this update without
	 killing the encoder that is compiling that update itself..."! !

!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'!
literals
	"Should only be used for decompiling primitives"
	^ literalStream contents! !

!Encoder methodsFor: 'results' stamp: 'di 10/12/1999 16:12'!
tempNames 

	^ self tempNodes collect:
		[:node | (node isMemberOf: MessageAsTempNode)
					ifTrue: [scopeTable keyAtValue: node]
					ifFalse: [node key]]! !

!Encoder methodsFor: 'results' stamp: 'eem 5/27/2008 12:07'!
tempNodes 
	| tempNodes |
	tempNodes := SortedCollection sortBlock: [:n1 :n2 | n1 code <= n2 code].
	scopeTable associationsDo:
		[:assn |
		assn value isArray
			ifTrue: [assn value do: [:temp| tempNodes add: temp]]
			ifFalse: [assn value isTemp ifTrue: [tempNodes add: assn value]]].
	^tempNodes! !

!Encoder methodsFor: 'results' stamp: 'eem 9/8/2008 18:27'!
tempsAndBlockArgs
	| tempNodes |
	tempNodes := OrderedCollection new.
	scopeTable associationsDo:
		[:assn | | var |
		var := assn value.
		(var isTemp
		 and: [var isMethodArg not
		 and: [var scope = 0 or: [var scope = -1]]]) ifTrue:
			[tempNodes add: var]].
	^tempNodes! !

!Encoder methodsFor: 'results' stamp: 'eem 6/24/2008 14:24'!
unusedTempNames 
	| unused |
	unused := OrderedCollection new.
	scopeTable associationsDo:
		[:assn | | name |
		(assn value isUnusedTemp) ifTrue:
			[name := assn value key.
			 name ~= self doItInContextName ifTrue: [unused add: name]]].
	^ unused! !

!Encoder methodsFor: 'temps' stamp: 'ar 9/9/2006 12:05'!
autoBind: name 
	"Declare a block argument as a temp if not already declared."
	| node |
	node := scopeTable 
			at: name
			ifAbsent: 
				[(self lookupInPools: name ifFound: [:assoc | assoc])
					ifTrue: [self warnAboutShadowed: name].
				^ (self reallyBind: name) nowHasDef nowHasRef scope: 1].
	node isTemp
		ifTrue: [node scope >= 0 ifTrue:
					[^ self notify: 'Name already used in this method'].
				node nowHasDef nowHasRef scope: 1]
		ifFalse: [^ self notify: 'Name already used in this class'].
	^node! !

!Encoder methodsFor: 'temps' stamp: 'di 10/12/1999 16:53'!
bindAndJuggle: name

	| node nodes first thisCode |
	node := self reallyBind: name.

	"Declared temps must precede block temps for decompiler and debugger to work right"
	nodes := self tempNodes.
	(first := nodes findFirst: [:n | n scope > 0]) > 0 ifTrue:
		[node == nodes last ifFalse: [self error: 'logic error'].
		thisCode := (nodes at: first) code.
		first to: nodes size - 1 do:
			[:i | (nodes at: i) key: (nodes at: i) key
							code: (nodes at: i+1) code].
		nodes last key: nodes last key code: thisCode].
	
	^ node! !

!Encoder methodsFor: 'temps' stamp: 'jm 9/18/97 21:06'!
bindArg: name 
	"Declare an argument."
	| node |
	nTemps >= 15
		ifTrue: [^self notify: 'Too many arguments'].
	node := self bindTemp: name.
	^ node nowHasDef nowHasRef! !

!Encoder methodsFor: 'temps' stamp: 'eem 5/30/2008 12:05'!
bindBlockArg: name within: aBlockNode
	"With standard Smalltalk-80 (BlueBook) blocks it used to be legal to use a
	 method temp as a block argument.  This shouldn't be the case with the
	 current compiler, which checks for temp names already being used as
	 block arguments.  But it is easily fooled by local block temps in optimized
	 blocks, e.g.
		false
			ifTrue: [| temp |]
			ifFalse:[[:temp|]]
	Rather than fix this we keep the semantics and fix it in the closure compiler."
	^self autoBind: name! !

!Encoder methodsFor: 'temps' stamp: 'crl 2/26/1999 12:18'!
bindBlockTemp: name 
	"Declare a temporary block variable; complain if it's not a field or class variable."

	| node |

	node := scopeTable at: name ifAbsent: [^self reallyBind: name].
	node isTemp
		ifTrue: [
			node scope >= 0 ifTrue: [^ self notify: 'Name already used in this method'].
			node scope: 0]
		ifFalse: [^self notify: 'Name already used in this class'].
	^node
! !

!Encoder methodsFor: 'temps' stamp: 'eem 5/30/2008 14:14'!
bindBlockTemp: name within: aBlockNode
	"The BlockContext compiler (the Smalltalk-80 BlueBook compiler)
	 does provide support for ANSI block syntax, but not for ANSI block
	 semantics.  Here all temps live at the same level, the method level.
	 The approach taken to two block-local temps in different blocks is to
	 merge them into a single temp.  e.g.
		expr
			ifTrue: [|temp| self statementOne]
			ifFalse: [|temp| self statementTwo]
	 is effectvely transformed into
		| temp |
		expr
			ifTrue: [self statementOne]
			ifFalse: [self statementTwo]
	 and
		expr do: [:each| | temp | ...].
		expr do: [:each| | temp | ...].
	 is also effectively transformed into
		| temp |
		expr do: [:each|  ...].
		expr do: [:each| ...].

	 The closure compiler treats the former similarly, but not the latter.
	 The indirection through #bindBlockTemp:within: allows the closure encoder to do this."
	^self bindBlockTemp: name! !

!Encoder methodsFor: 'temps' stamp: 'ar 9/9/2006 12:06'!
bindTemp: name 
	"Declare a temporary; error not if a field or class variable."
	scopeTable at: name ifPresent:[:node|
		"When non-interactive raise the error only if its a duplicate"
		(node isTemp)
			ifTrue:[^self notify:'Name is already defined']
			ifFalse:[self warnAboutShadowed: name]].
	^self reallyBind: name! !

!Encoder methodsFor: 'temps' stamp: 'mir 1/17/2004 12:31'!
bindTemp: name in: methodSelector
	"Declare a temporary; error not if a field or class variable."
	scopeTable at: name ifPresent:[:node|
		"When non-interactive raise the error only if its a duplicate"
		(node isTemp or:[requestor interactive])
			ifTrue:[^self notify:'Name is already defined']
			ifFalse:[Transcript 
				show: '(', name, ' is shadowed in "' , class printString , '>>' , methodSelector printString , '")']].
	^self reallyBind: name! !

!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'!
maxTemp

	^nTemps! !

!Encoder methodsFor: 'temps'!
newTemp: name

	nTemps := nTemps + 1.
	^ TempVariableNode new
		name: name
		index: nTemps - 1
		type: LdTempType
		scope: 0! !

!Encoder methodsFor: 'encoding'!
cantStoreInto: varName

	^StdVariables includesKey: varName! !

!Encoder methodsFor: 'encoding' stamp: 'eem 9/5/2009 20:04'!
doItInContextName
	^'ThisContext'! !

!Encoder methodsFor: 'encoding'!
encodeLiteral: object

	^self
		name: object
		key: (class literalScannedAs: object notifying: self)
		class: LiteralNode
		type: LdLitType
		set: litSet! !

!Encoder methodsFor: 'encoding'!
encodeSelector: selector

	^self
		name: selector
		key: selector
		class: SelectorNode
		type: SendType
		set: selectorSet! !

!Encoder methodsFor: 'encoding' stamp: 'di 12/4/1999 20:09'!
encodeVariable: name
	^ self encodeVariable: name sourceRange: nil ifUnknown: [ self undeclared: name ]! !

!Encoder methodsFor: 'encoding' stamp: 'ls 1/19/2001 12:59'!
encodeVariable: name ifUnknown: action
	^self encodeVariable: name sourceRange: nil ifUnknown: action! !

!Encoder methodsFor: 'encoding' stamp: 'yo 11/11/2002 10:22'!
encodeVariable: name sourceRange: range ifUnknown: action
	| varNode |
	varNode := scopeTable at: name
			ifAbsent: 
				[(self lookupInPools: name 
					ifFound: [:assoc | varNode := self global: assoc name: name])
					ifTrue: [varNode]
					ifFalse: [action value]].
	range ifNotNil: [
		name first canBeGlobalVarInitial ifTrue:
			[globalSourceRanges addLast: { name. range. false }]. ].

	(varNode isTemp and: [varNode scope < 0]) ifTrue: [
		OutOfScopeNotification signal ifFalse: [ ^self notify: 'out of scope'].
	].
	^ varNode! !

!Encoder methodsFor: 'encoding' stamp: 'eem 5/27/2009 09:25'!
environment
	"Answer the environment of the current compilation context,
	 be it in a class or global (e.g. a workspace)"
	^class == nil
		ifTrue: [Smalltalk]
		ifFalse: [class environment]! !

!Encoder methodsFor: 'encoding'!
litIndex: literal
	| p |
	p := literalStream position.
	p = 256 ifTrue:
		[self notify: 'More than 256 literals referenced. 
You must split or otherwise simplify this method.
The 257th literal is: ', literal printString. ^nil].
		"Would like to show where it is in the source code, 
		 but that info is hard to get."
	literalStream nextPut: literal.
	^ p! !

!Encoder methodsFor: 'encoding' stamp: 'eem 5/16/2008 18:30'!
sharableLitIndex: literal
	"Special access prevents multiple entries for post-allocated super send special selectors"
	1 to: literalStream position do:
		[:index|
		(litSet literalEquality: literal and: (literalStream originalContents at: index)) ifTrue:
			[^index - 1]].
	^self litIndex: literal! !

!Encoder methodsFor: 'encoding' stamp: 'eem 7/27/2008 17:41'!
undeclared: name
	| sym |
	requestor interactive ifTrue:
		[requestor requestor == #error: ifTrue:
			[requestor error: 'Undeclared'].
		 ^self notify: 'Undeclared'].
	"Allow knowlegeable clients to squash the undeclared warning if they want (e.g.
	 Diffing pretty printers that are simply formatting text).  As this breaks
	 compilation it should only be used by clients that want to discard the result
	 of the compilation.  To squash the warning use e.g.
		[Compiler format: code in: class notifying: nil decorated: false]
			on: UndeclaredVariableWarning
			do: [:ex| ex resume: false]"
	sym := name asSymbol.
	^(UndeclaredVariableWarning new name: name selector: selector class: class) signal
		ifTrue:
			[Undeclared at: sym put: nil.
			self global: (Undeclared associationAt: sym) name: sym]
		ifFalse:
			[self global: (Association key: sym) name: sym]! !

!Encoder methodsFor: 'private'!
classEncoding
	"This is a hack so that the parser may findout what class it was parsing for when it wants to create a syntax error view."
	^ class! !

!Encoder methodsFor: 'private' stamp: 'ar 8/14/2001 23:12'!
global: ref name: name

	^self
		name: name
		key: ref
		class: LiteralVariableNode
		type: LdLitIndType
		set: litIndSet! !

!Encoder methodsFor: 'private' stamp: 'ar 3/26/2004 15:44'!
interactive
	^requestor interactive! !

!Encoder methodsFor: 'private' stamp: 'eem 9/10/2008 14:03'!
lookupInPools: varName ifFound: assocBlock

	^Symbol
		hasInterned: varName
		ifTrue:
			[:sym|
			(class bindingOf: sym)
				ifNil: [^false]
				ifNotNil: [:assoc| assocBlock value: assoc]]! !

!Encoder methodsFor: 'private' stamp: 'eem 6/11/2008 17:31'!
name: name key: key class: leafNodeClass type: type set: dict

	^dict 
		at: key
		ifAbsent: 
			[dict
				at: key
				put: (leafNodeClass new
						name: name
						key: key
						index: nil
						type: type)]! !

!Encoder methodsFor: 'private' stamp: 'ar 1/2/2002 14:53'!
possibleNamesFor: proposedName
	| results |
	results := class possibleVariablesFor: proposedName continuedFrom: nil.
	^ proposedName correctAgainst: nil continuedFrom: results.
! !

!Encoder methodsFor: 'private' stamp: 'yo 11/11/2002 10:23'!
possibleVariablesFor: proposedVariable

	| results |
	results := proposedVariable correctAgainstDictionary: scopeTable
								continuedFrom: nil.
	proposedVariable first canBeGlobalVarInitial ifTrue:
		[ results := class possibleVariablesFor: proposedVariable
						continuedFrom: results ].
	^ proposedVariable correctAgainst: nil continuedFrom: results.
! !

!Encoder methodsFor: 'private'!
reallyBind: name

	| node |
	node := self newTemp: name.
	scopeTable at: name put: node.
	^node! !

!Encoder methodsFor: 'private' stamp: 'eem 6/19/2008 13:02'!
warnAboutShadowed: name
	requestor addWarning: name,' is shadowed'.
	selector ifNotNil:
		[Transcript cr; show: class name,'>>', selector, '(', name,' is shadowed)']! !

!Encoder methodsFor: 'initialize-release'!
fillDict: dict with: nodeClass mapping: keys to: codeArray
	| codeStream |
	codeStream := ReadStream on: codeArray.
	keys do: 
		[:key | dict 
				at: key
				put:  (nodeClass new name: key key: key code: codeStream next)]! !

!Encoder methodsFor: 'initialize-release' stamp: 'eem 6/24/2008 14:24'!
init: aClass context: aContext notifying: req
	requestor := req.
	class := aClass.
	nTemps := 0.
	supered := false.
	self initScopeAndLiteralTables.
	class variablesAndOffsetsDo:
		[:variable "<String|CFieldDefinition>" :offset "<Integer|nil>" |
		offset isNil
			ifTrue: [scopeTable at: variable name put: (FieldNode new fieldDefinition: variable)]
			ifFalse: [scopeTable
						at: variable
						put: (offset >= 0
								ifTrue: [InstanceVariableNode new
											name: variable index: offset]
								ifFalse: [MaybeContextInstanceVariableNode new
											name: variable index: offset negated])]].
	aContext ~~ nil ifTrue:
		[| 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: 'initialize-release' stamp: 'eem 3/12/2009 16:13'!
initScopeAndLiteralTables

	scopeTable := StdVariables copy.
	litSet := StdLiterals copy.
	"comments can be left hanging on nodes from previous compilations.
	 probably better than this hack fix is to create the nodes afresh on each compilation."
	scopeTable do:
		[:varNode| varNode comment: nil].
	litSet do:
		[:varNode| varNode comment: nil].
	selectorSet := StdSelectors copy.
	litIndSet := Dictionary new: 16.
	literalStream := WriteStream on: (Array new: 32).
	addedSelectorAndMethodClassLiterals := false! !

!Encoder methodsFor: 'initialize-release' stamp: 'ajh 1/24/2003 18:46'!
nTemps: n literals: lits class: cl 
	"Decompile."

	supered := false.
	class := cl.
	nTemps := n.
	literalStream := ReadStream on: lits.
	literalStream position: lits size.
	sourceRanges := Dictionary new: 32.
	globalSourceRanges := OrderedCollection new: 32.
! !

!Encoder methodsFor: 'initialize-release'!
noteSuper

	supered := true! !

!Encoder methodsFor: 'initialize-release'!
release

	requestor := nil! !

!Encoder methodsFor: 'initialize-release' stamp: 'ajh 7/21/2003 00:53'!
temps: tempVars literals: lits class: cl 
	"Decompile."

	supered := false.
	class := cl.
	nTemps := tempVars size.
	tempVars do: [:node | scopeTable at: node name put: node].
	literalStream := ReadStream on: lits.
	literalStream position: lits size.
	sourceRanges := Dictionary new: 32.
	globalSourceRanges := OrderedCollection new: 32.
! !

!Encoder methodsFor: 'source mapping' stamp: 'di 12/4/1999 22:27'!
globalSourceRanges

	^ globalSourceRanges! !

!Encoder methodsFor: 'source mapping'!
noteSourceRange: range forNode: node

	sourceRanges at: node put: range! !

!Encoder methodsFor: 'source mapping' stamp: 'RAA 8/21/1999 06:52'!
rawSourceRanges

	^ sourceRanges ! !

!Encoder methodsFor: 'source mapping'!
sourceMap
	"Answer with a sorted set of associations (pc range)."

	^ (sourceRanges keys collect: 
		[:key |  Association key: key pc value: (sourceRanges at: key)])
			asSortedCollection! !

!Encoder methodsFor: 'source mapping' stamp: 'ar 11/19/2002 14:41'!
sourceRangeFor: node

	^sourceRanges at: node! !

!Encoder methodsFor: 'accessing' stamp: 'eem 5/29/2008 09:36'!
methodNodeClass
	^MethodNode! !

!Encoder methodsFor: 'accessing' stamp: 'ar 9/9/2006 12:06'!
selector
	^selector! !

!Encoder methodsFor: 'accessing' stamp: 'ar 9/9/2006 12:06'!
selector: aSymbol
	selector := aSymbol! !

!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! !

!Encoder methodsFor: 'error handling'!
requestor: req
	"Often the requestor is a BrowserCodeController"
	requestor := req! !


!BytecodeEncoder methodsFor: 'temps' stamp: 'eem 6/23/2008 10:55'!
bindAndJuggle: name
	"This is used to insert a new temp and reorcder temps on editing.
	 It doesn't really work for closure compilation since we have multiple
	 locations for temps.  Simply signal a reparse is necessary."

	ReparseAfterSourceEditing signal! !

!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: 'eem 7/18/2008 07:33'!
bindTemp: name
	"Declare a temporary; error not if a field or class variable or out-of-scope temp.
	 Read the comment in Encoder>>bindBlockArg:within: and subclass implementations."
	self supportsClosureOpcodes ifFalse:
		[^super bindTemp: name].
	scopeTable at: name ifPresent:
		[:node|
		"When non-interactive raise the error only if it is a duplicate"
		node isTemp
			ifTrue:[node scope >= 0 ifTrue:
						[^self notify:'Name is already defined']]
			ifFalse:[self warnAboutShadowed: name]].
	^self reallyBind: name! !

!BytecodeEncoder methodsFor: 'temps' stamp: 'eem 6/5/2009 16:51'!
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|
					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! !

!BytecodeEncoder methodsFor: 'temps' stamp: 'eem 6/3/2008 12:33'!
noteBlockExtent: blockExtent hasLocals: tempNodes
	blockExtentsToLocals ifNil:
		[blockExtentsToLocals := Dictionary new].
	blockExtentsToLocals at: blockExtent put: tempNodes asArray! !

!BytecodeEncoder methodsFor: 'testing' stamp: 'eem 6/29/2009 11:11'!
hasGeneratedMethod
	^blockExtentsToLocals notNil! !

!BytecodeEncoder methodsFor: 'testing' stamp: 'eem 7/17/2008 12:34'!
supportsClosureOpcodes
	"Answer if the receiver supports the
		genPushNewArray:/genPushConsArray:
		genPushRemoteTemp:inVectorAt:
		genStoreRemoteTemp:inVectorAt:
		genStorePopRemoteTemp:inVectorAt:
		genPushClosureCopyCopiedValues:numArgs:jumpSize:
	 opcodes"
	^false! !

!BytecodeEncoder methodsFor: 'special literal encodings' stamp: 'eem 5/14/2008 16:02'!
if: code isSpecialLiteralForPush: aBlock
	"If code is that of a special literal for push then evaluate aBlock with the special literal
	 The special literals for push are nil true false -1 0 1 & 2 which have special encodings
	 in the blue book bytecode set.  Answer whether it was a special literal."
	^(code between: LdTrue and: LdNil + 4)
	    and: [aBlock value: (#(true false nil -1 0 1 2) at: code - LdSelf).
			true]! !

!BytecodeEncoder methodsFor: 'special literal encodings' stamp: 'eem 5/14/2008 17:49'!
if: code isSpecialLiteralForReturn: aBlock
	"If code is that of a special literal for return then evaluate aBlock with the special literal.
	 The special literals for return are nil true false which have special encodings
	 in the blue book bytecode set.  Answer whether it was a special literal."
	^(code between: LdTrue and: LdNil)
	   and: [aBlock value: (#(true false nil) at: code - LdSelf).
			true]! !

!BytecodeEncoder methodsFor: 'accessing' stamp: 'eem 5/29/2008 09:36'!
methodNodeClass
	^BytecodeAgnosticMethodNode! !

!BytecodeEncoder methodsFor: 'accessing' stamp: 'eem 5/14/2008 17:47'!
methodStreamPosition
	^stream position! !

!BytecodeEncoder methodsFor: 'accessing' stamp: 'eem 5/24/2008 11:56'!
rootNode "^<BlockNode>"
	^rootNode! !

!BytecodeEncoder methodsFor: 'accessing' stamp: 'eem 5/24/2008 11:56'!
rootNode: node "<BlockNode>"
	rootNode := node! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 7/27/2008 00:39'!
nextPut: aByte
	"For sizing make the encoder its own stream and
	 keep track of position with this version of nextPut:"
	position := position + 1! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 18:22'!
sizeBranchPopFalse: distance
	^self sizeOpcodeSelector: #genBranchPopFalse: withArguments: {distance}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 18:22'!
sizeBranchPopTrue: distance
	^self sizeOpcodeSelector: #genBranchPopTrue: withArguments: {distance}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:28'!
sizeDup
	^self sizeOpcodeSelector: #genDup withArguments: #()! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:40'!
sizeJump: distance
	^self sizeOpcodeSelector: #genJump: withArguments: {distance}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:40'!
sizeJumpLong: distance
	^self sizeOpcodeSelector: #genJumpLong: withArguments: {distance}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 7/27/2008 00:39'!
sizeOpcodeSelector: genSelector withArguments: args
	stream := self.
	position := 0.
	self perform: genSelector withArguments: args.
	^position! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:28'!
sizePop
	^self sizeOpcodeSelector: #genPop withArguments: #()! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/30/2008 16:46'!
sizePushClosureCopyNumCopiedValues: numCopied numArgs: numArgs jumpSize: jumpSize
	^self
		sizeOpcodeSelector: #genPushClosureCopyNumCopiedValues:numArgs:jumpSize:
		withArguments: {numCopied. numArgs. jumpSize}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/30/2008 16:36'!
sizePushConsArray: numElements
	^self sizeOpcodeSelector: #genPushConsArray: withArguments: {numElements}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 16:22'!
sizePushInstVar: instVarIndex
	^self sizeOpcodeSelector: #genPushInstVar: withArguments: {instVarIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 6/19/2008 08:54'!
sizePushInstVarLong: instVarIndex
	^self sizeOpcodeSelector: #genPushInstVarLong: withArguments: {instVarIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:43'!
sizePushLiteral: literalIndex
	^self sizeOpcodeSelector: #genPushLiteral: withArguments: {literalIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:43'!
sizePushLiteralVar: literalIndex
	^self sizeOpcodeSelector: #genPushLiteralVar: withArguments: {literalIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/24/2008 12:35'!
sizePushNewArray: size
	^self sizeOpcodeSelector: #genPushNewArray: withArguments: {size}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 16:21'!
sizePushReceiver
	^self sizeOpcodeSelector: #genPushReceiver withArguments: #()! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/24/2008 22:59'!
sizePushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	^self sizeOpcodeSelector: #genPushRemoteTemp:inVectorAt: withArguments: {tempIndex. tempVectorIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:37'!
sizePushSpecialLiteral: specialLiteral
	^self sizeOpcodeSelector: #genPushSpecialLiteral: withArguments: {specialLiteral}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:26'!
sizePushTemp: tempIndex
	^self sizeOpcodeSelector: #genPushTemp: withArguments: {tempIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:28'!
sizePushThisContext
	^self sizeOpcodeSelector: #genPushThisContext withArguments: #()! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/15/2008 09:07'!
sizeReturnReceiver
	^self sizeOpcodeSelector: #genReturnReceiver withArguments: #()! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:38'!
sizeReturnSpecialLiteral: specialLiteral
	^self sizeOpcodeSelector: #genReturnSpecialLiteral: withArguments: {specialLiteral}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:34'!
sizeReturnTop
	^self sizeOpcodeSelector: #genReturnTop withArguments: #()! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/15/2008 09:06'!
sizeReturnTopToCaller
	^self sizeOpcodeSelector: #genReturnTopToCaller withArguments: #()! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 16:11'!
sizeSend: selectorLiteralIndex numArgs: nArgs
	^self sizeOpcodeSelector: #genSend:numArgs: withArguments: {selectorLiteralIndex. nArgs}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 16:11'!
sizeSendSuper: selectorLiteralIndex numArgs: nArgs
	^self sizeOpcodeSelector: #genSendSuper:numArgs: withArguments: {selectorLiteralIndex. nArgs}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:44'!
sizeStoreInstVar: instVarIndex
	^self sizeOpcodeSelector: #genStoreInstVar: withArguments: {instVarIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 6/19/2008 08:54'!
sizeStoreInstVarLong: instVarIndex
	^self sizeOpcodeSelector: #genStoreInstVarLong: withArguments: {instVarIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:43'!
sizeStoreLiteralVar: literalIndex
	^self sizeOpcodeSelector: #genStoreLiteralVar: withArguments: {literalIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/15/2008 10:00'!
sizeStorePopInstVar: instVarIndex
	^self sizeOpcodeSelector: #genStorePopInstVar: withArguments: {instVarIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 6/19/2008 08:54'!
sizeStorePopInstVarLong: instVarIndex
	^self sizeOpcodeSelector: #genStorePopInstVarLong: withArguments: {instVarIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/15/2008 10:20'!
sizeStorePopLiteralVar: literalIndex
	^self sizeOpcodeSelector: #genStorePopLiteralVar: withArguments: {literalIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/24/2008 23:02'!
sizeStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	^self sizeOpcodeSelector: #genStorePopRemoteTemp:inVectorAt: withArguments: {tempIndex. tempVectorIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:36'!
sizeStorePopTemp: tempIndex
	^self sizeOpcodeSelector: #genStorePopTemp: withArguments: {tempIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/24/2008 23:02'!
sizeStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	^self sizeOpcodeSelector: #genStoreRemoteTemp:inVectorAt: withArguments: {tempIndex. tempVectorIndex}! !

!BytecodeEncoder methodsFor: 'opcode sizing' stamp: 'eem 5/14/2008 17:45'!
sizeStoreTemp: tempIndex
	^self sizeOpcodeSelector: #genStoreTemp: withArguments: {tempIndex}! !

!BytecodeEncoder methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:52'!
outOfRangeError: string index: index range: rangeStart to: rangeEnd
	"For now..."
	^self error: thisContext sender method selector, ' ', string
				, ' index ', index printString
				, ' is out of range ', rangeStart printString, ' to ', rangeEnd printString! !

!BytecodeEncoder methodsFor: 'results' stamp: 'eem 6/5/2009 17:53'!
printSchematicTempNamesOn: aStream blockExtents: blockExtents fromIndex: startIndex
	"Print the locals in the blockExtent startIndex, recursing to print any locals in nested blockExtents.
	 Answer the index of the last blockExtent printed."
	| blockExtent subsequentIndex |
	blockExtent := blockExtents at: startIndex.
	blockExtent first > 0 ifTrue:
		[aStream nextPut: $[ ].
	((blockExtentsToLocals at: blockExtent) reject: [:local| local isRemote])
		do:	[:local|
			local isIndirectTempVector
				ifTrue:
					[aStream nextPut: $(.
					 local remoteTemps
						do: [:remoteLocal| aStream nextPutAll: remoteLocal key]
						separatedBy: [aStream space].
					 aStream nextPut: $)]
				ifFalse: [aStream nextPutAll: local key]]
		separatedBy: [aStream space].
	subsequentIndex := startIndex + 1.
	[subsequentIndex <= blockExtents size
	 and: [(blockExtents at: subsequentIndex) last < blockExtent last]] whileTrue:
		[subsequentIndex := self printSchematicTempNamesOn: aStream
								blockExtents: blockExtents
								fromIndex: subsequentIndex].
	blockExtent first > 0 ifTrue:
		[aStream nextPut: $] ].
	^subsequentIndex! !

!BytecodeEncoder methodsFor: 'results' stamp: 'eem 5/29/2009 09:11'!
schematicTempNamesOn: aStream blockExtents: blockExtents fromIndex: startIndex
	"Print the locals in the blockExtent startIndex, recursing to print any locals in nested blockExtents.
	 Answer the index of the last blockExtent printed."
	| blockExtent subsequentIndex |
	blockExtent := blockExtents at: startIndex.
	((blockExtentsToLocals at: blockExtent) reject: [:local| local isRemote]) do:
		[:local|
		local isIndirectTempVector
			ifTrue: [local remoteTemps do:
						[:remoteLocal| aStream nextPut: remoteLocal key]]
			ifFalse: [aStream nextPut: local key]].
	subsequentIndex := startIndex + 1.
	[subsequentIndex <= blockExtents size
	 and: [(blockExtents at: subsequentIndex) last < blockExtent last]] whileTrue:
		[aStream nextPut: (Array streamContents:
				[:nestedTempStream|
				subsequentIndex := self schematicTempNamesOn: nestedTempStream
										blockExtents: blockExtents
										fromIndex: subsequentIndex])].
	^subsequentIndex! !

!BytecodeEncoder methodsFor: 'results' stamp: 'nice 10/21/2009 00:02'!
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 occurr
	 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 teh schematicTempNamesString."
	blockExtentsToLocals ifNil:
		[self error: 'blockExtentsToLocals uninitialized.  method not yet generated?'].
	^String streamContents:
		[:aStream|
		self printSchematicTempNamesOn: aStream
			blockExtents: (blockExtentsToLocals keys asArray sort:
							[:range1 :range2|
							range1 first <= range2 first])
			fromIndex: 1]! !

!BytecodeEncoder methodsFor: 'initialize-release' stamp: 'eem 7/24/2008 17:24'!
streamToMethod: aCompiledMethod
	stream := WriteStream with: aCompiledMethod.
	stream position: aCompiledMethod initialPC - 1! !


!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:52'!
genBranchPopFalse: distance
	"See BlueBook page 596"
	distance < 0 ifTrue:
		[^self outOfRangeError: 'distance' index: distance range: 0 to: 1023].
	distance < 1024 ifTrue:
		["172-175 	101011ii jjjjjjjj 	Pop and Jump On False ii *256+jjjjjjjj"
		 stream
			nextPut: 172 + (distance bitShift: -8);
			nextPut: distance + 1024 \\ 256.
		 ^self].
	^self outOfRangeError: 'distance' index: distance range: 0 to: 1023! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:53'!
genBranchPopTrue: distance
	"See BlueBook page 596"
	distance < 0 ifTrue:
		[^self outOfRangeError: 'distance' index: distance range: 0 to: 1023].
	distance < 1024 ifTrue:
		["168-171 	101010ii jjjjjjjj 	Pop and Jump On True ii *256+jjjjjjjj"
		 stream
			nextPut: 168 + (distance bitShift: -8);
			nextPut: distance + 1024 \\ 256.
		 ^self].
	^self outOfRangeError: 'distance' index: distance range: 0 to: 1023! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genDup
	"See BlueBook page 596"
	"136 	10001000 	Duplicate Stack Top"
	stream nextPut: 136! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:20'!
genJump: distance
	"See BlueBook page 596"
	^self genJumpLong: distance! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:53'!
genJumpLong: distance
	"See BlueBook page 596"
	(distance >= -1024 and: [distance < 1024]) ifTrue:
		["160-167 	10100iii jjjjjjjj 	Jump(iii - 4) *256+jjjjjjjj"
		 stream
			nextPut: 160 + (distance + 1024 bitShift: -8);
			nextPut: distance + 1024 \\ 256.
		 ^self].
	^self outOfRangeError: 'distance' index: distance range: -1024 to: 1023! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genPop
	"See BlueBook page 596"
	"135 	10000111 	Pop Stack Top"
	stream nextPut: 135! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:46'!
genPushInstVar: instVarIndex
	"See BlueBook page 596"
	(instVarIndex >= 0 and: [instVarIndex < 64]) ifTrue: 
		["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 128;
			nextPut: instVarIndex.
		 ^self].
	self genPushInstVarLong: instVarIndex! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:51'!
genPushInstVarLong: instVarIndex
	"See BlueBook page 596"
	"See also MaybeContextInstanceVariableNode"
	(instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 64;
			nextPut: instVarIndex.
		 ^self].
	^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:54'!
genPushLiteral: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue: 
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 64 ifTrue: 
		["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 128;
			nextPut: 128 + literalIndex.
		 ^self].
	literalIndex < 256 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 96;
			nextPut: literalIndex.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:54'!
genPushLiteralVar: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue: 
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 64 ifTrue: 
		["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 128;
			nextPut: 192 + literalIndex.
		 ^self].
	literalIndex < 256 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 128;
			nextPut: literalIndex.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genPushReceiver
	"See BlueBook page 596"
	"112-119 	01110iii 	Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]"
	stream nextPut: 112! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genPushSpecialLiteral: aLiteral
	"112-119 	01110iii 	Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]"
	| index |
	index := #(true false nil -1 0 1 2) indexOf: aLiteral ifAbsent: 0.
	index = 0 ifTrue:
		[^self error: 'push special literal: ', aLiteral printString,  ' is not one of true false nil -1 0 1 2'].
	stream nextPut: index + 112! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:54'!
genPushTemp: tempIndex
	"See BlueBook page 596"
	tempIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
	tempIndex < 64 ifTrue: 
		["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 128;
			nextPut: 64 + tempIndex.
		 ^self].
	^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genPushThisContext
	"See BlueBook page 596"
	"137 	10001001 	Push Active Context"
	stream nextPut: 137! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genReturnReceiver
	"See BlueBook page 596"
	"120-123 	011110ii 	Return (receiver, true, false, nil) [ii] From Message"
	stream nextPut: 120! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genReturnSpecialLiteral: aLiteral
	"120-123 	011110ii 	Return (receiver, true, false, nil) [ii] From Message"
	| index |
	index := #(true false nil) indexOf: aLiteral ifAbsent: 0.
	index = 0 ifTrue:
		[^self error: 'return special literal: ', aLiteral printString,  ' is not one of true false nil'].
	stream nextPut: 120 + index! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genReturnTop
	"See BlueBook page 596"
	"124-125 	0111110i 	Return Stack Top From (Message, Block) [i]"
	stream nextPut: 124! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 14:12'!
genReturnTopToCaller
	"See BlueBook page 596"
	"124-125 	0111110i 	Return Stack Top From (Message, Block) [i]"
	stream nextPut: 125! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:56'!
genSend: selectorLiteralIndex numArgs: nArgs
	"See BlueBook page 596 (with exceptions for 132 & 134)"
	nArgs < 0 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31 "!!!!"].
	selectorLiteralIndex < 0 ifTrue:
		["No special selector sends in long form."
		^self outOfRangeError: 'selector literal index' index: selectorLiteralIndex range: 0 to: 255].
	(selectorLiteralIndex < 32 and: [nArgs < 8]) ifTrue: 
		["	131 	10000011 jjjkkkkk 	Send Literal Selector #kkkkk With jjj Arguments"
		 stream
			nextPut: 131;
			nextPut: ((nArgs bitShift: 5) + selectorLiteralIndex).
		 ^self].
	(selectorLiteralIndex < 64 and: [nArgs < 4]) ifTrue: 
	 	["In Squeak V3
			134 	10000110 jjjjjjjj kkkkkkkk 	Send Literal Selector #kkkkkkkk To Superclass With jjjjjjjj Arguments
		 is replaced by
			134 	10000110 jjkkkkkk 	Send Literal Selector #kkkkkk With jj Arguments"
		 stream
			nextPut: 134;
			nextPut: ((nArgs bitShift: 6) + selectorLiteralIndex).
		 ^self].
	(selectorLiteralIndex <= 255 and: [nArgs <= 31]) ifTrue: 
		["In Squeak V3
			132 	10000100 jjjjjjjj kkkkkkkk 	Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments
		  is replaced by
			132 	10000100 ooojjjjj kkkkkkkk
				ooo = 0 => Send Literal Selector #kkkkkkkk With jjjjj Arguments
				ooo = 1 => Send Literal Selector #kkkkkkkk To Superclass With jjjjj Arguments"
		stream
			nextPut: 132;
			nextPut: nArgs;
			nextPut: selectorLiteralIndex.
		 ^self].
	nArgs > 31 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31].
	selectorLiteralIndex > 255 ifTrue: 
		[^self outOfRangeError: 'selector literal index' index: selectorLiteralIndex range: 0 to: 255]! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:55'!
genSendSuper: selectorLiteralIndex numArgs: nArgs
	"See BlueBook page 596 (with exceptions for 132 & 134)"
	nArgs < 0 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31 "!!!!"].
	selectorLiteralIndex < 0 ifTrue:
		[^self outOfRangeError: 'selector literal index' index: selectorLiteralIndex range: 0 to: 255].
	(selectorLiteralIndex < 32 and: [nArgs < 8]) ifTrue: 
		["	133 	10000011 jjjkkkkk 	Send Literal Selector #kkkkk To Superclass With jjj Arguments"
		 stream
			nextPut: 133;
			nextPut: ((nArgs bitShift: 5) + selectorLiteralIndex).
		 ^self].
	(selectorLiteralIndex <= 255 and: [nArgs <= 31]) ifTrue: 
		["In Squeak V3
			132 	10000100 jjjjjjjj kkkkkkkk 	Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments
		  is replaced by
			132 	10000100 ooojjjjj kkkkkkkk
				ooo = 0 => Send Literal Selector #kkkkkkkk With jjjjj Arguments
				ooo = 1 => Send Literal Selector #kkkkkkkk To Superclass With jjjjj Arguments"
		stream
			nextPut: 132;
			nextPut: 32 + nArgs;
			nextPut: selectorLiteralIndex.
		 ^self].
	nArgs > 31 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31].
	selectorLiteralIndex > 255 ifTrue: 
		[^self outOfRangeError: 'selector literal index' index: selectorLiteralIndex range: 0 to: 255]! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:48'!
genStoreInstVar: instVarIndex
	"See BlueBook page 596"
	(instVarIndex >= 0 and: [instVarIndex < 64]) ifTrue: 
		["129 	10000001 jjkkkkkk 	Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 129;
			nextPut: instVarIndex.
		 ^self].
	self genStoreInstVarLong: instVarIndex! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:51'!
genStoreInstVarLong: instVarIndex
	"See BlueBook page 596"
	"See also MaybeContextInstanceVariableNode"
	(instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 160;
			nextPut: instVarIndex.
		 ^self].
	^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:57'!
genStoreLiteralVar: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 64 ifTrue: 
		["129 	10000001 jjkkkkkk 	Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 129;
			nextPut: 192 + literalIndex.
		 ^self].
	literalIndex <= 255 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 224;
			nextPut: literalIndex.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:50'!
genStorePopInstVar: instVarIndex
	"See BlueBook page 596"
	(instVarIndex >= 0 and: [instVarIndex < 64]) ifTrue:
		["130 	10000010 jjkkkkkk 	Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 130;
			nextPut: instVarIndex.
		 ^self].
	self genStorePopInstVarLong: instVarIndex! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:51'!
genStorePopInstVarLong: instVarIndex
	"See BlueBook page 596"
	"See also MaybeContextInstanceVariableNode"
	(instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 192;
			nextPut: instVarIndex.
		 ^self].
	^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:58'!
genStorePopLiteralVar: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 64 ifTrue: 
		["130 	10000010 jjkkkkkk 	Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 130;
			nextPut: 192 + literalIndex.
		 ^self].
	literalIndex <= 255 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 224;
			nextPut: literalIndex.
		 self genPop.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:58'!
genStorePopTemp: tempIndex
	"See BlueBook page 596"
	tempIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
	tempIndex < 64 ifTrue: 
		["130 	10000010 jjkkkkkk 	Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 130;
			nextPut: 64 + tempIndex.
		 ^self].
	^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63! !

!EncoderForLongFormV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:58'!
genStoreTemp: tempIndex
	"See BlueBook page 596"
	tempIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
	tempIndex < 64 ifTrue: 
		["129 	10000001 jjkkkkkk 	Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 129;
			nextPut: 64 + tempIndex.
		 ^self].
	^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63! !

!EncoderForLongFormV3 methodsFor: 'initialize-release' stamp: 'eem 5/15/2008 14:11'!
initScopeAndLiteralTables
	super initScopeAndLiteralTables.
	"Start with an empty selector set to avoid the special selectors."
	selectorSet := Dictionary new: 16! !


!EncoderForLongFormV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:10'!
genPushClosureCopyNumCopiedValues: numCopied numArgs: numArgs jumpSize: jumpSize
	"143 	10001111 llllkkkk jjjjjjjj iiiiiiii	Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii"
	(jumpSize < 0 or: [jumpSize > 65535]) ifTrue:
		[^self outOfRangeError: 'block size' index: jumpSize range: 0 to: 65535].
	(numCopied < 0 or: [numCopied > 15]) ifTrue:
		[^self outOfRangeError: 'num copied' index: numCopied range: 0 to: 15].
	(numArgs < 0 or: [numArgs > 15]) ifTrue:
		[^self outOfRangeError: 'num args' index: numArgs range: 0 to: 15].
	stream
		nextPut: 143;
		nextPut: numArgs + (numCopied bitShift: 4);
		nextPut: (jumpSize bitShift: -8);
		nextPut: (jumpSize bitAnd: 16rFF)! !

!EncoderForLongFormV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:06'!
genPushConsArray: size
	(size < 0 or: [size > 127]) ifTrue:
		[^self outOfRangeError: 'numElements' index: size range: 0 to: 127].
	"138 	10001010 1kkkkkkk 	Pop kkkkkkk into: (Array new: kkkkkkk)"
	stream
		nextPut: 138;
		nextPut: size + 128! !

!EncoderForLongFormV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:05'!
genPushNewArray: size
	(size < 0 or: [size > 127]) ifTrue:
		[^self outOfRangeError: 'size' index: size range: 0 to: 127].
	"138 	10001010 0kkkkkkk 	Push (Array new: kkkkkkk)"
	stream
		nextPut: 138;
		nextPut: size! !

!EncoderForLongFormV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 6/16/2008 09:45'!
genPushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	(tempIndex >= 0 and: [tempIndex < 256
	 and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
		["140 	10001100 kkkkkkkk jjjjjjjj 	Push Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
		 stream
			nextPut: 140;
			nextPut: tempIndex;
			nextPut: tempVectorIndex.
		 ^self].
	tempIndex >= 256 ifTrue:
		[^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
	tempVectorIndex >= 256 ifTrue:
		[^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 255]! !

!EncoderForLongFormV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:04'!
genStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	"142 	10001110 kkkkkkkk jjjjjjjj 	Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
	(tempIndex >= 0 and: [tempIndex < 256
	 and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
		[stream
			nextPut: 142;
			nextPut: tempIndex;
			nextPut: tempVectorIndex.
		 ^self].
	tempIndex >= 256 ifTrue:
		[^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
	tempVectorIndex >= 256 ifTrue:
		[^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 255]! !

!EncoderForLongFormV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:04'!
genStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	"141 	10001101 kkkkkkkk jjjjjjjj 	Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
	(tempIndex >= 0 and: [tempIndex < 256
	 and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
		[stream
			nextPut: 141;
			nextPut: tempIndex;
			nextPut: tempVectorIndex.
		 ^self].
	tempIndex >= 256 ifTrue:
		[^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
	tempVectorIndex >= 256 ifTrue:
		[^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 255]! !

!EncoderForLongFormV3PlusClosures methodsFor: 'testing' stamp: 'eem 5/24/2008 18:12'!
supportsClosureOpcodes
	^true! !


!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:59'!
genBranchPopFalse: distance
	"See BlueBook page 596"
	distance < 0 ifTrue:
		[^self outOfRangeError: 'distance' index: distance range: 0 to: 1023].
	(distance > 0 and: [distance < 9]) ifTrue:
		["152-159 	10011iii 	Pop and Jump 0n False iii +1 (i.e., 1 through 8)"
		 stream nextPut: 152 + distance - 1.
		 ^self].
	distance < 1024 ifTrue:
		["172-175 	101011ii jjjjjjjj 	Pop and Jump On False ii *256+jjjjjjjj"
		 stream
			nextPut: 172 + (distance bitShift: -8);
			nextPut: distance + 1024 \\ 256.
		 ^self].
	^self outOfRangeError: 'distance' index: distance range: 0 to: 1023! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:59'!
genBranchPopTrue: distance
	"See BlueBook page 596"
	distance < 0 ifTrue:
		[^self outOfRangeError: 'distance' index: distance range: 0 to: 1023].
	distance < 1024 ifTrue:
		["168-171 	101010ii jjjjjjjj 	Pop and Jump On True ii *256+jjjjjjjj"
		 stream
			nextPut: 168 + (distance bitShift: -8);
			nextPut: distance + 1024 \\ 256.
		 ^self].
	^self outOfRangeError: 'distance' index: distance range: 0 to: 1023! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/15/2008 09:40'!
genDup
	"See BlueBook page 596"
	"136 	10001000 	Duplicate Stack Top"
	stream nextPut: 136! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:41'!
genJump: distance
	"See BlueBook page 596"
	(distance > 0 and: [distance < 9]) ifTrue:
		["144-151 	10010iii 	Jump iii + 1 (i.e., 1 through 8)"
		 stream nextPut: 144 + distance - 1.
		 ^self].
	"160-167 	10100iii jjjjjjjj 	Jump(iii - 4) *256+jjjjjjjj"
	^self genJumpLong: distance! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:59'!
genJumpLong: distance
	"See BlueBook page 596"
	(distance >= -1024 and: [distance < 1024]) ifTrue:
		["160-167 	10100iii jjjjjjjj 	Jump(iii - 4) *256+jjjjjjjj"
		 stream
			nextPut: 160 + (distance + 1024 bitShift: -8);
			nextPut: distance + 1024 \\ 256.
		 ^self].
	^self outOfRangeError: 'distance' index: distance range: -1024 to: 1023! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:27'!
genPop
	"See BlueBook page 596"
	"135 	10000111 	Pop Stack Top"
	stream nextPut: 135! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:40'!
genPushInstVar: instVarIndex
	"See BlueBook page 596"
	instVarIndex >= 0 ifTrue:
		[instVarIndex < 16 ifTrue:
			["0-15 	0000iiii 	Push Receiver Variable #iiii"
			 stream nextPut: 0 + instVarIndex.
			 ^self].
		instVarIndex < 64 ifTrue:
			["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
			 stream
				nextPut: 128;
				nextPut: instVarIndex.
			 ^self]].
	self genPushInstVarLong: instVarIndex! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:51'!
genPushInstVarLong: instVarIndex
	"See BlueBook page 596"
	"See also MaybeContextInstanceVariableNode"
	(instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 64;
			nextPut: instVarIndex.
		 ^self].
	^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:00'!
genPushLiteral: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue: 
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 32 ifTrue: 
		["32-63 	001iiiii 	Push Literal Constant #iiiii"
		 stream nextPut: 32 + literalIndex.
		 ^self].
	literalIndex < 64 ifTrue: 
		["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 128;
			nextPut: 128 + literalIndex.
		 ^self].
	literalIndex < 256 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 96;
			nextPut: literalIndex.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 16:59'!
genPushLiteralVar: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue: 
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 32 ifTrue: 
		["64-95 	010iiiii 	Push Literal Variable #iiiii"
		 stream nextPut: 64 + literalIndex.
		 ^self].
	literalIndex < 64 ifTrue: 
		["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 128;
			nextPut: 192 + literalIndex.
		 ^self].
	literalIndex < 256 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 128;
			nextPut: literalIndex.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 16:16'!
genPushReceiver
	"See BlueBook page 596"
	"112-119 	01110iii 	Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]"
	stream nextPut: 112! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:38'!
genPushSpecialLiteral: aLiteral
	"112-119 	01110iii 	Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]"
	| index |
	index := #(true false nil -1 0 1 2) indexOf: aLiteral ifAbsent: 0.
	index = 0 ifTrue:
		[^self error: 'push special literal: ', aLiteral printString,  ' is not one of true false nil -1 0 1 2'].
	stream nextPut: index + 112! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:00'!
genPushTemp: tempIndex
	"See BlueBook page 596"
	tempIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
	tempIndex < 16 ifTrue: 
		["16-31 	0001iiii 	Push Temporary Location #iiii"
		 stream nextPut: 16 + tempIndex.
		 ^self].
	tempIndex < 64 ifTrue: 
		["128 	10000000 jjkkkkkk 	Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 128;
			nextPut: 64 + tempIndex.
		 ^self].
	^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:36'!
genPushThisContext
	"See BlueBook page 596"
	"137 	10001001 	Push Active Context"
	stream nextPut: 137! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:40'!
genReturnReceiver
	"See BlueBook page 596"
	"120-123 	011110ii 	Return (receiver, true, false, nil) [ii] From Message"
	stream nextPut: 120! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:39'!
genReturnSpecialLiteral: aLiteral
	"120-123 	011110ii 	Return (receiver, true, false, nil) [ii] From Message"
	| index |
	index := #(true false nil) indexOf: aLiteral ifAbsent: 0.
	index = 0 ifTrue:
		[^self error: 'return special literal: ', aLiteral printString,  ' is not one of true false nil'].
	stream nextPut: 120 + index! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:35'!
genReturnTop
	"See BlueBook page 596"
	"124-125 	0111110i 	Return Stack Top From (Message, Block) [i]"
	stream nextPut: 124! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/14/2008 17:35'!
genReturnTopToCaller
	"See BlueBook page 596"
	"124-125 	0111110i 	Return Stack Top From (Message, Block) [i]"
	stream nextPut: 125! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:00'!
genSend: selectorLiteralIndex numArgs: nArgs
	"See BlueBook page 596 (with exceptions for 132 & 134)"
	nArgs < 0 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31 "!!!!"].
	selectorLiteralIndex < 0 ifTrue:
		["Special selector sends.
			176-191 	1011iiii 	Send Arithmetic Message #iiii
			192-207 	1100iiii 	Send Special Message #iiii"
		self flag: #yuck.
		 (selectorLiteralIndex negated between: 176 and: 207) ifFalse:
			[^self outOfRangeError: 'special selector code' index: selectorLiteralIndex negated range: 176 to: 207].
		 stream nextPut: selectorLiteralIndex negated.
		 ^self].
	(selectorLiteralIndex < 16 and: [nArgs < 3]) ifTrue:
		["	208-223 	1101iiii 	Send Literal Selector #iiii With No Arguments
			224-239 	1110iiii 	Send Literal Selector #iiii With 1 Argument
			240-255 	1111iiii 	Send Literal Selector #iiii With 2 Arguments"
		 stream nextPut: 208 + (nArgs * 16) + selectorLiteralIndex.
		 ^self].
	(selectorLiteralIndex < 32 and: [nArgs < 8]) ifTrue: 
		["	131 	10000011 jjjkkkkk 	Send Literal Selector #kkkkk With jjj Arguments"
		 stream
			nextPut: 131;
			nextPut: ((nArgs bitShift: 5) + selectorLiteralIndex).
		 ^self].
	(selectorLiteralIndex < 64 and: [nArgs < 4]) ifTrue: 
	 	["In Squeak V3
			134 	10000110 jjjjjjjj kkkkkkkk 	Send Literal Selector #kkkkkkkk To Superclass With jjjjjjjj Arguments
		 is replaced by
			134 	10000110 jjkkkkkk 	Send Literal Selector #kkkkkk With jj Arguments"
		 stream
			nextPut: 134;
			nextPut: ((nArgs bitShift: 6) + selectorLiteralIndex).
		 ^self].
	(selectorLiteralIndex < 256 and: [nArgs < 32]) ifTrue: 
		["In Squeak V3
			132 	10000100 jjjjjjjj kkkkkkkk 	Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments
		  is replaced by
			132 	10000100 ooojjjjj kkkkkkkk
				ooo = 0 => Send Literal Selector #kkkkkkkk With jjjjj Arguments
				ooo = 1 => Send Literal Selector #kkkkkkkk To Superclass With jjjjj Arguments"
		stream
			nextPut: 132;
			nextPut: nArgs;
			nextPut: selectorLiteralIndex.
		 ^self].
	nArgs >= 32 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31].
	selectorLiteralIndex >= 256 ifTrue: 
		[^self outOfRangeError: 'selector literal index' index: selectorLiteralIndex range: 0 to: 255]! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:00'!
genSendSuper: selectorLiteralIndex numArgs: nArgs
	"See BlueBook page 596 (with exceptions for 132 & 134)"
	nArgs < 0 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31 "!!!!"].
	selectorLiteralIndex < 0 ifTrue:
		[^self outOfRangeError: 'selector literal index' index: selectorLiteralIndex range: 0 to: 255].
	(selectorLiteralIndex < 32 and: [nArgs < 8]) ifTrue: 
		["	133 	10000011 jjjkkkkk 	Send Literal Selector #kkkkk To Superclass With jjj Arguments"
		 stream
			nextPut: 133;
			nextPut: ((nArgs bitShift: 5) + selectorLiteralIndex).
		 ^self].
	(selectorLiteralIndex < 256 and: [nArgs < 32]) ifTrue: 
		["In Squeak V3
			132 	10000100 jjjjjjjj kkkkkkkk 	Send Literal Selector #kkkkkkkk With jjjjjjjj Arguments
		  is replaced by
			132 	10000100 ooojjjjj kkkkkkkk
				ooo = 0 => Send Literal Selector #kkkkkkkk With jjjjj Arguments
				ooo = 1 => Send Literal Selector #kkkkkkkk To Superclass With jjjjj Arguments"
		stream
			nextPut: 132;
			nextPut: 32 + nArgs;
			nextPut: selectorLiteralIndex.
		 ^self].
	nArgs >= 32 ifTrue:
		[^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31].
	selectorLiteralIndex >= 256 ifTrue: 
		[^self outOfRangeError: 'selector literal index' index: selectorLiteralIndex range: 0 to: 255]! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:37'!
genStoreInstVar: instVarIndex
	"See BlueBook page 596"
	(instVarIndex >= 0 and: [instVarIndex < 64]) ifTrue: 
		["129 	10000001 jjkkkkkk 	Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 129;
			nextPut: instVarIndex.
		 ^self].
	self genStoreInstVarLong: instVarIndex! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:51'!
genStoreInstVarLong: instVarIndex
	"See BlueBook page 596"
	"See also MaybeContextInstanceVariableNode"
	(instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 160;
			nextPut: instVarIndex.
		 ^self].
	^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:01'!
genStoreLiteralVar: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 64 ifTrue: 
		["129 	10000001 jjkkkkkk 	Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 129;
			nextPut: 192 + literalIndex.
		 ^self].
	literalIndex < 256 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 224;
			nextPut: literalIndex.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:43'!
genStorePopInstVar: instVarIndex
	"See BlueBook page 596"
	instVarIndex >= 0 ifTrue:
		[instVarIndex < 8 ifTrue:
			["96-103 	01100iii 	Pop and Store Receiver Variable #iii"
			 stream nextPut: 96 + instVarIndex.
			 ^self].
		instVarIndex < 64 ifTrue:
			["130 	10000010 jjkkkkkk 	Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
			 stream
				nextPut: 130;
				nextPut: instVarIndex.
			 ^self]].
	self genStorePopInstVarLong: instVarIndex! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 6/19/2008 08:52'!
genStorePopInstVarLong: instVarIndex
	"See BlueBook page 596"
	"See also MaybeContextInstanceVariableNode"
	(instVarIndex >= 0 and: [instVarIndex < 256]) ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 192;
			nextPut: instVarIndex.
		 ^self].
	^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 255! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:01'!
genStorePopLiteralVar: literalIndex
	"See BlueBook page 596"
	literalIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255].
	literalIndex < 64 ifTrue: 
		["130 	10000010 jjkkkkkk 	Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 130;
			nextPut: 192 + literalIndex.
		 ^self].
	literalIndex < 256 ifTrue: 
		["132 	10000100 iiijjjjj kkkkkkkk 	(Send, Send Super, Push Receiver Variable, Push Literal Constant, Push Literal Variable, Store Receiver Variable, Store-Pop Receiver Variable, Store Literal Variable)[iii] #kkkkkkkk jjjjj"
		 stream
			nextPut: 132;
			nextPut: 224;
			nextPut: literalIndex.
		 self genPop.
		 ^self].
	^self outOfRangeError: 'index' index: literalIndex range: 0 to: 255! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:01'!
genStorePopTemp: tempIndex
	"See BlueBook page 596"
	tempIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
	tempIndex < 8 ifTrue: 
		["104-111 	01101iii 	Pop and Store Temporary Location #iii"
		 stream nextPut: 104 + tempIndex.
		 ^self].
	tempIndex < 64 ifTrue: 
		["130 	10000010 jjkkkkkk 	Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 130;
			nextPut: 64 + tempIndex.
		 ^self].
	^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63! !

!EncoderForV3 methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:01'!
genStoreTemp: tempIndex
	"See BlueBook page 596"
	tempIndex < 0 ifTrue:
		[^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
	tempIndex < 64 ifTrue: 
		["129 	10000001 jjkkkkkk 	Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
		 stream
			nextPut: 129;
			nextPut: 64 + tempIndex.
		 ^self].
	^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63! !


!EncoderForV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:11'!
genPushClosureCopyNumCopiedValues: numCopied numArgs: numArgs jumpSize: jumpSize
	"143 	10001111 llllkkkk jjjjjjjj iiiiiiii	Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii"
	(jumpSize < 0 or: [jumpSize > 65535]) ifTrue:
		[^self outOfRangeError: 'block size' index: jumpSize range: 0 to: 65535].
	(numCopied < 0 or: [numCopied > 15]) ifTrue:
		[^self outOfRangeError: 'num copied' index: numCopied range: 0 to: 15].
	(numArgs < 0 or: [numArgs > 15]) ifTrue:
		[^self outOfRangeError: 'num args' index: numArgs range: 0 to: 15].
	stream
		nextPut: 143;
		nextPut: numArgs + (numCopied bitShift: 4);
		nextPut: (jumpSize bitShift: -8);
		nextPut: (jumpSize bitAnd: 16rFF)! !

!EncoderForV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:03'!
genPushConsArray: size
	(size < 0 or: [size > 127]) ifTrue:
		[^self outOfRangeError: 'numElements' index: size range: 0 to: 127].
	"138 	10001010 1kkkkkkk 	Push (Array new: kkkkkkk)"
	stream
		nextPut: 138;
		nextPut: size + 128! !

!EncoderForV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:06'!
genPushNewArray: size
	(size < 0 or: [size > 127]) ifTrue:
		[^self outOfRangeError: 'numElements' index: size range: 0 to: 127].
	"138 	10001010 0kkkkkkk 	Pop kkkkkkk into: (Array new: kkkkkkk)"
	stream
		nextPut: 138;
		nextPut: size! !

!EncoderForV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 6/16/2008 09:45'!
genPushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	(tempIndex >= 0 and: [tempIndex < 256
	 and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
		["140 	10001100 kkkkkkkk jjjjjjjj 	Push Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
		 stream
			nextPut: 140;
			nextPut: tempIndex;
			nextPut: tempVectorIndex.
		 ^self].
	tempIndex >= 256 ifTrue:
		[^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
	tempVectorIndex >= 256 ifTrue:
		[^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 255]! !

!EncoderForV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:02'!
genStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	"142 	10001110 kkkkkkkk jjjjjjjj 	Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
	(tempIndex >= 0 and: [tempIndex < 256
	 and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
		[stream
			nextPut: 142;
			nextPut: tempIndex;
			nextPut: tempVectorIndex.
		 ^self].
	tempIndex >= 256 ifTrue:
		[^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
	tempVectorIndex >= 256 ifTrue:
		[^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 255]! !

!EncoderForV3PlusClosures methodsFor: 'bytecode generation' stamp: 'eem 5/30/2008 17:02'!
genStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
	"141 	10001101 kkkkkkkk jjjjjjjj 	Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
	(tempIndex >= 0 and: [tempIndex < 256
	 and: [tempVectorIndex >= 0 and: [tempVectorIndex < 256]]]) ifTrue:
		[stream
			nextPut: 141;
			nextPut: tempIndex;
			nextPut: tempVectorIndex.
		 ^self].
	tempIndex >= 256 ifTrue:
		[^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
	tempVectorIndex >= 256 ifTrue:
		[^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 255]! !

!EncoderForV3PlusClosures methodsFor: 'testing' stamp: 'eem 5/24/2008 18:12'!
supportsClosureOpcodes
	^true! !


!LeafNode methodsFor: 'code generation (closures)' stamp: 'eem 6/16/2008 09:32'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	"This is a no-op except in TempVariableNode"
	^self! !

!LeafNode methodsFor: 'code generation' stamp: 'ab 7/6/2004 17:39'!
code

	^ code! !

!LeafNode methodsFor: 'code generation'!
emitForEffect: stack on: strm

	^self! !

!LeafNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:44'!
emitLong: mode on: aStream 
	"Emit extended variable access."
	| type index |
	code < 256
		ifTrue:
			[code < 16
			ifTrue: [type := 0.
					index := code]
			ifFalse: [code < 32
					ifTrue: [type := 1.
							index := code - 16]
					ifFalse: [code < 96
							ifTrue: [type := code // 32 + 1.
									index := code \\ 32]
							ifFalse: [self error: 
									'Sends should be handled in SelectorNode']]]]
		ifFalse: 
			[index := code \\ 256.
			type := code // 256 - 1].
	index <= 63 ifTrue:
		[aStream nextPut: mode.
		^ aStream nextPut: type * 64 + index].
	"Compile for Double-exetended Do-anything instruction..."
	mode = LoadLong ifTrue:
		[aStream nextPut: DblExtDoAll.
		aStream nextPut: (#(64 0 96 128) at: type+1).  "Cant be temp (type=1)"
		^ aStream nextPut: index].
	mode = Store ifTrue:
		[aStream nextPut: DblExtDoAll.
		aStream nextPut: (#(160 0 0 224) at: type+1).  "Cant be temp or const (type=1 or 2)"
		^ aStream nextPut: index].
	mode = StorePop ifTrue:
		[aStream nextPut: DblExtDoAll.
		aStream nextPut: (#(192 0 0 0) at: type+1).  "Can only be inst"
		^ aStream nextPut: index].
! !

!LeafNode methodsFor: 'code generation' stamp: 'eem 5/14/2008 15:57'!
reserve: encoder 
	"If this is a yet unused literal of type -code, reserve it."

	code < 0 ifTrue: [code := self code: (index := encoder litIndex: key) type: 0 - code]! !

!LeafNode methodsFor: 'code generation'!
sizeForEffect: encoder

	^0! !

!LeafNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:44'!
sizeForValue: encoder
	self reserve: encoder.
	code < 256 ifTrue: [^ 1].
	(code \\ 256) <= 63 ifTrue: [^ 2].
	^ 3! !

!LeafNode methodsFor: 'private'!
code: index type: type

	index isNil 
		ifTrue: [^type negated].
	(CodeLimits at: type) > index 
		ifTrue: [^(CodeBases at: type) + index].
	^type * 256 + index! !

!LeafNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForEffect: stack encoder: encoder

	^self! !

!LeafNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/20/2008 15:25'!
emitCodeForLoad: stack encoder: encoder
	"Default is to do nothing.
	 Subclasses may need to override."! !

!LeafNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForEffect: encoder

	^0! !

!LeafNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/20/2008 15:24'!
sizeCodeForLoad: encoder
	"Default is to do nothing.
	 Subclasses may need to override."
	^0! !

!LeafNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/19/2008 15:10'!
sizeCodeForValue: encoder
	self subclassResponsibility! !

!LeafNode methodsFor: 'accessing'!
key

	^key! !

!LeafNode methodsFor: 'initialize-release' stamp: 'ar 3/26/2004 15:44'!
key: object code: byte

	key := object.
	code := byte! !

!LeafNode methodsFor: 'initialize-release' stamp: 'eem 5/14/2008 15:56'!
key: object index: i type: type

	key := object.
	code := (self code: i type: type).
	index := i! !

!LeafNode methodsFor: 'initialize-release' stamp: 'ar 3/26/2004 15:44'!
name: ignored key: object code: byte

	key := object.
	code := byte! !

!LeafNode methodsFor: 'copying' stamp: 'eem 5/14/2008 11:25'!
veryDeepFixupWith: deepCopier
	"If fields were weakly copied, fix them here.  If they were in the tree being copied, fix them up, otherwise point to the originals!!!!"

super veryDeepFixupWith: deepCopier.
key := (deepCopier references at: key ifAbsent: [key]).
! !

!LeafNode methodsFor: 'copying' stamp: 'eem 7/12/2008 17:24'!
veryDeepInner: deepCopier
	"Copy all of my instance variables.  Some need to be not copied at all, but shared.  	Warning!!!!  Every instance variable defined in this class must be handled.  We must also implement veryDeepFixupWith:.  See DeepCopier class comment."

super veryDeepInner: deepCopier.
"key := key.		Weakly copied"
code := code veryDeepCopyWith: deepCopier.
index := index veryDeepCopyWith: deepCopier.
! !


!LiteralNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:48'!
accept: aVisitor
	aVisitor visitLiteralNode: self! !

!LiteralNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:19'!
emitCodeForValue: stack encoder: encoder
	stack push: 1.
	(encoder
		if: code
		isSpecialLiteralForPush:
			[:specialLiteral|
			 encoder genPushSpecialLiteral: specialLiteral])
		ifFalse:
			[encoder genPushLiteral: index]! !

!LiteralNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:03'!
sizeCodeForValue: encoder
	self reserve: encoder.
	(encoder
		if: code
		isSpecialLiteralForPush:
			[:specialLiteral|
			 ^encoder sizePushSpecialLiteral: specialLiteral])
		ifFalse:
			[^encoder sizePushLiteral: index]! !

!LiteralNode methodsFor: 'code generation'!
emitForValue: stack on: strm

	code < 256
		ifTrue: [strm nextPut: code]
		ifFalse: [self emitLong: LoadLong on: strm].
	stack push: 1! !

!LiteralNode methodsFor: 'evaluation' stamp: 'tk 8/4/1999 17:35'!
eval
	"When everything in me is a constant, I can produce a value.  This is only used by the Scripting system (TilePadMorph tilesFrom:in:)"

	^ key! !

!LiteralNode methodsFor: 'testing'!
isConstantNumber
	^ key isNumber! !

!LiteralNode methodsFor: 'testing' stamp: 'di 4/5/2000 11:13'!
isLiteral

	^ true! !

!LiteralNode methodsFor: 'testing'!
isSpecialConstant
	^ code between: LdTrue and: LdMinus1+3! !

!LiteralNode methodsFor: 'testing'!
literalValue

	^key! !

!LiteralNode methodsFor: 'initialize-release' stamp: 'eem 5/14/2008 09:30'!
name: literal key: object index: i type: type
	"For compatibility with Encoder>>name:key:class:type:set:"
	^self key: object index: i type: type! !

!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: 'visiting' stamp: 'eem 9/10/2008 15:50'!
accept: aVisitor
	aVisitor visitMessageNode: self! !

!MessageNode methodsFor: 'visiting' stamp: 'eem 9/23/2008 21:52'!
argumentsInEvaluationOrder
	"Answer the receivers arguments in evaluation order.
	 If the receiver is a transformed to:do: node this will undo the misordering done by the transformation."
	^(special > 0
	   and: [(MacroTransformers at: special) == #transformToDo:
	   and: [arguments size >= 7]])
		"arguments are in a weid order and may be nil in a transformed to:do: loop.  sigh...
		 c.f. emitCodeForToDo:encoder:value:"
		ifTrue:
			[(arguments at: 7)	"limitInit"
				ifNil: [{	(arguments at: 4).	"initStmt"
						(arguments at: 5).	"test"
						(arguments at: 3).	"block"
						(arguments at: 6) 	"incStmt" }]
				ifNotNil: [:limitInit|
						{ limitInit.
						(arguments at: 4).	"initStmt"
						(arguments at: 5).	"test"
						(arguments at: 3).	"block"
						(arguments at: 6) 	"incStmt" }]]
		ifFalse:
			[arguments]! !

!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: 'equation translation'!
arguments
	^arguments! !

!MessageNode methodsFor: 'equation translation' stamp: 'tk 10/27/2000 15:11'!
arguments: list
	arguments := list! !

!MessageNode methodsFor: 'equation translation' stamp: 'eem 9/25/2008 14:50'!
eval
	"When everything in me is a constant, I can produce a value.  This is only used by the Scripting system (TilePadMorph tilesFrom:in:)"

	| rec args |
	receiver isVariableNode ifFalse: [^ #illegal].
	rec := receiver key value.
	args := arguments collect: [:each | each eval].
	^ rec perform: selector key withArguments: args! !

!MessageNode methodsFor: 'equation translation'!
receiver
	^receiver! !

!MessageNode methodsFor: 'equation translation' stamp: 'RAA 2/14/2001 14:07'!
receiver: val
	"14 feb 2001 - removed return arrow"

	receiver := val! !

!MessageNode methodsFor: 'equation translation'!
selector
	^selector! !

!MessageNode methodsFor: 'printing' stamp: 'RAA 6/9/2000 18:06'!
asMorphicCaseOn: parent indent: ignored
	"receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"

	| braceNode otherwise |

	braceNode := arguments first.
	otherwise := arguments last.
	((arguments size = 1) or: [otherwise isJustCaseError]) ifTrue: [
		self morphFromKeywords: #caseOf: arguments: {braceNode} on: parent indent: nil.
		^parent
	].
	self morphFromKeywords: #caseOf:otherwise: arguments: arguments on: parent indent: nil.
	^parent
! !

!MessageNode methodsFor: 'printing' stamp: 'RAA 2/15/2001 19:25'!
macroPrinter

	special > 0 ifTrue: [^MacroPrinters at: special].
	^nil
! !

!MessageNode methodsFor: 'printing'!
precedence

	^precedence! !

!MessageNode methodsFor: 'printing' stamp: 'eem 5/6/2008 13:56'!
printCaseOn: aStream indent: level 
	"receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
	| braceNode otherwise extra |
	braceNode := arguments first.
	otherwise := arguments last.
	(arguments size = 1 or: [otherwise isJustCaseError]) ifTrue:
		[otherwise := nil].
	receiver
		printOn: aStream
		indent: level
		precedence: 3.
	aStream nextPutAll: ' caseOf: '.
	braceNode isVariableReference
		ifTrue: [braceNode printOn: aStream indent: level]
		ifFalse: 
			[aStream nextPutAll: '{'; crtab: level + 1.
			 braceNode casesForwardDo:
				[:keyNode :valueNode :last | 
				keyNode printOn: aStream indent: level + 1.
				aStream nextPutAll: ' -> '.
				valueNode isComplex
					ifTrue: 
						[aStream crtab: level + 2.
						extra := 1]
					ifFalse: [extra := 0].
				valueNode printOn: aStream indent: level + 1 + extra.
				last ifTrue: [aStream nextPut: $}]
					ifFalse: [aStream nextPut: $.;
							 crtab: level + 1]]].
	otherwise notNil ifTrue:
		[aStream crtab: level + 1; nextPutAll: ' otherwise: '.
		 extra := otherwise isComplex
					ifTrue: 
						[aStream crtab: level + 2.
						 1]
					ifFalse: [0].
		 otherwise printOn: aStream indent: level + 1 + extra]! !

!MessageNode methodsFor: 'printing' stamp: 'di 5/1/2000 23:20'!
printIfNil: aStream indent: level

	self printReceiver: receiver on: aStream indent: level.

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

!MessageNode methodsFor: 'printing' stamp: 'di 5/1/2000 23:20'!
printIfNilNotNil: aStream indent: level

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

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

!MessageNode methodsFor: 'printing' stamp: 'eem 5/6/2008 13:57'!
printIfOn: aStream indent: level

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

!MessageNode methodsFor: 'printing' stamp: 'eem 9/25/2008 15:41'!
printKeywords: key arguments: args on: aStream indent: level
	| keywords indent arg kwd doCrTab |
	args size = 0 ifTrue:
		[aStream space; nextPutAll: key.
		 ^self].
	keywords := key keywords.
	doCrTab := args size > 2
				or: [{receiver} , args anySatisfy:
						[:thisArg |
						thisArg notNil
						and: [thisArg isBlockNode
							 or: [thisArg isMessageNode and: [thisArg precedence >= 3]]]]].
	1 to: (args size min: keywords size) do:
		[:i |
		arg := args at: i.
		kwd := keywords at: i.
		doCrTab
			ifTrue: [aStream crtab: level+1. indent := 1] "newline after big args"
			ifFalse: [aStream space. indent := 0].
		aStream nextPutAll: kwd; space.
		arg printOn: aStream
			indent: level + 1 + indent
			precedence: (precedence = 2 ifTrue: [1] ifFalse: [precedence])]! !

!MessageNode methodsFor: 'printing' stamp: 'eem 9/25/2008 16:12'!
printOn: aStream indent: level
	"may not need this check anymore - may be fixed by the #receiver: change"
	special ifNil: [^aStream nextPutAll: '** MessageNode with nil special **'].

	special > 0 ifTrue:
		[^self perform: self macroPrinter with: aStream with: level].

	self printReceiver: receiver on: aStream indent: level.
	selector isForFFICall
		ifTrue:
			[aStream space.
			 selector
				printAsFFICallWithArguments: arguments
				on: aStream
				indent: 0]
		ifFalse:
			[self printKeywords: selector key
				 arguments: arguments
				 on: aStream
				 indent: level]! !

!MessageNode methodsFor: 'printing' stamp: 'di 5/30/2000 23:17'!
printOn: strm indent: level precedence: outerPrecedence

	| parenthesize |
	parenthesize := precedence > outerPrecedence
		or: [outerPrecedence = 3 and: [precedence = 3 "both keywords"]].
	parenthesize
		ifTrue: [strm nextPutAll: '('.
				self printOn: strm indent: level.
				strm nextPutAll: ')']
		ifFalse: [self printOn: strm indent: level]! !

!MessageNode methodsFor: 'printing' stamp: 'eem 9/25/2008 14:51'!
printParenReceiver: rcvr on: aStream indent: level
					
	rcvr isBlockNode ifTrue:
		[^rcvr printOn: aStream indent: level].
	aStream nextPut: $(.
	rcvr printOn: aStream indent: level.
	aStream nextPut: $)
! !

!MessageNode methodsFor: 'printing' stamp: 'eem 5/6/2008 14:09'!
printReceiver: rcvr on: aStream indent: level
					
	rcvr ifNil: [^ self].

	"Force parens around keyword receiver of kwd message"
	rcvr printOn: aStream indent: level precedence: precedence! !

!MessageNode methodsFor: 'printing' stamp: 'eem 9/25/2008 14:41'!
printToDoOn: aStream indent: level

	| limitNode |
	self printReceiver: receiver on: aStream indent: level.

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

!MessageNode methodsFor: 'printing' stamp: 'eem 5/6/2008 14:14'!
printWhileOn: aStream indent: level

	self printReceiver: receiver on: aStream indent: level.
	(arguments isEmpty not
	 and: [arguments first isJust: NodeNil]) ifTrue:
			[selector := SelectorNode new
							key:
									(selector key == #whileTrue:
										ifTrue: [#whileTrue]
										ifFalse: [#whileFalse])
							code: #macro.
			arguments := Array new].
	self printKeywords: selector key arguments: arguments
		on: aStream indent: level! !

!MessageNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisCaseOn: aStream indent: level 
	"receiver caseOf: {[key]->[value]. ...} otherwise: [otherwise]"
	| braceNode otherwise extra |
	braceNode := arguments first.
	otherwise := arguments last.
	(arguments size = 1 or: [otherwise isJustCaseError]) ifTrue:
		[otherwise := nil].
	receiver
		printWithClosureAnalysisOn: aStream
		indent: level
		precedence: 3.
	aStream nextPutAll: ' caseOf: '.
	braceNode isVariableReference
		ifTrue: [braceNode printWithClosureAnalysisOn: aStream indent: level]
		ifFalse: 
			[aStream nextPutAll: '{'; crtab: level + 1.
			 braceNode casesForwardDo:
				[:keyNode :valueNode :last | 
				keyNode printWithClosureAnalysisOn: aStream indent: level + 1.
				aStream nextPutAll: ' -> '.
				valueNode isComplex
					ifTrue: 
						[aStream crtab: level + 2.
						extra := 1]
					ifFalse: [extra := 0].
				valueNode printWithClosureAnalysisOn: aStream indent: level + 1 + extra.
				last ifTrue: [aStream nextPut: $}]
					ifFalse: [aStream nextPut: $.;
							 crtab: level + 1]]].
	otherwise notNil ifTrue:
		[aStream crtab: level + 1; nextPutAll: ' otherwise: '.
		 extra := otherwise isComplex
					ifTrue: 
						[aStream crtab: level + 2.
						 1]
					ifFalse: [0].
		 otherwise printWithClosureAnalysisOn: aStream indent: level + 1 + extra]! !

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

	self printWithClosureAnalysisReceiver: receiver on: aStream indent: level.

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

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

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

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

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

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

!MessageNode methodsFor: 'printing' stamp: 'eem 9/25/2008 14:51'!
printWithClosureAnalysisKeywords: key arguments: args on: aStream indent: level
	| keywords indent arg kwd doCrTab |
	args size = 0 ifTrue: [aStream space; nextPutAll: key. ^self].
	keywords := key keywords.
	doCrTab := args size > 2
				or: [{receiver} , args anySatisfy:
						[:thisArg |
						thisArg isBlockNode
						or: [thisArg isMessageNode and: [thisArg precedence >= 3]]]].
	1 to: (args size min: keywords size) do:
		[:i |
		arg := args at: i.
		kwd := keywords at: i.
		doCrTab
			ifTrue: [aStream crtab: level+1. indent := 1] "newline after big args"
			ifFalse: [aStream space. indent := 0].
		aStream nextPutAll: kwd; space.
		arg printWithClosureAnalysisOn: aStream
			indent: level + 1 + indent
			precedence: (precedence = 2 ifTrue: [1] ifFalse: [precedence])]! !

!MessageNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: aStream indent: level
	"may not need this check anymore - may be fixed by the #receiver: change"
	special ifNil: [^aStream nextPutAll: '** MessageNode with nil special **'].

	special > 0 ifTrue:
		[^self perform: self macroPrinter with: aStream with: level].

	self printWithClosureAnalysisReceiver: receiver on: aStream indent: level.
	self printWithClosureAnalysisKeywords: selector key
		 arguments: arguments
		 on: aStream
		 indent: level! !

!MessageNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisOn: strm indent: level precedence: outerPrecedence

	| parenthesize |
	parenthesize := precedence > outerPrecedence
		or: [outerPrecedence = 3 and: [precedence = 3 "both keywords"]].
	parenthesize
		ifTrue: [strm nextPutAll: '('.
				self printWithClosureAnalysisOn: strm indent: level.
				strm nextPutAll: ')']
		ifFalse: [self printWithClosureAnalysisOn: strm indent: level]! !

!MessageNode methodsFor: 'printing' stamp: 'eem 9/25/2008 14:53'!
printWithClosureAnalysisParenReceiver: rcvr on: aStream indent: level
					
	rcvr isBlockNode ifTrue:
		[^rcvr printWithClosureAnalysisOn: aStream indent: level].
	aStream nextPut: $(.
	rcvr printWithClosureAnalysisOn: aStream indent: level.
	aStream nextPut: $)! !

!MessageNode methodsFor: 'printing' stamp: 'eem 6/2/2008 11:47'!
printWithClosureAnalysisReceiver: rcvr on: aStream indent: level
					
	rcvr ifNil: [^self].

	"Force parens around keyword receiver of kwd message"
	rcvr printWithClosureAnalysisOn: aStream indent: level precedence: precedence! !

!MessageNode methodsFor: 'printing' stamp: 'eem 9/25/2008 14:53'!
printWithClosureAnalysisToDoOn: aStream indent: level

	| limitNode |
	self printWithClosureAnalysisReceiver: receiver on: aStream indent: level.

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

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

	self printWithClosureAnalysisReceiver: receiver on: aStream indent: level.
	(arguments isEmpty not
	 and: [arguments first isJust: NodeNil]) ifTrue:
			[selector := SelectorNode new
							key:
									(selector key == #whileTrue:
										ifTrue: [#whileTrue]
										ifFalse: [#whileFalse])
							code: #macro.
			arguments := Array new].
	self printWithClosureAnalysisKeywords: selector key arguments: arguments
		on: aStream indent: level! !

!MessageNode methodsFor: 'printing' stamp: 'di 5/2/2000 00:16'!
test

	3 > 4 ifTrue: [4+5 between: 6 and: 7]
			ifFalse: [4 between: 6+5 and: 7-2]! !

!MessageNode methodsFor: 'testing'!
canCascade

	^(receiver == NodeSuper or: [special > 0]) not! !

!MessageNode methodsFor: 'testing'!
isComplex
	
	^(special between: 1 and: 10) or: [arguments size > 2 or: [receiver isComplex]]! !

!MessageNode methodsFor: 'testing' stamp: 'md 7/27/2006 19:09'!
isMessage
	^true! !

!MessageNode methodsFor: 'testing'!
isMessage: selSymbol receiver: rcvrPred arguments: argsPred
	"Answer whether selector is selSymbol, and the predicates rcvrPred and argsPred
	 evaluate to true with respect to receiver and the list of arguments.  If selSymbol or
	 either predicate is nil, it means 'don't care'.  Note that argsPred takes numArgs
	 arguments.  All block arguments are ParseNodes."

	^(selSymbol isNil or: [selSymbol==selector key]) and:
		[(rcvrPred isNil or: [rcvrPred value: receiver]) and:
			[(argsPred isNil or: [argsPred valueWithArguments: arguments])]]! !

!MessageNode methodsFor: 'testing' stamp: 'ar 7/10/2009 22:42'!
isMessageNode
	^true! !

!MessageNode methodsFor: 'testing' stamp: 'eem 9/23/2008 14:06'!
isNilIf

	^(special between: 3 and: 4)
	   and: [(arguments first returns or: [arguments first isJust: NodeNil])
	   and: [(arguments last returns or: [arguments last isJust: NodeNil])]]! !

!MessageNode methodsFor: 'testing' stamp: 'eem 7/20/2009 09:31'!
isOptimized
	^special > 0! !

!MessageNode methodsFor: 'testing' stamp: 'eem 7/20/2009 10:44'!
isOptimizedLoop
	^special > 0
	   and: [#(transformWhile: transformToDo:) includes: (MacroTransformers at: special)]! !

!MessageNode methodsFor: 'testing' stamp: 'eem 9/26/2008 12:39'!
isReturningIf

	^((special between: 3 and: 4) "ifTrue:ifFalse:/ifFalse:ifTrue:"
	    or: [special between: 17 and: 18]) "ifNil:ifNotNil:/ifNotNil:ifNil:"
		and: [arguments first returns and: [arguments last returns]]! !

!MessageNode methodsFor: 'testing'!
toDoIncrement: variable
	(receiver = variable and: [selector key = #+]) 
		ifFalse: [^ nil].
	arguments first isConstantNumber
		ifTrue: [^ arguments first]
		ifFalse: [^ nil]! !

!MessageNode methodsFor: 'testing'!
toDoLimit: variable
	(receiver = variable and: [selector key = #<= or: [selector key = #>=]]) 
		ifTrue: [^ arguments first]
		ifFalse: [^ nil]! !

!MessageNode methodsFor: 'cascading'!
cascadeReceiver
	"Nil out rcvr (to indicate cascade) and return what it had been."

	| rcvr |
	rcvr := receiver.
	receiver := nil.
	^rcvr! !

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

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

!MessageNode methodsFor: 'private' stamp: 'eem 9/25/2008 14:48'!
checkBlock: node as: nodeName from: encoder maxArgs: maxArgs
	"vb: #canBeSpecialArgument for blocks hardcodes 0 arguments as the requirement for special blocks. We work around that here by further checking the number of arguments for blocks.."

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

!MessageNode methodsFor: 'private' stamp: 'acg 1/28/2000 00:57'!
ifNilReceiver

	^receiver! !

!MessageNode methodsFor: 'private' stamp: 'tk 8/2/1999 18:40'!
pvtCheckForPvtSelector: encoder
	"If the code being compiled is trying to send a private message (e.g. 'pvtCheckForPvtSelector:') to anyone other than self, then complain to encoder."

	selector isPvtSelector ifTrue:
		[receiver isSelfPseudoVariable ifFalse:
			[encoder notify: 'Private messages may only be sent to self']].! !

!MessageNode methodsFor: 'private'!
receiver: rcvr arguments: args precedence: p

	receiver := rcvr.
	arguments := args.
	sizes := Array new: arguments size.
	precedence := p! !

!MessageNode methodsFor: 'code generation' stamp: 'tao 8/20/97 22:24'!
emitCase: stack on: strm value: forValue

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

!MessageNode methodsFor: 'code generation' stamp: 'hmm 7/28/2001 14:39'!
emitForEffect: stack on: strm
	"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: strm with: false]
		ifFalse: 
			[super emitForEffect: stack on: strm]! !

!MessageNode methodsFor: 'code generation' stamp: 'eem 7/29/2008 20:44'!
emitForValue: stack on: strm
	"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: strm with: true]
		ifFalse: 
			[receiver ~~ nil ifTrue: [receiver emitForValue: stack on: strm].
			arguments do: [:argument | argument emitForValue: stack on: strm].
			pc := strm position + 1. "debug pc is first byte of the send, i.e. the next byte".
			selector
				emit: stack
				args: arguments size
				on: strm
				super: receiver == NodeSuper]! !

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

!MessageNode methodsFor: 'code generation' stamp: 'eem 5/23/2008 10:47'!
emitIfNil: stack on: strm value: forValue

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

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

!MessageNode methodsFor: 'code generation' stamp: 'hmm 7/28/2001 14:36'!
emitWhile: stack on: strm value: forValue 
	" L1: ... Bfp(L2)|Btp(L2) ... Jmp(L1) L2: "
	| cond stmt stmtSize loopSize |
	cond := receiver.
	stmt := arguments at: 1.
	stmtSize := sizes at: 1.
	loopSize := sizes at: 2.
	cond emitForEvaluatedValue: stack on: strm.
	self emitBranchOn: (selector key == #whileFalse:)  "Bfp for whileTrue"
					dist: stmtSize pop: stack on: strm.   "Btp for whileFalse"
	pc := strm position.
	stmt emitForEvaluatedEffect: stack on: strm.
	self emitJump: 0 - loopSize on: strm.
	forValue ifTrue: [strm nextPut: LdNil. stack push: 1]! !

!MessageNode methodsFor: 'code generation' stamp: 'tao 8/20/97 22:25'!
sizeCase: encoder value: forValue

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

!MessageNode methodsFor: 'code generation'!
sizeForEffect: encoder

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

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

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

!MessageNode methodsFor: 'code generation' stamp: 'acg 1/28/2000 22:00'!
sizeIfNil: encoder value: forValue

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

! !

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

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

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 9/29/2008 14:45'!
emitCodeForCase: stack encoder: encoder value: forValue

	| braceNode sizeStream allReturn |
	forValue ifFalse:
		[^super emitCodeForEffect: stack encoder: encoder].
	braceNode := arguments first.
	sizeStream := ReadStream on: sizes.
	receiver emitCodeForValue: stack encoder: encoder.
	"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 | | thenSize elseSize |
		thenSize := sizeStream next.
		elseSize := sizeStream next.
		last ifFalse: [encoder genDup. stack push: 1].
		keyNode emitCodeForEvaluatedValue: stack encoder: encoder.
		equalNode emitCode: stack args: 1 encoder: encoder.
		self emitCodeForBranchOn: false dist: thenSize pop: stack encoder: encoder.
		last ifFalse: [encoder genPop. stack pop: 1].
		valueNode emitCodeForEvaluatedValue: stack encoder: encoder.
		last ifTrue: [stack pop: 1].
		valueNode returns ifFalse:
			[self emitCodeForJump: elseSize encoder: encoder.
			 allReturn := false].
		(last and: [allReturn]) ifTrue:
			[self emitCodeForJump: elseSize encoder: encoder]].
	arguments size = 2
		ifTrue:
			[arguments last emitCodeForEvaluatedValue: stack encoder: encoder] "otherwise: [...]"
		ifFalse:
			[NodeSelf emitCodeForValue: stack encoder: encoder.
			caseErrorNode emitCode: stack args: 0 encoder: encoder]! !

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:13'!
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: (NewStyleMacroEmitters at: special) with: stack with: encoder with: false]
		ifFalse: 
			[super emitCodeForEffect: stack encoder: encoder]! !

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:12'!
emitCodeForIf: stack encoder: encoder value: forValue
	| thenExpr thenSize elseExpr elseSize |
	thenSize := sizes at: 1.
	elseSize := sizes at: 2.
	(forValue not and: [elseSize * thenSize > 0]) ifTrue:
		"Two-armed IFs forEffect share a single pop"
		[^super emitCodeForEffect: stack encoder: encoder].
	thenExpr := arguments at: 1.
	elseExpr := arguments at: 2.
	receiver emitCodeForValue: stack encoder: encoder.
	forValue
		ifTrue:  "Code all forValue as two-armed"
			[self emitCodeForBranchOn: false dist: thenSize pop: stack encoder: encoder.
			pc := encoder methodStreamPosition.
			thenExpr emitCodeForEvaluatedValue: stack encoder: encoder.
			stack pop: 1.  "then and else alternate; they don't accumulate"
			thenExpr returns not ifTrue:
				"...not ifTrue: avoids using ifFalse: alone during this compile)"
				"Elide jump over else after a return"
				[self emitCodeForJump: elseSize encoder: encoder].
			elseExpr emitCodeForEvaluatedValue: stack encoder: encoder]
		ifFalse:  "One arm is empty here (two-arms code forValue)"
			[thenSize > 0
				ifTrue:
					[self emitCodeForBranchOn: false dist: thenSize pop: stack encoder: encoder.
					pc := encoder methodStreamPosition.
					thenExpr emitCodeForEvaluatedEffect: stack encoder: encoder]
				ifFalse:
					[self emitCodeForBranchOn: true dist: elseSize pop: stack encoder: encoder.
					pc := encoder methodStreamPosition.
					elseExpr emitCodeForEvaluatedEffect: stack encoder: encoder]]! !

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:28'!
emitCodeForIfNil: stack encoder: encoder value: forValue

	| theNode theSize ifNotNilSelector |
	theNode := arguments first.
	theSize := sizes at: 1.
	ifNotNilSelector := #ifNotNil:.
	receiver emitCodeForValue: stack encoder: encoder.
	forValue ifTrue: [encoder genDup. stack push: 1].
	encoder genPushSpecialLiteral: nil. stack push: 1.
	equalNode emitCode: stack args: 1 encoder: encoder.
	self 
		emitCodeForBranchOn: (selector key == ifNotNilSelector)
		dist: theSize 
		pop: stack 
		encoder: encoder.
	pc := encoder methodStreamPosition.
	forValue 
		ifTrue: 
			[encoder genPop. stack pop: 1.
			theNode emitCodeForEvaluatedValue: stack encoder: encoder]	
		ifFalse: [theNode emitCodeForEvaluatedEffect: stack encoder: encoder]! !

!MessageNode methodsFor: 'code generation (new scheme)' 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 (new scheme)' stamp: 'eem 6/5/2008 16:48'!
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: (NewStyleMacroEmitters 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 (new scheme)' stamp: 'eem 5/14/2008 16:36'!
emitCodeForWhile: stack encoder: encoder value: forValue 
	"L1: ... Bfp(L2)|Btp(L2) ... Jmp(L1) L2: "
	| cond stmt stmtSize loopSize |
	cond := receiver.
	stmt := arguments at: 1.
	stmtSize := sizes at: 1.
	loopSize := sizes at: 2.
	cond emitCodeForEvaluatedValue: stack encoder: encoder.
	self emitCodeForBranchOn: (selector key == #whileFalse:)  "Bfp for whileTrue"
					dist: stmtSize pop: stack encoder: encoder.   "Btp for whileFalse"
	pc := encoder methodStreamPosition.
	stmt emitCodeForEvaluatedEffect: stack encoder: encoder.
	self emitCodeForJump: 0 - loopSize encoder: encoder.
	forValue ifTrue: [encoder genPushSpecialLiteral: nil. stack push: 1]! !

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 9/29/2008 14:43'!
sizeCodeForCase: encoder value: forValue

	| braceNode sizeIndex thenSize 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 |
		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 (new scheme)' stamp: 'eem 5/14/2008 18:16'!
sizeCodeForEffect: encoder

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

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:15'!
sizeCodeForIf: encoder value: forValue
	| thenExpr elseExpr branchSize thenSize elseSize |
	thenExpr := arguments at: 1.
	elseExpr := arguments at: 2.
	(forValue
	 or: [(thenExpr isJust: NodeNil)
	 or: [elseExpr isJust: NodeNil]]) not
			"(...not ifTrue: avoids using ifFalse: alone during this compile)"
		ifTrue:  "Two-armed IFs forEffect share a single pop"
			[^super sizeCodeForEffect: encoder].
	forValue
		ifTrue:  "Code all forValue as two-armed"
			[elseSize := elseExpr sizeCodeForEvaluatedValue: encoder.
			thenSize := (thenExpr sizeCodeForEvaluatedValue: encoder)
					+ (thenExpr returns
						ifTrue: [0]  "Elide jump over else after a return"
						ifFalse: [self sizeCode: encoder forJump: elseSize]).
			branchSize := self sizeCode: encoder forBranchOn: false dist: thenSize]
		ifFalse:  "One arm is empty here (two-arms code forValue)"
			[(elseExpr isJust: NodeNil)
				ifTrue:
					[elseSize := 0.
					thenSize := thenExpr sizeCodeForEvaluatedEffect: encoder.
					branchSize := self sizeCode: encoder forBranchOn: false dist: thenSize]
				ifFalse:
					[thenSize := 0.
					elseSize := elseExpr sizeCodeForEvaluatedEffect: encoder.
					branchSize := self sizeCode: encoder forBranchOn: true dist: elseSize]].
	sizes := Array with: thenSize with: elseSize.
	^(receiver sizeCodeForValue: encoder)
	+ branchSize + thenSize + elseSize! !

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 09:57'!
sizeCodeForIfNil: encoder value: forValue

	| theNode theSize theSelector |
	equalNode := encoder encodeSelector: #==.
	sizes := Array new: 1.
	theNode := arguments first.
	theSelector := #ifNotNil:.
	forValue
		ifTrue:
			[sizes at: 1 put: (theSize := (encoder sizePop + (theNode sizeCodeForEvaluatedValue: encoder))).
			 ^(receiver sizeCodeForValue: encoder)
			 + encoder sizeDup
			 + (encoder sizePushSpecialLiteral: nil)
			 + (equalNode sizeCode: encoder args: 1 super: false)
			 + (self 
					sizeCode: encoder forBranchOn: selector key == theSelector 
					dist: theSize)
			 + theSize]
		ifFalse:
			[sizes at: 1 put: (theSize := (theNode sizeCodeForEvaluatedEffect: encoder)).
			 ^(receiver sizeCodeForValue: encoder)
				+ (encoder sizePushSpecialLiteral: nil)
				+ (equalNode sizeCode: encoder args: 1 super: false)
				+ (self 
					sizeCode: encoder
					forBranchOn: selector key == theSelector 
					dist: theSize)
				+ theSize]! !

!MessageNode methodsFor: 'code generation (new scheme)' 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 (new scheme)' stamp: 'eem 5/14/2008 18:17'!
sizeCodeForValue: encoder
	| total argSize |
	special > 0 
		ifTrue: [^self perform: (NewStyleMacroSizers 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 := arg sizeCodeForValue: encoder.
					total := total + argSize.
					argSize].
	^total! !

!MessageNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 10:00'!
sizeCodeForWhile: encoder value: forValue 
	"L1: ... Bfp(L2) ... Jmp(L1) L2: nil (nil for value only);
	justStmt, wholeLoop, justJump."
	| cond stmt stmtSize loopSize branchSize |
	cond := receiver.
	stmt := arguments at: 1.
	stmtSize := (stmt sizeCodeForEvaluatedEffect: encoder) + (encoder sizeJumpLong: 1).
	branchSize := self
					sizeCode: encoder
					forBranchOn: selector key == #whileFalse:  "Btp for whileFalse"
					dist: stmtSize.
	loopSize := (cond sizeCodeForEvaluatedValue: encoder) + branchSize + stmtSize.
	sizes := Array with: stmtSize with: loopSize.
	^loopSize + (forValue ifTrue: [encoder sizePushSpecialLiteral: nil] ifFalse: [0])! !

!MessageNode methodsFor: 'tiles' stamp: 'RAA 2/14/2001 22:26'!
morphFromKeywords: key arguments: args on: parent indent: ignored

	^parent
		messageNode: self 
		receiver: receiver 
		selector: selector 
		keywords: key 
		arguments: args
! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/23/2008 13:14'!
noteSpecialSelector: selectorSymbol
	"special > 0 denotes specially treated (potentially inlined) messages. "

	special := MacroSelectors indexOf: selectorSymbol.
! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 7/21/2009 12:34'!
toDoFromWhileWithInit: initStmt
	"Return nil, or a to:do: expression equivalent to this whileTrue:"
	| variable increment limit toDoBlock body test |
	(selector key == #whileTrue:
	 and: [initStmt isAssignmentNode
	 and: [initStmt variable isTemp]]) ifFalse:
		[^nil].
	body := arguments last statements.
	variable := initStmt variable.
	increment := body last toDoIncrement: variable.
	(increment == nil
	 or: [receiver statements size ~= 1]) ifTrue:
		[^nil].
	test := receiver statements first.
	"Note: test chould really be checked that <= or >= comparison
	jibes with the sign of the (constant) increment"
	(test isMessageNode
	 and: [(limit := test toDoLimit: variable) notNil]) ifFalse:
		[^nil].
	toDoBlock := BlockNode statements: body allButLast returns: false.
	toDoBlock arguments: (Array with: variable).
	variable scope: -1.
	variable beBlockArg.
	^MessageNode new
		receiver: initStmt value
		selector: (SelectorNode new key: #to:by:do: code: #macro)
		arguments: (Array with: limit with: increment with: toDoBlock)
		precedence: precedence! !

!MessageNode methodsFor: 'macro transformations'!
transform: encoder
	special = 0 ifTrue: [^false].
	(self perform: (MacroTransformers at: special) with: encoder)
		ifTrue: 
			[^true]
		ifFalse: 
			[special := 0. ^false]! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/19/2008 17:15'!
transformAnd: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments := 
				Array 
					with: (arguments at: 1) noteOptimized
					with: (BlockNode withJust: NodeFalse) noteOptimized.
			^true]
		ifFalse: 
			[^false]! !

!MessageNode methodsFor: 'macro transformations'!
transformBoolean: encoder
	^self
		checkBlock: (arguments at: 1)
		as: 'argument'
		from: encoder! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 7/27/2008 18:50'!
transformCase: encoder

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

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/19/2008 17:15'!
transformIfFalse: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments := 
				Array 
					with: (BlockNode withJust: NodeNil) noteOptimized
					with: (arguments at: 1) noteOptimized.
			^true]
		ifFalse:
			[^false]! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 7/27/2008 16:19'!
transformIfFalseIfTrue: encoder
	^(self checkBlock: (arguments at: 1) as: 'False arg' from: encoder)
	   and: [(self checkBlock: (arguments at: 2) as: 'True arg' from: encoder)
	   and: [selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
			arguments swap: 1 with: 2.
			arguments do: [:arg| arg noteOptimized].
			true]]! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/23/2008 10:51'!
transformIfNil: encoder

	"vb: Removed the original transformBoolean: which amounds to a test we perform in each of the branches below."
	(MacroSelectors at: special) = #ifNotNil: ifTrue:
		[(self checkBlock: arguments first as: 'ifNotNil arg' from: encoder maxArgs: 1) ifFalse:
			[^false].

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

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/23/2008 10:56'!
transformIfNilIfNotNil: encoder
	"vb: Changed to support one-argument ifNotNil: branch. In the 1-arg case we
	 transform the receiver to
		(var := receiver)
	 which is further transformed to
		(var := receiver) == nil ifTrue: .... ifFalse: ...
	 This does not allow the block variable to shadow an existing temp, but it's no different
	 from how to:do: is done."
	| ifNotNilArg |
	ifNotNilArg := arguments at: 2.
	((self checkBlock: (arguments at: 1) as: 'Nil arg' from: encoder)
	  and: [self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder maxArgs: 1]) ifFalse:
		[^false].

	ifNotNilArg numberOfArguments = 1 ifTrue:
		[receiver := AssignmentNode new
						variable: ifNotNilArg firstArgument
						value: receiver].

	selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
	receiver := MessageNode new
					receiver: receiver
					selector: #==
					arguments: (Array with: NodeNil)
					precedence: 2
					from: encoder.
	arguments do: [:arg| arg noteOptimized].
	^true! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/23/2008 11:00'!
transformIfNotNilIfNil: encoder
	"vb: Changed to support one-argument ifNotNil: branch. In the 1-arg case we
	 transform the receiver to
		(var := receiver)
	 which is further transformed to
		(var := receiver) == nil ifTrue: .... ifFalse: ...
	 This does not allow the block variable to shadow an existing temp, but it's no different
	 from how to:do: is done."
	| ifNotNilArg |
	ifNotNilArg := arguments at: 1.
	((self checkBlock: ifNotNilArg as: 'NotNil arg' from: encoder maxArgs: 1)
	  and: [self checkBlock: (arguments at: 2) as: 'Nil arg' from: encoder]) ifFalse:
		[^false].

	ifNotNilArg numberOfArguments = 1 ifTrue:
		[receiver := AssignmentNode new
						variable: ifNotNilArg firstArgument
						value: receiver].

	selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
	receiver := MessageNode new
					receiver: receiver
					selector: #==
					arguments: (Array with: NodeNil)
					precedence: 2
					from: encoder.
	arguments swap: 1 with: 2.
	arguments do: [:arg| arg noteOptimized].
	^true! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/19/2008 17:17'!
transformIfTrue: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments := 
				Array 
					with: (arguments at: 1) noteOptimized
					with: (BlockNode withJust: NodeNil) noteOptimized.
			^true]
		ifFalse: 
			[^false]! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/19/2008 17:17'!
transformIfTrueIfFalse: encoder
	^(self checkBlock: (arguments at: 1) as: 'True arg' from: encoder)
	   and: [(self checkBlock: (arguments at: 2) as: 'False arg' from: encoder)
	   and: [arguments do: [:arg| arg noteOptimized].
			true]]! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/19/2008 17:15'!
transformOr: encoder
	(self transformBoolean: encoder)
		ifTrue: 
			[arguments := 
				Array 
					with: (BlockNode withJust: NodeTrue) noteOptimized
					with: (arguments at: 1) noteOptimized.
			^true]
		ifFalse: 
			[^false]! !

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

	"Now generate auxiliary structures"
	myRange := encoder rawSourceRanges at: self ifAbsent: [1 to: 0].
	block := arguments last.
	blockRange := encoder rawSourceRanges at: block ifAbsent: [1 to: 0].
	blockVar := block firstArgument.
	initStmt := AssignmentNode new variable: blockVar value: receiver.
	limit := arguments at: 1.
	limit isVariableReference | limit isConstantNumber
		ifTrue: [limitInit := nil]
		ifFalse:  "Need to store limit in a var"
			[limit := encoder bindBlockArg: blockVar key, 'LimiT' within: block.
			 limit scope: -2.  "Already done parsing block; flag so it won't print"
			 block addArgument: limit.
			 limitInit := AssignmentNode new
							variable: limit
							value: arguments first].
	test := MessageNode new
				receiver: blockVar
				selector: (increment key > 0 ifTrue: [#<=] ifFalse: [#>=])
				arguments: (Array with: limit)
				precedence: precedence from: encoder
				sourceRange: (myRange first to: blockRange first).
	incStmt := AssignmentNode new
				variable: blockVar
				value: (MessageNode new
							receiver: blockVar selector: #+
							arguments: (Array with: increment)
							precedence: precedence from: encoder)
				from: encoder
				sourceRange: (myRange last to: myRange last).
	arguments := (Array with: limit with: increment with: block),
					(Array with: initStmt with: test with: incStmt with: limitInit).
	block noteOptimized.
	^true! !

!MessageNode methodsFor: 'macro transformations' stamp: 'eem 5/19/2008 19:17'!
transformWhile: encoder
	(self checkBlock: receiver as: 'receiver' from: encoder) ifFalse:
		[^false].
	arguments size = 0 ifTrue:  "transform bodyless form to body form"
		[selector := SelectorNode new
						key: (special = 10 ifTrue: [#whileTrue:] ifFalse: [#whileFalse:])
						code: #macro.
		 arguments := Array with: (BlockNode withJust: NodeNil) noteOptimized.
		 receiver noteOptimized.
		 ^true].
	^(self transformBoolean: encoder)
	   and: [receiver noteOptimized.
			arguments first noteOptimized.
			true]! !

!MessageNode methodsFor: 'initialize-release' stamp: 'eem 9/25/2008 17:22'!
receiver: rcvr selector: selNode arguments: args precedence: p 
	"Decompile."

	self receiver: rcvr
		arguments: args
		precedence: p.
	selNode code == #macro
		ifTrue: [self noteSpecialSelector: selNode key]
		ifFalse: [special := 0].
	selector := selNode.
	"self pvtCheckForPvtSelector: encoder"
	"We could test code being decompiled, but the compiler should've checked already. And where to send the complaint?"! !

!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 methodsFor: 'initialize-release' stamp: 'eem 7/18/2008 16:26'!
receiver: rcvr selector: selName arguments: args precedence: p from: encoder sourceRange: range
	"Compile."
	((selName == #future) or:[selName == #future:]) ifTrue:
		[Smalltalk at: #FutureNode ifPresent:
			[:futureNode|
			^futureNode new
				receiver: rcvr
				selector: selName
				arguments: args
				precedence: p
				from: encoder
				sourceRange: range]].
	(rcvr isFutureNode
	 and: [rcvr futureSelector == nil]) ifTrue:
		"Transform regular message into future"
		[^rcvr futureMessage: selName
			arguments: args
			from: encoder
			sourceRange: range].

	encoder noteSourceRange: range forNode: self.
	^self
		receiver: rcvr
		selector: selName
		arguments: args
		precedence: p
		from: encoder! !

!MessageNode methodsFor: 'initialize-release' stamp: 'tk 10/26/2000 15:37'!
selector: sel
	selector := sel! !


!MessageAsTempNode methodsFor: 'access to remote temps' stamp: 'di 3/22/1999 09:38'!
asStorableNode: encoder
	"This node is a message masquerading as a temporary variable.
	It currently has the form {homeContext tempAt: offset}.
	We need to generate code for {expr storeAt: offset inTempFrame: homeContext},
	where the expr, the block argument, is already on the stack.
	This, in turn will get turned into {homeContext tempAt: offset put: expr}
	at runtime if nobody disturbs storeAt:inTempFrame: in Object (not clean)"
	^ MessageAsTempNode new
		receiver: nil  "suppress code generation for reciever already on stack"
		selector: #storeAt:inTempFrame:
		arguments: (arguments copyWith: receiver)
		precedence: precedence
		from: encoder! !

!MessageAsTempNode methodsFor: 'access to remote temps' stamp: 'di 10/12/1999 17:29'!
code
	"Allow synthetic temp nodes to be sorted by code"
	^ arguments first literalValue! !

!MessageAsTempNode methodsFor: 'access to remote temps' stamp: 'di 3/22/1999 09:39'!
emitStorePop: stack on: codeStream
	"This node has the form {expr storeAt: offset inTempFrame: homeContext},
	where the expr, the block argument, is already on the stack."
	^ self emitForEffect: stack on: codeStream! !

!MessageAsTempNode methodsFor: 'access to remote temps' stamp: 'di 3/22/1999 09:39'!
sizeForStorePop: encoder
	"This node has the form {expr storeAt: offset inTempFrame: homeContext},
	where the expr, the block argument, is already on the stack."
	^ self sizeForEffect: encoder! !

!MessageAsTempNode methodsFor: 'access to remote temps' stamp: 'eem 6/24/2008 11:50'!
store: expr from: encoder 
	"ctxt tempAt: n -> ctxt tempAt: n put: expr (see Assignment).
	For assigning into temps of a context being debugged."

	selector key ~= #namedTempAt: 
		ifTrue: [^self error: 'cant transform this message'].
	^ MessageAsTempNode new
		receiver: receiver
		selector: #namedTempAt:put:
		arguments: (arguments copyWith: expr)
		precedence: precedence
		from: encoder! !

!MessageAsTempNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForStorePop: stack encoder: encoder
	"This node has the form {expr storeAt: offset inTempFrame: homeContext},
	where the expr, the block argument, is already on the stack."
	^self emitCodeForEffect: stack encoder: encoder! !

!MessageAsTempNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForStorePop: encoder
	"This node has the form {expr storeAt: offset inTempFrame: homeContext},
	where the expr, the block argument, is already on the stack."
	^self sizeCodeForEffect: encoder! !


!MethodNode methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:52'!
accept: aVisitor
	aVisitor visitMethodNode: self.
	^aVisitor! !

!MethodNode methodsFor: 'accessing' stamp: 'eem 7/21/2009 16:00'!
arguments
	"For transformations etc, not used in compilation"
	^arguments! !

!MethodNode methodsFor: 'accessing' stamp: 'eem 7/21/2009 16:00'!
arguments: aSequence
	"For transformations etc, not used in compilation"
	arguments := aSequence! !

!MethodNode methodsFor: 'accessing' stamp: 'md 7/27/2006 19:12'!
body
	^block! !

!MethodNode methodsFor: 'accessing' stamp: 'eem 1/19/2009 10:28'!
primitiveErrorVariableName
	"Answer the primitive error code temp name, or nil if none."
	(primitive isInteger and: [primitive > 0]) ifTrue:
		[properties pragmas do:
			[:pragma| | kwds ecIndex |
			((kwds := pragma keyword keywords) first = 'primitive:'
			and: [(ecIndex := kwds indexOf: 'error:') > 0]) ifTrue:
				[^pragma argumentAt: ecIndex]]].
	^nil

	"(Parser new parse: (MethodNode sourceCodeAt: #primitiveErrorVariableName) class: Parser) primitiveErrorVariableName"

	"(Parser new parse: 'foo <primitive: 111 error: ''foo''> self primitiveFailed' class: Object) primitiveErrorVariableName"

	"(Parser new parse: 'foo <primitive: 111 error: foo> self primitiveFailed' class: Object) primitiveErrorVariableName"

	"(Parser new parse: 'foo <primitive: 111> self primitiveFailed' class: Object) primitiveErrorVariableName"

	"(Parser new parse: 'foo <primitive: ''foo'' error: foo module: ''bar''> self primitiveFailed' class: Object) primitiveErrorVariableName"

	"(Parser new parse: 'foo <primitive: ''foo'' module: ''bar'' error: foo> self primitiveFailed' class: Object) primitiveErrorVariableName"

	"(Parser new parse: 'foo <primitive: 111 error: foo> self primitiveFailed' class: Object) generate"! !

!MethodNode methodsFor: 'accessing' stamp: 'eem 6/11/2009 17:27'!
removeProperty: aSymbol
	properties := properties copyWithout: (Association
											key: aSymbol
											value: (properties propertyValueAt: aSymbol))! !

!MethodNode methodsFor: 'accessing' stamp: 'eem 7/21/2009 15:59'!
temporaries
	"For transformations etc, not used in compilation"
	^temporaries! !

!MethodNode methodsFor: 'accessing' stamp: 'eem 7/21/2009 15:59'!
temporaries: aSequence
	"For transformations etc, not used in compilation"
	temporaries := aSequence! !

!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: 'eem 5/6/2008 15:17'!
decompileString 
	"Answer a string description of the parse tree whose root is the receiver."

	^self printString
! !

!MethodNode methodsFor: 'converting' stamp: 'eem 5/6/2008 15:17'!
decompileText 
	"Answer a string description of the parse tree whose root is the receiver."

	^self asColorizedSmalltalk80Text! !

!MethodNode methodsFor: 'initialize-release' stamp: 'tk 8/3/1999 12:47'!
block
	^ block! !

!MethodNode methodsFor: 'initialize-release' stamp: 'ajh 1/24/2003 17:37'!
selector: symbol

	selectorOrFalse := symbol! !

!MethodNode methodsFor: 'initialize-release' stamp: 'jcg 9/30/2009 00:55'!
selector: selOrFalse arguments: args precedence: p temporaries: temps block: blk encoder: anEncoder primitive: prim 
	
	self 
		selector: selOrFalse
		arguments: args
		precedence: p
		temporaries: temps
		block: blk encoder:
		anEncoder 
		primitive: prim 
		properties: AdditionalMethodState new.! !

!MethodNode methodsFor: 'initialize-release' stamp: 'ar 1/4/2002 00:23'!
selector: selOrFalse arguments: args precedence: p temporaries: temps block: blk encoder: anEncoder primitive: prim properties: propDict
	"Initialize the receiver with respect to the arguments given."

	encoder := anEncoder.
	selectorOrFalse := selOrFalse.
	precedence := p.
	arguments := args.
	temporaries := temps.
	block := blk.
	primitive := prim.
	properties := propDict.! !

!MethodNode methodsFor: 'initialize-release' stamp: 'ajh 1/22/2003 17:53'!
sourceText: stringOrText

	sourceText := stringOrText! !

!MethodNode methodsFor: 'code generation'!
encoder
	^ encoder! !

!MethodNode methodsFor: 'code generation' stamp: 'al 4/21/2006 17:25'!
generate
	"The receiver is the root of a parse tree. Answer a CompiledMethod. The
	argument, trailer, is the references to the source code that is stored with 
	every CompiledMethod."

	^self generate: #(0 0 0 0)! !

!MethodNode methodsFor: 'code generation' stamp: 'eem 12/1/2008 12:03'!
generate: trailer 
	"The receiver is the root of a parse tree. Answer a CompiledMethod. The
	argument, trailer, is the references to the source code that is stored with 
	every CompiledMethod."

	| literals blkSize method nArgs nLits primErrNode stack strm |
	self generate: trailer ifQuick: 
		[:m |
		literals := encoder allLiterals.
		(nLits := literals size) > 255 ifTrue:
			[^self error: 'Too many literals referenced'].
		1 to: nLits do: [:lit | m literalAt: lit put: (literals at: lit)].
		m properties: properties.
		^m].
	primErrNode := self primitiveErrorVariableName ifNotNil:
						[encoder fixTemp: self primitiveErrorVariableName].
	nArgs := arguments size.
	blkSize := (block sizeForEvaluatedValue: encoder)
				+ (primErrNode ifNil: [0] ifNotNil: [2 "We force store-long (129)"]).
	(nLits := (literals := encoder allLiterals) size) > 255 ifTrue:
		[^self error: 'Too many literals referenced'].
	method := CompiledMethod	"Dummy to allocate right size"
				newBytes: blkSize
				trailerBytes: trailer 
				nArgs: nArgs
				nTemps: encoder maxTemp
				nStack: 0
				nLits: nLits
				primitive: primitive.
	strm := ReadWriteStream with: method.
	strm position: method initialPC - 1.
	stack := ParseStack new init.
	primErrNode ifNotNil: [primErrNode emitStore: stack on: strm].
	block emitForEvaluatedValue: stack on: strm.
	stack position ~= 1 ifTrue:
		[^self error: 'Compiler stack discrepancy'].
	strm position ~= (method size - trailer size) ifTrue:
		[^self error: 'Compiler code size discrepancy'].
	method needsFrameSize: stack size.
	1 to: nLits do: [:lit | method literalAt: lit put: (literals at: lit)].
	method properties: properties.
	^method! !

!MethodNode methodsFor: 'code generation' stamp: 'di 5/25/2000 06:45'!
generate: trailer ifQuick: methodBlock
	| v |
	(primitive = 0 and: [arguments size = 0 and: [block isQuick]])
		ifFalse: [^ self].
	v := block code.
	v < 0
		ifTrue: [^ self].
	v = LdSelf
		ifTrue: [^ methodBlock value: (CompiledMethod toReturnSelfTrailerBytes: trailer)].
	(v between: LdTrue and: LdMinus1 + 3)
		ifTrue: [^ methodBlock value: (CompiledMethod toReturnConstant: v - LdSelf trailerBytes: trailer)].
	v < ((CodeBases at: LdInstType) + (CodeLimits at: LdInstType))
		ifTrue: [^ methodBlock value: (CompiledMethod toReturnField: v trailerBytes: trailer)].
	v // 256 = 1
		ifTrue: [^ methodBlock value: (CompiledMethod toReturnField: v \\ 256 trailerBytes: trailer)]! !

!MethodNode methodsFor: 'code generation' stamp: 'ajh 7/6/2003 15:25'!
parserClass
	"Which parser produces this class of parse node"

	^ Parser! !

!MethodNode methodsFor: 'code generation' stamp: 'lr 2/6/2006 23:24'!
properties
	^ properties! !

!MethodNode methodsFor: 'code generation' stamp: 'yo 8/30/2002 14:07'!
selector 
	"Answer the message selector for the method represented by the receiver."

	(selectorOrFalse isSymbol)
		ifTrue: [^selectorOrFalse].
	^selectorOrFalse key.
! !

!MethodNode methodsFor: 'code generation' stamp: 'eem 9/25/2008 15:20'!
selectorNode
	"Answer a SelectorNode for the message selector of the method represented by the receiver."

	^(selectorOrFalse isMemberOf: SelectorNode)
		ifTrue: [selectorOrFalse]
		ifFalse: [SelectorNode new key: selectorOrFalse]! !

!MethodNode methodsFor: 'printing' stamp: 'ajh 1/22/2003 17:39'!
methodClass

	^ encoder classEncoding! !

!MethodNode methodsFor: 'printing' stamp: 'eem 12/1/2008 14:36'!
printOn: aStream
	| selectorNode |
	selectorNode := self selectorNode.
	precedence = 1
		ifTrue:
			[selectorNode isForFFICall
				ifTrue: [selectorNode
							printAsFFICallWithArguments: arguments
							on: aStream
							indent: 0]
				ifFalse: [aStream nextPutAll: selectorNode key]]
		ifFalse:
			[selectorNode key keywords with: arguments do:
				[:kwd :arg |
				aStream nextPutAll: kwd; space; nextPutAll: arg key; space]].
	comment == nil ifFalse:
		[aStream crtab: 1.
		 self printCommentOn: aStream indent: 1].
	block printTemporaries: temporaries on: aStream doPrior: [aStream crtab: 1].
	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 printStatementsOn: aStream indent: 0! !

!MethodNode methodsFor: 'printing' stamp: 'eem 12/1/2008 14:35'!
printPragmasOn: aStream
	properties ifNil: [^self].
	properties pragmas do:
		[:pragma|
		"Primitives are printed in printPrimitiveOn:; skip these"
		(Parser primitivePragmaSelectors includes: pragma keyword) ifFalse:
			[aStream crtab: 1.
			 pragma printOn: aStream]]! !

!MethodNode methodsFor: 'printing' stamp: 'eem 12/5/2008 09:49'!
printPrimitiveOn: aStream
	"Print the primitive on aStream"
	| primDecl |
	primitive = 0 ifTrue:
		[^self].
	primitive = 120 ifTrue: "External call spec"
		[^aStream print: encoder literals first].
	aStream nextPutAll: '<primitive: '.
	primitive = 117
		ifTrue:
			[primDecl := encoder literals at: 1.
			 (primDecl at: 2) asString printOn: aStream.
			 (primDecl at: 1) ifNotNil:
				[:moduleName|
				aStream nextPutAll:' module: '.
				moduleName asString printOn: aStream]]
		ifFalse:
			[aStream print: primitive].
	self primitiveErrorVariableName ifNotNil:
		[:primitiveErrorVariableName|
		 aStream nextPutAll: ' error: '; nextPutAll: primitiveErrorVariableName].
	aStream nextPut: $>.
	Smalltalk at: #Interpreter ifPresent:[:cls|
		aStream nextPutAll: ' "',
							((cls classPool at: #PrimitiveTable) at: primitive + 1),
							'" ']! !

!MethodNode methodsFor: 'printing' stamp: 'eem 12/1/2008 14:25'!
printPropertiesOn: aStream
	properties ifNil: [^self].
	properties propertyKeysAndValuesDo:
		[:prop :val|
		aStream crtab; nextPut: $<.
		prop = #on:in:
			ifTrue:
				[prop keywords with: val do:
					[:k :v | aStream nextPutAll: k; space; nextPutAll: v; space]]
			ifFalse:
				[prop = #on
					ifTrue: [aStream nextPutAll: prop; nextPutAll:': '; nextPutAll: val] 
					ifFalse: [aStream nextPutAll: prop; nextPutAll:': '; print: val]]. 
		aStream nextPut: $>]! !

!MethodNode methodsFor: 'printing' stamp: 'eem 12/1/2008 14:36'!
printWithClosureAnalysisOn: aStream 

	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: 'printing' stamp: 'ajh 1/24/2003 17:41'!
sourceText

	^ sourceText ifNil: [self printString]! !

!MethodNode methodsFor: 'printing'!
tempNames
	^ encoder tempNames! !

!MethodNode methodsFor: 'source mapping' stamp: 'eem 6/4/2008 19:21'!
rawSourceRanges

	^self rawSourceRangesAndMethodDo: [:rawSourceRanges :method| rawSourceRanges]! !

!MethodNode methodsFor: 'source mapping' stamp: 'eem 3/14/2009 17:01'!
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: #(0 0 0 0).  "set bytecodes to map to"
	^aBinaryBlock
		value: methNode encoder rawSourceRanges
		value: method! !

!MethodNode methodsFor: 'primitive error codes' stamp: 'eem 12/1/2008 14:56'!
removeAndRenameLastTempIfErrorCode
	self primitiveErrorVariableName ifNotNil:
		[:primitiveErrorVariableName|
		 temporaries last
			name: primitiveErrorVariableName
			key: primitiveErrorVariableName
			code: temporaries last code.
		 temporaries removeLast].! !


!BytecodeAgnosticMethodNode 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! !

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

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

!BytecodeAgnosticMethodNode 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! !

!BytecodeAgnosticMethodNode 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! !

!BytecodeAgnosticMethodNode 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]]! !

!BytecodeAgnosticMethodNode methodsFor: 'debugger support' stamp: 'eem 6/5/2009 16:51'!
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: #(0 0 0 0).
		methNode encoder blockExtentsToTempsMap]! !

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

!BytecodeAgnosticMethodNode methodsFor: 'debugger support' stamp: 'eem 7/6/2009 09:46'!
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: #(0 0 0 0)) isQuick ifTrue:
			[^'']].
	^encoder schematicTempNamesString! !

!BytecodeAgnosticMethodNode methodsFor: 'code generation (new scheme)' stamp: 'eem 12/1/2008 13:48'!
generate: trailer 
	"The receiver is the root of a parse tree. Answer a CompiledMethod.
	 The argument, trailer, is the reference to the source code that is
	 stored with every CompiledMethod."

	| 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: [2 "We force store-long (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! !

!BytecodeAgnosticMethodNode methodsFor: 'printing' stamp: 'eem 7/24/2008 10:07'!
printWithClosureAnalysisOn: aStream
	self ensureClosureAnalysisDone.
	super printWithClosureAnalysisOn: aStream! !


!NewArrayNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:55'!
accept: aVisitor
	aVisitor visitNewArrayNode: self! !

!NewArrayNode methodsFor: 'code generation (closures)' stamp: 'eem 6/16/2008 09:31'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	"This is a no-op except in TempVariableNode"
	^self! !

!NewArrayNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/25/2008 14:58'!
emitCodeForValue: stack encoder: encoder
	encoder genPushNewArray: numElements.
	stack push: 1! !

!NewArrayNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/25/2008 14:58'!
sizeCodeForValue: encoder
	^encoder sizePushNewArray: numElements! !

!NewArrayNode methodsFor: 'accessing' stamp: 'eem 5/25/2008 14:58'!
numElements
	^numElements! !

!NewArrayNode methodsFor: 'accessing' stamp: 'eem 5/25/2008 14:59'!
numElements: n
	numElements := n! !


!ParseNode class methodsFor: 'accessing' stamp: 'ajh 8/12/2002 11:10'!
blockReturnCode

	^ EndRemote! !

!ParseNode class methodsFor: 'accessing' stamp: 'ajh 8/6/2002 12:04'!
popCode

	^ Pop! !

!ParseNode class methodsFor: 'accessing' stamp: 'eem 5/21/2008 13:18'!
pushNilCode

	^LdNil! !

!ParseNode class methodsFor: 'accessing' stamp: 'eem 8/4/2009 12:34'!
tempSortBlock
	"Answer a block that can sort a set of temporaries into a stable
	 order so that different compilations produce the same results."
	^[:t1 :t2| | be1 be2 bs1 bs2 |
	   t1 index < t2 index "simple sort by index."
	   or: [t1 index = t2 index "complex tie break" 
		  and: [t1 isRemote ~= t2 isRemote
				ifTrue: [t2 isRemote] "put direct temps before indirect temps"
				ifFalse: 
					[((be1 := t1 definingScope blockExtent) isNil
					  or: [(be2 := t2 definingScope blockExtent) isNil])
						ifTrue: [t1 name < t2 name] "only have the name left to go on"
						ifFalse: "put temps from outer scopes before those from inner scopes"
							[(bs1 := be1 first) < (bs2 := be2 first)
							 or: [bs1 = bs2 and: [t1 name < t2 name]]]]]]] "only have the name left to go on"! !

!ParseNode class methodsFor: 'class initialization'!
initialize
	"ParseNode initialize. VariableNode initialize"
	LdInstType := 1.
	LdTempType := 2.
	LdLitType := 3.
	LdLitIndType := 4.
	SendType := 5.
	CodeBases := #(0 16 32 64 208 ).
	CodeLimits := #(16 16 32 32 16 ).
	LdSelf := 112.
	LdTrue := 113.
	LdFalse := 114.
	LdNil := 115.
	LdMinus1 := 116.
	LoadLong := 128.
	Store := 129.
	StorePop := 130.
	ShortStoP := 96.
	SendLong := 131.
	DblExtDoAll := 132.
	SendLong2 := 134.
	LdSuper := 133.
	Pop := 135.
	Dup := 136.
	LdThisContext := 137.
	EndMethod := 124.
	EndRemote := 125.
	Jmp := 144.
	Bfp := 152.
	JmpLimit := 8.
	JmpLong := 164.  "code for jmp 0"
	BtpLong := 168.
	SendPlus := 176.
	Send := 208.
	SendLimit := 16! !


!BlockNode class methodsFor: 'instance creation' stamp: 'sma 3/3/2000 13:34'!
statements: statements returns: returns
	^ self new statements: statements returns: returns! !

!BlockNode class methodsFor: 'instance creation' stamp: 'eem 5/19/2008 17:10'!
withJust: aNode
	^ self new statements: (Array with: aNode) returns: false! !


!BraceNode class methodsFor: 'examples' stamp: 'di 11/19/1999 09:05'!
example
	"Test the {a. b. c} syntax."

	| x |
	x := {1. {2. 3}. 4}.
	^ {x first. x second first. x second last. x last. 5} as: Set

"BraceNode example Set (0 1 2 3 4 5 )"
! !


!MessageNode class methodsFor: 'class initialization' stamp: 'eem 5/14/2008 18:15'!
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 := 
		#(	emitIf:on:value: emitIf:on:value: emitIf:on:value: emitIf:on:value:
			emitIf:on:value: emitIf:on:value:
			emitWhile:on:value: emitWhile:on:value: emitWhile:on:value: emitWhile:on:value:
			emitToDo:on:value: emitToDo:on:value:
			emitCase:on:value: emitCase:on:value:
			emitIfNil:on:value: emitIfNil:on:value: emitIf:on:value: emitIf:on:value:).
	NewStyleMacroEmitters := 
		#(	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 := 
		#(	sizeIf:value: sizeIf:value: sizeIf:value: sizeIf:value:
			sizeIf:value: sizeIf:value:
			sizeWhile:value: sizeWhile:value: sizeWhile:value: sizeWhile:value:
			sizeToDo:value: sizeToDo:value:
			sizeCase:value: sizeCase:value:
			sizeIfNil:value: sizeIfNil:value: sizeIf:value: sizeIf:value:).
	NewStyleMacroSizers := 
		#(	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:)! !


!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:10'!
visitAssignmentNode: anAssignmentNode
	"N.B.  since assigment happens after the value is evaluated the value is visited first."
	anAssignmentNode value accept: self.
	anAssignmentNode variable accept: self! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:13'!
visitBlockNode: aBlockNode
	aBlockNode statements do:
		[:statement| statement accept: self]! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:14'!
visitBraceNode: aBraceNode
	aBraceNode elements do:
		[:element| element accept: self]! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 9/10/2008 16:13'!
visitCascadeNode: aCascadeNode
	aCascadeNode receiver accept: self.
	aCascadeNode messages do:
		[:message| self visitMessageNodeInCascade: message]! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitCommentNode: aCommentNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitFieldNode: aFieldNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 2/9/2009 10:04'!
visitFutureNode: aFutureNode
	aFutureNode receiver accept: self.
	(aFutureNode originalSelector isKindOf: SelectorNode) ifTrue:
		[aFutureNode originalSelector accept: self]! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitInstanceVariableNode: anInstanceVariableNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitLiteralNode: aLiteralNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitLiteralVariableNode: aLiteralVariableNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 9/10/2008 16:02'!
visitMessageNode: aMessageNode.
	aMessageNode receiver accept: self.
	"receiver notNil ifTrue: ''receiver is nil for cascades''
		[receiver accept: self]."
	aMessageNode selector accept: self.
	aMessageNode argumentsInEvaluationOrder do:
		[:argument| argument accept: self]! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 2/9/2009 10:04'!
visitMessageNodeInCascade: aMessageNode
	"receiver is nil for cascades"
	aMessageNode selector accept: self.
	aMessageNode argumentsInEvaluationOrder do:
		[:argument| argument accept: self]! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:53'!
visitMethodNode: aMethodNode
	aMethodNode block accept: self! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitNewArrayNode: aNewArrayNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitRemoteTempVectorNode: aRemoteTempVectorNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:53'!
visitReturnNode: aReturnNode
	aReturnNode expr accept: self! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitSelectorNode: aSelectorNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:07'!
visitTempVariableNode: aTempVariableNode! !

!ParseNodeVisitor methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:32'!
visitVariableNode: aVariableNode! !


!ParseNodeEnumerator methodsFor: 'initialize-release' stamp: 'eem 7/20/2009 19:44'!
ofBlock: aBlock
	theBlock := aBlock! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitAssignmentNode: anAssignmentNode
	theBlock value: anAssignmentNode.
	^super visitAssignmentNode: anAssignmentNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitBlockNode: aBlockNode
	theBlock value: aBlockNode.
	^super visitBlockNode: aBlockNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitBraceNode: aBraceNode
	theBlock value: aBraceNode.
	^super visitBraceNode: aBraceNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitCascadeNode: aCascadeNode
	theBlock value: aCascadeNode.
	^super visitCascadeNode: aCascadeNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitCommentNode: aCommentNode
	theBlock value: aCommentNode.
	^super visitCommentNode: aCommentNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitFieldNode: aFieldNode
	theBlock value: aFieldNode.
	^super visitFieldNode: aFieldNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitFutureNode: aFutureNode
	theBlock value: aFutureNode.
	^super visitFutureNode: aFutureNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitInstanceVariableNode: anInstanceVariableNode
	theBlock value: anInstanceVariableNode.
	^super visitInstanceVariableNode: anInstanceVariableNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitLiteralNode: aLiteralNode
	theBlock value: aLiteralNode.
	^super visitLiteralNode: aLiteralNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitLiteralVariableNode: aLiteralVariableNode
	theBlock value: aLiteralVariableNode.
	^super visitLiteralVariableNode: aLiteralVariableNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitMessageNode: aMessageNode
	theBlock value: aMessageNode.
	^super visitMessageNode: aMessageNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitMessageNodeInCascade: aMessageNodeInCascade
	theBlock value: aMessageNodeInCascade.
	^super visitMessageNodeInCascade: aMessageNodeInCascade! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitMethodNode: aMethodNode
	theBlock value: aMethodNode.
	^super visitMethodNode: aMethodNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitNewArrayNode: aNewArrayNode
	theBlock value: aNewArrayNode.
	^super visitNewArrayNode: aNewArrayNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitRemoteTempVectorNode: aRemoteTempVectorNode
	theBlock value: aRemoteTempVectorNode.
	^super visitRemoteTempVectorNode: aRemoteTempVectorNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitReturnNode: aReturnNode
	theBlock value: aReturnNode.
	^super visitReturnNode: aReturnNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitSelectorNode: aSelectorNode
	theBlock value: aSelectorNode.
	^super visitSelectorNode: aSelectorNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitTempVariableNode: aTempVariableNode
	theBlock value: aTempVariableNode.
	^super visitTempVariableNode: aTempVariableNode! !

!ParseNodeEnumerator methodsFor: 'visiting' stamp: 'eem 7/20/2009 19:41'!
visitVariableNode: aVariableNode
	theBlock value: aVariableNode.
	^super visitVariableNode: aVariableNode! !


!ParseNodeEnumerator class methodsFor: 'instance creation' stamp: 'eem 7/20/2009 19:45'!
ofBlock: aBlock
	^self new ofBlock: aBlock! !


!ParseStack methodsFor: 'initialize-release'!
init

	length := position := 0! !

!ParseStack methodsFor: 'accessing'!
pop: n

	(position := position - n) < 0 
		ifTrue: [self error: 'Parse stack underflow']! !

!ParseStack methodsFor: 'accessing' stamp: 'eem 9/12/2008 10:31'!
position: n 
	(position := n) > length
		ifTrue: [length := position]! !

!ParseStack methodsFor: 'accessing'!
push: n

	(position := position + n) > length 
		ifTrue: [length := position]! !

!ParseStack methodsFor: 'accessing'!
size

	^length! !

!ParseStack methodsFor: 'results'!
position

	^position! !

!ParseStack methodsFor: 'printing'!
printOn: aStream
	
	super printOn: aStream.
	aStream nextPutAll: ' at '; print: position; nextPutAll: ' of '; print: length! !


!ParserNotification methodsFor: 'as yet unclassified' stamp: 'jmv 12/7/2009 22:47'!
defaultAction
	
	self openMenuIn: 
		[ :labels :lines :caption |
			(PopUpMenu labelArray: labels lines: lines) startUpWithCaption: caption ]! !

!ParserNotification methodsFor: 'as yet unclassified' stamp: 'cwp 10/17/2007 21:36'!
openMenuIn: aBlock
	self subclassResponsibility! !

!ParserNotification methodsFor: 'as yet unclassified' stamp: 'cwp 10/17/2007 23:29/eem 9/5/2009 11:10 - => :='!
setName: aString
	name := aString! !


!ParserNotification class methodsFor: 'as yet unclassified' stamp: 'cwp 10/17/2007 23:31'!
name: aString
	^ (self new setName: aString) signal! !


!ReturnNode methodsFor: 'visiting' stamp: 'eem 9/10/2008 15:53'!
accept: aVisitor
	aVisitor visitReturnNode: self! !

!ReturnNode methodsFor: 'code generation (closures)' stamp: 'eem 7/24/2009 09:44'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	"Note we could do this:
		scopeBlock ~~ rootNode block ifTrue:
			[scopeBlock noteNonLocalReturn].
	 and pass up the flag in <BlockNode>>>analyseTempsWithin:rootNode:
	 which may be fast but will also give less information the debugger.
	 For now we consider clean blocks a premature optimization."
	self flag: 'consider clean blocks'.
	expr analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools! !

!ReturnNode methodsFor: 'converting'!
asReturnNode! !

!ReturnNode methodsFor: 'code generation'!
code

	^expr code! !

!ReturnNode methodsFor: 'code generation'!
emitForReturn: stack on: strm

	expr emitForReturn: stack on: strm.
	pc := strm position! !

!ReturnNode methodsFor: 'code generation'!
emitForValue: stack on: strm

	expr emitForReturn: stack on: strm.
	pc := strm position! !

!ReturnNode methodsFor: 'code generation'!
sizeForReturn: encoder

	^expr sizeForReturn: encoder! !

!ReturnNode methodsFor: 'code generation'!
sizeForValue: encoder

	^expr sizeForReturn: encoder! !

!ReturnNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:40'!
emitCodeForReturn: stack encoder: encoder

	expr emitCodeForReturn: stack encoder: encoder.
	pc := encoder methodStreamPosition! !

!ReturnNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:40'!
emitCodeForValue: stack encoder: encoder

	expr emitCodeForReturn: stack encoder: encoder.
	pc := encoder methodStreamPosition! !

!ReturnNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForReturn: encoder

	^expr sizeCodeForReturn: encoder! !

!ReturnNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForValue: encoder

	^expr sizeCodeForReturn: encoder! !

!ReturnNode methodsFor: 'printing' stamp: 'yo 8/2/2004 17:21'!
expr

	^ expr.
! !

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

	aStream nextPutAll: '^ '. "make this a preference??"
	expr printOn: aStream indent: level.
	expr printCommentOn: aStream indent: level! !

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

	aStream nextPutAll: '^ '. "make this a preference??"
	expr printWithClosureAnalysisOn: aStream indent: level.
	expr printCommentOn: aStream indent: level! !

!ReturnNode methodsFor: 'initialize-release'!
expr: e

	expr := e! !

!ReturnNode methodsFor: 'initialize-release'!
expr: e encoder: encoder sourceRange: range

	expr := e.
	encoder noteSourceRange: range forNode: self! !

!ReturnNode methodsFor: 'testing'!
isReturnSelf

	^expr == NodeSelf! !

!ReturnNode methodsFor: 'testing'!
isSpecialConstant

	^expr isSpecialConstant! !

!ReturnNode methodsFor: 'testing'!
isVariableReference

	^expr isVariableReference! !


!Scanner methodsFor: 'expression types'!
advance

	| prevToken |
	prevToken := token.
	self scanToken.
	^prevToken! !

!Scanner methodsFor: 'expression types' stamp: 'di 4/23/2000 22:15'!
checkpoint
	"Return a copy of all changeable state.  See revertToCheckpoint:"

	^ {self clone. source clone. currentComment copy}! !

!Scanner methodsFor: 'expression types'!
nextLiteral
	"Same as advance, but -4 comes back as a number instead of two tokens"

	| prevToken |
	prevToken := self advance.
	(prevToken == #- and: [token isKindOf: Number])
		ifTrue: 
			[^self advance negated].
	^prevToken! !

!Scanner methodsFor: 'expression types' stamp: 'di 4/23/2000 22:11'!
revertToCheckpoint: checkpoint
	"Revert to the state when checkpoint was made."

	| myCopy |
	myCopy := checkpoint first.
	1 to: self class instSize do:
		[:i | self instVarAt: i put: (myCopy instVarAt: i)].
	source := checkpoint second.
	currentComment := checkpoint third! !

!Scanner methodsFor: 'expression types' stamp: 'nice 10/27/2009 10:46'!
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 chaacters.  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: 'expression types' stamp: 'PeterHugossonMiller 9/3/2009 11:10'!
scanLitByteVec
	| stream |
	stream := (ByteArray new: 16) writeStream.
	[ tokenType = #rightBracket or: [ tokenType = #doIt ] ] whileFalse: [
		tokenType = #word
			ifTrue: [ self scanLitWord ].
		(token isInteger and: [ token between: 0 and: 255 ])
			ifFalse: [ ^ self offEnd: '8-bit integer or right bracket expected' ].
		stream nextPut: token.
		self scanToken ].
	token := stream contents! !

!Scanner methodsFor: 'expression types' stamp: 'eem 5/13/2008 12:47'!
scanLitVec
	| s |
	s := WriteStream on: (Array new: 16).
	[tokenType = #rightParenthesis or: [tokenType = #doIt]] whileFalse:
		[tokenType = #leftParenthesis
			ifTrue: 
				[self scanToken; scanLitVec]
			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]]].
		s nextPut: token.
		self scanToken].
	token := s contents! !

!Scanner methodsFor: 'expression types' stamp: 'ar 5/10/2005 12:24'!
scanLitWord
	"Accumulate keywords and asSymbol the result."

	| t |
	[(self typeTableAt: hereChar) = #xLetter]
		whileTrue: 
			[t := token.
			self xLetter.
			token := t , token].
	token := token asSymbol! !

!Scanner methodsFor: 'expression types'!
scanStringStruct

	| s |
	s := WriteStream on: (Array new: 16).
	[tokenType = #rightParenthesis or: [tokenType = #doIt]]
		whileFalse: 
			[tokenType = #leftParenthesis
				ifTrue: 
					[self scanToken; scanStringStruct]
				ifFalse: 
					[tokenType = #word ifFalse:
						[^self error: 'only words and parens allowed']].
			s nextPut: token.
			self scanToken].
	token := s contents! !

!Scanner methodsFor: 'expression types' stamp: 'ar 5/10/2005 12:24'!
scanToken

	[(tokenType := self typeTableAt: hereChar) == #xDelimiter]
		whileTrue: [self step].  "Skip delimiters fast, there almost always is one."
	mark := source position - 1.
	(tokenType at: 1) = $x "x as first letter"
		ifTrue: [self perform: tokenType "means perform to compute token & type"]
		ifFalse: [token := self step asSymbol "else just unique the first char"].
	^token! !

!Scanner methodsFor: 'expression types'!
step

	| c |
	c := hereChar.
	hereChar := aheadChar.
	source atEnd
		ifTrue: [aheadChar := 30 asCharacter "doit"]
		ifFalse: [aheadChar := source next].
	^c! !

!Scanner methodsFor: 'error handling' stamp: 'yo 8/28/2002 17:43'!
errorMultibyteCharacter

	self error: 'multi-byte character is found at unexpected place'.
! !

!Scanner methodsFor: 'error handling'!
notify: string 
	"Refer to the comment in Object|notify:." 
	self error: string! !

!Scanner methodsFor: 'error handling'!
offEnd: aString 
	"Parser overrides this"

	^self notify: aString! !

!Scanner methodsFor: 'initialize-release'!
initScanner

	buffer := WriteStream on: (String new: 40).
	typeTable := TypeTable! !

!Scanner methodsFor: 'initialize-release' stamp: 'ul 12/6/2009 19:57'!
initScannerForTokenization
	"Use a version of typeTable that doesn't raise xIllegal when enocuntering an _"
	| underscoreIndex |
	underscoreIndex := typeTable identityIndexOf: #xUnderscore ifAbsent: [^self].
	typeTable := typeTable copy.
	typeTable at: underscoreIndex put: #xUnderscoreForTokenization! !

!Scanner methodsFor: 'initialize-release'!
scan: inputStream 
	"Bind the input stream, fill the character buffers and first token buffer."

	source := inputStream.
	self step.
	self step.
	self scanToken! !

!Scanner methodsFor: 'public access'!
scanFieldNames: stringOrArray
	"Answer an Array of Strings that are the identifiers in the input string, 
	stringOrArray. If passed an Array, just answer with that Array, i.e., 
	assume it has already been scanned."

	| strm |
	(stringOrArray isMemberOf: Array)
		ifTrue: [^stringOrArray].
	self scan: (ReadStream on: stringOrArray asString).
	strm := WriteStream on: (Array new: 10).
	[tokenType = #doIt]
		whileFalse: 
			[tokenType = #word ifTrue: [strm nextPut: token].
			self scanToken].
	^strm contents

	"Scanner new scanFieldNames: 'abc  def ghi' ('abc' 'def' 'ghi' )"! !

!Scanner methodsFor: 'public access' stamp: 'sw 1/28/2001 23:31'!
scanMessageParts: sourceString
	"Return an array of the form (comment keyword comment arg comment keyword comment arg comment) for the message pattern of this method.  Courtesy of Ted Kaehler, June 1999"

	| coll nonKeywords |
	coll := OrderedCollection new.
	self scan: (ReadStream on: sourceString asString).
	nonKeywords := 0.
	[tokenType = #doIt] whileFalse:
		[(currentComment == nil or: [currentComment isEmpty])
			ifTrue: [coll addLast: nil]
			ifFalse: [coll addLast: currentComment removeFirst.
				[currentComment isEmpty] whileFalse:
					[coll at: coll size put: (coll last, ' ', currentComment removeFirst)]].
		(token numArgs < 1 or: [(token = #|) & (coll size > 1)])
			ifTrue: [(nonKeywords := nonKeywords + 1) > 1 ifTrue: [^ coll]]
						"done with header"
			ifFalse: [nonKeywords := 0].
		coll addLast: token.
		self scanToken].
	(currentComment == nil or: [currentComment isEmpty])
		ifTrue: [coll addLast: nil]
		ifFalse: [coll addLast: currentComment removeFirst.
			[currentComment isEmpty] whileFalse: [
				coll at: coll size put: (coll last, ' ', currentComment removeFirst)]].
	^ coll! !

!Scanner methodsFor: 'public access'!
scanStringStruct: textOrString 
	"The input is a string whose elements are identifiers and parenthesized
	 groups of identifiers.  Answer an array reflecting that structure, representing
	 each identifier by an uninterned string."

	self scan: (ReadStream on: textOrString asString).
	self scanStringStruct.
	^token

	"Scanner new scanStringStruct: 'a b (c d) (e f g)'"! !

!Scanner methodsFor: 'public access' stamp: 'eem 8/20/2008 20:55'!
scanTokenPositionsIn: textOrString into: aBlock
	"Evaluate aBlock with the start and end positions of all separate non-white-space tokens, including comments, in textOrString."

	self initScannerForTokenization.
	source := (ReadStream on: textOrString asString).
	self step.
	self step.
	self scanAllTokenPositionsInto: aBlock

	"| code |
	code := '       #( 1 2 #( 3 4 ))  16r123 123 123.0  ', (Scanner sourceCodeAt: #scanTokenPositionsIn:into:).
	Scanner new scanTokenPositionsIn: code into: [:start :end| Transcript cr; nextPut: $_; nextPutAll: (code copyFrom: start to: end); nextPut: $_; endEntry]"

	"CodeDiffBuilder buildDisplayPatchFrom:  (Scanner sourceCodeAt: #scanTokenPositionsIn:into:) to:  ((Scanner sourceCodeAt: #scanTokenPositionsIn:into:) copyReplaceAll: (String with: Character cr) with: '')"

	"CodeDiffBuilder buildDisplayPatchFrom:  'colorTable ^colorTable ifNil: [colorTable _ ST80ColorTable]' to:'colorTable ^colorTable ifNil: [colorTable _ ST80ColorTable]'"! !

!Scanner methodsFor: 'public access'!
scanTokens: textOrString 
	"Answer an Array that has been tokenized as though the input text, 
	textOrString, had appeared between the array delimitors #( and ) in a 
	Smalltalk literal expression."

	self scan: (ReadStream on: textOrString asString).
	self scanLitVec.
	^token

	"Scanner new scanTokens: 'identifier keyword: 8r31 ''string'' .'"! !

!Scanner methodsFor: 'public access' stamp: 'eem 6/11/2009 14:28'!
typedScanTokens: textOrString 
	"Answer an Array that has been tokenized with literals mapped to literals,
	 special characters mapped to symbols and variable names and keywords
	 to strings. This methiod accepts _ (underscore) as an assignment token
	 irrespective of whether the system prefers := as the assignment token."
	| s |
	self initScannerForTokenization.
	self scan: (ReadStream on: textOrString asString).
	s := WriteStream on: (Array new: 16).
	[tokenType = #doIt] whileFalse:
		[(token == #- 
		  and: [(self typeTableAt: hereChar) = #xDigit]) ifTrue: 
			[self scanToken.
			 token := token negated].
		s nextPut: token.
		self scanToken].
	^s contents

	"Scanner new typedScanTokens: (Scanner sourceCodeAt: #typedScanTokens:)"! !

!Scanner methodsFor: 'multi-character scans' stamp: 'jmv 12/7/2009 22:53'!
typeTableAt: aCharacter
	^typeTable at: aCharacter asciiValue ifAbsent:[#xLetter]! !

!Scanner methodsFor: 'multi-character scans' stamp: 'eem 5/13/2008 13:00'!
xBinary

	tokenType := #binary.
	token := String with: self step.
	[hereChar ~~ $- and: [(self typeTableAt: hereChar) == #xBinary]] whileTrue:
		[token := token, (String with: self step)].
	token := token asSymbol! !

!Scanner methodsFor: 'multi-character scans' stamp: 'nice 4/14/2009 19:34'!
xColon
	"Allow := for assignment"
	
	aheadChar = $= ifTrue:
		[self step.
		tokenType := #leftArrow.
		self step.
		^ token := #':='].
	"Otherwise, just do what normal scan of colon would do"
	tokenType := #colon.
	^ token := self step asSymbol! !

!Scanner methodsFor: 'multi-character scans'!
xDelimiter
	"Ignore blanks, etc."

	self scanToken! !

!Scanner methodsFor: 'multi-character scans' stamp: 'tao 4/23/98 12:55'!
xDigit
	"Form a number."

	tokenType := #number.
	(aheadChar = 30 asCharacter and: [source atEnd
			and:  [source skip: -1. source next ~= 30 asCharacter]])
		ifTrue: [source skip: -1 "Read off the end last time"]
		ifFalse: [source skip: -2].
	token := [Number readFrom: source] ifError: [:err :rcvr | self offEnd: err].
	self step; step! !

!Scanner methodsFor: 'multi-character scans'!
xDollar
	"Form a Character literal."

	self step. "pass over $"
	token := self step.
	tokenType := #number "really should be Char, but rest of compiler doesn't know"! !

!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 12/7/2009 22:53'!
xIllegal
	"An illegal character was encountered"
	self notify: 'Illegal character (char code ' , hereChar asciiValue , ' 16r' , hereChar charCode hex , ')' at: mark! !

!Scanner methodsFor: 'multi-character scans' stamp: 'eem 5/13/2008 13:05'!
xLetter
	"Form a word or keyword."

	| type |
	buffer reset.
	[(type := self typeTableAt: hereChar) == #xLetter or: [type == #xDigit]]
		whileTrue:
			["open code step for speed"
			buffer nextPut: hereChar.
			hereChar := aheadChar.
			aheadChar := source atEnd
							ifTrue: [30 asCharacter "doit"]
							ifFalse: [source next]].
	tokenType := (type == #colon or: [type == #xColon and: [aheadChar ~~ $=]])
					ifTrue: 
						[buffer nextPut: self step.
						"Allow any number of embedded colons in literal symbols"
						[(self typeTableAt: hereChar) == #xColon] whileTrue:
							[buffer nextPut: self step].
						#keyword]
					ifFalse: 
						[type == #leftParenthesis 
							ifTrue:
								[buffer nextPut: self step; nextPut: $).
								 #positionalMessage]
							ifFalse:[#word]].
	token := buffer contents! !

!Scanner methodsFor: 'multi-character scans' stamp: 'nice 11/27/2009 23:13'!
xLitQuote
	"Symbols and vectors: #(1 (4 5) 2 3) #ifTrue:ifFalse: #'abc'."
	| start |
	start := mark.
	self step. "litQuote"
	self scanToken.
	tokenType = #leftParenthesis
		ifTrue: [self scanToken; scanLitVec.
			mark := start + 1.
			tokenType == #doIt
				ifTrue: [self offEnd: 'Unmatched parenthesis']]
		ifFalse: [tokenType = #leftBracket
				ifTrue: [self scanToken; scanLitByteVec.
					mark := start + 1.
					tokenType == #doIt
						ifTrue: [self offEnd: 'Unmatched bracket']]
				ifFalse: [(#(#word #keyword #colon ) includes: tokenType)
						ifTrue: [self scanLitWord]
						ifFalse: [tokenType == #literal
								ifTrue: [token isSymbol
										ifTrue: ["##word"
											token := token
											"May want to move toward ANSI
											here "]]
								ifFalse: [tokenType == #string
										ifTrue: [token := token asSymbol]]]]].
	mark := start.
	tokenType := #literal

	"#(Pen)
	#Pen
	#'Pen'
	##Pen
	###Pen
	"! !

!Scanner methodsFor: 'multi-character scans' stamp: 'ar 3/26/2004 15:45'!
xSingleQuote
	"String."

	self step.
	buffer reset.
	[hereChar = $' 
		and: [aheadChar = $' 
				ifTrue: [self step. false]
				ifFalse: [true]]]
		whileFalse: 
			[buffer nextPut: self step.
			(hereChar = 30 asCharacter and: [source atEnd])
				ifTrue: [^self offEnd: 'Unmatched string quote']].
	self step.
	token := buffer contents.
	tokenType := #string! !

!Scanner methodsFor: 'multi-character scans' stamp: 'ar 4/5/2006 01:31'!
xUnderscore
	Preferences allowUnderscoreAssignment ifFalse:[^self xIllegal].
	self step.
	tokenType := #leftArrow.
	^token := #':='! !

!Scanner methodsFor: 'multi-character scans' stamp: 'eem 5/8/2008 17:01'!
xUnderscoreForTokenization
	self step.
	tokenType := #leftArrow.
	^token := #'_'! !


!Parser methodsFor: 'private'!
addComment

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

!Parser methodsFor: 'private'!
init: sourceStream notifying: req failBlock: aBlock

	requestor := req.
	failBlock := aBlock.
	super scan: sourceStream.
	prevMark := hereMark := mark.
	requestorOffset := 0.
	self advance! !

!Parser methodsFor: 'private'!
initPattern: aString notifying: req return: aBlock

	| result |
	self
		init: (ReadStream on: aString asString)
		notifying: req
		failBlock: [^nil].
	encoder := self.
	result := aBlock value: (self pattern: false inContext: nil).
	encoder := failBlock := nil.  "break cycles"
	^result! !

!Parser methodsFor: 'pragmas' stamp: 'jcg 9/30/2009 00:20'!
addPragma: aPragma
	properties := self properties copyWith: aPragma! !

!Parser methodsFor: 'pragmas' stamp: 'eem 12/1/2008 11:39'!
pragmaLiteral: selectorSoFar
	"Read a pragma literal.  As a nicety we allow a variable name (rather
	 than a literal string) as the second argument to primitive:error:"

	(hereType == #string or: [ hereType == #literal or: [ hereType == #number ] ])
		ifTrue: [ ^ self advance ].
	(here == $# and: [ tokenType == #word ])
		ifTrue: [ ^ self advance ].
	(here == #- and: [ tokenType == #number ])
		ifTrue: [ ^ (self advance; advance) negated ].
	(here = 'true' or: [ here = 'false' or: [ here = 'nil' ] ])
		ifTrue: [ ^ Compiler evaluate: self advance ].
	"This nicety allows one to supply a primitive error
	 temp as a variable name, rather than a string."
	((selectorSoFar beginsWith: 'primitive:')
	 and: [(selectorSoFar endsWith: 'error:')
	 and: [hereType == #word]]) ifTrue:
		[^self advance].
	^self expected: 'Literal constant'! !

!Parser methodsFor: 'pragmas' stamp: 'jcg 9/30/2009 00:20'!
pragmaPrimitives
	| primitives |
	self properties isEmpty ifTrue:
		[^0].
	primitives := properties pragmas select:
					[:pragma|
					self class primitivePragmaSelectors includes: pragma keyword].
	primitives isEmpty ifTrue:
		[^0].
	primitives size > 1 ifTrue:
		[^self notify: 'Ambigous primitives'].
	^self perform: primitives first keyword withArguments: primitives first arguments! !

!Parser methodsFor: 'pragmas' stamp: 'lr 10/5/2006 09:47'!
pragmaSequence
	"Parse a sequence of method pragmas."
	
	[ true ] whileTrue: [
		(self matchToken: #<)
			ifFalse: [ ^ self ].
		self pragmaStatement.
		(self matchToken: #>)
			ifFalse: [ ^ self expected: '>' ] ]! !

!Parser methodsFor: 'pragmas' stamp: 'mha 9/1/2009 16:32'!
pragmaStatement
	"Read a single pragma statement. Parse all generic pragmas in the form of: <key1: val1 key2: val2 ...> and remember them, including primitives."
	
	| selector arguments words index keyword |
	(hereType = #keyword or: [ hereType = #word or: [ hereType = #binary ] ])
		ifFalse: [  ^ self expected: 'pragma declaration' ].

	" This is a ugly hack into the compiler of the FFI package. FFI should be changed to use propre pragmas that can be parsed with the code here. "
	(here = #apicall: or: [ here = #cdecl: ])
		ifTrue: [ ^ self externalFunctionDeclaration ].

	selector := String new.
	arguments := OrderedCollection new.
	words := OrderedCollection new.
	[ hereType = #keyword or: [ (hereType = #word or: [ hereType = #binary ]) and: [ selector isEmpty ] ] ] whileTrue: [
		index := self startOfNextToken + requestorOffset.
		selector := selector , self advance.
		words add: (index to: self endOfLastToken + requestorOffset).
		(selector last = $: or: [ selector first isLetter not ])
			ifTrue: [ arguments add: (self pragmaLiteral: selector) ] ].
	selector numArgs ~= arguments size
		ifTrue: [ ^ self expected: 'pragma argument' ].
	(Symbol hasInterned: selector 
		ifTrue: [ :value | keyword := value]) 
		ifFalse: [ 
			keyword := self 
				correctSelector: selector wordIntervals: words
				exprInterval: (words first first to: words last last)
				ifAbort: [ ^ self fail ] ].
	self addPragma: (Pragma keyword: keyword arguments: arguments asArray).
	^ true! !

!Parser methodsFor: 'pragmas' stamp: 'jcg 9/30/2009 00:19'!
properties
	^ properties ifNil: [ properties := AdditionalMethodState new ]! !

!Parser methodsFor: 'error handling' stamp: 'eem 5/14/2008 13:34'!
addWarning: aString
	"ignored by the default compiler."! !

!Parser methodsFor: 'error handling' stamp: 'hmm 7/18/2001 21:45'!
expected: aString 
	"Notify a problem at token 'here'."

	tokenType == #doIt ifTrue: [hereMark := hereMark + 1].
	hereType == #doIt ifTrue: [hereMark := hereMark + 1].
	^ self notify: aString , ' expected' at: hereMark + requestorOffset! !

!Parser methodsFor: 'error handling'!
fail

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

!Parser methodsFor: 'error handling' stamp: 'stephaneducassse 11/5/2005 16:39'!
interactive
	"this version of the method is necessary to load code from MC else the interactive mode is one. 
	This method is really bad since it links the compiler package with the Tools
	one. The solution would be to have a real SyntaxError exception belonging to the 
	compiler package and not a subclass of StringHolder - sd Nov 2005"
	"the code submitted by PlusTools is ideally the one that should be used
	interactive

	      ^requestor ~~ nil "
	
	^ (requestor == nil or: [requestor isKindOf: SyntaxError]) not! !

!Parser methodsFor: 'error handling'!
notify: aString 
	"Notify problem at token before 'here'."

	^self notify: aString at: prevMark + requestorOffset! !

!Parser methodsFor: 'error handling' stamp: 'eem 9/25/2008 12:41'!
notify: string at: location
	requestor isNil
		ifTrue: [(encoder == self or: [encoder isNil]) ifTrue: [^ self fail  "failure setting up syntax error"].
				SyntaxErrorNotification
					inClass: encoder classEncoding
					category: category
					withCode: 
						(source contents
							copyReplaceFrom: location
							to: location - 1
							with: string , ' ->')
					doitFlag: doitFlag
					errorMessage: string
					location: location]
		ifFalse: [requestor
					notify: string , ' ->'
					at: location
					in: source].
	^self fail! !

!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: 'scanning' stamp: 'hmm 7/16/2001 20:12'!
advance
	| this |
	prevMark := hereMark.
	prevEnd := hereEnd.
	this := here.
	here := token.
	hereType := tokenType.
	hereMark := mark.
	hereEnd := source position - (source atEnd ifTrue: [hereChar == 30 asCharacter ifTrue: [0] ifFalse: [1]] ifFalse: [2]).
	self scanToken.
	"Transcript show: 'here: ', here printString, ' mark: ', hereMark printString, ' end: ', hereEnd printString; cr."
	^this! !

!Parser methodsFor: 'scanning' stamp: 'hmm 7/16/2001 19:23'!
endOfLastToken

	^ prevEnd ifNil: [mark]! !

!Parser methodsFor: 'scanning'!
match: type 
	"Answer with true if next tokens type matches."

	hereType == type
		ifTrue: 
			[self advance.
			^true].
	^false! !

!Parser methodsFor: 'scanning' stamp: 'di 6/7/2000 08:44'!
matchReturn

	^ self match: #upArrow! !

!Parser methodsFor: 'scanning'!
matchToken: thing 
	"Matches the token, not its type."

	here = thing ifTrue: [self advance. ^true].
	^false! !

!Parser methodsFor: 'scanning'!
startOfNextToken
	"Return starting position in source of next token."

	hereType == #doIt ifTrue: [^source position + 1].
	^hereMark! !

!Parser methodsFor: 'primitives'!
allocateLiteral: lit
	encoder litIndex: lit! !

!Parser methodsFor: 'primitives' stamp: 'eem 9/5/2009 14:47'!
externalFunctionDeclaration
	"Parse the function declaration for a call to an external library."
	| descriptorClass callType retType externalName args argType module fn |
	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].
	].
	(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 := 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: 'primitives' stamp: 'eem 12/1/2008 09:17'!
primitive: anIntegerOrString
	"Create indexed primitive."
	
	^self primitive: anIntegerOrString error: nil! !

!Parser methodsFor: 'primitives' stamp: 'eem 12/1/2008 09:21'!
primitive: anIntegerOrString error: errorCodeVariableOrNil
	"Create indexed primitive with optional error code."
	
	^anIntegerOrString isInteger
		ifTrue:
			[errorCodeVariableOrNil ifNotNil:
				[encoder floatTemp: (encoder bindTemp: errorCodeVariableOrNil) nowHasDef].
			 anIntegerOrString]
		ifFalse:
			[anIntegerOrString isString
				ifTrue: [self primitive: anIntegerOrString module: nil error: errorCodeVariableOrNil]
				ifFalse: [self expected: 'Indexed primitive']]! !

!Parser methodsFor: 'primitives' stamp: 'eem 12/1/2008 09:20'!
primitive: aNameString error: errorCodeVariableOrNil module: aModuleStringOrNil
	"Create named primitive with optional error code."
	
	^self primitive: aNameString module: aModuleStringOrNil error: errorCodeVariableOrNil! !

!Parser methodsFor: 'primitives' stamp: 'eem 12/1/2008 09:21'!
primitive: aNameString module: aModuleStringOrNil
	"Create named primitive."
	
	^self primitive: aNameString module: aModuleStringOrNil error: nil! !

!Parser methodsFor: 'primitives' stamp: 'eem 12/1/2008 09:18'!
primitive: aNameString module: aModuleStringOrNil error: errorCodeVariableOrNil
	"Create named primitive with optional error code."
	
	(aNameString isString and: [ aModuleStringOrNil isNil or: [ aModuleStringOrNil isString ] ])
		ifFalse: [ ^ self expected: 'Named primitive' ].
	self allocateLiteral: (Array 
		with: (aModuleStringOrNil isNil 
			ifFalse: [ aModuleStringOrNil asSymbol ])
		with: aNameString asSymbol
		with: 0 with: 0).
	errorCodeVariableOrNil ifNotNil:
		[encoder floatTemp: (encoder bindTemp: errorCodeVariableOrNil) nowHasDef].
	^117! !

!Parser methodsFor: 'expression types'!
argumentName

	hereType == #word
		ifFalse: [^self expected: 'Argument name'].
	^self advance! !

!Parser methodsFor: 'expression types' stamp: 'eem 6/2/2009 10:26'!
assignment: varNode
	" var ':=' expression => AssignmentNode."
	| loc start |
	(loc := varNode assignmentCheck: encoder at: prevMark + requestorOffset) >= 0
		ifTrue: [^self notify: 'Cannot store into' at: loc].
	start := self startOfNextToken.
	self advance.
	self expression ifFalse: [^self expected: 'Expression'].
	parseNode := AssignmentNode new
				variable: varNode
				value: parseNode
				from: encoder
				sourceRange: (start to: self endOfLastToken).
	varNode nowHasDef.
	^true! !

!Parser methodsFor: 'expression types' stamp: 'eem 7/20/2009 12:09'!
blockExpression
	"[ ({:var} |) (| {temps} |) (statements) ] => BlockNode."

	| blockNode variableNodes temporaryBlockVariables start |
	blockNode := BlockNode new.
	variableNodes := OrderedCollection new.
	start := prevMark + requestorOffset.
	"Gather parameters."
	[self match: #colon] whileTrue:
		[variableNodes addLast: (encoder bindBlockArg: self argumentName within: blockNode)].
	(variableNodes size > 0 & (hereType ~~ #rightBracket) and: [(self match: #verticalBar) not]) ifTrue:
		[^self expected: 'Vertical bar'].

	temporaryBlockVariables := self temporaryBlockVariablesFor: blockNode.
	self statements: variableNodes innerBlock: true blockNode: blockNode.
	blockNode temporaries: temporaryBlockVariables.

	(self match: #rightBracket) ifFalse: [^self expected: 'Period or right bracket'].

	blockNode noteSourceRangeStart: start end: self endOfLastToken encoder: encoder.

	"The scope of the parameters and temporary block variables is no longer active."
	temporaryBlockVariables do: [:variable | variable scope: -1].
	variableNodes do: [:variable | variable scope: -1]! !

!Parser methodsFor: 'expression types' stamp: 'di 3/8/2000 09:36'!
braceExpression
	" { elements } => BraceNode."

	| elements locations loc more |
	elements := OrderedCollection new.
	locations := OrderedCollection new.
	self advance.
	more := hereType ~~ #rightBrace.
	[more]
		whileTrue: 
			[loc := hereMark + requestorOffset.
			self expression
				ifTrue: 
					[elements addLast: parseNode.
					locations addLast: loc]
				ifFalse:
					[^self expected: 'Variable or expression'].
			(self match: #period)
				ifTrue: [more := hereType ~~ #rightBrace]
				ifFalse: [more := false]].
	parseNode := BraceNode new elements: elements sourceLocations: locations.
	(self match: #rightBrace)
		ifFalse: [^self expected: 'Period or right brace'].
	^true! !

!Parser methodsFor: 'expression types'!
cascade
	" {; message} => CascadeNode."

	| rcvr msgs |
	parseNode canCascade
		ifFalse: [^self expected: 'Cascading not'].
	rcvr := parseNode cascadeReceiver.
	msgs := OrderedCollection with: parseNode.
	[self match: #semicolon]
		whileTrue: 
			[parseNode := rcvr.
			(self messagePart: 3 repeat: false)
				ifFalse: [^self expected: 'Cascade'].
			parseNode canCascade
				ifFalse: [^self expected: '<- No special messages'].
			parseNode cascadeReceiver.
			msgs addLast: parseNode].
	parseNode := CascadeNode new receiver: rcvr messages: msgs! !

!Parser methodsFor: 'expression types' stamp: 'di 11/19/1999 07:43'!
expression

	(hereType == #word and: [tokenType == #leftArrow])
		ifTrue: [^ self assignment: self variable].
	hereType == #leftBrace
		ifTrue: [self braceExpression]
		ifFalse: [self primaryExpression ifFalse: [^ false]].
	(self messagePart: 3 repeat: true)
		ifTrue: [hereType == #semicolon ifTrue: [self cascade]].
	^ true! !

!Parser methodsFor: 'expression types' stamp: 'yo 8/30/2002 14:41'!
messagePart: level repeat: repeat

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

!Parser methodsFor: 'expression types' stamp: 'jcg 9/30/2009 00:20'!
method: doit context: ctxt encoder: encoderToUse
	" pattern [ | temporaries ] block => MethodNode."

	| sap blk prim temps messageComment methodNode |
	encoder := encoderToUse.
	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'].
	self interactive ifTrue: [self removeUnusedTemps].
	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! !

!Parser methodsFor: 'expression types' stamp: 'eem 5/29/2008 09:36'!
newMethodNode
	^self encoder methodNodeClass new! !

!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'!
primaryExpression 
	hereType == #word 
		ifTrue: 
			[parseNode := self variable.
			(parseNode isUndefTemp and: [self interactive])
				ifTrue: [self queryUndefined].
			parseNode nowHasRef.
			^ true].
	hereType == #leftBracket
		ifTrue: 
			[self advance.
			self blockExpression.
			^true].
	hereType == #leftBrace
		ifTrue: 
			[self braceExpression.
			^true].
	hereType == #leftParenthesis
		ifTrue: 
			[self advance.
			self expression ifFalse: [^self expected: 'expression'].
			(self match: #rightParenthesis)
				ifFalse: [^self expected: 'right parenthesis'].
			^true].
	(hereType == #string or: [hereType == #number or: [hereType == #literal]])
		ifTrue: 
			[parseNode := encoder encodeLiteral: self advance.
			^true].
	(here == #- and: [tokenType == #number])
		ifTrue: 
			[self advance.
			parseNode := encoder encodeLiteral: self advance negated.
			^true].
	^false! !

!Parser methodsFor: 'expression types' stamp: 'eem 5/30/2008 11:51'!
statements: argNodes innerBlock: inner

	^self statements: argNodes innerBlock: inner blockNode: BlockNode new! !

!Parser methodsFor: 'expression types' stamp: 'eem 8/4/2008 10:56'!
statements: argNodes innerBlock: inner blockNode: theBlockNode

	| stmts returns start |
	"give initial comment to block, since others trail statements"
	theBlockNode comment: currentComment.
	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: 'ar 1/4/2002 00:23'!
temporaries
	" [ '|' (variable)* '|' ]"
	| vars theActualText |
	(self match: #verticalBar) ifFalse: 
		["no temps"
		doitFlag ifTrue: [self interactive
				ifFalse: [tempsMark := 1]
				ifTrue: [tempsMark := requestor selectionInterval first].
			^ #()].
		tempsMark := (prevEnd ifNil: [0]) + 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 5/13/2008 14:32'!
temporariesIn: methodSelector
	" [ '|' (variable)* '|' ]"
	| vars theActualText |
	(self match: #verticalBar) ifFalse: 
		["no temps"
		doitFlag ifTrue: [self interactive
				ifFalse: [tempsMark := 1]
				ifTrue: [tempsMark := requestor selectionInterval first].
			^ #()].
		tempsMark := (prevEnd ifNil: [0]) + 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 5/30/2008 14:16'!
temporaryBlockVariablesFor: aBlockNode
	"Scan and answer temporary block variables."

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

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

!Parser methodsFor: 'expression types' stamp: 'di 12/4/1999 21:04'!
variable

	| varName varStart varEnd |
	varStart := self startOfNextToken + requestorOffset.
	varName := self advance.
	varEnd := self endOfLastToken + requestorOffset.
	^ encoder encodeVariable: varName
		sourceRange: (varStart to: varEnd)
		ifUnknown: [self correctVariable: varName interval: (varStart to: varEnd)]! !

!Parser methodsFor: 'temps'!
bindArg: name

	^ self bindTemp: name! !

!Parser methodsFor: 'temps'!
bindTemp: name

	^name! !

!Parser methodsFor: 'temps' stamp: 'eem 5/13/2008 12:17'!
bindTemp: name in: methodSelector

	^name! !

!Parser methodsFor: 'error correction' stamp: 'cwp 10/15/2007 23:00'!
canDeclareClassVariable
	^encoder classEncoding ~~ UndefinedObject! !

!Parser methodsFor: 'error correction' stamp: 'cwp 10/17/2007 23:39/eem 9/5/2009 11:10 - => :='!
correctSelector: proposedKeyword wordIntervals: spots exprInterval: expInt ifAbort: abortAction
	"Correct the proposedKeyword to some selector symbol, correcting the original text if such action is indicated.  abortAction is invoked if the proposedKeyword couldn't be converted into a valid selector.  Spots is an ordered collection of intervals within the test stream of the for each of the keyword parts."

	| correctSelector userSelection |
	"If we can't ask the user, assume that the keyword will be defined later"
	self interactive ifFalse: [^proposedKeyword asSymbol].

	userSelection := requestor selectionInterval.
	requestor selectFrom: spots first first to: spots last last.
	requestor select.

	correctSelector := UnknownSelector name: proposedKeyword.
	correctSelector ifNil: [^abortAction value].

	requestor deselect.
	requestor selectInvisiblyFrom: userSelection first to: userSelection last.

	self substituteSelector: correctSelector keywords wordIntervals: spots.
	^(proposedKeyword last ~~ $:
	   and: [correctSelector last == $:])
		ifTrue: [abortAction value]
		ifFalse: [correctSelector]! !

!Parser methodsFor: 'error correction' stamp: 'eem 9/5/2009 11:53'!
correctVariable: proposedVariable interval: spot 
	"Correct the proposedVariable to a known variable, or declare it as a new
	variable if such action is requested.  We support declaring lowercase
	variables as temps or inst-vars, and uppercase variables as Globals or 
	ClassVars, depending on whether the context is nil (class=UndefinedObject).
	Spot is the interval within the test stream of the variable.
	rr 3/4/2004 10:26 : adds the option to define a new class. "

	"Check if this is an i-var, that has been corrected already (ugly)"

	"Display the pop-up menu"

	| tempIvar binding userSelection action |
	(encoder classEncoding instVarNames includes: proposedVariable) ifTrue: 
		[^InstanceVariableNode new 
			name: proposedVariable
			index: (encoder classEncoding allInstVarNames indexOf: proposedVariable)].

	"If we can't ask the user for correction, make it undeclared"
	self interactive ifFalse: [^encoder undeclared: proposedVariable].

	"First check to see if the requestor knows anything about the variable"
	tempIvar := proposedVariable first isLowercase.
	(tempIvar and: [(binding := requestor bindingOf: proposedVariable) notNil]) 
		ifTrue: [^encoder global: binding name: proposedVariable].
	userSelection := requestor selectionInterval.
	requestor selectFrom: spot first to: spot last.
	requestor select.

	"Build the menu with alternatives"
	action := UndeclaredVariable 
				signalFor: self
				name: proposedVariable
				inRange: spot.
	action ifNil: [^self fail].

	"Execute the selected action"
	requestor deselect.
	requestor selectInvisiblyFrom: userSelection first to: userSelection last.
	^action value! !

!Parser methodsFor: 'error correction'!
declareClassVar: name
	| sym class |
	sym := name asSymbol.
	class := encoder classEncoding.
	class := class theNonMetaClass.		"not the metaclass"
	class addClassVarName: name.
	^ encoder global: (class classPool associationAt: sym)
			name: sym! !

!Parser methodsFor: 'error correction' stamp: 'eem 5/27/2009 09:27'!
declareGlobal: name
	| sym |
	sym := name asSymbol.
	^encoder
		global: (encoder environment
					at: sym put: nil;
					associationAt: sym)
		name: sym! !

!Parser methodsFor: 'error correction' stamp: 'eem 8/21/2008 13:56'!
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.
	^InstanceVariableNode new name: name index: encoder classEncoding instSize
		! !

!Parser methodsFor: 'error correction' stamp: 'RAA 6/5/2001 11:57'!
declareTempAndPaste: 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.
	^ encoder bindAndJuggle: name! !

!Parser methodsFor: 'error correction' stamp: 'jmv 12/7/2009 22:48'!
defineClass: className 
	"prompts the user to define a new class,  
	asks for it's category, and lets the users edit further  
	the definition"
	| sym cat def d2 |
	sym := className asSymbol.
	cat := FillInTheBlank default request: 'Enter class category : ' initialAnswer: self encoder classEncoding category.
	cat
		ifEmpty: [cat := 'Unknown'].
	def := 'Object subclass: #' , sym , '
		instanceVariableNames: '''' 
		classVariableNames: ''''
		poolDictionaries: ''''
		category: ''' , cat , ''''.
	d2 := FillInTheBlank default request: 'Edit class definition : ' initialAnswer: def.
	d2
		ifEmpty: [d2 := def].
	Compiler evaluate: d2.
	^ encoder
		global: (Smalltalk associationAt: sym)
		name: sym! !

!Parser methodsFor: 'error correction' stamp: 'cwp 10/15/2007 22:58'!
possibleVariablesFor: proposedVariable 
	^encoder possibleVariablesFor: proposedVariable! !

!Parser methodsFor: 'error correction' stamp: 'cwp 10/17/2007 22:38/eem 9/5/2009 11:10 - => :='!
queryUndefined
	| varStart varName | 
	varName := parseNode key.
	varStart := self endOfLastToken + requestorOffset - varName size + 1.
	requestor selectFrom: varStart to: varStart + varName size - 1; select.
	(UndefinedVariable name: varName) ifFalse: [^ self fail]! !

!Parser methodsFor: 'error correction' stamp: 'eem 9/5/2009 11:59'!
removeUnusedTemps
	"Scan for unused temp names, and prompt the user about the prospect of removing each one found"

	| str end start madeChanges | 
	madeChanges := false.
	str := requestor text asString.
	((tempsMark between: 1 and: str size)
		and: [(str at: tempsMark) = $|]) ifFalse: [^ self].
	encoder unusedTempNames do:
		[:temp |
		(UnusedVariable name: temp) ifTrue:
			[(encoder encodeVariable: temp) isUndefTemp
				ifTrue:
					[end := tempsMark.
					["Beginning at right temp marker..."
					start := end - temp size + 1.
					end < temp size or: [temp = (str copyFrom: start to: end)
							and: [(str at: start-1) isSeparator & (str at: end+1) isSeparator]]]
						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'!
substituteSelector: selectorParts wordIntervals: spots
	"Substitute the correctSelector into the (presuamed interactive) receiver."
	| offset |
	offset := 0.
	selectorParts with: spots do:
		[ :word :interval |
		offset := self substituteWord: word wordInterval: interval offset: offset ]
! !

!Parser methodsFor: 'error correction' stamp: 'eem 9/5/2009 14:41'!
substituteVariable: each atInterval: anInterval 
	self 
		substituteWord: each
		wordInterval: anInterval
		offset: 0.
	^encoder encodeVariable: each! !

!Parser methodsFor: 'error correction'!
substituteWord: correctWord wordInterval: spot offset: o
	"Substitute the correctSelector into the (presuamed interactive) receiver."

	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: 'eem 9/12/2008 13:34'!
parse: sourceStreamOrString class: behavior

	^ self parse: sourceStreamOrString readStream class: behavior
		noPattern: false context: nil notifying: nil ifFail: [^nil]! !

!Parser methodsFor: 'public access' stamp: 'eem 7/2/2008 11:24'!
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 init: myStream notifying: req failBlock: [^ aBlock value].
	 doitFlag := noPattern.
	 failBlock:= aBlock.
	 [methNode := self
					method: noPattern
					context: ctxt
					encoder: (self encoder init: class context: ctxt notifying: self)] 
		on: ReparseAfterSourceEditing 
		do:	[ :ex |
			repeatNeeded := true.
			myStream := ReadStream on: requestor text string].
	 repeatNeeded] whileTrue:
		[encoder := self encoder class new].
	methNode sourceText: s.
	^methNode
! !

!Parser methodsFor: 'public access' stamp: 'ar 9/27/2005 19:19'!
parse: sourceStream class: class noPattern: noPattern context: ctxt notifying: req ifFail: aBlock 
	^self parse: sourceStream class: class category: nil noPattern: noPattern context: ctxt notifying: req ifFail: aBlock ! !

!Parser methodsFor: 'public access' stamp: 'md 1/20/2006 16:31'!
parse: sourceStream class: class noPattern: noPattern notifying: req ifFail: aBlock

	^ self parse: sourceStream class: class noPattern: noPattern context: nil notifying: req ifFail: aBlock! !

!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: 'eem 8/20/2008 20:55'!
parseSelector: aString 
	"Answer the message selector for the argument, aString, which should 
	 parse successfully up to the temporary declaration or the end of the 
	 method header."

	self initScannerForTokenization.
	^self
		initPattern: aString
		notifying: nil
		return: [:pattern | pattern at: 1]! !


!Scanner class methodsFor: 'initialization' stamp: 'sd 3/20/2008 22:23'!
initialize
	| newTable |
	newTable := Array new: 256 withAll: #xBinary. "default"
	newTable atAll: #(9 10 12 13 32 ) put: #xDelimiter. "tab lf ff cr space"
	newTable atAll: ($0 asciiValue to: $9 asciiValue) put: #xDigit.

	1 to: 255
		do: [:index |
			(Character value: index) isLetter
				ifTrue: [newTable at: index put: #xLetter]].

	newTable at: 30 put: #doIt.
	newTable at: $" asciiValue put: #xDoubleQuote.
	newTable at: $# asciiValue put: #xLitQuote.
	newTable at: $$ asciiValue put: #xDollar.
	newTable at: $' asciiValue put: #xSingleQuote.
	newTable at: $: asciiValue put: #xColon.
	newTable at: $( asciiValue put: #leftParenthesis.
	newTable at: $) asciiValue put: #rightParenthesis.
	newTable at: $. asciiValue put: #period.
	newTable at: $; asciiValue put: #semicolon.
	newTable at: $[ asciiValue put: #leftBracket.
	newTable at: $] asciiValue put: #rightBracket.
	newTable at: ${ asciiValue put: #leftBrace.
	newTable at: $} asciiValue put: #rightBrace.
	newTable at: $^ asciiValue put: #upArrow.
	newTable at: $_ asciiValue put: #leftArrow.
	newTable at: $| asciiValue put: #verticalBar.
	TypeTable := newTable "bon voyage!!"

	"Scanner initialize"! !

!Scanner class methodsFor: 'testing' stamp: 'sd 3/30/2005 22:00'!
inviolateInstanceVariableNames
	"Answer a list of instance variable names not to be used.  (Place holder for real list)"
	^ #('thisContext' 'self')! !

!Scanner class methodsFor: 'testing' stamp: 'sd 3/30/2005 22:00'!
isLegalInstVarName: aString
	"Answer whether aString is a legal instance variable name."

	^ ((self isLiteralSymbol: aString) and: [(aString includes: $:) not]) and:
		[(self inviolateInstanceVariableNames includes:  aString) not]! !

!Scanner class methodsFor: 'testing' stamp: 'nice 10/10/2008 20:08'!
isLiteralSymbol: aSymbol 
	"Test whether a symbol can be stored as # followed by its characters.  
	Symbols created internally with asSymbol may not have this property, 
	e.g. '3' asSymbol."

	| i ascii type next last |
	i := aSymbol size.
	i = 0 ifTrue: [^ false].

	"TypeTable should have been origined at 0 rather than 1 ..."
	ascii := (aSymbol at: 1) asciiValue.
	type := TypeTable at: ascii ifAbsent: [^false].
	type == #xLetter ifTrue: [
		next := last := nil.
		[i > 1]
				whileTrue: 
					[ascii := (aSymbol at: i) asciiValue.
					type := TypeTable at: ascii ifAbsent: [^false].
					(type == #xLetter or: [type == #xDigit or: [type == #xColon
							and: [
								next == nil
									ifTrue: [last := #xColon. true] 
									ifFalse: [last == #xColon and: [next ~~ #xDigit and: [next ~~ #xColon]]]]]])
						ifFalse: [^ false].
					next := type.
					i := i - 1].
			^ true].	
	type == #xBinary ifTrue: [^i = 1]. "Here we could extend to
		^(2 to: i) allSatisfy: [:j |
			ascii := (aSymbol at: j) asciiValue.
			(TypeTable at: ascii ifAbsent: []) == #xBinary]"
	type == #verticalBar ifTrue: [^i = 1].
	^false! !

!Scanner class methodsFor: 'testing' stamp: 'fbs 2/13/2006 22:33'!
wellFormedInstanceVariableNameFrom: aString
	"Answer a legal instance variable name, derived from aString"

	| cleansedString |
	cleansedString := aString select: [:ch | ch isDigit or: [ch isLetter]].
	(cleansedString isEmpty or: [cleansedString first isDigit])
		ifTrue: [cleansedString := 'a', cleansedString]
		ifFalse:	[cleansedString := cleansedString withFirstCharacterDownshifted].

	[self isLegalInstVarName: cleansedString] whileFalse:
		[cleansedString := cleansedString, 'x'].
	^ cleansedString

"Scanner wellFormedInstanceVariableNameFrom:  '234 xx\ Uml /ler42342380-4'"! !

!Scanner class methodsFor: 'instance creation' stamp: 'ar 1/30/2005 11:50'!
new

	^self basicNew initScanner! !


!Parser class methodsFor: 'class initialization' stamp: 'jmv 12/7/2009 22:33'!
initialize
	Preferences
		addPreference: #allowUnderscoreAssignment 
		category: #compiler 
		default: false
		balloonHelp: 'If enabled, the compiler will accept _ (underscore) for assignment.\This provides backward compatibility with the pre-ANSI compiler.' withCRs.
	Preferences
		addPreference: #allowBlockArgumentAssignment 
		category: #compiler 
		default: false
		balloonHelp: 'If enabled, the compiler will allow assignment into block arguments.\This provides backward compatibility with the pre-closure compiler.' withCRs.! !

!Parser class methodsFor: 'accessing' stamp: 'eem 12/1/2008 14:32'!
primitivePragmaSelectors
	"Answer the selectors of pragmas that specify VM primitives.
	 Needed for compile and decomple."
	^#(primitive:
		primitive:error:
		primitive:error:module:
		primitive:module:
		primitive:module:error:)! !


!ScannerTest methodsFor: 'testing' stamp: 'nice 10/10/2008 20:42'!
testLiteralSymbols

	self assert: ('*+-/\~=<>&@%,|' allSatisfy: [:char | Scanner isLiteralSymbol: (Symbol with: char)])
		description: 'single letter binary symbols can be printed without string quotes'.
		
	self assert: (#('x' 'x:' 'x:y:' 'from:to:by:' 'yourself') allSatisfy: [:str | Scanner isLiteralSymbol: str asSymbol])
		description: 'valid ascii selector symbols can be printed without string quotes'.
		
	((32 to: 126) collect: [:ascii | Character value: ascii]) ,
	#(':x:yourself' '::' 'x:yourself' '123' 'x0:1:2:' 'x.y.z' '1abc' 'a1b0c2' ' x' 'x ' '+x-y' '||' '--' '++' '+-' '+/-' '-/+' '<|>' '#x' '()' '[]' '{}' '')
		do: [:str |
			self assert: (Compiler evaluate: str asSymbol printString) = str asSymbol
				description: 'in all case, a Symbol must be printed in an interpretable fashion']! !


!SelectorNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:48'!
accept: aVisitor
	aVisitor visitSelectorNode: self! !

!SelectorNode methodsFor: 'code generation'!
emit: stack args: nArgs on: strm

	self emit: stack
		args: nArgs
		on: strm
		super: false! !

!SelectorNode methodsFor: 'code generation'!
emit: stack args: nArgs on: aStream super: supered
	| index |
	stack pop: nArgs.
	(supered not and: [code - Send < SendLimit and: [nArgs < 3]]) ifTrue:
		["short send"
		code < Send
			ifTrue: [^ aStream nextPut: code "special"]
			ifFalse: [^ aStream nextPut: nArgs * 16 + code]].
	index := code < 256 ifTrue: [code - Send] ifFalse: [code \\ 256].
	(index <= 31 and: [nArgs <= 7]) ifTrue: 
		["extended (2-byte) send [131 and 133]"
		aStream nextPut: SendLong + (supered ifTrue: [2] ifFalse: [0]).
		^ aStream nextPut: nArgs * 32 + index].
	(supered not and: [index <= 63 and: [nArgs <= 3]]) ifTrue:
		["new extended (2-byte) send [134]"
		aStream nextPut: SendLong2.
		^ aStream nextPut: nArgs * 64 + index].
	"long (3-byte) send"
	aStream nextPut: DblExtDoAll.
	aStream nextPut: nArgs + (supered ifTrue: [32] ifFalse: [0]).
	aStream nextPut: index! !

!SelectorNode methodsFor: 'code generation' stamp: 'eem 5/14/2008 16:08'!
reserve: encoder 
	"If this is a yet unused literal of type -code, reserve it."

	code < 0 ifTrue: [code := self code: (index := encoder sharableLitIndex: key) type: 0 - code]! !

!SelectorNode methodsFor: 'code generation' stamp: 'di 1/7/2000 12:32'!
size: encoder args: nArgs super: supered
	| index |
	self reserve: encoder.
	(supered not and: [code - Send < SendLimit and: [nArgs < 3]])
		ifTrue: [^1]. "short send"
	(supered and: [code < Send]) ifTrue: 
		["super special:"
		code := self code: (encoder sharableLitIndex: key) type: 5].
	index := code < 256 ifTrue: [code - Send] ifFalse: [code \\ 256].
	(index <= 31 and: [nArgs <= 7])
		ifTrue: [^ 2]. "medium send"
	(supered not and: [index <= 63 and: [nArgs <= 3]])
		ifTrue: [^ 2]. "new medium send"
	^ 3 "long send"! !

!SelectorNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCode: stack args: nArgs encoder: encoder

	self emitCode: stack
		args: nArgs
		encoder: encoder
		super: false! !

!SelectorNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:47'!
emitCode: stack args: nArgs encoder: encoder super: supered
	stack pop: nArgs.
	^supered
		ifTrue:
			[encoder genSendSuper: index numArgs: nArgs]
		ifFalse:
			[encoder
				genSend: (code < Send ifTrue: [code negated] ifFalse: [index])
				numArgs: nArgs]! !

!SelectorNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForEffect: stack encoder: encoder

	self shouldNotImplement! !

!SelectorNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForValue: stack encoder: encoder

	self shouldNotImplement! !

!SelectorNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:15'!
sizeCode: encoder args: nArgs super: supered
	self reserve: encoder.
	^supered
		ifTrue:
			[code < Send "i.e. its a special selector" ifTrue:
				[code := self code: (index := encoder sharableLitIndex: key) type: 5].
			 encoder sizeSendSuper: index numArgs: nArgs]
		ifFalse:
			[self flag: #yuck. "special selector sends cause this problem"
			 encoder
				sizeSend: (code < Send ifTrue: [code negated] ifFalse: [index])
				numArgs: nArgs]! !

!SelectorNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForEffect: encoder

	self shouldNotImplement! !

!SelectorNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForValue: encoder

	self shouldNotImplement! !

!SelectorNode methodsFor: 'inappropriate'!
emitForEffect: stack on: strm

	self shouldNotImplement! !

!SelectorNode methodsFor: 'inappropriate'!
emitForValue: stack on: strm

	self shouldNotImplement! !

!SelectorNode methodsFor: 'inappropriate'!
sizeForEffect: encoder

	self shouldNotImplement! !

!SelectorNode methodsFor: 'inappropriate'!
sizeForValue: encoder

	self shouldNotImplement! !

!SelectorNode methodsFor: 'testing' stamp: 'eem 9/25/2008 15:18'!
isForFFICall
	^key includesSubString: '()/'! !

!SelectorNode methodsFor: 'testing'!
isPvtSelector
	"Answer if this selector node is a private message selector."

	^key isPvtSelector! !

!SelectorNode methodsFor: 'printing' stamp: 'eem 9/25/2008 14:56'!
key: aSelector
	"This is for printing of FFI selectors."
	key := aSelector! !

!SelectorNode methodsFor: 'printing' stamp: 'eem 9/25/2008 15:01'!
printAsFFICallWithArguments: aSequence on: aStream indent: level
	aStream nextPutAll: (key copyUpTo: $)).
	aSequence
		do: [:arg| arg printOn: aStream indent: level]
		separatedBy: [aStream nextPutAll: ', '].
	aStream nextPut: $)! !

!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])! !

!SelectorNode methodsFor: 'initialize-release' stamp: 'eem 5/14/2008 09:30'!
name: literal key: object index: i type: type
	"For compatibility with Encoder>>name:key:class:type:set:"
	^self key: object index: i type: type! !


!UndeclaredVariable methodsFor: 'as yet unclassified' stamp: 'eem 9/5/2009 14:41'!
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 temp'.
			actions add: [parser declareTempAndPaste: name].
			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] fixTemps].
	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])! !

!UndeclaredVariable methodsFor: 'as yet unclassified' stamp: 'cwp 10/15/2007 23:04'!
setParser: aParser name: aString range: anInterval 
	parser := aParser.
	name := aString.
	interval := anInterval! !


!UndeclaredVariable class methodsFor: 'as yet unclassified' stamp: 'cwp 10/15/2007 22:37'!
signalFor: aParser name: aString inRange: anInterval 
	^ (self new setParser: aParser name: aString range: anInterval) signal! !


!UndeclaredVariableReference methodsFor: 'exceptionDescription' stamp: 'ar 12/8/2002 13:13'!
defaultAction
	^parser correctVariable: varName interval: (varStart to: varEnd)! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:13'!
parser
	^parser! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:13'!
parser: aParser
	parser := aParser! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:14'!
varEnd
	^varEnd! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:14'!
varEnd: aNumber
	varEnd := aNumber! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:13'!
varName
	^varName! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:13'!
varName: aString
	varName := aString! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:14'!
varStart
	^varStart! !

!UndeclaredVariableReference methodsFor: 'accessing' stamp: 'ar 12/8/2002 13:14'!
varStart: aNumber
	varStart := aNumber! !


!UndeclaredVariableWarning methodsFor: 'exceptionDescription' stamp: 'bgf 3/10/2009 19:03'!
defaultAction
	"The user should be notified of the occurrence of an exceptional occurrence and
	 given an option of continuing or aborting the computation. The description of the
	 occurrence should include any text specified as the argument of the #signal: message."
	
	selector ifNotNil: [Transcript cr; nextPutAll: class name, '>>', selector, ' ']
			ifNil: [Transcript cr ].
	Transcript show: '(' , name , ' is Undeclared) '.
	^true! !

!UndeclaredVariableWarning methodsFor: 'initialize-release' stamp: 'eem 7/27/2008 17:37'!
name: aString selector: aSymbolOrNil class: aBehavior
	name := aString.
	selector := aSymbolOrNil.
	class := aBehavior! !


!UndefinedVariable methodsFor: 'as yet unclassified' stamp: 'cwp 10/17/2007 22:39/eem 9/5/2009 11:10 - => :='!
openMenuIn: aBlock
	| labels caption index |
	labels := #('yes' 'no').
	caption := name, ' appears to be 
undefined at this point.
Proceed anyway?'.

	index := aBlock value: labels value: #() value: caption.
	^ self resume: index = 1! !


!UnknownSelector methodsFor: 'as yet unclassified' stamp: 'cwp 10/17/2007 23:34/eem 9/5/2009 11:10 - => :='!
openMenuIn: aBlock
	| alternatives labels lines caption choice |
	alternatives := Symbol possibleSelectorsFor: name.
	labels := Array streamContents:
				[:s | s nextPut: name; nextPutAll: alternatives; nextPut: 'cancel'].
	lines := {1. alternatives size + 1}.
	caption := 'Unknown selector, please\confirm, correct, or cancel' withCRs.
	
	choice := aBlock value: labels value: lines value: caption.
	choice = 0 ifTrue: [self resume: nil].
	choice = 1 ifTrue: [self resume: name asSymbol].
	choice = labels size ifTrue: [self resume: nil].
	self resume: (alternatives at: choice - 1)! !


!UnusedVariable methodsFor: 'as yet unclassified' stamp: 'eem 9/5/2009 11:10'!
openMenuIn: aBlock
	| index |
	index := aBlock value: #('yes' 'no')
					value: #()
					value: name, ' appears to be\unused in this method.\OK to remove it?' withCRs.
	self resume: index = 1! !


!Utilities class methodsFor: 'closure support' stamp: 'jmv 12/7/2009 22:39'!
compileUsingClosures	"Utilities compileUsingClosures"
	"Recompile the system and do some minimal clean-ups"
	| classes compilationErrors |
	Preferences setPreference: #allowBlockArgumentAssignment toValue: true.
	compilationErrors := Set new.
	classes := Smalltalk forgetDoIts allClasses reject: [:c| c name == #GeniePlugin].

	'Recompiling The System' displayProgressAt: Sensor cursorPoint
		from: 0 to: classes size during:[:bar |
			classes withIndexDo:[:c :i|
				bar value: i.
				{ c. c class } do:[:b|
					"Transcript cr; print: b; endEntry."
					b selectors "asSortedCollection" do:[:s| 
						"Transcript cr; show: b asString, '>>', s."
						[b recompile: s from: b] on: Error do:[:ex|
							Transcript
								cr; nextPutAll: 'COMPILATION ERROR: ';
								print: b; nextPutAll: '>>'; nextPutAll: s; flush.
							compilationErrors add: (MethodReference class: b selector: s)]]]]].

	(Smalltalk respondsTo: #allTraits) ifTrue:[
		'Recompiling Traits' displayProgressAt: Sensor cursorPoint
		from: 0 to: Smalltalk allTraits size during:[:bar |
			Smalltalk allTraits do:[:t|
				t selectors do:[:s|
					[t recompile: s] on: Error do:[:ex|
							Transcript
								cr; nextPutAll: 'COMPILATION ERROR: ';
								print: t; nextPutAll: '>>'; nextPutAll: s; flush.
							compilationErrors add: (MethodReference class: t selector: s)]]]]].

	compilationErrors notEmpty ifTrue:[
		Smalltalk
			browseMessageList: compilationErrors asSortedCollection
			name: 'Compilation Errors'].! !

!Utilities class methodsFor: 'closure support' stamp: 'jmv 12/7/2009 22:37'!
postRecompileCleanup	"Utilities postRecompileCleanup"
	"Cleanup after loading closure bootstrap"
	| unboundMethods contexts |
	ProcessorScheduler startUp.
	WeakArray restartFinalizationProcess.
	MethodChangeRecord allInstancesDo:[:x| x noteNewMethod: nil].
	Undeclared removeUnreferencedKeys.
	Delay startTimerEventLoop.
	EventSensor install.
	WorldState allInstancesDo:[:ws| ws convertAlarms; convertStepList].
	(Workspace canUnderstand: #initializeBindings) 
		ifTrue:[Workspace allInstancesDo:[:ws| ws initializeBindings]].
	Smalltalk garbageCollect.
	Smalltalk
		at: #DebuggerMethodMap
		ifPresent: [:dmm| dmm voidMapCache].
	(ProcessBrowser respondsTo: #registerWellKnownProcesses) ifTrue:
		[ProcessBrowser registerWellKnownProcesses].
	Smalltalk
		at: #DebuggerMethodMap
		ifPresent: [:dmm| dmm voidMapCache].
	Smalltalk at: #ServiceRegistry ifPresent:[:cls| cls rebuild].
	Smalltalk forgetDoIts.
	Smalltalk garbageCollect.
	unboundMethods := CompiledMethod allInstances select:[:m|
		m methodClass isNil or: [m ~~ (m methodClass compiledMethodAt: m selector ifAbsent: nil)]].
	unboundMethods := unboundMethods reject:[:m| m selector isDoIt].
	unboundMethods notEmpty ifTrue:
		[unboundMethods inspectWithLabel: 'Unbound Methods'].
	contexts := BlockContext allInstances.
	contexts ifNotEmpty:[contexts inspect. self inform: 'There are left-over BlockContexts'].
	(unboundMethods isEmpty and:[contexts isEmpty]) ifTrue:[
		self inform:'Congratulations - The bootstrap is now complete.'.
	].
! !


!VariableNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 10:32'!
accept: aVisitor
	aVisitor visitVariableNode: self! !

!VariableNode methodsFor: 'initialize-release'!
asStorableNode: encoder
	^ self! !

!VariableNode methodsFor: 'initialize-release' stamp: 'eem 12/1/2008 13:51'!
name: string
	"Change name"

	name := string! !

!VariableNode methodsFor: 'initialize-release' stamp: 'eem 5/14/2008 09:33'!
name: varName index: i type: type
	"Only used for initting instVar refs"
	^self name: varName key: varName index: i type: type! !

!VariableNode methodsFor: 'initialize-release' stamp: 'ar 3/26/2004 15:46'!
name: string key: object code: byte
	"Only used for initting std variables, nil, true, false, self, etc."
	name := string.
	key := object.
	code := byte! !

!VariableNode methodsFor: 'initialize-release' stamp: 'eem 5/14/2008 16:01'!
name: varName key: objRef index: i type: type
	"Only used for initting global (litInd) variables"
	^self name: varName key: objRef code: (self code: (index := i) type: type)! !

!VariableNode methodsFor: 'testing' stamp: 'eem 5/14/2008 09:11'!
assignmentCheck: encoder at: location
	^(encoder cantStoreInto: name) ifTrue: [location] ifFalse: [-1]! !

!VariableNode methodsFor: 'testing' stamp: 'ar 3/26/2004 15:46'!
canBeSpecialArgument
	"Can I be an argument of (e.g.) ifTrue:?"

	^code < LdNil! !

!VariableNode methodsFor: 'testing' stamp: 'eem 5/21/2008 11:06'!
index
	"This code attempts to reconstruct the index from its encoding in code."
	code < 0 ifTrue:[^nil].
	code > 256 ifTrue:
		[self assert: index = (code \\ 256).
		^code \\ 256].
	code >= (CodeBases at: self type) ifTrue:
		[self assert: index = (code - (CodeBases at: self type)).
		^code - (CodeBases at: self type)].
	self assert: index = (code - self type).
	^code - self type! !

!VariableNode methodsFor: 'testing' stamp: 'eem 5/14/2008 09:13'!
isSelfPseudoVariable
	"Answer if this ParseNode represents the 'self' pseudo-variable."

	^ key = 'self' or: [name = '{{self}}']! !

!VariableNode methodsFor: 'testing' stamp: 'ar 11/19/2002 14:58'!
isVariableNode
	^true! !

!VariableNode methodsFor: 'testing'!
isVariableReference

	^true! !

!VariableNode methodsFor: 'testing' stamp: 'eem 5/14/2008 09:18'!
type
	"This code attempts to reconstruct the type from its encoding in code.
		This allows one to test, for instance, (aNode type = LdInstType)."
	| type |
	code < 0 ifTrue: [^code negated].
	code >= 256 ifTrue: [^code // 256].
	type := CodeBases findFirst: [:one | code < one].
	^type = 0 ifTrue: [5] ifFalse: [type - 1]! !

!VariableNode methodsFor: 'code generation (closures)' stamp: 'eem 7/20/2009 10:38'!
beingAssignedToAnalyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	"No-op overridden by TempVariableNode"! !

!VariableNode methodsFor: 'tiles' stamp: 'RAA 8/24/1999 16:34'!
currentValueIn: aContext

	aContext ifNil: [^nil].
	^((self variableGetterBlockIn: aContext) ifNil: [^nil]) value printString
	

! !

!VariableNode methodsFor: 'tiles' stamp: 'ab 7/13/2004 13:54'!
variableGetterBlockIn: aContext

	| temps index ivars |

	(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.
		index := ivars indexOf: self name ifAbsent: [^nil].
		^[aContext receiver instVarAt: index]
	].
	self type = 2 ifTrue: [
		temps := aContext tempNames.
		index := temps indexOf: self name ifAbsent: [^nil].
		^[aContext tempAt: index]
	].
	^nil
! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForLoad: stack encoder: encoder
	"Do nothing"! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:41'!
emitCodeForReturn: stack encoder: encoder
	encoder
		if: code
		isSpecialLiteralForReturn:
			[:specialLiteral|
			"short returns"
			 encoder genReturnSpecialLiteral: specialLiteral.
			 stack push: 1 "doesnt seem right".
			 ^self].
	(self code = LdSelf or: [self code = LdSuper]) ifTrue: 
		["short returns"
		 encoder genReturnReceiver.
		 stack push: 1 "doesnt seem right".
		 ^self].
	super emitCodeForReturn: stack encoder: encoder! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:08'!
emitCodeForStore: stack encoder: encoder

	self shouldNotImplement! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:41'!
emitCodeForStorePop: stack encoder: encoder
	self type ~= 1 ifTrue:
		[self halt].
	encoder genStorePopInstVar: index.
	stack pop: 1! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:07'!
emitCodeForValue: stack encoder: encoder
	stack push: 1.
	encoder
		if: code
		isSpecialLiteralForPush:
			[:specialLiteral|
			 ^encoder genPushSpecialLiteral: specialLiteral].
	(code = LdSelf or: [code = LdSuper]) ifTrue:
		[^encoder genPushReceiver].
	code = LdThisContext ifTrue:
		[^encoder genPushThisContext].
	self flag: 'probably superfluous'.
	self halt.
	^encoder genPushInstVar: index! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:58'!
sizeCodeForReturn: encoder
	encoder
		if: code
		isSpecialLiteralForPush:
			[:specialLiteral|
			 ^encoder sizeReturnSpecialLiteral: specialLiteral].
	(self code = LdSelf or: [self code = LdSuper]) ifTrue:
		[^encoder sizeReturnReceiver].
	^super sizeCodeForReturn: encoder! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:09'!
sizeCodeForStore: encoder
	self shouldNotImplement! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:09'!
sizeCodeForStorePop: encoder
	self shouldNotImplement! !

!VariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:54'!
sizeCodeForValue: encoder
	self reserve: encoder.
	encoder
		if: code
		isSpecialLiteralForPush:
			[:specialLiteral| "i.e. the pseudo-variables nil true & false"
			 ^encoder sizePushSpecialLiteral: specialLiteral].
	(code = LdSelf or: [code = LdSuper]) ifTrue:
		[^encoder sizePushReceiver].
	code = LdThisContext ifTrue:
		[^encoder sizePushThisContext].
	self flag: 'probably superfluous'.
	self halt.
	^encoder sizePushInstVar: index! !

!VariableNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:46'!
emitForReturn: stack on: strm

	(code >= LdSelf and: [code <= LdNil])
		ifTrue: 
			["short returns"
			strm nextPut: EndMethod - 4 + (code - LdSelf).
			stack push: 1 "doesnt seem right"]
		ifFalse: 
			[super emitForReturn: stack on: strm]! !

!VariableNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:46'!
emitForValue: stack on: strm

	code < 256
		ifTrue: 
			[strm nextPut: (code = LdSuper ifTrue: [LdSelf] ifFalse: [code]).
			stack push: 1]
		ifFalse: 
			[self emitLong: LoadLong on: strm.
			stack push: 1]! !

!VariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2001 23:14'!
emitLoad: stack on: strm
	"Do nothing"! !

!VariableNode methodsFor: 'code generation'!
emitStore: stack on: strm

	self emitLong: Store on: strm! !

!VariableNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:46'!
emitStorePop: stack on: strm
	(code between: 0 and: 7)
		ifTrue: 
			[strm nextPut: ShortStoP + code "short stopop inst"]
		ifFalse:
			[(code between: 16 and: 23)
				ifTrue: [strm nextPut: ShortStoP + 8 + code - 16 "short stopop temp"]
				ifFalse: [(code >= 256 and: [code \\ 256 > 63 and: [code // 256 = 4]])
						ifTrue: [self emitLong: Store on: strm. strm nextPut: Pop]
						ifFalse: [self emitLong: StorePop on: strm]]].
	stack pop: 1! !

!VariableNode methodsFor: 'code generation' stamp: 'eem 9/5/2008 18:14'!
fieldOffset
	"Return temp or instVar offset for this variable"
	^index ifNil: [code < 256
					ifTrue: [code \\ 16]
					ifFalse: [code \\ 256]]! !

!VariableNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:46'!
sizeForReturn: encoder

	(code >= LdSelf and: [code <= LdNil])
		ifTrue: ["short returns" ^1].
	^super sizeForReturn: encoder! !

!VariableNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:46'!
sizeForStore: encoder
	self reserve: encoder.
	code < 256 ifTrue: [^ 2].
	(code \\ 256) <= 63 ifTrue: [^ 2].
	^ 3! !

!VariableNode methodsFor: 'code generation' stamp: 'ar 3/26/2004 15:46'!
sizeForStorePop: encoder
	self reserve: encoder.
	(code < 24 and: [code noMask: 8]) ifTrue: [^ 1].
	code < 256 ifTrue: [^ 2].
	code \\ 256 <= 63 ifTrue: [^ 2].  "extended StorePop"
	code // 256 = 1 ifTrue: [^ 3].  "dbl extended StorePopInst"
	code // 256 = 4 ifTrue: [^ 4].  "dbl extended StoreLitVar , Pop"
	self halt.  "Shouldn't get here"! !

!VariableNode methodsFor: 'accessing' stamp: 'tk 1/30/2001 13:45'!
name
	^ name! !

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

	aStream nextPutAll: name! !

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

	aStream nextPutAll: name! !


!FieldNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:49'!
accept: aVisitor
	aVisitor visitFieldNode: self! !

!FieldNode methodsFor: 'testing' stamp: 'eem 5/12/2008 13:40'!
assignmentCheck: encoder at: location
	(encoder cantStoreInto: name) ifTrue: [^location].
	fieldDef toSet ifNil:[
		encoder interactive ifTrue:[^location].
		fieldDef := fieldDef clone assignDefaultSetter.
	].
	^-1! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForEffect: stack encoder: encoder! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForLoad: stack encoder: encoder
	rcvrNode emitCodeForValue: stack encoder: encoder.
	fieldDef accessKey ifNotNil:[
		super emitCodeForValue: stack encoder: encoder.
	].! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForStore: stack encoder: encoder
	fieldDef accessKey ifNil:[
		writeNode emitCode: stack args: 1 encoder: encoder super: false.
	] ifNotNil:[
		writeNode emitCode: stack args: 2 encoder: encoder super: false.
	].! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 16:18'!
emitCodeForStorePop: stack encoder: encoder
	self emitCodeForStore: stack encoder: encoder.
	encoder genPop.
	stack pop: 1.! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
emitCodeForValue: stack encoder: encoder
	fieldDef accessKey ifNil:[
		rcvrNode emitCodeForValue: stack encoder: encoder.
		readNode emitCode: stack args: 0 encoder: encoder super: false.
	] ifNotNil:[
		rcvrNode emitCodeForValue: stack encoder: encoder.
		super emitCodeForValue: stack encoder: encoder.
		readNode emitCode: stack args: 1 encoder: encoder super: false.
	].! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForEffect: encoder
	^0! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForStore: encoder
	rcvrNode ifNil:[self encodeReceiverOn: encoder].
	fieldDef accessKey ifNil:[
		writeNode ifNil:[writeNode := encoder encodeSelector: fieldDef toSet].
		^(rcvrNode sizeCodeForValue: encoder) + 
			(writeNode sizeCode: encoder args: 1 super: false)	
	].
	writeNode ifNil:[writeNode := encoder encodeSelector: #set:to:].
	^(rcvrNode sizeCodeForValue: encoder) + 
		(super sizeCodeForValue: encoder) +
			(writeNode sizeCode: encoder args: 2 super: false)! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:17'!
sizeCodeForStorePop: encoder
	^(self sizeCodeForStore: encoder) + encoder sizePop! !

!FieldNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 14:52'!
sizeCodeForValue: encoder
	rcvrNode ifNil:[self encodeReceiverOn: encoder].
	fieldDef accessKey ifNil:[
		readNode ifNil:[readNode := encoder encodeSelector: fieldDef toGet].
		^(rcvrNode sizeCodeForValue: encoder) + 
			(readNode sizeCode: encoder args: 0 super: false)
	].
	readNode ifNil:[readNode := encoder encodeSelector: #get:].
	^(rcvrNode sizeCodeForValue: encoder) + 
		(super sizeCodeForValue: encoder) + 
			(readNode sizeCode: encoder args: 1 super: false)! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
emitForEffect: stack on: strm
! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
emitForValue: stack on: aStream
	fieldDef accessKey ifNil:[
		rcvrNode emitForValue: stack on: aStream.
		readNode emit: stack args: 0 on: aStream super: false.
	] ifNotNil:[
		rcvrNode emitForValue: stack on: aStream.
		super emitForValue: stack on: aStream.
		readNode emit: stack args: 1 on: aStream super: false.
	].
! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
emitLoad: stack on: strm
	rcvrNode emitForValue: stack on: strm.
	fieldDef accessKey ifNotNil:[
		super emitForValue: stack on: strm.
	].! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
emitStore: stack on: strm
	fieldDef accessKey ifNil:[
		writeNode emit: stack args: 1 on: strm super: false.
	] ifNotNil:[
		writeNode emit: stack args: 2 on: strm super: false.
	].! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
emitStorePop: stack on: strm
	self emitStore: stack on: strm.
	strm nextPut: Pop.
	stack pop: 1.! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
encodeReceiverOn: encoder
	"encode the receiver node"
	rcvrNode := encoder encodeVariable: 'self'.! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
sizeForEffect: encoder
	^0! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
sizeForStore: encoder
	rcvrNode ifNil:[self encodeReceiverOn: encoder].
	fieldDef accessKey ifNil:[
		writeNode ifNil:[writeNode := encoder encodeSelector: fieldDef toSet].
		^(rcvrNode sizeForValue: encoder) + 
			(writeNode size: encoder args: 1 super: false)	
	].
	writeNode ifNil:[writeNode := encoder encodeSelector: #set:to:].
	^(rcvrNode sizeForValue: encoder) + 
		(super sizeForValue: encoder) +
			(writeNode size: encoder args: 2 super: false)! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
sizeForStorePop: encoder
	^(self sizeForStore: encoder) + 1! !

!FieldNode methodsFor: 'code generation' stamp: 'eem 5/12/2008 13:40'!
sizeForValue: encoder
	rcvrNode ifNil:[self encodeReceiverOn: encoder].
	fieldDef accessKey ifNil:[
		readNode ifNil:[readNode := encoder encodeSelector: fieldDef toGet].
		^(rcvrNode sizeForValue: encoder) + 
			(readNode size: encoder args: 0 super: false)
	].
	readNode ifNil:[readNode := encoder encodeSelector: #get:].
	^(rcvrNode sizeForValue: encoder) + 
		(super sizeForValue: encoder) + 
			(readNode size: encoder args: 1 super: false)! !

!FieldNode methodsFor: 'accessing' stamp: 'eem 5/12/2008 13:40'!
fieldDef
	^fieldDef! !

!FieldNode methodsFor: 'initialize-release' stamp: 'eem 5/12/2008 13:40'!
fieldDefinition: fieldDefinition
	self name: fieldDefinition name key: fieldDefinition index: nil type: LdLitType! !

!FieldNode methodsFor: 'initialize-release' stamp: 'eem 5/12/2008 13:40'!
name: varName key: objRef index: i type: type
	fieldDef := objRef.
	^super name: varName key: objRef key index: nil type: LdLitType! !


!InstanceVariableNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:50'!
accept: aVisitor
	aVisitor visitInstanceVariableNode: self! !

!InstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:08'!
emitCodeForStore: stack encoder: encoder
	encoder genStoreInstVar: index! !

!InstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 10:05'!
emitCodeForStorePop: stack encoder: encoder
	encoder genStorePopInstVar: index.
	stack pop: 1! !

!InstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:08'!
emitCodeForValue: stack encoder: encoder
	stack push: 1.
	^encoder genPushInstVar: index! !

!InstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:57'!
sizeCodeForStore: encoder
	^encoder sizeStoreInstVar: index! !

!InstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:07'!
sizeCodeForStorePop: encoder
	^encoder sizeStorePopInstVar: index! !

!InstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:53'!
sizeCodeForValue: encoder
	^encoder sizePushInstVar: index! !

!InstanceVariableNode methodsFor: 'initialize-release' stamp: 'eem 5/13/2008 10:17'!
name: varName index: varIndex
	^self name: varName index: varIndex-1 type: LdInstType! !


!LiteralVariableNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:50'!
accept: aVisitor
	aVisitor visitLiteralVariableNode: self! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 09:44'!
emitCodeForLoad: stack encoder: encoder
	writeNode ifNotNil:
		[encoder genPushLiteral: index.
		 stack push: 1]! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 10:43'!
emitCodeForStore: stack encoder: encoder
	writeNode ifNil: [^encoder genStoreLiteralVar: index].
	"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
	or use e.g. valueForStore:"
	self flag: #bogus.
	writeNode
		emitCode: stack
		args: 1
		encoder: encoder
		super: false! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 10:09'!
emitCodeForStorePop: stack encoder: encoder
	writeNode ifNil:
		[stack pop: 1.
		 ^encoder genStorePopLiteralVar: index].
	self emitCodeForStore: stack encoder: encoder.
	encoder genPop.
	stack pop: 1.! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:11'!
emitCodeForValue: stack encoder: encoder
	stack push: 1.
	^encoder genPushLiteralVar: index! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 09:45'!
sizeCodeForLoad: encoder
	^writeNode ifNil: [0] ifNotNil: [encoder sizePushLiteral: index]! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:06'!
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:.
	^(encoder sizePushLiteralVar: index)
	 + (writeNode sizeCode: encoder args: 1 super: false)! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/15/2008 10:17'!
sizeCodeForStorePop: encoder
	self reserve: encoder.
	^(key isVariableBinding and: [key isSpecialWriteBinding])
		ifTrue: [(self sizeCodeForStorePop: encoder) + encoder sizePop]
		ifFalse: [encoder sizeStorePopLiteralVar: index]! !

!LiteralVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:03'!
sizeCodeForValue: encoder
	self reserve: encoder.
	^encoder sizePushLiteralVar: index! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2003 02:01'!
emitForValue: stack on: strm
	super emitForValue: stack on: strm.
	readNode ifNotNil:[readNode emit: stack args: 0 on: strm super: false].! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2003 01:59'!
emitLoad: stack on: strm
	writeNode ifNil:[^super emitLoad: stack on: strm].
	code < 256
		ifTrue: [strm nextPut: code]
		ifFalse: [self emitLong: LoadLong on: strm].
	stack push: 1.! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2003 02:00'!
emitStore: stack on: strm
	writeNode ifNil:[^super emitStore: stack on: strm].
	writeNode
			emit: stack
			args: 1
			on: strm
			super: false.! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2003 02:00'!
emitStorePop: stack on: strm
	writeNode ifNil:[^super emitStorePop: stack on: strm].
	self emitStore: stack on: strm.
	strm nextPut: Pop.
	stack pop: 1.! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2003 02:00'!
sizeForStore: encoder
	| index |
	(key isVariableBinding and:[key isSpecialWriteBinding]) 
		ifFalse:[^super sizeForStore: encoder].
	code < 0 ifTrue:[
		index := self index.
		code := self code: index type: LdLitType].
	writeNode := encoder encodeSelector: #value:.
	^(writeNode size: encoder args: 1 super: false) + (super sizeForValue: encoder)! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2003 02:00'!
sizeForStorePop: encoder
	| index |
	(key isVariableBinding and:[key isSpecialWriteBinding]) 
		ifFalse:[^super sizeForStorePop: encoder].
	code < 0 ifTrue:[
		index := self index.
		code := self code: index type: LdLitType].
	writeNode := encoder encodeSelector: #value:.
	^(writeNode size: encoder args: 1 super: false) + (super sizeForValue: encoder) + 1! !

!LiteralVariableNode methodsFor: 'code generation' stamp: 'ar 8/14/2003 02:02'!
sizeForValue: encoder
	| index |
	(key isVariableBinding and:[key isSpecialReadBinding]) 
		ifFalse:[^super sizeForValue: encoder].
	code < 0 ifTrue:[
		index := self index.
		code := self code: index type: LdLitType].
	readNode := encoder encodeSelector: #value.
	^(readNode size: encoder args: 0 super: false) + (super sizeForValue: encoder)! !


!MaybeContextInstanceVariableNode methodsFor: 'accessing' stamp: 'eem 6/19/2008 09:27'!
code
	"Answer a bogus code to avoid creating quick methods.
	 See MethodNode>>generate:ifQuick:"
	^LoadLong! !

!MaybeContextInstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:08'!
emitCodeForStore: stack encoder: encoder
	encoder genStoreInstVarLong: index! !

!MaybeContextInstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 6/19/2008 09:36'!
emitCodeForStorePop: stack encoder: encoder
	encoder genStorePopInstVarLong: index.
	stack pop: 1! !

!MaybeContextInstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:08'!
emitCodeForValue: stack encoder: encoder
	stack push: 1.
	^encoder genPushInstVarLong: index! !

!MaybeContextInstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:57'!
sizeCodeForStore: encoder
	^encoder sizeStoreInstVarLong: index! !

!MaybeContextInstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 18:07'!
sizeCodeForStorePop: encoder
	^encoder sizeStorePopInstVarLong: index! !

!MaybeContextInstanceVariableNode methodsFor: 'code generation (new scheme)' stamp: 'eem 5/14/2008 17:53'!
sizeCodeForValue: encoder
	^encoder sizePushInstVarLong: index! !


!TempVariableNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:51'!
accept: aVisitor
	aVisitor visitTempVariableNode: self! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 8/3/2009 18:54'!
addReadWithin: scopeBlock "<BlockNode>" at: location "<Integer>"
	readingScopes ifNil: [readingScopes := Dictionary new].
	(readingScopes at: scopeBlock ifAbsentPut: [Set new]) add: location.
	remoteNode ifNotNil:
		[remoteNode addReadWithin: scopeBlock at: location]! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 8/3/2009 18:55'!
addWriteWithin: scopeBlock "<BlockNode>" at: location "<Integer>"
	writingScopes ifNil: [writingScopes := Dictionary new].
	(writingScopes at: scopeBlock ifAbsentPut: [Set new]) add: location.
	remoteNode ifNotNil:
		[remoteNode addReadWithin: scopeBlock at: location]! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 7/24/2009 15:07'!
analyseClosure: rootNode "<MethodNode>"
	"Analyse whether the temporary needs to be made remote
	 or not, and answer whether it was made remote.
	 A temp cannot be local if it is written to remotely,
	 or if it is written to after it is closed-over.  An exception
	 is an inlined block argument that appears to be written
	 remotely but is actually local to a block."
	| latestWrite |
	self isBlockArg ifTrue: [^false].
	remoteNode ifNotNil: [^false]. "If already remote, don't remote a second time"
	latestWrite := 0.
	((writingScopes notNil
	 and: [writingScopes associations anySatisfy: [:assoc|
			[:blockScope :refs|
			refs do: [:write| latestWrite := write max: latestWrite].
			"A temp cannot be local if it is written to remotely."
			blockScope actualScope ~~ definingScope actualScope]
				value: assoc key value: assoc value]])
	or: [readingScopes notNil
		and: [readingScopes associations anySatisfy: [:assoc|
				[:blockScope :refs|
				 "A temp cannot be local if it is written to after it is closed-over."
				 blockScope actualScope ~~ definingScope actualScope
				 and: [refs anySatisfy: [:read| read < latestWrite]]]
					value: assoc key value: assoc value]]]) ifTrue:
		[remoteNode := definingScope addRemoteTemp: self rootNode: rootNode.
		 ^true].
	^false! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 5/20/2008 10:56'!
analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	self addReadWithin: scopeBlock at: rootNode locationCounter! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 7/24/2009 11:46'!
beingAssignedToAnalyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
	self addWriteWithin: scopeBlock at: rootNode locationCounter.
	"For analysis of optimized blocks also record the set of temporaries written to
	 within optimized blocks so that additional writes can be added at locations that
	 represent subsequent iterations of the loop. e.g. testInlineBlockCollectionSD1"
	assignmentPools keysAndValuesDo:
		[:outerScopeBlock :set|
		"definingScope can be nil in expr in expr ifNil: [:arg|...] expressions because
		 arg gets its definingScope set when [:arg|...] is analysed."
		outerScopeBlock actualScope
			= (definingScope
				ifNil: [scopeBlock]
				ifNotNil: [definingScope actualScope]) ifTrue:
			[set add: self]]! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 7/20/2009 16:33'!
definingScope
	^definingScope! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 5/30/2008 11:17'!
definingScope: scopeBlock "<BlockNode>"
	definingScope := scopeBlock! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 8/4/2009 13:26'!
index: anInteger
	"For renumbering temps in the closure compiler."
	index := anInteger.
	code := self code: index type: LdTempType! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 7/20/2009 14:27'!
isDefinedWithinBlockExtent: anInterval
	^anInterval rangeIncludes: definingScope actualScope blockExtent first! !

!TempVariableNode methodsFor: 'code generation (closures)' stamp: 'eem 6/2/2008 16:50'!
isIndirectTempVector
	^false! !

!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 9/10/2008 10:04'!
assignmentCheck: encoder at: location
	^((self isBlockArg and: [Preferences allowBlockArgumentAssignment not])
	    or: [self isMethodArg])
			ifTrue: [location]
			ifFalse: [-1]! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 9/8/2008 18:22'!
beBlockArg
	argType := #block! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 9/8/2008 18:21'!
beMethodArg
	argType := #method! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 9/8/2008 18:24'!
isArg
	^argType notNil! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 9/8/2008 18:20'!
isBlockArg
	^#block == argType! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 9/8/2008 18:20'!
isMethodArg
	^#method == argType! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 5/29/2008 15:51'!
isRemote
	^remoteNode notNil! !

!TempVariableNode methodsFor: 'testing'!
isTemp
	^ true! !

!TempVariableNode methodsFor: 'testing'!
isUndefTemp
	^ hasDefs not! !

!TempVariableNode methodsFor: 'testing'!
isUnusedTemp
	^ hasRefs not! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 5/29/2008 15:51'!
remoteNode
	^remoteNode! !

!TempVariableNode methodsFor: 'testing' stamp: 'eem 5/30/2008 12:31'!
scope
	"Answer scope of temporary variables.
	 Currently only the following distinctions are made:
		 0	outer level: args and user-declared temps
		 1	block args and doLimiT temps
		-1	a block temp that is no longer active
		-2	a block temp that held limit of to:do:"
	^scope! !

!TempVariableNode methodsFor: 'debugger access' stamp: 'eem 6/21/2008 13:32'!
cleanUpForRegeneration
	remoteNode := nil.
	definingScope := writingScopes := readingScopes := nil! !

!TempVariableNode methodsFor: 'code generation (new scheme)' 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 (new scheme)' 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 (new scheme)' 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 (new scheme)' 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 (new scheme)' stamp: 'eem 5/20/2008 16:23'!
sizeCodeForLoad: encoder
	^remoteNode isNil
		ifTrue: [0]
		ifFalse: [remoteNode sizeCodeForLoadFor: self encoder: encoder]! !

!TempVariableNode methodsFor: 'code generation (new scheme)' 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 (new scheme)' 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 (new scheme)' stamp: 'eem 5/20/2008 14:51'!
sizeCodeForValue: encoder
	remoteNode ~~ nil ifTrue:
		[^remoteNode sizeCodeForValueOf: self encoder: encoder].
	self reserve: encoder.
	^encoder sizePushTemp: index! !

!TempVariableNode methodsFor: 'initialize-release' stamp: 'eem 9/8/2008 18:27'!
name: varName index: i type: type scope: level
	"Only used for initting temporary variables"
	hasDefs := hasRefs := false.
	scope := level.
	^super name: varName key: varName index: i type: type! !

!TempVariableNode methodsFor: 'initialize-release'!
nowHasDef
	hasDefs := true! !

!TempVariableNode methodsFor: 'initialize-release'!
nowHasRef
	hasRefs := true! !

!TempVariableNode methodsFor: 'initialize-release'!
scope: level
	"Note scope of temporary variables.
	Currently only the following distinctions are made:
		0	outer level: args and user-declared temps
		1	block args and doLimiT temps
		-1	a block temp that is no longer active
		-2	a block temp that held limit of to:do:"
	scope := level! !

!TempVariableNode 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]].
	writingScopes notNil ifTrue:
		[refs := Set new.
		writingScopes do: [:elems| refs addAll: elems].
		refs asSortedCollection do: [:write| aStream nextPutAll: ' w@'; print: write]].
	aStream nextPut: $}! !

!TempVariableNode methodsFor: 'printing' stamp: 'eem 5/8/2008 11:39'!
printOn: aStream indent: level 

	aStream nextPutAll: name! !

!TempVariableNode methodsFor: 'printing' stamp: 'eem 7/24/2009 12:44'!
printWithClosureAnalysisOn: aStream indent: level 

	aStream nextPutAll: name.
	readingScopes notNil ifTrue:
		[(readingScopes inject: Set new into: [:them :reads| them addAll: reads. them]) asSortedCollection do:
			[:location|
			aStream space; nextPut: $r; nextPut: $@; print: location]].
	writingScopes notNil ifTrue:
		[(writingScopes inject: Set new into: [:them :writes| them addAll: writes. them]) asSortedCollection do:
			[:location|
			aStream space; nextPut: $w; nextPut: $@; print: location]]! !

!TempVariableNode methodsFor: 'decompiler' stamp: 'eem 9/25/2008 09:45'!
remoteNode: aRemoteTempVectorNode
	remoteNode := aRemoteTempVectorNode! !


!RemoteTempVectorNode methodsFor: 'visiting' stamp: 'eem 5/30/2008 09:51'!
accept: aVisitor
	aVisitor visitRemoteTempVectorNode: self! !

!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: 'code generation (closures)' stamp: 'eem 5/24/2008 18:20'!
emitCodeForIndexOf: aTempVariableNode stack: stack encoder: encoder
	self assert: encoder supportsClosureOpcodes not.
	(encoder encodeLiteral: (remoteTemps indexOf: aTempVariableNode))
		emitCodeForValue: stack encoder: encoder! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 18:19'!
emitCodeForLoadFor: aTempVariableNode stack: stack encoder: encoder
	encoder supportsClosureOpcodes ifTrue:
		[^self].
	"Need to generate the first half of
		tempVector at: index put: expr
	 i.e. the push of tempVector and index."
	super emitCodeForValue: stack encoder: encoder.
	self emitCodeForIndexOf: aTempVariableNode stack: stack encoder: encoder! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 23:02'!
emitCodeForStoreInto: aTempVariableNode stack: stack encoder: encoder
	encoder supportsClosureOpcodes
		ifTrue:
			[encoder
				genStoreRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
				inVectorAt: index]
		ifFalse:
			[writeNode
				emitCode: stack
				args: 2
				encoder: encoder
				super: false]! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 23:02'!
emitCodeForStorePopInto: aTempVariableNode stack: stack encoder: encoder
	encoder supportsClosureOpcodes
		ifTrue:
			[encoder
				genStorePopRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
				inVectorAt: index]
		ifFalse:
			[self emitCodeForStoreInto: aTempVariableNode stack: stack encoder: encoder.
			 encoder genPop].
	stack pop: 1! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 23:20'!
emitCodeForValueOf: aTempVariableNode stack: stack encoder: encoder
	encoder supportsClosureOpcodes
		ifTrue:
			[encoder
				genPushRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
				inVectorAt: index.
			 stack push: 1]
		ifFalse:
			[self emitCodeForLoadFor: aTempVariableNode stack: stack encoder: encoder.
			 readNode
				emitCode: stack
				args: 1
				encoder: encoder
				super: false]! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 6/2/2008 16:50'!
isIndirectTempVector
	^true! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 9/25/2008 17:16'!
nodeToInitialize: encoder
	^AssignmentNode new
		variable: self
		value: (encoder supportsClosureOpcodes
					ifTrue: [NewArrayNode new numElements: remoteTemps size]
					ifFalse:
						[MessageNode new
							receiver: (encoder encodeVariable: 'Array')
							selector: #new:
							arguments: (Array with: (encoder encodeLiteral: remoteTemps size))
							precedence: 3
							from: encoder])! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/20/2008 17:57'!
referenceScopesAndIndicesDo: aBinaryBlock
	self shouldNotImplement! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 9/8/2008 10:47'!
scope
	"Answer scope of temporary variables.
	 Currently only the following distinctions are made:
		 0	outer level: args and user-declared temps
		 1	block args and doLimiT temps
		-1	a block temp that is no longer active
		-2	a block temp that held limit of to:do:
		-3	an indirect temp vector"
	^-3! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 18:20'!
sizeCodeForIndexOf: aTempVariableNode encoder: encoder
	self assert: encoder supportsClosureOpcodes not.
	^(encoder encodeLiteral: (remoteTemps indexOf: aTempVariableNode)) sizeCodeForValue: encoder! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 18:19'!
sizeCodeForLoadFor: aTempVariableNode encoder: encoder
	encoder supportsClosureOpcodes ifTrue:
		[^0].
	"Need to size the first half of
		tempVector at: index put: expr
	 i.e. the push of tempVector and index."
	^(super sizeCodeForValue: encoder)
	+ (self sizeCodeForIndexOf: aTempVariableNode encoder: encoder)! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 18:24'!
sizeCodeForStoreInto: aTempVariableNode encoder: encoder
	encoder supportsClosureOpcodes ifTrue:
		[^encoder sizeStoreRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1 inVectorAt: index].
	^writeNode sizeCode: encoder args: 2 super: false! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 18:23'!
sizeCodeForStorePopInto: aTempVariableNode encoder: encoder
	encoder supportsClosureOpcodes ifTrue:
		[^encoder sizeStorePopRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1 inVectorAt: index].
	^(self sizeCodeForStoreInto: aTempVariableNode encoder: encoder)
	+ encoder sizePop! !

!RemoteTempVectorNode methodsFor: 'code generation (closures)' stamp: 'eem 5/24/2008 18:23'!
sizeCodeForValueOf: aTempVariableNode encoder: encoder
	encoder supportsClosureOpcodes ifTrue:
		[^encoder sizePushRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1 inVectorAt: index].
	^(self sizeCodeForValue: encoder)
	+ (self sizeCodeForIndexOf: aTempVariableNode encoder: encoder)
	+ (readNode sizeCode: encoder args: 1 super: false)! !

!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: $}! !

!RemoteTempVectorNode methodsFor: 'accessing' stamp: 'eem 6/2/2008 16:47'!
remoteTemps
	^remoteTemps! !

!RemoteTempVectorNode methodsFor: 'decompiler' stamp: 'eem 9/25/2008 09:46'!
remoteTemps: anArray
	remoteTemps := anArray.
	anArray do: [:tempNode| tempNode remoteNode: self]! !


!VariableNode class methodsFor: 'class initialization'!
initialize    "VariableNode initialize.  Decompiler initialize"
	| encoder |
	encoder := Encoder new.
	StdVariables := Dictionary new: 16.
	encoder
		fillDict: StdVariables
		with: VariableNode
		mapping: #('self' 'thisContext' 'super' 'nil' 'false' 'true' )
		to: (Array with: LdSelf with: LdThisContext with: LdSuper)
				, (Array with: LdNil with: LdFalse with: LdTrue).
	StdSelectors := Dictionary new: 64.
	encoder
		fillDict: StdSelectors
		with: SelectorNode
		mapping: ((1 to: Smalltalk specialSelectorSize) collect: 
							[:i | Smalltalk specialSelectorAt: i])
		to: (SendPlus to: SendPlus + 31).
	StdLiterals := LiteralDictionary new: 16.
	encoder
		fillDict: StdLiterals
		with: LiteralNode
		mapping: #(-1 0 1 2 )
		to: (LdMinus1 to: LdMinus1 + 3).
	encoder initScopeAndLiteralTables.

	NodeNil := encoder encodeVariable: 'nil'.
	NodeTrue := encoder encodeVariable: 'true'.
	NodeFalse := encoder encodeVariable: 'false'.
	NodeSelf := encoder encodeVariable: 'self'.
	NodeThisContext := encoder encodeVariable: 'thisContext'.
	NodeSuper := encoder encodeVariable: 'super'! !

ParseNode initialize!
VariableNode initialize!
Parser initialize!
Scanner initialize!
MessageNode initialize!
ParseNode removeSelector: #addCommentToMorph:!
Decompiler initialize!
Compiler initialize!
ColoredCodeStream initialize!
BlockClosure removeSelector: #valueSupplyingAnswer:!
BlockClosure removeSelector: #valueSupplyingAnswers:!
BlockClosure removeSelector: #valueSuppressingAllMessages!
BlockClosure removeSelector: #valueSuppressingMessages:!
BlockClosure removeSelector: #valueSuppressingMessages:supplyingAnswers:!
