[squeak-dev] Duffing broken for Inbox [was: The Inbox: Compiler-ct.480.mcz]

Eliot Miranda eliot.miranda at gmail.com
Tue Sep 13 14:34:25 UTC 2022


The below shows that code diffing is broken for Inbox.  Instead of showing the difference in the commit the below appears to list the entire Compiler package starting with AssignmentNode.

_,,,^..^,,,_ (phone)

> On Sep 9, 2022, at 5:48 AM, commits at source.squeak.org wrote:
> 
> A new version of Compiler was added to project The Inbox:
> http://source.squeak.org/inbox/Compiler-ct.480.mcz
> 
> ==================== Summary ====================
> 
> Name: Compiler-ct.480
> Author: ct
> Time: 9 September 2022, 2:48:27.444614 pm
> UUID: 03d9ed0c-8807-be4a-89bf-891d9f639f09
> Ancestors: Compiler-eem.479
> 
> Attempts to fix a GC issue while creating an Undeclared variable. Hold a strong reference on the newly created association until it has been stored as a global.
> 
> Note: This change makes the assumption that undeclared is not a SystemDictionary, which overrides #at:put:. However, I cannot explain why AttemptToWriteReadOnlyGlobal is handled in this place, no idea how this code could touch any ClassBindings ...
> 
> Please review.
> 
> =============== Diff against Compiler-eem.479 ===============
> 
> Item was added:
> + (PackageInfo named: 'Compiler') preamble: '"Make sure closures are initialized before starting to use them"
> + Utilities initializeClosures.
> + '!
> 
> Item was added:
> + SystemOrganization addCategory: #'Compiler-Exceptions'!
> + SystemOrganization addCategory: #'Compiler-Kernel'!
> + SystemOrganization addCategory: #'Compiler-ParseNodes'!
> + SystemOrganization addCategory: #'Compiler-Support'!
> + SystemOrganization addCategory: #'Compiler-Syntax'!
> 
> Item was added:
> + ParserNotification subclass: #AmbiguousSelector
> +    instanceVariableNames: 'interval'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> + 
> + !AmbiguousSelector commentStamp: 'nice 2/23/2010 15:40' prior: 0!
> + An AmbiguousSelector is a notification produced by the Scanner/Parser/Compiler when encountering this ambiguous construct:
> + 
> + 1 at -2
> + 
> + Upper expression can be interpreted both
> + 1 @ -2 (regular st-80 and former Squeak syntax, the minus is attached to the literal number)
> + 1 @- 2 (extended binary selector, the minus sign is allowed at any position and thus part of the binary selector)
> + !
> 
> Item was added:
> + ----- Method: AmbiguousSelector class>>signalName:inRange: (in category 'instance creation') -----
> + signalName: aString inRange: anInterval 
> +    ^ (self new setName: aString range: anInterval) signal!
> 
> Item was added:
> + ----- Method: AmbiguousSelector>>openMenuIn: (in category 'handling') -----
> + openMenuIn: aBlock 
> +    "Ask the user which selector to choose.
> +    Answer the choosen selector or nil if cancellation is requested."
> +    
> +    | labels actions lines caption choice |
> +    labels := {
> +        ('selector is {1} and argument is negative' translated format: {name copyFrom: 1 to: name size - 1}).
> +        ('selector is {1} and argument is positive' translated format: {name}).
> +        'cancel' translated}.
> +    actions := {
> +        name copyReplaceFrom: name size to: name size - 1 with: ' '.
> +        name copyReplaceFrom: name size + 1 to: name size with: ' '.
> +        nil.
> +    }.
> +    lines := {2}.
> +    caption := 'Ambiguous selector: {1} please correct, or cancel:' translated format: {name}.
> +    choice := aBlock value: labels value: lines value: caption.
> +    self resume: (actions at: choice ifAbsent: [nil])!
> 
> Item was added:
> + ----- Method: AmbiguousSelector>>setName:range: (in category 'initialization') -----
> + setName: aString range: anInterval 
> +    name := aString.
> +    interval := anInterval!
> 
> Item was added:
> + ParseNode subclass: #AssignmentNode
> +    instanceVariableNames: 'variable value'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !AssignmentNode commentStamp: '<historical>' prior: 0!
> + AssignmentNode comment: 'I represent a (var_expr) construct.'!
> 
> Item was added:
> + ----- Method: AssignmentNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitAssignmentNode: self!
> 
> Item was added:
> + ----- Method: AssignmentNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + 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!
> 
> Item was added:
> + ----- Method: AssignmentNode>>emitCodeForEffect:encoder: (in category 'code generation') -----
> + emitCodeForEffect: stack encoder: encoder
> + 
> +    variable emitCodeForLoad: stack forValue: false encoder: encoder.
> +    value emitCodeForValue: stack encoder: encoder.
> +    pc := encoder nextPC. "debug pc is first byte of the store, i.e. the next byte".
> +    variable emitCodeForStorePop: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: AssignmentNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> + 
> +    variable emitCodeForLoad: stack forValue: true encoder: encoder.
> +    value emitCodeForValue: stack encoder: encoder.
> +    pc := encoder nextPC. "debug pc is first byte of the store, i.e. the next byte".
> +    variable emitCodeForStore: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: AssignmentNode>>ifNilTemporary (in category 'private') -----
> + ifNilTemporary
> +    "(temp := object) == nil ifTrue: [...] ifFalse: [...]"
> +    
> +    ^ self variable!
> 
> Item was added:
> + ----- Method: AssignmentNode>>ifNilValue (in category 'private') -----
> + ifNilValue
> +    "(temp := object) == nil ifTrue: [...] ifFalse: [...]"
> +    
> +    ^ self value!
> 
> Item was added:
> + ----- Method: AssignmentNode>>isAssignmentNode (in category 'testing') -----
> + isAssignmentNode
> +    ^true!
> 
> Item was added:
> + ----- Method: AssignmentNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level 
> +    variable printOn: aStream indent: level.
> +    aStream nextPutAll: ' := '.
> +    value printOn: aStream indent: level + 2!
> 
> Item was added:
> + ----- Method: AssignmentNode>>printOn:indent:precedence: (in category 'printing') -----
> + printOn: aStream indent: level precedence: p
> + 
> +    aStream nextPut: $(.
> +    self printOn: aStream indent: level.
> +    aStream nextPut: $)!
> 
> Item was added:
> + ----- Method: AssignmentNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level 
> +    variable printWithClosureAnalysisOn: aStream indent: level.
> +    aStream nextPutAll: ' := '.
> +    value printWithClosureAnalysisOn: aStream indent: level + 2!
> 
> Item was added:
> + ----- Method: AssignmentNode>>printWithClosureAnalysisOn:indent:precedence: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level precedence: p
> + 
> +    aStream nextPut: $(.
> +    self printWithClosureAnalysisOn: aStream indent: level.
> +    aStream nextPut: $)!
> 
> Item was added:
> + ----- Method: AssignmentNode>>sizeCodeForEffect: (in category 'code generation') -----
> + sizeCodeForEffect: encoder
> + 
> +    ^(variable sizeCodeForLoad: encoder forValue: false)
> +    + (value sizeCodeForValue: encoder)
> +    + (variable sizeCodeForStorePop: encoder)!
> 
> Item was added:
> + ----- Method: AssignmentNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> + 
> +    ^(variable sizeCodeForLoad: encoder forValue: true)
> +    + (value sizeCodeForValue: encoder)
> +    + (variable sizeCodeForStore: encoder)!
> 
> Item was added:
> + ----- Method: AssignmentNode>>toDoIncrement: (in category 'initialize-release') -----
> + toDoIncrement: var
> +    ^(var = variable
> +       and: [value isMessageNode]) ifTrue:
> +        [value toDoIncrement: var]!
> 
> Item was added:
> + ----- Method: AssignmentNode>>value (in category 'initialize-release') -----
> + value
> +    ^ value!
> 
> Item was added:
> + ----- Method: AssignmentNode>>variable (in category 'equation translation') -----
> + variable
> +    ^variable!
> 
> Item was added:
> + ----- Method: AssignmentNode>>variable:value: (in category 'initialize-release') -----
> + variable: aVariable value: expression
> + 
> +    variable := aVariable.
> +    value := expression!
> 
> Item was added:
> + ----- Method: AssignmentNode>>variable:value:from: (in category 'initialize-release') -----
> + variable: aVariable value: expression from: encoder
> + 
> +    (aVariable isMemberOf: MessageAsTempNode)
> +        ifTrue: ["Case of remote temp vars"
> +                ^ aVariable store: expression from: encoder].
> +    variable := aVariable.
> +    value := expression!
> 
> Item was added:
> + ----- Method: AssignmentNode>>variable:value:from:sourceRange: (in category 'initialize-release') -----
> + variable: aVariable value: expression from: encoder sourceRange: range
> + 
> +    encoder noteSourceRange: range forNode: self.
> +    ^self
> +        variable: aVariable
> +        value: expression
> +        from: encoder!
> 
> Item was added:
> + ParseNode subclass: #BlockArgsNode
> +    instanceVariableNames: 'temporaries'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Syntax'!
> 
> Item was added:
> + ParseNode subclass: #BlockNode
> +    instanceVariableNames: 'arguments statements returns nArgsNode size temporaries optimized optimizedMessageNode actualScopeIfOptimized blockExtent remoteTempNode copiedValues closureCreationNode startOfLastStatement tempsMark'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !BlockNode commentStamp: 'ct 1/17/2020 13:05' 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. I can emit for value in the usual way, in which case I create a BlockClosure 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 certain optimized control structures (see MessageNode class>>initialize MacroSelectors).
> + 
> + Instance Variables
> +     actualScopeIfOptimized:    <nil | BlockNode>
> +     arguments:                    <SequencableCollection of: TempVariableNode>
> +     blockExtent:                <nil | Interval>
> +     closureCreationNode:        <LeafNode>
> +     copiedValues:                <nil | (SequencableCollection of: TempVariableNode)>
> +     nArgsNode:                    <nil | Integer>
> +     optimized:                    <Boolean>
> +     optimizedMessageNode:    <nil | MessageNode>
> +     remoteTempNode:            <nil | RemoteTempVectorNode>
> +     returns:                    <Boolean>
> +     size:                        <nil | Integer>
> +     startOfLastStatement:        <nil | Integer>
> +     statements:                <SequencableCollection of: ParseNode>
> +     temporaries:                <SequencableCollection of: TempVariableNode>
> +     tempsMark:                    <nil | Integer>
> + 
> + actualScopeIfOptimized
> +     - if the receiver has been inlined this is the non-optimized BlockNode the receiver is inlined into.
> + 
> + arguments
> +     - the sequence of arguments to the block (or method if a top-level block)
> + 
> + blockExtent
> +     - the interval defining the range of block scopes the receiver comprises, which is itself and any blocks it may contain.  See #analyseArguments:temporaries:rootNode:
> + 
> + closureCreationNode
> +     - a place-holder representing the body of the block.
> + 
> + copiedValues
> +     - blocks do not reference the temporary variables of their outer context they close over directly; instead, temporary variables which won't change value are collected and copied into the block, and temporary variables that are modified either within the block or after it has closed over the variables are allocated in a remote temp vector that again becomes one of the block's copied values.  In this way, a block refers to the outer temporaries it closes over only through copiedValues.  copiedValues is the sequence of these TempVariableNodes.
> + 
> + nArgsNode
> +     - a place holder for the encoder to allow it to number block temporaries
> + 
> + optimized
> +     - true if the receiver is inlined, false if a true block
> + 
> + optimizedMessageNode
> +     - the MessageNode in which the receiver is optimized, if it is optimized.
> + 
> + remoteTempNode
> +     - if any of the blocks nested into the receiver either modify a temp or access a temp that is modified after the block is created, then this temp is allocated remotely in a remote temp vector that allows the temp's location to be shared between blocks.  This is the node that creates the remote temp vector.
> + 
> + returns
> +     - true if the receiver contains a method return.
> + 
> + size
> +     - the size of the block's bytecodes if it is generated by embedding its bytecodes within an enclosing CompiledMethod.
> + 
> + startOfLastStatement
> +     - the index in the source of the start of the last statement in the block.
> + 
> + statements
> +     - the sequence of statements comprising the receiver
> + 
> + temporaries
> +     - the sequence of temporaries (including the remoteTempNode if any) of block-local temporaries
> + 
> + tempsMark
> +     - the index in the source of the last block-local temporary, used to auto-insert temps declared during compilation!
> 
> Item was added:
> + ----- Method: BlockNode class>>statements:returns: (in category 'instance creation') -----
> + statements: statements returns: returns
> +    ^ self new statements: statements returns: returns!
> 
> Item was added:
> + ----- Method: BlockNode class>>withJust: (in category 'instance creation') -----
> + withJust: aNode
> +    ^ self new statements: (Array with: aNode) returns: false!
> 
> Item was added:
> + ----- Method: BlockNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitBlockNode: self!
> 
> Item was added:
> + ----- Method: BlockNode>>actualScope (in category 'closure analysis') -----
> + 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]!
> 
> Item was added:
> + ----- Method: BlockNode>>addArgument: (in category 'accessing') -----
> + addArgument: aTempVariableNode
> +    temporaries := temporaries copyWith: aTempVariableNode!
> 
> Item was added:
> + ----- Method: BlockNode>>addHoistedTemps: (in category 'closure analysis') -----
> + addHoistedTemps: additionalTemporaries "<SequenceableCollection>"
> +    | tempsToBeMerged additionalTempsToAdd |
> +    additionalTemporaries do:
> +        [:temp|
> +        temp definingScope ifNil:
> +            [temp definingScope: self]].
> +    (temporaries isNil or: [temporaries isEmpty]) ifTrue:
> +        [temporaries := additionalTemporaries copy.
> +         ^self].
> +    tempsToBeMerged := additionalTemporaries select:
> +                        [:t|
> +                        t isBlockArg
> +                        and: [temporaries anySatisfy: [:existing| existing isBlockArg and: [existing key = t key]]]].
> +    additionalTempsToAdd := tempsToBeMerged isEmpty
> +                                    ifTrue: [additionalTemporaries copy]
> +                                    ifFalse: [additionalTemporaries reject: [:temp| tempsToBeMerged identityIncludes: temp]].
> +    temporaries := (temporaries isNil or: [temporaries isEmpty])
> +                    ifTrue: [additionalTempsToAdd]
> +                    ifFalse:
> +                        [temporaries last isIndirectTempVector
> +                            ifTrue: [temporaries allButLast, additionalTempsToAdd, { temporaries last }]
> +                            ifFalse: [temporaries, additionalTempsToAdd]].
> +    tempsToBeMerged do:
> +        [:t| | merge |
> +        merge := temporaries detect: [:existing| existing isBlockArg and: [existing key = t key]].
> +        merge absorbHoistedTemp: t]!
> 
> Item was added:
> + ----- Method: BlockNode>>addRemoteTemp:rootNode: (in category 'closure analysis') -----
> + addRemoteTemp: aTempVariableNode rootNode: rootNode "<MethodNode>"
> +    "Add aTempVariableNode to my actualScope's sequence of
> +     remote temps.  If I am an optimized block then the actual
> +     scope is my actualScopeIfOptimized, otherwise it is myself."
> +    remoteTempNode == nil ifTrue:
> +        [remoteTempNode := RemoteTempVectorNode new
> +                                name: self remoteTempNodeName
> +                                index: arguments size + temporaries size
> +                                type: LdTempType
> +                                scope: 0.
> +         actualScopeIfOptimized
> +            ifNil:
> +                [self addTempNode: remoteTempNode.
> +                 remoteTempNode definingScope: self]
> +            ifNotNil: [actualScopeIfOptimized addHoistedTemps: { remoteTempNode }]].
> +    remoteTempNode addRemoteTemp: aTempVariableNode encoder: rootNode encoder.
> +    "use remove:ifAbsent: because the deferred analysis for optimized
> +     loops can result in the temp has already been hoised into the root."
> +    self removeTempNode: aTempVariableNode ifAbsent: [
> +        self actualScope removeTempNode: aTempVariableNode ifAbsent: ["should not happen"]].
> +    ^remoteTempNode!
> 
> Item was added:
> + ----- Method: BlockNode>>addTempNode: (in category 'closure analysis') -----
> + addTempNode: aTempVariableNode
> +    "Utilities for when we want to add some temporaries."
> +    
> +    self makeTemporariesRemovable.
> +    ^temporaries add: aTempVariableNode!
> 
> Item was added:
> + ----- Method: BlockNode>>analyseArguments:temporaries:rootNode: (in category 'closure analysis') -----
> + 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 at 1 := 1. b w at 1 := 2. t w at 1 := 0.
> +        blk w at 5 := [entry at 2 | s |
> +                     t  w at 3 := t r at 3 + a r at 3 + b r at 3
> +                    ] exit at 4.
> +        r1 w at 5 := blk r at 5 value.
> +        b w at 5 := nil.
> +        r2 w at 5 := blk r at 5 value.
> +        r1 r at 5 -> r2 r at 5 -> t r at 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!
> 
> Item was added:
> + ----- Method: BlockNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + 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
> +        ifTrue: "if optimized loop need to add nils for any temps read before written"
> +            [optimizedMessageNode isOptimizedLoop ifTrue:
> +                [self nilReadBeforeWrittenTemps]]
> +        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]]!
> 
> Item was added:
> + ----- Method: BlockNode>>arguments (in category 'accessing') -----
> + arguments
> +    ^arguments ifNil: [#()]!
> 
> Item was added:
> + ----- Method: BlockNode>>arguments: (in category 'accessing') -----
> + arguments: argNodes 
> +    "Decompile."
> + 
> +    arguments := argNodes!
> 
> Item was added:
> + ----- Method: BlockNode>>arguments:statements:returns:from: (in category 'initialize-release') -----
> + arguments: argNodes statements: statementsCollection returns: returnBool from: encoder
> +    "Compile."
> + 
> +    arguments := argNodes.
> +    statements := statementsCollection size > 0
> +                    ifTrue: [statementsCollection]
> +                    ifFalse: [Array with: NodeNil].
> +    optimized := false.
> +    returns := returnBool!
> 
> Item was added:
> + ----- Method: BlockNode>>block (in category 'accessing') -----
> + block
> +    ^ self!
> 
> Item was added:
> + ----- Method: BlockNode>>blockExtent (in category 'closure analysis') -----
> + blockExtent "^<nil | Interval>"
> +    ^blockExtent!
> 
> Item was added:
> + ----- Method: BlockNode>>code (in category 'code generation') -----
> + code
> + 
> +    ^statements first code!
> 
> Item was added:
> + ----- Method: BlockNode>>computeCopiedValues: (in category 'closure analysis') -----
> + computeCopiedValues: rootNode
> +    | referencedValues |
> +    referencedValues := rootNode referencedValuesWithinBlockExtent: blockExtent.
> +    ^(referencedValues reject: [:temp| temp isDefinedWithinBlockExtent: blockExtent])
> +        asArray sort: ParseNode tempSortBlock!
> 
> Item was added:
> + ----- Method: BlockNode>>constructClosureCreationNode: (in category 'code generation') -----
> + constructClosureCreationNode: encoder
> +    copiedValues := self computeCopiedValues: encoder rootNode.
> +    ^self ensureClosureCreationNode: encoder!
> 
> Item was added:
> + ----- Method: BlockNode>>createBlockLiteral: (in category 'code generation') -----
> + createBlockLiteral: encoder
> +    ^self
> +        reindexingLocalsDo: [encoder blockLiteralFor: self]
> +        encoder: encoder!
> 
> Item was added:
> + ----- Method: BlockNode>>decompileString (in category 'printing') -----
> + decompileString 
> +    "Answer a string description of the parse tree whose root is the receiver."
> + 
> +    ^ self decompileText asString
> + !
> 
> Item was added:
> + ----- Method: BlockNode>>decompileText (in category 'printing') -----
> + decompileText
> +    "Answer a text description of the parse tree whose root is the receiver."
> + 
> +    ^ ColoredCodeStream contents: [:strm | self printOn: strm indent: 0]
> + !
> 
> Item was added:
> + ----- Method: BlockNode>>deoptimize (in category 'closure analysis') -----
> + deoptimize
> +    optimized := false.
> +    optimizedMessageNode := nil!
> 
> Item was added:
> + ----- Method: BlockNode>>emitCodeExceptLast:encoder: (in category 'code generation') -----
> + 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].!
> 
> Item was added:
> + ----- Method: BlockNode>>emitCodeForEvaluatedClosureValue:encoder: (in category 'code generation') -----
> + emitCodeForEvaluatedClosureValue: stack encoder: encoder
> +    | position |
> +    position := stack position.
> +    stack position: arguments size + temporaries size + copiedValues size.
> +    encoder genPushNClosureTemps: temporaries size.
> +    self
> +        reindexingLocalsDo: [self emitCodeForEvaluatedValue: stack encoder: encoder]
> +        encoder: encoder.
> +    self returns ifFalse:
> +        [encoder genReturnTopToCaller.
> +         pc := encoder pc].
> +    stack position: position!
> 
> Item was added:
> + ----- Method: BlockNode>>emitCodeForEvaluatedEffect:encoder: (in category 'code generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: BlockNode>>emitCodeForEvaluatedFullClosureValue:encoder: (in category 'code generation') -----
> + emitCodeForEvaluatedFullClosureValue: stack encoder: encoder
> +    | position |
> +    position := stack position.
> +    self emitCodeExceptLast: stack encoder: encoder.
> +    (statements last == NodeNil
> +     and: [self returns not])
> +        ifTrue:
> +            [stack push: 1.
> +             encoder genReturnNilToCaller.
> +             pc := encoder pc]
> +        ifFalse:
> +            [statements last emitCodeForBlockValue: stack encoder: encoder.
> +             self returns ifFalse:
> +                [encoder genReturnTopToCaller.
> +                 pc := encoder pc]].
> +    self assert: stack position - 1 = position!
> 
> Item was added:
> + ----- Method: BlockNode>>emitCodeForEvaluatedValue:encoder: (in category 'code generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: BlockNode>>emitCodeForFullBlockValue:encoder: (in category 'code generation') -----
> + emitCodeForFullBlockValue: stack encoder: encoder
> +    copiedValues do:
> +        [:copiedValue| copiedValue emitCodeForValue: stack encoder: encoder].
> +    closureCreationNode pc: encoder nextPC.
> +    encoder
> +        genPushFullClosure: closureCreationNode index
> +        numCopied: copiedValues size.
> +    stack
> +        pop: copiedValues size;
> +        push: 1!
> 
> Item was added:
> + ----- Method: BlockNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    encoder supportsFullBlocks ifTrue:
> +        [^self emitCodeForFullBlockValue: stack encoder: encoder].
> +    copiedValues do:
> +        [:copiedValue| copiedValue emitCodeForValue: stack encoder: encoder].
> +    closureCreationNode pc: encoder nextPC.
> +    encoder
> +        genPushClosureCopyNumCopiedValues: copiedValues size
> +        numArgs: arguments size
> +        jumpSize: size.
> +    stack
> +        pop: copiedValues size;
> +        push: 1.
> +    "Emit the body of the block"
> +    self emitCodeForEvaluatedClosureValue: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: BlockNode>>ensureClosureCreationNode: (in category 'accessing') -----
> + ensureClosureCreationNode: encoder
> +    closureCreationNode ifNil:
> +        [closureCreationNode := LiteralNode new
> +                                    key: #closureCreationNode
> +                                    code: (encoder supportsFullBlocks ifTrue: [LdLitType negated])].
> +    ^closureCreationNode!
> 
> Item was added:
> + ----- Method: BlockNode>>ensureNotQuick: (in category 'converting') -----
> + ensureNotQuick: encoder
> +    "If the receiver is quick (can be generated as a Quick method, ^self,^inst var or ^ special constant)
> +     make it not so.  This is used to create break-pointable versions of quick methods.   Answer if the
> +     receiver was quick."
> +    self isQuick ifFalse:
> +        [^false].
> +    "Making statements size > 1 is sufficient to cause isQuick to answer false (see BlockNode>>isQuick).
> +     N.B. This is a no-op since statements generate via emitCodeForEffect: and VariableNodes have no effect."
> +    statements addFirst: (encoder encodeVariable: 'self').
> +    ^true!
> 
> Item was added:
> + ----- Method: BlockNode>>firstArgument (in category 'accessing') -----
> + firstArgument
> +    ^ arguments first!
> 
> Item was added:
> + ----- Method: BlockNode>>ifHasRemoteTempNodeEnsureInitializationStatementExists: (in category 'closure analysis') -----
> + 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)]].!
> 
> Item was added:
> + ----- Method: BlockNode>>isBlockNode (in category 'testing') -----
> + isBlockNode
> +    ^true!
> 
> Item was added:
> + ----- Method: BlockNode>>isComplex (in category 'testing') -----
> + isComplex
> + 
> +    ^statements size > 1 or: [statements size = 1 and: [statements first isComplex]]!
> 
> Item was added:
> + ----- Method: BlockNode>>isJust: (in category 'testing') -----
> + isJust: node
> + 
> +    returns ifTrue: [^false].
> +    ^statements size = 1 and: [statements first == node]!
> 
> Item was added:
> + ----- Method: BlockNode>>isJustCaseError (in category 'testing') -----
> + isJustCaseError
> + 
> +    ^ statements size = 1 and:
> +        [statements first
> +            isMessage: #caseError
> +            receiver: [:r | r==NodeSelf]
> +            arguments: nil]!
> 
> Item was added:
> + ----- Method: BlockNode>>isQuick (in category 'testing') -----
> + isQuick
> +    ^ statements size = 1
> +        and: [statements first isVariableReference
> +                or: [statements first isSpecialConstant]]!
> 
> Item was added:
> + ----- Method: BlockNode>>localsNodes (in category 'accessing') -----
> + localsNodes
> +    "Answer the correctly ordered sequence of local nodes (arguments and temporaries) in the receiver."
> +    ^arguments asArray, copiedValues, temporaries!
> 
> Item was added:
> + ----- Method: BlockNode>>makeTemporariesRemovable (in category 'closure analysis') -----
> + makeTemporariesRemovable
> +    "Utilities for when we want to remove some temporaries."
> +    
> +    temporaries isArray ifTrue:
> +        [temporaries := temporaries asOrderedCollection].!
> 
> Item was added:
> + ----- Method: BlockNode>>nArgsSlot (in category 'accessing') -----
> + nArgsSlot
> +    "Private for the Encoder to use in bindArg"
> +    ^nArgsNode!
> 
> Item was added:
> + ----- Method: BlockNode>>nArgsSlot: (in category 'accessing') -----
> + nArgsSlot: anInteger
> +    "Private for the Encoder to use in bindArg"
> +    nArgsNode := anInteger!
> 
> Item was added:
> + ----- Method: BlockNode>>nilReadBeforeWrittenTemps (in category 'closure analysis') -----
> + nilReadBeforeWrittenTemps
> +    | visitor readBeforeWritten |
> +    temporaries isEmpty ifTrue:
> +        [^self].
> +    self accept: (visitor := OptimizedBlockLocalTempReadBeforeWrittenVisitor new).
> +    readBeforeWritten := visitor readBeforeWritten.
> +    temporaries reverseDo:
> +        [:temp|
> +        ((readBeforeWritten includes: temp)
> +         and: [temp isRemote not]) ifTrue:
> +            [statements addFirst: (AssignmentNode new variable: temp value: NodeNil)]]!
> 
> Item was added:
> + ----- Method: BlockNode>>noteOptimizedIn: (in category 'closure analysis') -----
> + noteOptimizedIn: anOptimizedMessageNode
> +    optimized := true.
> +    optimizedMessageNode := anOptimizedMessageNode!
> 
> Item was added:
> + ----- Method: BlockNode>>noteSourceRangeStart:end:encoder: (in category 'initialize-release') -----
> + 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 ensureClosureCreationNode: encoder).
> +    startOfLastStatement
> +        ifNil:
> +            [encoder
> +                noteSourceRange: (start to: end)
> +                forNode: self]
> +        ifNotNil:
> +            [encoder
> +                noteSourceRange: (startOfLastStatement to: end - 1)
> +                forNode: self]!
> 
> Item was added:
> + ----- Method: BlockNode>>numberOfArguments (in category 'accessing') -----
> + numberOfArguments
> + 
> +    ^arguments size!
> 
> Item was added:
> + ----- Method: BlockNode>>optimized (in category 'accessing') -----
> + optimized
> +    ^optimized!
> 
> Item was added:
> + ----- Method: BlockNode>>optimizedBlockHoistTempsInto: (in category 'closure analysis') -----
> + 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 := #()]!
> 
> Item was added:
> + ----- Method: BlockNode>>postNumberingProcessTempsWithin:rootNode: (in category 'closure analysis') -----
> + 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!
> 
> Item was added:
> + ----- Method: BlockNode>>printArgumentsOn:indent: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: BlockNode>>printOn:indent: (in category 'printing') -----
> + 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: $]!
> 
> Item was added:
> + ----- Method: BlockNode>>printStatementsOn:indent: (in category 'printing') -----
> + printStatementsOn: aStream indent: levelOrZero
> +    | len shown thisStatement level |
> +    level := 1 max: levelOrZero.
> +    comment ifNotNil: 
> +        [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, not if the last statement answers nil."
> +                ((arguments size > 0 and: [len = 0])
> +                 or: [(statements at: len) == NodeNil
> +                    and: [len = 1
> +                        or: [len > 1
> +                            and: [(statements at: len - 1) isMessageNode
> +                            and: [(statements at: len - 1) isNilIf
> +                                or: [(statements at: len - 1) isOptimizedWhileLoop]]]]]])
> +                    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]]]!
> 
> Item was added:
> + ----- Method: BlockNode>>printTemporaries:on:doPrior: (in category 'printing') -----
> + 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: [
> +                        "This is for the deocmpiler which may create a block arg when converting
> +                        a ifTrue:ifFalse: into a ifNil:ifNotNil: but won't remove it from temporaries"
> +                        tempVariableNode isBlockArg not
> +                      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 from 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!
> 
> Item was added:
> + ----- Method: BlockNode>>printWithClosureAnalysisArgumentsOn:indent: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: BlockNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + 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: $]!
> 
> Item was added:
> + ----- Method: BlockNode>>printWithClosureAnalysisStatementsOn:indent: (in category 'printing') -----
> + 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]]]!
> 
> Item was added:
> + ----- Method: BlockNode>>printWithClosureAnalysisTemporariesOn:indent: (in category 'printing') -----
> + 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]]!
> 
> Item was added:
> + ----- Method: BlockNode>>reindexingLocalsDo:encoder: (in category 'closure analysis') -----
> + 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!
> 
> Item was added:
> + ----- Method: BlockNode>>remoteTempNodeName (in category 'closure analysis') -----
> + 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]), '>']!
> 
> Item was added:
> + ----- Method: BlockNode>>removeTempNode:ifAbsent: (in category 'closure analysis') -----
> + removeTempNode: aTempVariableNode ifAbsent: aBlock
> +    "Utilities for when we want to remove some temporaries."
> +    
> +    self makeTemporariesRemovable.
> +    ^temporaries remove: aTempVariableNode ifAbsent: aBlock
> +    !
> 
> Item was added:
> + ----- Method: BlockNode>>returnLast (in category 'accessing') -----
> + returnLast
> + 
> +    self returns
> +        ifFalse: 
> +            [returns := true.
> +            statements at: statements size put: statements last asReturnNode]!
> 
> Item was added:
> + ----- Method: BlockNode>>returnNilIfNoOther (in category 'accessing') -----
> + returnNilIfNoOther
> + 
> +    self returns
> +        ifFalse: 
> +            [statements last == NodeNil ifFalse: [statements add: NodeNil].
> +            self returnLast]!
> 
> Item was added:
> + ----- Method: BlockNode>>returnSelfIfNoOther: (in category 'accessing') -----
> + returnSelfIfNoOther: encoder
> + 
> +    self returns ifTrue:[^self].
> +    statements last == NodeSelf ifFalse: [
> +        statements := statements copyWith: (encoder encodeVariable: 'self').
> +    ].
> +    self returnLast.
> + !
> 
> Item was added:
> + ----- Method: BlockNode>>returns (in category 'testing') -----
> + returns
> + 
> +    ^returns or: [statements last isReturningIf]!
> 
> Item was added:
> + ----- Method: BlockNode>>sizeCodeExceptLast: (in category 'code generation') -----
> + sizeCodeExceptLast: encoder
> +    | codeSize |
> +    codeSize := 0.
> +    1 to: statements size - 1 do: 
> +        [:i | | statement |
> +         statement := statements at: i.
> +         codeSize := codeSize + (statement sizeCodeForEffect: encoder)].
> +    ^codeSize!
> 
> Item was added:
> + ----- Method: BlockNode>>sizeCodeForEvaluatedClosureValue: (in category 'code generation') -----
> + 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."
> +    ^(encoder sizePushNClosureTemps: temporaries size)
> +    + (self
> +        reindexingLocalsDo: [self sizeCodeForEvaluatedValue: encoder]
> +        encoder: nil "don't store temps yet")
> +    + (self returns ifTrue: [0] ifFalse: [encoder sizeReturnTopToCaller])!
> 
> Item was added:
> + ----- Method: BlockNode>>sizeCodeForEvaluatedEffect: (in category 'code generation') -----
> + sizeCodeForEvaluatedEffect: encoder
> + 
> +    ^self returns
> +        ifTrue: [self sizeCodeForEvaluatedValue: encoder]
> +        ifFalse: [(self sizeCodeExceptLast: encoder)
> +                + (statements last sizeCodeForEffect: encoder)]!
> 
> Item was added:
> + ----- Method: BlockNode>>sizeCodeForEvaluatedFullClosureValue: (in category 'code generation') -----
> + sizeCodeForEvaluatedFullClosureValue: 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 full closure activation we need do nothing."
> +    (statements last == NodeNil
> +     and: [self returns not]) ifTrue:
> +        [^(self sizeCodeExceptLast: encoder)
> +         + encoder sizeReturnNilToCaller].
> +    ^(self sizeCodeForEvaluatedValue: encoder)
> +    + (self returns ifTrue: [0] ifFalse: [encoder sizeReturnTopToCaller])!
> 
> Item was added:
> + ----- Method: BlockNode>>sizeCodeForEvaluatedValue: (in category 'code generation') -----
> + sizeCodeForEvaluatedValue: encoder
> + 
> +    ^(self sizeCodeExceptLast: encoder)
> +        + (statements last sizeCodeForBlockValue: encoder)!
> 
> Item was added:
> + ----- Method: BlockNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    "Compute the size for the creation of the block and its code."
> +    copiedValues := self computeCopiedValues: encoder rootNode.
> +    self ensureClosureCreationNode: encoder.
> +    encoder supportsFullBlocks ifTrue:
> +        [^(copiedValues inject: 0 into: [:sum :node| sum + (node sizeCodeForValue: encoder)])
> +         + (encoder
> +                sizePushFullClosure:
> +                    (closureCreationNode
> +                        key: (self createBlockLiteral: encoder);
> +                        reserve: encoder;
> +                        index)
> +                numCopied: copiedValues size)].
> +    "Remember size of body for emit time so we know the size of the jump around it."
> +    size := self sizeCodeForEvaluatedClosureValue: encoder.
> +    ^(copiedValues inject: 0 into: [:sum :node| sum + (node sizeCodeForValue: encoder)])
> +      + (encoder sizePushClosureCopyNumCopiedValues: copiedValues size numArgs: arguments size jumpSize: size)
> +      + size!
> 
> Item was added:
> + ----- Method: BlockNode>>startOfLastStatement (in category 'accessing') -----
> + startOfLastStatement
> +    ^startOfLastStatement!
> 
> Item was added:
> + ----- Method: BlockNode>>startOfLastStatement: (in category 'accessing') -----
> + 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!
> 
> Item was added:
> + ----- Method: BlockNode>>statements (in category 'accessing') -----
> + statements
> +    ^statements!
> 
> Item was added:
> + ----- Method: BlockNode>>statements: (in category 'accessing') -----
> + statements: val
> +    statements := val!
> 
> Item was added:
> + ----- Method: BlockNode>>statements:returns: (in category 'initialize-release') -----
> + 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]!
> 
> Item was added:
> + ----- Method: BlockNode>>temporaries (in category 'accessing') -----
> + temporaries
> +    ^temporaries ifNil: [#()]!
> 
> Item was added:
> + ----- Method: BlockNode>>temporaries: (in category 'accessing') -----
> + temporaries: aCollection
> +    temporaries := aCollection!
> 
> Item was added:
> + ----- Method: BlockNode>>tempsMark (in category 'accessing') -----
> + tempsMark
> +    ^tempsMark!
> 
> Item was added:
> + ----- Method: BlockNode>>tempsMark: (in category 'accessing') -----
> + tempsMark: anInteger
> +    tempsMark := anInteger!
> 
> Item was added:
> + InstructionClient subclass: #BlockStartLocator
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !BlockStartLocator commentStamp: 'eem 1/11/2018 08:32' prior: 0!
> + A BlockStartLocator is a scanner that locates the block creation bytecodes in a method.  For block creation bytecodes it answers information salient to the kind of block being created, and for all other bytecodes simply answers itself.
> + 
> + Instance Variables
> + !
> 
> Item was added:
> + ----- Method: BlockStartLocator>>pushClosureCopyNumCopiedValues:numArgs:blockSize: (in category 'instruction decoding') -----
> + pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
> +    "Answer the size of the block"
> +    ^blockSize!
> 
> Item was added:
> + ----- Method: BlockStartLocator>>pushFullClosure:numCopied: (in category 'instruction decoding') -----
> + pushFullClosure: aCompiledBlock numCopied: numCopied
> +    "Answer the block method"
> +    ^aCompiledBlock!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: BraceNode class>>example (in category 'examples') -----
> + 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 )"
> + !
> 
> Item was added:
> + ----- Method: BraceNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitBraceNode: self!
> 
> Item was added:
> + ----- Method: BraceNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> +    elements do:
> +        [:node|
> +        node analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools]!
> 
> Item was added:
> + ----- Method: BraceNode>>blockAssociationCheck: (in category 'testing') -----
> + 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!
> 
> Item was added:
> + ----- Method: BraceNode>>casesForwardDo: (in category '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]!
> 
> Item was added:
> + ----- Method: BraceNode>>casesReverseDo: (in category '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]!
> 
> Item was added:
> + ----- Method: BraceNode>>deoptimize (in category 'closure analysis') -----
> + deoptimize
> +    "Deoptimize the blocks in a caseOf:[otherwise:] that is being used in a cascade."
> +    elements do:
> +        [:aMessage|
> +        self assert: aMessage selector key == #->.
> +        aMessage receiver deoptimize.
> +        aMessage arguments first deoptimize]!
> 
> Item was added:
> + ----- Method: BraceNode>>elements (in category 'code generation') -----
> + elements
> +    ^elements!
> 
> Item was added:
> + ----- Method: BraceNode>>elements: (in category 'initialize-release') -----
> + elements: collection
> +    "Decompile."
> + 
> +    elements := collection!
> 
> Item was added:
> + ----- Method: BraceNode>>elements:sourceLocations: (in category 'initialize-release') -----
> + elements: collection sourceLocations: locations
> +    "Compile."
> + 
> +    elements := collection.
> +    sourceLocations := locations!
> 
> Item was added:
> + ----- Method: BraceNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    "Hack; when sizing we have no way of knowing how much stack space is available."
> +    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!
> 
> Item was added:
> + ----- Method: BraceNode>>isBraceNode (in category 'testing') -----
> + isBraceNode
> +    ^true!
> 
> Item was added:
> + ----- Method: BraceNode>>matchBraceStreamReceiver:messages: (in category 'initialize-release') -----
> + 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])!
> 
> Item was added:
> + ----- Method: BraceNode>>maxElementsForConsArray (in category 'code generation') -----
> + maxElementsForConsArray
> +    "Hack; we have no way of knowing how much stack space is available during sizing"
> +    ^8!
> 
> Item was added:
> + ----- Method: BraceNode>>numElements (in category 'testing') -----
> + numElements
> + 
> +    ^ elements size!
> 
> Item was added:
> + ----- Method: BraceNode>>printOn:indent: (in category 'printing') -----
> + 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: $}!
> 
> Item was added:
> + ----- Method: BraceNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + 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: $}!
> 
> Item was added:
> + ----- Method: BraceNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> + 
> +    "Hack; we have no way of knowing how much stack space is available."
> +    elements size <= self maxElementsForConsArray ifTrue:
> +        [^(elements inject: 0 into: [:sum :node| sum + (node sizeCodeForValue: encoder)])
> +          + (encoder sizePushConsArray: elements size)].
> +    "Long form: (Array braceStream: N) nextPut: a; nextPut: b; ...; braceArray"
> +    emitNode := CascadeNode new
> +                    receiver: (MessageNode new
> +                                receiver: (encoder encodeVariable: #Array)
> +                                selector: #braceStream:
> +                                arguments: {encoder encodeLiteral: elements size}
> +                                precedence: 3 from: encoder)
> +                    messages: ((elements collect: [:elt |
> +                                            MessageNode new
> +                                                receiver: nil
> +                                                selector: #nextPut:
> +                                                arguments: {elt}
> +                                                precedence: 3
> +                                                from: encoder])
> +                                copyWith: (MessageNode new
> +                                                receiver: nil
> +                                                selector: #braceArray
> +                                                arguments: #()
> +                                                precedence: 1
> +                                                from: encoder)).
> +    ^emitNode sizeCodeForValue: encoder!
> 
> Item was added:
> + Encoder subclass: #BytecodeEncoder
> +    instanceVariableNames: 'stream position rootNode blockExtentsToLocals blockMethod'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !BytecodeEncoder commentStamp: 'eem 1/10/2018 17:28' 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.
> + 
> + Instance Variables
> +    blockExtentsToLocals:    <Dictionary from: Interval to: (Array of: String)>
> +    blockMethod:            <CompiledBlock>
> +    position:                <Integer>
> +    rootNode:                <MethodNode>
> +    stream:                    <WriteStream | BytecodeEncoder>
> + 
> + blockExtentsToLocals
> +    - is a map from block extent to the sequence of temps defined in the block with that extent
> + 
> + blockMethod
> +    - the compiled block being generated in generateBlockMethodOfClass:trailer:from:
> + 
> + position
> +    - used to size bytecodes by having the receiver masquerade as a stream during sizeOpcodeSelector:withArguments:
> + 
> + rootNode
> +    - the MethodNode for the method being generated
> + 
> + stream
> +    - during bytecode sizing this is the receiver.  During bytecode generation this is the WriteStream on the method!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>bindingReadScanBlockFor:using: (in category 'compiled method support') -----
> + bindingReadScanBlockFor: litVarIndex using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for reads of the value of the binding with zero-relative index litVarIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>bindingWriteScanBlockFor:using: (in category 'compiled method support') -----
> + bindingWriteScanBlockFor: litVarIndex using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for writes of the value of the binding with zero-relative index litVarIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>blockMethodOrNilFor:in:at: (in category 'instruction stream support') -----
> + blockMethodOrNilFor: anInstructionStream in: method at: pc
> +    "If anInstructionStream is at a block creation bytecode then answer the block's
> +     CompiledBlock, otherwise answer nil.
> +     Subclasses override as appropriate."
> + 
> +    ^nil!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>bytecodeSetName (in category 'compiled method support') -----
> + bytecodeSetName 
> +    ^self name copyReplaceAll: 'EncoderFor' with: ''!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>bytecodeSize: (in category 'instruction stream support') -----
> + bytecodeSize: aByte
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>callPrimitiveCode (in category 'bytecode decoding') -----
> + callPrimitiveCode
> +    "Answer the call primitive bytecode, if it exists in the encoder's byetcode set, or nil if not."
> +    ^nil!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>canBeSpecialLiteral: (in category 'testing') -----
> + canBeSpecialLiteral: aLiteral
> +    "This check can be used to prevent unnecessary use of #scanBlockOrNilForLiteral:. For performance, this method summarizes specializations from all known bytecode encoders. It is not meant to be refined per bytecode encoder."
> + 
> +    aLiteral isVariableBinding ifTrue: [^false]. "a common case; don't waste time analysing..."
> +    
> +    aLiteral isSymbol ifTrue: [^ Smalltalk specialSelectors identityIncludes: aLiteral].
> +    aLiteral isCharacter ifTrue: [^ aLiteral asInteger <= 65535].
> +    aLiteral isInteger ifTrue: [^ aLiteral between: -32768 and: 32767].
> + 
> +    aLiteral == true ifTrue: [^ true].
> +    aLiteral == false ifTrue: [^ true].
> +    aLiteral == nil ifTrue: [^ true].
> + 
> +    ^ false!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>createClosureCode (in category 'bytecode decoding') -----
> + createClosureCode
> +    "Answer the create closure bytecode, if it exists in the encoder's bytecode set, or nil if not."
> +    ^nil!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>createClosureScanBlock (in category 'compiled method support') -----
> + createClosureScanBlock
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for block closure creation bytecodes."
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>extensionsAt:in:into: (in category 'instruction stream support') -----
> + extensionsAt: pc in: aCompiledMethod into: trinaryBlock
> +    "If the bytecode at pc is an extension then evaluate aTrinaryBlock
> +     with the values of extA and extB and number of extension *bytes*.
> +     If the bytecode at pc is not an extension then evaluate with 0, 0, 0."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>extensionsFor:in:into: (in category 'instruction stream support') -----
> + extensionsFor: pc in: aCompiledMethod into: trinaryBlock
> +    "If the bytecode at pc is an extension, or if the bytecode at pc is preceded by extensions,
> +     then evaluate aTrinaryBlock with the values of extA and extB and number of extension *bytes*.
> +     If the bytecode at pc is neither an extension or extended then evaluate with 0, 0, 0."
> +  
> +    | prevPC |
> +    "If there is what appears to be an extension bytecode before this bytecode
> +     then scan for the previous pc to confirm."
> +    (pc - 2 >= aCompiledMethod initialPC
> +     and: [self isExtension: (aCompiledMethod at: pc - 2)]) ifTrue:
> +        [prevPC := aCompiledMethod pcPreviousTo: pc.
> +         (self nonExtensionPcAt: prevPC in: aCompiledMethod) = pc ifTrue:
> +            [^self extensionsAt: prevPC in: aCompiledMethod into: trinaryBlock]].
> +    ^self extensionsAt: pc in: aCompiledMethod into: trinaryBlock!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>instVarReadScanBlockFor:using: (in category 'compiled method support') -----
> + instVarReadScanBlockFor: varIndexCode using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for reads of the inst var with zero-relative index varIndexCode.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>instVarWriteScanBlockFor:using: (in category 'compiled method support') -----
> + instVarWriteScanBlockFor: varIndexCode using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for writes of the inst var with zero-relative index varIndexCode.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>interpretJumpIfCondIn: (in category 'instruction stream support') -----
> + interpretJumpIfCondIn: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct conditional jump decoder for the instruction set."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>interpretJumpIn: (in category 'instruction stream support') -----
> + interpretJumpIn: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct jump decoder for the instruction set."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>interpretNextInstructionFor:in: (in category 'instruction stream support') -----
> + interpretNextInstructionFor: aClient in: anInstructionStream
> +    "Double-dispatch instruction interpretation through the encoder
> +     to select the correct instruction set decoder."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isBlockReturnAt:in: (in category 'instruction stream support') -----
> + isBlockReturnAt: pc in: method
> +    "Answer whether the bytecode at pc is a return from block."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isBranchIfFalseAt:in: (in category 'instruction stream support') -----
> + isBranchIfFalseAt: pc in: method
> +    "Answer whether the bytecode at pc is a conditional branch-if-false."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isBranchIfTrueAt:in: (in category 'instruction stream support') -----
> + isBranchIfTrueAt: pc in: method
> +    "Answer whether the bytecode at pc is a conditional branch-if-true."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isExtension: (in category 'instruction stream support') -----
> + isExtension: bytecode
> +    "Answer if the bytecode is an extension bytecode, i.e. one that extends
> +     the range of the following bytecode."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isJumpAt:in: (in category 'instruction stream support') -----
> + isJumpAt: pc in: method
> +    "Answer whether the bytecode at pc is an (unconditional) jump."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isJustPopAt:in: (in category 'instruction stream support') -----
> + isJustPopAt: pc in: method
> +    "Answer whether the bytecode at pc is a pop."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isNonSyntheticStoreAt:in:for: (in category 'instruction stream support') -----
> + isNonSyntheticStoreAt: pc in: method for: anInstructionStream
> +    "Answer whether the bytecode at pc is a store or store-pop into an explicit variable.
> +     This eliminates stores into indirect temp vectors, which implement mutable closed-over
> +     variables in the the closure implementation, and hence stores into temp vectors are not real stores."
> + 
> +    ^(self isStoreAt: pc in: method)
> +      and: [(self isSyntheticStoreAt: pc in: method for: anInstructionStream) not]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isRealSendAt:in: (in category 'instruction stream support') -----
> + isRealSendAt: pc in: method
> +    "Answer whether the bytecode at pc is a real message-send, not blockCopy:."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isReturnAt:in: (in category 'instruction stream support') -----
> + isReturnAt: pc in: method
> +    "Answer whether the bytecode at pc is a return."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isReturnSelfFromMethodAt:in: (in category 'instruction stream support') -----
> + isReturnSelfFromMethodAt: pc in: method
> +    "Answer whether the bytecode at pc is a return self from method."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isReturnTopFromMethodAt:in: (in category 'instruction stream support') -----
> + isReturnTopFromMethodAt: pc in: method
> +    "Answer whether the bytecode at pc is a return stack top from method."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isSendAt:in: (in category 'instruction stream support') -----
> + isSendAt: pc in: method
> +    "Answer whether the bytecode at pc is a message-send."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isStoreAt:in: (in category 'instruction stream support') -----
> + isStoreAt: pc in: method
> +    "Answer whether the bytecode at pc is a store or store-pop."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isStorePopAt:in: (in category 'instruction stream support') -----
> + isStorePopAt: pc in: method
> +    "Answer whether the bytecode at pc is a store-pop."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>isSyntheticStoreAt:in:for: (in category 'instruction stream support') -----
> + isSyntheticStoreAt: pc in: method for: anInstructionStream
> +    "Answer whether the bytecode at pc is a store or store-pop of an indirect temp vector,
> +     which implement mutable closed-over variables in the the closure implementation.
> +     Stores into temp vectors are not real stores."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>markerOrNilFor: (in category 'compiled method support') -----
> + markerOrNilFor: aMethod
> +    "If aMethod is a marker method, answer the symbol used to mark it.  Otherwise
> +     answer nil.  What is a marker method?  It is method with body like 
> +        'self subclassResponsibility' or '^ self subclassResponsibility' 
> +     used to indicate ('mark') a special property.
> + 
> +    Marker methods compile to two bytecode forms, this:
> +        self
> +        send: <literal 1>
> +        pop
> +        returnSelf
> +    or this:
> +        self
> +        send: <literal 1>
> +        returnTop"
> +    ^self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>method:readsField: (in category 'scanning') -----
> + method: method readsField: varIndex
> +    "Answer if method loads the instance variable indexed by varIndex."
> +    ^self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>method:writesField: (in category 'scanning') -----
> + method: method writesField: varIndex
> +    "Answer if method stores into the instance variable indexed by varIndex."
> +    ^self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>nonExtensionBytecodeAt:in: (in category 'instruction stream support') -----
> + nonExtensionBytecodeAt: pc in: method
> +    "Answer the actual bytecode at pc in method, skipping past any preceding extensions."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>nonExtensionPcAt:in: (in category 'instruction stream support') -----
> + nonExtensionPcAt: pc in: method
> +    "Answer the pc of the actual bytecode at pc in method, skipping past any preceding extensions."
> +    | thePC bytecode |
> +    thePC := pc.
> +    [self isExtension: (bytecode := method at: thePC)] whileTrue:
> +        [thePC := thePC + (self bytecodeSize: bytecode)].
> +    ^thePC!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>pcFollowingBlockAt:in: (in category 'bytecode decoding') -----
> + pcFollowingBlockAt: pc in: method
> +    "Assuming the pc is that of a block creation bytecode, answer the pc immediately following the block,
> +     i.e. the next pc after the block creation."
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category 'bytecode decoding') -----
> + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method
> +    "Answer the pc of the push closure bytecode whose block starts at startpc in method."
> +    ^self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>pcPreviousTo:in:for: (in category 'bytecode decoding') -----
> + pcPreviousTo: thePC in: method for: anInstructionStreamOrContext
> +    "Answer the pc of the bytecode before the bytecode at thePC.
> +     Unlike CompiledMethod>>pcPreviousTo:, this version answers nil for
> +     the first bytecode of an embedded block, and answers the pc of the
> +     block creation bytecode for a bytecode following an embedded block."
> +    | pc nextPc prevPc byte createClosureCode |
> +    thePC > method endPC ifTrue:
> +        [^method endPC].
> +    pc := method initialPC.
> +    "We could save time by scanning from the block creation bytecode of an embedded block,
> +     using the following, but it saves less time than it loses in additional tests."
> +    "(anInstructionStreamOrContext isContext
> +     and: [anInstructionStreamOrContext isClosureContext
> +     and: [(nextPc := anInstructionStreamOrContext startpc) > pc]]) ifTrue:
> +        [pc := self pcOfBlockCreationBytecodeForBlockStartingAt: nextPc in: method]."
> +    createClosureCode := self createClosureCode.
> +    [pc < thePC] whileTrue:
> +        [byte := method at: (prevPc := pc).
> +         [pc := createClosureCode = byte
> +                    ifTrue:
> +                        [nextPc := self pcFollowingBlockAt: pc in: method.
> +                         nextPc = thePC ifTrue: "first bytecode following block"
> +                            [^prevPc].
> +                         nextPc > thePC
> +                            ifTrue:
> +                                [pc + (self bytecodeSize: byte) = thePC ifTrue: "first bytecode of block"
> +                                    [^nil].
> +                                 pc + (self bytecodeSize: byte)]
> +                            ifFalse: [nextPc]]
> +                    ifFalse: [pc + (self bytecodeSize: byte)].
> +          self isExtension: byte] whileTrue:
> +            [byte := method at: pc]].
> +    ^prevPc
> + 
> + "Here's code to measure the effect of short-cutting scanning for blocks by starting at the startpc.
> +  It measures how much time is used to scan for the pcs from the last block to the end of all methods containing blocks.  Uncomment out the short-cut above to compare time with the optimization and time without.  I see approximately 290ms for all such methods with the optimization and 292 ms without, so given that this slows down the substantial majority of methods without blocks, we KISS."
> + "| candidates |
> + candidates := Dictionary new.
> + self systemNavigation allSelect:
> +    [:m| | ebc |
> +    (m isQuick or: [(ebc := m embeddedBlockClosures) isEmpty]) ifFalse:
> +        [candidates at: m put: { ebc last.
> +                                Array streamContents:
> +                                    [:s| | is |
> +                                    (is:= InstructionStream on: m)
> +                                        pc: ebc last startpc;
> +                                        scanFor:
> +                                            [:b|
> +                                            s nextPut: is pc.
> +                                            false]] }].
> +     false].
> + (1 to: 10) collect:
> +    [:ign|
> +    { [candidates keysAndValuesDo:
> +        [:m :tuple|
> +        [:ebc :pcs| | c |
> +        c := ebc outerContext.
> +        pcs do:
> +            [:pc| m encoderClass pcPreviousTo: pc in: m for: c]] valueWithArguments: tuple]] timeToRun.
> +      [candidates keysAndValuesDo:
> +        [:m :tuple|
> +        [:ebc :pcs| | c |
> +        c := ebc outerContext.
> +        pcs do:
> +            [:pc| m encoderClass pcPreviousTo: pc in: m for: nil]] valueWithArguments: tuple]] timeToRun. }]"!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>pushClosureBytecodeSize (in category 'bytecode decoding') -----
> + pushClosureBytecodeSize
> +    "Answer the size of the push closure bytecode, if there is one."
> +    ^self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>pushNewArrayCode (in category 'bytecode decoding') -----
> + pushNewArrayCode
> +    "Answer the pushNewArray bytecode, if it exists in the encoder's bytecode set, or nil if not."
> +    ^nil!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>pushNilCode (in category 'bytecode decoding') -----
> + pushNilCode
> +    "Answer the pushNil bytecode."
> +    ^self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>scanBlockOrNilForLiteral: (in category 'scanning') -----
> + scanBlockOrNilForLiteral: aLiteral
> +    "Answer a block argument for CompiledMethod>>#scanFor: that answers
> +     if the method refers to the literal implicitly via a special bytecode.
> +     If the literal is not accessible via a special bytecode, answer nil.
> +     Subclasses override as appropriate"
> +    ^nil!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>selectorToSendOrItselfFor:in:at: (in category 'instruction stream support') -----
> + selectorToSendOrItselfFor: anInstructionStream in: method at: pc
> +    "If anInstructionStream is at a send bytecode then answer the send's selector,
> +     otherwise answer anInstructionStream itself.  The rationale for answering
> +     anInstructionStream instead of, say, nil, is that potentially any existing object
> +     can be used as a selector, but since anInstructionStream postdates the method,
> +     it can't be one of them."
> + 
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>stackDeltaForPrimitive:in: (in category 'bytecode decoding') -----
> + stackDeltaForPrimitive: primitiveIndex in: method
> +    "This is the default implementation.  Subclasses with inline primitives will need to override."
> +    ^0!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>superSendScanBlockUsing: (in category 'compiled method support') -----
> + superSendScanBlockUsing: scanner
> +    "Answer a block argument for InstructionStream>>scanFor:
> +     that answers true for super sends."
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>supportsClosures (in category 'compiled method support') -----
> + supportsClosures
> +    "Answer if the instruction set supports closures (contains
> +     closure creation and indirect temp access bytecodes)."
> +    
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>supportsFullBlocks (in category 'testing') -----
> + supportsFullBlocks
> +    "Answer if the instruction set supports full closures (closure creation from
> +     specfic methods instead of bytecodes embedded in an outer home method)."
> + 
> +    ^self basicNew supportsFullBlocks!
> 
> Item was added:
> + ----- Method: BytecodeEncoder class>>unusedBytecode (in category 'bytecode decoding') -----
> + unusedBytecode
> +    "Answer the opcode of a single-byte unused bytecode, if it exists in the encoder's bytecode set, or nil if not."
> +    ^nil!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>allLiteralsForBlockMethod (in category 'results') -----
> + allLiteralsForBlockMethod
> +    addedExtraLiterals ifFalse:
> +        [addedExtraLiterals := true.
> +        "Put the optimized selectors in literals so as to browse senders more easily"
> +        optimizedSelectors := optimizedSelectors reject: [:e| literalStream originalContents hasLiteral: e].
> +        optimizedSelectors isEmpty ifFalse: [
> +            "Use one entry per literal if enough room, else make anArray"
> +            literalStream position + optimizedSelectors size + 2 >= self maxNumLiterals
> +                ifTrue: [self litIndex: optimizedSelectors asArray]
> +                ifFalse: [optimizedSelectors do: [:e | self litIndex: e]]].
> +        "Add a slot for outerCode"
> +        self litIndex: nil].
> +    ^literalStream contents!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>bindAndJuggle: (in category 'temps') -----
> + 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!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>bindBlockArg:within: (in category 'temps') -----
> + bindBlockArg: name within: aBlockNode
> +    | nArgs |
> +    (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!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>bindBlockTemp: (in category 'temps') -----
> + bindBlockTemp: name
> +    "This shouldn't be used with BytecodeEncoder.  Use bindBlockTemp:within: instead."
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>bindBlockTemp:within: (in category 'temps') -----
> + bindBlockTemp: name within: aBlockNode
> +    | nArgs |
> +    (nArgs := aBlockNode nArgsSlot) ifNil:
> +        [aBlockNode nArgsSlot: (nArgs := 0)].
> +    nArgs >= (CompiledMethod fullFrameSize - 1) ifTrue:
> +        [^self notify: 'Too many temporaries'].
> +    aBlockNode nArgsSlot: nArgs + 1.
> +    ^self bindTemp: name!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>bindTemp: (in category 'temps') -----
> + bindTemp: name
> +    "Declare a temporary; error not if a field or class variable or out-of-scope temp."
> +    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 already used in this method']]
> +            ifFalse:[self warnAboutShadowed: name]].
> +    ^self reallyBind: name!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>blockExtentsToTempsMap (in category 'temps') -----
> + 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:
> +                    [:aStream|
> +                    locals withIndexDo:
> +                        [:local :index|
> +                        local isIndirectTempVector
> +                            ifTrue: [local remoteTemps withIndexDo:
> +                                        [:remoteLocal :innerIndex| aStream nextPut: { remoteLocal key. { index. innerIndex } }]]
> +                            ifFalse: [aStream nextPut: { local key. index }]]])].
> +    ^blockExtentsToTempsMap!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>blockLiteralFor: (in category 'full blocks') -----
> + blockLiteralFor: aBlockNode
> +    "Answer a new CompiledBlock for the code in aBlockNode"
> +    ^self reindexingLiteralsDo:
> +        [self shallowCopy resetForFullBlockGeneration
> +            generateBlockMethodOfClass: CompiledBlock
> +            trailer: CompiledMethodTrailer empty
> +            from: aBlockNode]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>computeMethodHeaderForNumArgs:numTemps:numLits:primitive: (in category 'method generation') -----
> + computeMethodHeaderForNumArgs: numArgs numTemps: numTemps numLits: numLits primitive: primitiveIndex
> +    numArgs > 15 ifTrue:
> +        [^self error: 'Cannot compile -- too many arguments'].
> +    numTemps > 63 ifTrue:
> +        [^self error: 'Cannot compile -- too many temporary variables'].    
> +    numLits > self maxNumLiterals ifTrue:
> +        [^self error: 'Cannot compile -- too many literals'].
> +    ^(CompiledMethod headerFlagForEncoder: self)
> +    + (numArgs bitShift: 24)
> +    + (numTemps bitShift: 18)
> +    "+ (largeBit bitShift: 17)" "largeBit gets filled in later"
> +    + (primitiveIndex > 0 ifTrue: [1 bitShift: 16] ifFalse: [0])
> +    "+ (optimizedBit bitShift: 15)" "Sista marker may get filled in later"
> +    + numLits!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>genPushNClosureTemps: (in category 'bytecode generation') -----
> + genPushNClosureTemps: numTemps
> +    "To reduce the number of bytecodes required, the embedded
> +     block closure implementation uses explicit push nil instructions
> +     to create block-local temps.  In bytecode sets supporting
> +     FullBlockClosure/CompiledBlock this isn't needed and the
> +     number of temps is derived from the block method header."
> +    numTemps timesRepeat: [self genPushSpecialLiteral: nil]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>generateBlockMethodOfClass:trailer:from: (in category 'method generation') -----
> + generateBlockMethodOfClass: aCompiledBlockClass trailer: trailer from: blockNode
> +    "Generate a CompiledBlock for the block whose parse tree is blockNode."
> + 
> +    "The closure analysis should already have been done."
> +    | blkSize header literals locals method nLits stack |
> +    self assert: blockNode blockExtent notNil.
> +    self assert: rootNode notNil.
> +    blkSize := blockNode sizeCodeForEvaluatedFullClosureValue: self.
> +    locals := blockNode localsNodes.
> +    self noteBlockExtent: blockNode blockExtent hasLocals: locals.
> +    header := self computeMethodHeaderForNumArgs: blockNode arguments size
> +                    numTemps: locals size
> +                    numLits: (nLits := (literals := self allLiteralsForBlockMethod) size)
> +                    primitive: 0.
> +    method := trailer
> +                    createMethod: blkSize
> +                    class: aCompiledBlockClass
> +                    header: header.
> +    1 to: nLits do:
> +        [:lit |
> +        (method literalAt: lit put: (literals at: lit)) isCompiledCode ifTrue:
> +            [(literals at: lit) outerCode: method]].
> +    self streamToMethod: method.
> +    stack := ParseStack new init.
> +    stack position: method numTemps.
> +    blockMethod := method. "For BytecodeEncoder>>pc & BytecodeEncoder>>nextPC"
> +    [blockNode emitCodeForEvaluatedFullClosureValue: stack encoder: self]
> +        on: Error "If an attempt is made to write too much code the method will be asked"
> +        do: [:ex|  "to grow, and the grow attempt will fail in CompiledCode class>>#newMethodViaNewError"
> +            ex signalerContext sender method = (CompiledCode class>>#newMethodViaNewError)
> +                ifTrue: [^self error: 'Compiler code size discrepancy']
> +                ifFalse: [ex pass]].
> +    stack position ~= (method numTemps + 1) ifTrue:
> +        [^self error: 'Compiler stack discrepancy'].
> +    stream position ~= (method size - trailer size) ifTrue:
> +        [^self error: 'Compiler code size discrepancy'].
> +    method needsFrameSize: stack size - method numTemps.
> +    ^method!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>generateMethodOfClass:trailer:from: (in category 'method generation') -----
> + generateMethodOfClass: aCompiledMethodClass trailer: trailer from: methodNode
> +    "The receiver is the root of a parse tree. Answer an instance of aCompiledMethodClass.
> +     The argument, trailer, is arbitrary but is typically either the reference to the source code
> +     that is stored with every CompiledMethod, or an encoding of the method's temporary names."
> + 
> +    | primErrNode blkSize nLits locals literals header method stack |
> +    primErrNode := methodNode primitiveErrorVariableName ifNotNil:
> +                        [self fixTemp: methodNode primitiveErrorVariableName].
> +    methodNode ensureClosureAnalysisDone.
> +    self rootNode: methodNode. "this is for BlockNode>>sizeCodeForClosureValue:"
> +    blkSize := (methodNode block sizeCodeForEvaluatedValue: self)
> +                + (methodNode primitive > 0
> +                    ifTrue: [self sizeCallPrimitive: methodNode primitive]
> +                    ifFalse: [0])
> +                + (primErrNode
> +                    ifNil: [0]
> +                    ifNotNil:
> +                        [primErrNode
> +                            index: methodNode arguments size + methodNode temporaries size;
> +                            sizeCodeForStore: self "The VM relies on storeIntoTemp: (129)"]).
> +    locals := methodNode arguments, methodNode temporaries, (primErrNode ifNil: [#()] ifNotNil: [{primErrNode}]).
> +    self noteBlockExtent: methodNode block blockExtent hasLocals: locals.
> +    header := self computeMethodHeaderForNumArgs: methodNode arguments size
> +                    numTemps: locals size
> +                    numLits: (nLits := (literals := self allLiterals) size)
> +                    primitive: methodNode primitive.
> +    method := trailer
> +                    createMethod: blkSize
> +                    class: aCompiledMethodClass
> +                    header: header.
> +    1 to: nLits do:
> +        [:lit |
> +        (method literalAt: lit put: (literals at: lit)) isCompiledCode ifTrue:
> +            [(literals at: lit) outerCode: method]].
> +    self streamToMethod: method.
> +    stack := ParseStack new init.
> +    methodNode primitive > 0 ifTrue:
> +        [self genCallPrimitive: methodNode primitive].
> +    primErrNode ifNotNil:
> +        [primErrNode emitCodeForStore: stack encoder: self].
> +    stack position: method numTemps.
> +    [methodNode block emitCodeForEvaluatedValue: stack encoder: self]
> +        on: Error "If an attempt is made to write too much code the method will be asked"
> +        do: [:ex|  "to grow, and the grow attempt will fail in CompiledCode class>>#newMethodViaNewError"
> +            ex signalerContext sender method = (CompiledCode class>>#newMethodViaNewError)
> +                ifTrue: [^self error: 'Compiler code size discrepancy']
> +                ifFalse: [ex pass]].
> +    stack position ~= (method numTemps + 1) ifTrue:
> +        [^self error: 'Compiler stack discrepancy'].
> +    stream position ~= (method size - trailer size) ifTrue:
> +        [^self error: 'Compiler code size discrepancy'].
> +    method needsFrameSize: stack size - method numTemps.
> +    ^method!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>generatingFullBlock (in category 'testing') -----
> + generatingFullBlock
> +    "Answer if the encoder is currently generating a FullBlock, embedded in some method."
> + 
> +    "When generating a FullBlock a copy of the encoder for the home emthod (rootNode)
> +     is used, and hence the following is true."
> +    ^rootNode encoder ~~ self!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>hasGeneratedMethod (in category 'testing') -----
> + hasGeneratedMethod
> +    ^blockExtentsToLocals notNil!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>if:isSpecialLiteralForPush: (in category 'special literal encodings') -----
> + 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 at least 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]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>if:isSpecialLiteralForReturn: (in category 'special literal encodings') -----
> + 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]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>methodStreamPosition (in category 'accessing') -----
> + methodStreamPosition
> +    ^stream position!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>nextPC (in category 'accessing') -----
> + nextPC
> +    "Answer the pc to store in a node for source range identification when the node is associated with its following pc."
> +    ^blockMethod
> +        ifNil: [stream position + 1]
> +        ifNotNil: [:proxy| proxy -> (stream position + 1)]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>nextPut: (in category 'opcode sizing') -----
> + nextPut: aByte
> +    "For sizing make the encoder its own stream and
> +     keep track of position with this version of nextPut:"
> +    position := position + 1!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>noteBlockExtent:hasLocals: (in category 'temps') -----
> + noteBlockExtent: blockExtent hasLocals: tempNodes
> +    blockExtentsToLocals ifNil:
> +        [blockExtentsToLocals := Dictionary new].
> +    blockExtentsToLocals at: blockExtent put: tempNodes asArray!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>outOfRangeError:index:range:to: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>pc (in category 'accessing') -----
> + pc
> +    "Answer the pc to store in a node for source range identification."
> +    ^blockMethod
> +        ifNil: [stream position]
> +        ifNotNil: [:aCompiledBlock| aCompiledBlock -> stream position]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>printSchematicTempNamesOn:blockExtents:fromIndex: (in category 'results') -----
> + 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!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>reindexingLiteralsDo: (in category 'code generation') -----
> + reindexingLiteralsDo: aBlock
> +    "Reset any and all literals so that they will be given new indices in
> +     the literalStream during aBlock (which will be used to generate a
> +     nested block method).  Afterwards restore those same literals to
> +     their original state, and reset any and all new literals added during
> +     aBlock  so that they will be given new indices if used subsequently."
> +    | savedNodes saveBlock |
> +    savedNodes := IdentityDictionary new.
> +    saveBlock := [:node|
> +                    savedNodes at: node put: node shallowCopy.
> +                    node resetForBlockGeneration].
> +    litSet do: saveBlock.
> +    litIndSet do: saveBlock.
> +    selectorSet do: saveBlock.
> +    ^aBlock ensure:
> +        [| restoreBlock |
> +         restoreBlock := [:node|
> +                            savedNodes
> +                                at: node
> +                                ifPresent: [:copy| node resetFromCopy: copy]
> +                                ifAbsent: [node resetForBlockGeneration]].
> +         litSet do: restoreBlock.
> +         litIndSet do: restoreBlock.
> +         selectorSet do: restoreBlock]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>resetForFullBlockGeneration (in category 'code generation') -----
> + resetForFullBlockGeneration
> +    literalStream := WriteStream on: (Array new: 8).
> +    addedExtraLiterals := false.
> +    optimizedSelectors := Set new!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>resetLiteralStreamForFullBlock (in category 'code generation') -----
> + resetLiteralStreamForFullBlock
> +    literalStream := WriteStream on: (Array new: 32).
> +    addedExtraLiterals := false.
> +    optimizedSelectors := Set new!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>rootNode (in category 'accessing') -----
> + rootNode "^<BlockNode>"
> +    ^rootNode!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>rootNode: (in category 'accessing') -----
> + rootNode: node "<BlockNode>"
> +    rootNode := node!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>schematicTempNamesString (in category 'results') -----
> + 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]!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeBranchPopFalse: (in category 'opcode sizing') -----
> + sizeBranchPopFalse: distance
> +    ^self sizeOpcodeSelector: #genBranchPopFalse: withArguments: {distance}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeBranchPopTrue: (in category 'opcode sizing') -----
> + sizeBranchPopTrue: distance
> +    ^self sizeOpcodeSelector: #genBranchPopTrue: withArguments: {distance}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeCallPrimitive: (in category 'opcode sizing') -----
> + sizeCallPrimitive: primitiveIndex
> +    ^self sizeOpcodeSelector: #genCallPrimitive: withArguments: {primitiveIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeDup (in category 'opcode sizing') -----
> + sizeDup
> +    ^self sizeOpcodeSelector: #genDup withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeJump: (in category 'opcode sizing') -----
> + sizeJump: distance
> +    ^self sizeOpcodeSelector: #genJump: withArguments: {distance}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeJumpLong: (in category 'opcode sizing') -----
> + sizeJumpLong: distance
> +    ^self sizeOpcodeSelector: #genJumpLong: withArguments: {distance}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeOpcodeSelector:withArguments: (in category 'opcode sizing') -----
> + sizeOpcodeSelector: genSelector withArguments: args
> +    stream := self.
> +    position := 0.
> +    self perform: genSelector withArguments: args.
> +    ^position!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePop (in category 'opcode sizing') -----
> + sizePop
> +    ^self sizeOpcodeSelector: #genPop withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushClosureCopyNumCopiedValues:numArgs:jumpSize: (in category 'opcode sizing') -----
> + sizePushClosureCopyNumCopiedValues: numCopied numArgs: numArgs jumpSize: jumpSize
> +    ^self
> +        sizeOpcodeSelector: #genPushClosureCopyNumCopiedValues:numArgs:jumpSize:
> +        withArguments: {numCopied. numArgs. jumpSize}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushConsArray: (in category 'opcode sizing') -----
> + sizePushConsArray: numElements
> +    ^self sizeOpcodeSelector: #genPushConsArray: withArguments: {numElements}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushFullClosure:numCopied: (in category 'opcode sizing') -----
> + sizePushFullClosure: compiledBlockLiteralIndex numCopied: numCopied
> +    ^self sizeOpcodeSelector: #genPushFullClosure:numCopied:
> +        withArguments: {compiledBlockLiteralIndex. numCopied}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushFullClosure:numCopied:receiverOnStack:ignoreOuterContext: (in category 'opcode sizing') -----
> + sizePushFullClosure: compiledBlockLiteralIndex numCopied: numCopied receiverOnStack: receiverOnStack ignoreOuterContext: ignoreOuterContext
> +    ^self sizeOpcodeSelector: #genPushFullClosure:numCopied:receiverOnStack:ignoreOuterContext:
> +        withArguments: {compiledBlockLiteralIndex. numCopied. receiverOnStack. ignoreOuterContext}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushInstVar: (in category 'opcode sizing') -----
> + sizePushInstVar: instVarIndex
> +    ^self sizeOpcodeSelector: #genPushInstVar: withArguments: {instVarIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushInstVarLong: (in category 'opcode sizing') -----
> + sizePushInstVarLong: instVarIndex
> +    ^self sizeOpcodeSelector: #genPushInstVarLong: withArguments: {instVarIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushLiteral: (in category 'opcode sizing') -----
> + sizePushLiteral: literalIndex
> +    ^self sizeOpcodeSelector: #genPushLiteral: withArguments: {literalIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushLiteralVar: (in category 'opcode sizing') -----
> + sizePushLiteralVar: literalIndex
> +    ^self sizeOpcodeSelector: #genPushLiteralVar: withArguments: {literalIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushNClosureTemps: (in category 'opcode sizing') -----
> + sizePushNClosureTemps: numTemps
> +    ^self sizeOpcodeSelector: #genPushNClosureTemps: withArguments: {numTemps}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushNewArray: (in category 'opcode sizing') -----
> + sizePushNewArray: size
> +    ^self sizeOpcodeSelector: #genPushNewArray: withArguments: {size}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushReceiver (in category 'opcode sizing') -----
> + sizePushReceiver
> +    ^self sizeOpcodeSelector: #genPushReceiver withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushRemoteTemp:inVectorAt: (in category 'opcode sizing') -----
> + sizePushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> +    ^self sizeOpcodeSelector: #genPushRemoteTemp:inVectorAt: withArguments: {tempIndex. tempVectorIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushSpecialLiteral: (in category 'opcode sizing') -----
> + sizePushSpecialLiteral: specialLiteral
> +    ^self sizeOpcodeSelector: #genPushSpecialLiteral: withArguments: {specialLiteral}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushTemp: (in category 'opcode sizing') -----
> + sizePushTemp: tempIndex
> +    ^self sizeOpcodeSelector: #genPushTemp: withArguments: {tempIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushTempLong: (in category 'opcode sizing') -----
> + sizePushTempLong: tempIndex
> +    ^self sizeOpcodeSelector: #genPushTempLong: withArguments: {tempIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizePushThisContext (in category 'opcode sizing') -----
> + sizePushThisContext
> +    ^self sizeOpcodeSelector: #genPushThisContext withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeReturnNilToCaller (in category 'opcode sizing') -----
> + sizeReturnNilToCaller
> +    ^self sizeOpcodeSelector: #genReturnNilToCaller withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeReturnReceiver (in category 'opcode sizing') -----
> + sizeReturnReceiver
> +    ^self sizeOpcodeSelector: #genReturnReceiver withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeReturnSpecialLiteral: (in category 'opcode sizing') -----
> + sizeReturnSpecialLiteral: specialLiteral
> +    ^self sizeOpcodeSelector: #genReturnSpecialLiteral: withArguments: {specialLiteral}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeReturnTop (in category 'opcode sizing') -----
> + sizeReturnTop
> +    ^self sizeOpcodeSelector: #genReturnTop withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeReturnTopToCaller (in category 'opcode sizing') -----
> + sizeReturnTopToCaller
> +    ^self sizeOpcodeSelector: #genReturnTopToCaller withArguments: #()!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeSend:numArgs: (in category 'opcode sizing') -----
> + sizeSend: selectorLiteralIndex numArgs: nArgs
> +    ^self sizeOpcodeSelector: #genSend:numArgs: withArguments: {selectorLiteralIndex. nArgs}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeSendDirectedSuper:numArgs: (in category 'opcode sizing') -----
> + sizeSendDirectedSuper: selectorLiteralIndex numArgs: numArgs
> +    ^self sizeOpcodeSelector: #genSendDirectedSuper:numArgs: withArguments: {selectorLiteralIndex. numArgs}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeSendSpecial:numArgs: (in category 'opcode sizing') -----
> + sizeSendSpecial: specialSelectorIndex numArgs: nArgs
> +    ^self sizeOpcodeSelector: #genSendSpecial:numArgs: withArguments: {specialSelectorIndex. nArgs}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeSendSuper:numArgs: (in category 'opcode sizing') -----
> + sizeSendSuper: selectorLiteralIndex numArgs: nArgs
> +    ^self sizeOpcodeSelector: #genSendSuper:numArgs: withArguments: {selectorLiteralIndex. nArgs}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStoreInstVar: (in category 'opcode sizing') -----
> + sizeStoreInstVar: instVarIndex
> +    ^self sizeOpcodeSelector: #genStoreInstVar: withArguments: {instVarIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStoreInstVarLong: (in category 'opcode sizing') -----
> + sizeStoreInstVarLong: instVarIndex
> +    ^self sizeOpcodeSelector: #genStoreInstVarLong: withArguments: {instVarIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStoreLiteralVar: (in category 'opcode sizing') -----
> + sizeStoreLiteralVar: literalIndex
> +    ^self sizeOpcodeSelector: #genStoreLiteralVar: withArguments: {literalIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStorePopInstVar: (in category 'opcode sizing') -----
> + sizeStorePopInstVar: instVarIndex
> +    ^self sizeOpcodeSelector: #genStorePopInstVar: withArguments: {instVarIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStorePopInstVarLong: (in category 'opcode sizing') -----
> + sizeStorePopInstVarLong: instVarIndex
> +    ^self sizeOpcodeSelector: #genStorePopInstVarLong: withArguments: {instVarIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStorePopLiteralVar: (in category 'opcode sizing') -----
> + sizeStorePopLiteralVar: literalIndex
> +    ^self sizeOpcodeSelector: #genStorePopLiteralVar: withArguments: {literalIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStorePopRemoteTemp:inVectorAt: (in category 'opcode sizing') -----
> + sizeStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> +    ^self sizeOpcodeSelector: #genStorePopRemoteTemp:inVectorAt: withArguments: {tempIndex. tempVectorIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStorePopTemp: (in category 'opcode sizing') -----
> + sizeStorePopTemp: tempIndex
> +    ^self sizeOpcodeSelector: #genStorePopTemp: withArguments: {tempIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStoreRemoteTemp:inVectorAt: (in category 'opcode sizing') -----
> + sizeStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> +    ^self sizeOpcodeSelector: #genStoreRemoteTemp:inVectorAt: withArguments: {tempIndex. tempVectorIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeStoreTemp: (in category 'opcode sizing') -----
> + sizeStoreTemp: tempIndex
> +    ^self sizeOpcodeSelector: #genStoreTemp: withArguments: {tempIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>sizeTrapIfNotInstanceOf: (in category 'opcode sizing') -----
> + sizeTrapIfNotInstanceOf: litIndex
> +    ^self sizeOpcodeSelector: #genTrapIfNotInstanceOf: withArguments: {litIndex}!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>streamToMethod: (in category 'initialize-release') -----
> + streamToMethod: aCompiledMethod
> +    stream := WriteStream with: aCompiledMethod.
> +    stream position: aCompiledMethod initialPC - 1!
> 
> Item was added:
> + ----- Method: BytecodeEncoder>>supportsFullBlocks (in category 'testing') -----
> + supportsFullBlocks
> +    "Answer if the instruction set supports full closures (closure creation from
> +     specfic methods instead of bytecodes embedded in an outer home method)."
> + 
> +    ^self subclassResponsibility!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: CascadeNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitCascadeNode: self!
> 
> Item was added:
> + ----- Method: CascadeNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> +    { receiver }, messages do:
> +        [:node| node analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools]!
> 
> Item was added:
> + ----- Method: CascadeNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: CascadeNode>>messages (in category 'accessing') -----
> + messages
> +    ^messages!
> 
> Item was added:
> + ----- Method: CascadeNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level
> +    self printOn: aStream indent: level precedence: 0!
> 
> Item was added:
> + ----- Method: CascadeNode>>printOn:indent:precedence: (in category 'printing') -----
> + 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: $)]!
> 
> Item was added:
> + ----- Method: CascadeNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level
> +    self printWithClosureAnalysisOn: aStream indent: level precedence: 0!
> 
> Item was added:
> + ----- Method: CascadeNode>>printWithClosureAnalysisOn:indent:precedence: (in category 'printing') -----
> + 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: $)]!
> 
> Item was added:
> + ----- Method: CascadeNode>>receiver (in category 'accessing') -----
> + receiver
> +    ^receiver!
> 
> Item was added:
> + ----- Method: CascadeNode>>receiver:messages: (in category 'initialize-release') -----
> + receiver: receivingObject messages: msgs
> +    " Transcript show: 'abc'; cr; show: 'def' "
> + 
> +    receiver := receivingObject.
> +    messages := msgs!
> 
> Item was added:
> + ----- Method: CascadeNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    | size |
> +    size := (receiver sizeCodeForValue: encoder)
> +             + (messages size - 1 * (encoder sizeDup + encoder sizePop)).
> +    messages do: [:aMessage | size := size + (aMessage sizeCodeForValue: encoder)].
> +    ^size!
> 
> Item was added:
> + TextStream subclass: #ColoredCodeStream
> +    instanceVariableNames: 'dialect colorTable'
> +    classVariableNames: 'ST80ColorTable'
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> 
> Item was added:
> + ----- Method: ColoredCodeStream class>>contents: (in category 'instance creation') -----
> + contents: blockWithArg 
> +    "Evaluate blockWithArg on a DialectStream of the given description"
> + 
> +    | stream |
> +    stream := self on: (Text new: 400).
> +    blockWithArg value: stream.
> +    ^ stream contents!
> 
> Item was added:
> + ----- Method: ColoredCodeStream class>>initialize (in category 'class initialization') -----
> + 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"!
> 
> Item was added:
> + ----- Method: ColoredCodeStream>>colorTable (in category 'color/style') -----
> + colorTable
> +    "Answer the table to use to determine colors"
> + 
> +    ^ colorTable ifNil: [colorTable := ST80ColorTable]!
> 
> Item was added:
> + ----- Method: ColoredCodeStream>>withColor:emphasis:do: (in category 'color/style') -----
> + 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!
> 
> Item was added:
> + ----- Method: ColoredCodeStream>>withStyleFor:do: (in category 'color/style') -----
> + 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!
> 
> Item was added:
> + ParseNode subclass: #CommentNode
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> 
> Item was added:
> + ----- Method: CommentNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitCommentNode: self!
> 
> Item was added:
> + Object subclass: #CompilationCue
> +    instanceVariableNames: 'source sourceStream context receiver class environment requestor encoderClass methodTrailer'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !CompilationCue commentStamp: 'eem 3/30/2017 17:32' prior: 0!
> + A CompilationCue is a helper class holding enough context for evaluating/compiling Smalltalk code.
> + 
> + That is mainly the source code, and the source code editor to interact with if the Compiler is used interactively.
> + But that is also any additional information necessary to resolve variable names.
> + 
> + When compiling a method, the Compiler typically need to know the target class in which to install the method.
> + 
> + When evaluating an expression, the Compiler also needs a receiver (for accessing the value of its instance variables), its class (for resolving instance/class variable names), and optionnally a context of execution when debugging a method (for accessing values of temporaries and parameters).
> + 
> + Instance Variables
> +    class:            <Behavior>
> +    context:        <Context | nil>
> +    environment:    <Environment | nil>
> +    receiver:        <Object>
> +    requestor:        <TextEditor | nil>
> +    source:            <Stream>
> + 
> + class
> +    - the target class in which to install the compiled method;
> +      this enables to resolve the instance variable names, class variable names and shared pool variable names.
> +      When evaluating, this should be the receiver class
> + 
> + context
> +    - the context introspected when evaluating the code: this is typically for accessing parameters and temporary variables when debugging
> + 
> + environment
> +    - the environment in which to resolve global variable names
> + 
> + receiver
> +    - the receiver into which to evaluate the code: this is typically for accessing instance variables in an inspector
> + 
> + requestor
> +    - typically the text editor containing the source code being compiled/evaluated. This enables the Compiler to interact in case of syntax error.
> + 
> + source
> +    - a ReadStream on the source code to be compiled
> + !
> 
> Item was added:
> + ----- Method: CompilationCue class>>class: (in category 'instance creation') -----
> + class: aClass
> +    ^ self 
> +        source: nil
> +        context: nil
> +        receiver: nil
> +        class: aClass
> +        environment: (aClass ifNotNil: [aClass environment])
> +        requestor: nil!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source: (in category 'instance creation') -----
> + source: aTextOrStream
> +    ^ self
> +        source: aTextOrStream
> +        class: nil
> +        requestor: nil!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source:class:environment:requestor: (in category 'instance creation') -----
> + source: aTextOrStream class: aClass environment: anEnvironment requestor: anObject
> +    ^ self
> +        source: aTextOrStream
> +        context: nil
> +        receiver: nil
> +        class: aClass
> +        environment: anEnvironment
> +        requestor: anObject!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source:class:requestor: (in category 'instance creation') -----
> + source: aTextOrStream class: aClass requestor: anObject
> +    ^ self 
> +        source: aTextOrStream 
> +        context: nil 
> +        receiver: nil
> +        class: aClass 
> +        environment: (aClass ifNotNil: [aClass environment])
> +        requestor: anObject!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source:context:class:environment:requestor: (in category 'instance creation') -----
> + source: aTextOrStream context: aContext class: aClass environment: anEnvironment requestor: reqObject
> +    ^ self basicNew
> +        initializeWithSource: aTextOrStream 
> +        context: aContext 
> +        receiver: (aContext ifNotNil: [aContext receiver]) 
> +        class: aClass 
> +        environment: anEnvironment 
> +        requestor: reqObject!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source:context:class:requestor: (in category 'instance creation') -----
> + source: aTextOrStream context: aContext class: aClass requestor: anObject
> +    ^ self 
> +        source: aTextOrStream 
> +        context: aContext 
> +        receiver: (aContext ifNotNil: [aContext receiver])
> +        class: aClass 
> +        environment: (aClass ifNotNil: [aClass environment])
> +        requestor: anObject!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source:context:receiver:class:environment:requestor: (in category 'instance creation') -----
> + source: aTextOrStream context: aContext receiver: recObject class: aClass environment: anEnvironment requestor: reqObject
> +    ^ self basicNew
> +        initializeWithSource: aTextOrStream 
> +        context: aContext 
> +        receiver: recObject 
> +        class: aClass 
> +        environment: anEnvironment 
> +        requestor: reqObject!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source:environment: (in category 'instance creation') -----
> + source: aString environment: anEnvironment
> +    ^ self 
> +        source: aString
> +        context: nil
> +        receiver: nil
> +        class: UndefinedObject
> +        environment: anEnvironment
> +        requestor: nil!
> 
> Item was added:
> + ----- Method: CompilationCue class>>source:environment:requestor: (in category 'instance creation') -----
> + source: aString environment: anEnvironment requestor: aRequestor
> +    ^ self 
> +        source: aString
> +        context: nil
> +        receiver: nil
> +        class: UndefinedObject
> +        environment: anEnvironment
> +        requestor: aRequestor!
> 
> Item was added:
> + ----- Method: CompilationCue>>bindingOf: (in category 'binding') -----
> + bindingOf: aSymbol
> +    ^ class bindingOf: aSymbol environment: environment!
> 
> Item was added:
> + ----- Method: CompilationCue>>context (in category 'accessing') -----
> + context
> +    ^ context!
> 
> Item was added:
> + ----- Method: CompilationCue>>encoderClass (in category 'accessing') -----
> + encoderClass
> +    ^encoderClass!
> 
> Item was added:
> + ----- Method: CompilationCue>>encoderClass: (in category 'accessing') -----
> + encoderClass: aBytecodeEncoderClass
> +    encoderClass := aBytecodeEncoderClass!
> 
> Item was added:
> + ----- Method: CompilationCue>>environment (in category 'accessing') -----
> + environment
> +    ^ environment!
> 
> Item was added:
> + ----- Method: CompilationCue>>getClass (in category 'accessing') -----
> + getClass
> +    ^ class!
> 
> Item was added:
> + ----- Method: CompilationCue>>initializeWithSource:context:receiver:class:environment:requestor: (in category 'initialization') -----
> + initializeWithSource: aTextOrStringOrStream context: aContext receiver: recObject class: aClass environment: anEnvironment requestor: reqObject
> +    self initialize.
> +    aTextOrStringOrStream isStream
> +        ifTrue: [sourceStream := aTextOrStringOrStream]
> +        ifFalse:
> +            [source := aTextOrStringOrStream.
> +             sourceStream := ReadStream on: aTextOrStringOrStream asString].
> +    context := aContext.
> +    receiver := recObject.
> +    class := aClass.
> +    environment := anEnvironment.
> +    requestor := reqObject!
> 
> Item was added:
> + ----- Method: CompilationCue>>methodTrailer (in category 'accessing') -----
> + methodTrailer
> +    ^methodTrailer!
> 
> Item was added:
> + ----- Method: CompilationCue>>methodTrailer: (in category 'accessing') -----
> + methodTrailer: aCompiledMethodTrailer
> +    methodTrailer := aCompiledMethodTrailer!
> 
> Item was added:
> + ----- Method: CompilationCue>>receiver (in category 'accessing') -----
> + receiver
> +    ^ receiver!
> 
> Item was added:
> + ----- Method: CompilationCue>>requestor (in category 'accessing') -----
> + requestor
> +    ^ requestor!
> 
> Item was added:
> + ----- Method: CompilationCue>>source (in category 'accessing') -----
> + source
> +    ^source!
> 
> Item was added:
> + ----- Method: CompilationCue>>source: (in category 'accessing') -----
> + source: aString
> + 
> +    source := aString.
> +    sourceStream := source readStream.!
> 
> Item was added:
> + ----- Method: CompilationCue>>sourceStream (in category 'accessing') -----
> + sourceStream
> +    ^sourceStream!
> 
> Item was added:
> + ----- Method: CompilationCue>>stringToLog (in category 'accessing') -----
> + stringToLog
> +    "Answer a string to be logged in a change log.
> +    Implementation note:
> +    If the requestor is a TextEditor, preferably take its selection.
> +    This convoluted code is presumably crafted to avoid broken contents
> +    (ReadStream on: '123456' from: 3 to: 4) contents -> '1234'
> +    As long as selectionAsStream is using such construct this might be required."
> +    | itsSelection itsSelectionString |
> +    source ifNotNil:
> +        [^source].
> +    ((requestor respondsTo: #selection)  
> +     and:[(itsSelection := requestor selection) notNil
> +     and:[(itsSelectionString := itsSelection asString) isEmptyOrNil not]]) ifTrue:
> +        [^itsSelectionString].
> +    ^sourceStream contents!
> 
> Item was added:
> + ----- Method: CompiledMethod>>mapFromBlockKeys:toSchematicTemps: (in category '*Compiler-support') -----
> + mapFromBlockKeys: keys toSchematicTemps: schematicTempNamesString
> +    "Decode a schematicTempNamesString that encodes the layout of temp names
> +     in a method and any closures/blocks within it, matching keys in keys to
> +     vectors of temp names."
> +    | map tempNames |
> +    map := self newBlockStartMap.
> +    tempNames := schematicTempNamesString readStream.
> +    keys do:
> +        [:key| | tempSequence tempIndex |
> +        tempSequence := OrderedCollection new.
> +        tempIndex := 0.
> +        [(tempNames skipSeparators; peek) ifNil: [true] ifNotNil: [:ch| '[]' includes: ch]] whileFalse:
> +            [tempNames peek = $(
> +                ifTrue: [tempSequence addAllLast: ((self tempsSubSequenceFrom: (tempNames next; yourself)) withIndexCollect:
> +                                                        [:temp :index|
> +                                                        { temp. { tempIndex + 1. index } }]).
> +                        tempNames peek ~= $) ifTrue: [self error: 'parse error'].
> +                        tempIndex := tempIndex + 1.
> +                        tempNames next]
> +                ifFalse: [tempSequence addAllLast: ((self tempsSubSequenceFrom: tempNames) withIndexCollect:
> +                                                        [:temp :index|
> +                                                        { temp. tempIndex := tempIndex + 1 }])]].
> +        map at: key put: tempSequence asArray.
> +        [tempNames peek = $]] whileTrue: [tempNames next].
> +        tempNames peek = $[ ifTrue:
> +            [tempNames next]].
> +    ^map!
> 
> Item was added:
> + ----- Method: CompiledMethod>>newBlockStartMap (in category '*Compiler-private') -----
> + newBlockStartMap
> +    "If blocks are embedded then keys in the map are simple integer pcs and a Dictionary can be used.
> +     If blocks are full (separate method objects) then keys in the map are CompiledBlocks and
> +     IdentityDictionary must be used to avoid confusing blocks with identical code."
> +    ^(self encoderClass supportsFullBlocks
> +        ifTrue: [IdentityDictionary]
> +        ifFalse: [Dictionary]) new!
> 
> Item was added:
> + Object subclass: #CompiledMethodWithNode
> +    instanceVariableNames: 'node method'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> 
> Item was added:
> + ----- Method: CompiledMethodWithNode class>>generateMethodFromNode:trailer: (in category 'instance creation') -----
> + generateMethodFromNode: aMethodNode trailer: bytes
> +    ^ self method: (aMethodNode generate: bytes) node: aMethodNode.!
> 
> Item was added:
> + ----- Method: CompiledMethodWithNode class>>method:node: (in category 'instance creation') -----
> + method: aCompiledMethod node: aMethodNode
> +    ^ self new method: aCompiledMethod; node: aMethodNode.!
> 
> Item was added:
> + ----- Method: CompiledMethodWithNode>>method (in category 'accessing') -----
> + method
> +    ^ method!
> 
> Item was added:
> + ----- Method: CompiledMethodWithNode>>method: (in category 'private') -----
> + method: aCompiledMethod
> +    method := aCompiledMethod!
> 
> Item was added:
> + ----- Method: CompiledMethodWithNode>>node (in category 'accessing') -----
> + node
> +    ^ node!
> 
> Item was added:
> + ----- Method: CompiledMethodWithNode>>node: (in category 'private') -----
> + node: aMethodNode
> +    node := aMethodNode!
> 
> Item was added:
> + ----- Method: CompiledMethodWithNode>>selector (in category 'accessing') -----
> + selector
> +    ^ self node selector!
> 
> Item was added:
> + Object subclass: #Compiler
> +    instanceVariableNames: 'parser cue'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !Compiler commentStamp: 'cwp 12/26/2012 23:17' 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.!
> 
> Item was added:
> + ----- Method: Compiler class>>couldEvaluate: (in category 'accessing') -----
> + couldEvaluate: anObject
> +    "Answer true if anObject can be passed to my various #evaluate: methods."
> +    ^anObject isString or: [ anObject isText or: [ anObject isStream ]]!
> 
> Item was added:
> + ----- Method: Compiler class>>decompilerClass (in category 'accessing') -----
> + decompilerClass
> +    ^Decompiler!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate: (in category 'evaluating') -----
> + 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!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:environment: (in category 'evaluating') -----
> + evaluate: aString environment: anEnvironment
> +    ^  self new
> +        evaluateCue: (CompilationCue
> +            source: aString
> +            environment: anEnvironment)
> +        ifFail: [^ nil]!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:environment:logged: (in category 'evaluating logged') -----
> + evaluate: aString environment: anEnvironment logged: aBoolean
> +    ^ self new
> +        evaluateCue: (CompilationCue
> +            source: aString
> +            environment: anEnvironment)
> +        ifFail: [^ nil]
> +        logged: aBoolean!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:for: (in category 'evaluating') -----
> + evaluate: textOrString for: anObject  
> +    "See Compiler|evaluate:for:notifying:. If a compilation error occurs, 
> +    a Syntax Error view is created rather than notifying any requestor."
> + 
> +    ^self evaluate: textOrString for: anObject notifying: nil!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:for:logged: (in category 'evaluating logged') -----
> + 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!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:for:notifying: (in category 'evaluating') -----
> + evaluate: textOrString for: anObject notifying: aController
> +    "Compile and execute the argument, textOrString with respect to the class 
> +    of anObject. If a compilation error occurs, notify aController."
> + 
> +    ^ self new
> +        evaluate: textOrString
> +        in: nil
> +        to: anObject
> +        notifying: aController
> +        ifFail: [^nil]!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:for:notifying:logged: (in category 'evaluating logged') -----
> + 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.!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:in:notifying:logged: (in category 'evaluating logged') -----
> + evaluate: textOrString in: anEnvironment notifying: aController logged: logFlag
> +    "Compile and execute the argument, textOrString in anEnvironment.
> +    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: anEnvironment
> +                notifying: aController
> +                logged: logFlag.!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:logged: (in category 'evaluating logged') -----
> + 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!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:notifying: (in category 'evaluating') -----
> + evaluate: textOrString notifying: aController
> +    "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!
> 
> Item was added:
> + ----- Method: Compiler class>>evaluate:notifying:logged: (in category 'evaluating logged') -----
> + 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!
> 
> Item was added:
> + ----- Method: Compiler class>>format:in:notifying: (in category 'evaluating') -----
> + format: textOrStream in: aClass notifying: aRequestor
> +    ^self new format: textOrStream in: aClass notifying: aRequestor!
> 
> Item was added:
> + ----- Method: Compiler class>>format:in:notifying:decorated: (in category 'evaluating') -----
> + format: textOrStream in: aClass notifying: aRequestor decorated: aBoolean
> +    ^self new format: textOrStream in: aClass notifying: aRequestor decorated: aBoolean!
> 
> Item was added:
> + ----- Method: Compiler class>>initialize (in category 'class initialization') -----
> + initialize
> +    "For the benefit of MC running a required script in the proper order."
> +    self recompileAll.!
> 
> Item was added:
> + ----- Method: Compiler class>>new (in category 'accessing') -----
> + new
> +    ^ super new parser: self newParser!
> 
> Item was added:
> + ----- Method: Compiler class>>parserClass (in category 'accessing') -----
> + parserClass
> +    "Answer a parser class to use for parsing methods compiled by instances of the receiver."
> + 
> +    ^Parser!
> 
> Item was added:
> + ----- Method: Compiler class>>recompileAll (in category 'utilities') -----
> + recompileAll    "Compiler recompileAll"
> +    "Recompile all classes and traits in the system.
> +     After recompilation invoke the postRecompileAction on any "
> + 
> +    | classesWithRecompileActions |
> +    classesWithRecompileActions := OrderedCollection new.
> +    Smalltalk allClassesAndTraits "This is unordered; I find that unsatisfactory and fragile, because
> +                                    if there is a bug it could be difficult to reproduce. eem 10/8/2019"
> +        do: [:classOrTrait |
> +            classOrTrait compileAll.
> +            (classOrTrait class includesSelector: #postRecompileAction) ifTrue:
> +                [classesWithRecompileActions addLast: classOrTrait]] 
> +        displayingProgress:[:classOrTrait| 'Recompiling ', classOrTrait].
> + 
> +    classesWithRecompileActions do: [:classOrTrait| classOrTrait postRecompileAction]!
> 
> Item was added:
> + ----- Method: Compiler class>>recompileAllFrom: (in category 'utilities') -----
> + recompileAllFrom: firstName 
> +    "Recompile all classes, starting with given name."
> +    | classesWithRecompileActions |
> +    classesWithRecompileActions := OrderedCollection new.
> + 
> +    Smalltalk allClassesDo: 
> +        [:class |
> +        class name >= firstName ifTrue: 
> +            [Transcript show: class name; cr.
> +             class compileAll.
> +             (class class includesSelector: #postRecompileAction) ifTrue:
> +                [classesWithRecompileActions addLast: class]]].
> + 
> +    classesWithRecompileActions do:
> +        [:classOrTrait| classOrTrait postRecompileAction]
> + 
> +    "Compiler recompileAllFrom: 'AAABodyShop'"!
> 
> Item was added:
> + ----- Method: Compiler>>classForReceiver:context: (in category 'private') -----
> + classForReceiver: receiver context: contextOrNil
> +    "Answer the class to compile in for a receiver and aContext.
> +     If aContext is non-nil use its receiver's class (if we use the context's
> +     methodClass we may exclude instance variables of the receiver).
> +     Access the class of the receiver via the mirror primitive to avoid issues with proxies."
> + 
> +    ^thisContext objectClass: (contextOrNil ifNil: [receiver] ifNotNil: [contextOrNil receiver])!
> 
> Item was added:
> + ----- Method: Compiler>>compile:ifFail: (in category 'public access') -----
> + compile: aCue ifFail: failBlock 
> +    "Answer a MethodNode. If the MethodNode can not be created, notify 
> +    the requestor in the contxt. If the requestor 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 class specified by the context."
> +    
> +    ^self
> +        compileCue: aCue
> +        noPattern: false
> +        ifFail: failBlock !
> 
> Item was added:
> + ----- Method: Compiler>>compile:in:environment:notifying:ifFail: (in category 'public access') -----
> + compile: textOrStream in: aClass environment: anEnvironment 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."
> + 
> +    ^self
> +        compileCue: (CompilationCue
> +            source: textOrStream
> +            class: aClass
> +            environment: anEnvironment
> +            requestor: aRequestor)
> +        noPattern: false
> +        ifFail: failBlock
> + !
> 
> Item was added:
> + ----- Method: Compiler>>compile:in:notifying:ifFail: (in category 'public access') -----
> + compile: textOrStream in: aClass 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."
> + 
> +    ^self
> +        compileCue: (CompilationCue
> +            source: textOrStream
> +            class: aClass
> +            requestor: aRequestor)
> +        noPattern: false
> +        ifFail: failBlock
> + !
> 
> Item was added:
> + ----- Method: Compiler>>compileCue:noPattern:ifFail: (in category 'private') -----
> + compileCue: aCue noPattern: aBoolean ifFail: failBlock 
> +    "Answer a MethodNode corresponding to cue source.
> +    If the MethodNode can not be created, notify the cue requestor.
> +    If the cue requestor is nil, evaluate failBlock instead.
> +    The MethodNode is the root  of a parse tree.
> +    It can be told to generate a CompiledMethod
> +    - either to be evaluated in cue context if aBoolean is true, with cue receiver as method receiver,
> +    - or to be installed in the method dictionary of the target class specified by the cue if aBoolean is false."
> +    
> +    self setCue: aCue.
> +    ^self translateNoPattern: aBoolean    ifFail: failBlock!
> 
> Item was added:
> + ----- Method: Compiler>>compileNoPattern:in:context:environment:notifying:ifFail: (in category 'public access') -----
> + compileNoPattern: textOrStream in: aClass context: aContext environment: anEnvironment 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,
> +    and it will be in an explicit environment."
> + 
> +    ^self
> +        compileCue: (CompilationCue
> +            source: textOrStream
> +            context: aContext
> +            class: aClass
> +            environment: anEnvironment
> +            requestor: aRequestor)
> +        noPattern: true
> +        ifFail: failBlock
> + !
> 
> Item was added:
> + ----- Method: Compiler>>compileNoPattern:in:context:notifying:ifFail: (in category 'public access') -----
> + 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
> +        compileCue: (CompilationCue
> +            source: textOrStream
> +            context: aContext
> +            class: aClass
> +            requestor: aRequestor)
> +        noPattern: true
> +        ifFail: failBlock
> + !
> 
> Item was added:
> + ----- Method: Compiler>>compileNoPattern:in:notifying:ifFail: (in category 'public access') -----
> + compileNoPattern: textOrStream in: aClass 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
> +        compileCue: (CompilationCue
> +            source: textOrStream
> +            class: aClass
> +            requestor: aRequestor)
> +        noPattern: true
> +        ifFail: failBlock
> + !
> 
> Item was added:
> + ----- Method: Compiler>>compiledMethodFor:in:to:notifying:ifFail: (in category 'public access') -----
> + compiledMethodFor: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock
> +    "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 |
> +    methodNode := self
> +        compileNoPattern: textOrStream
> +        in: (self classForReceiver: receiver context: aContext)
> +        context: aContext
> +        notifying: aRequestor
> +        ifFail: [^failBlock value].
> +    method := self interactive
> +        ifTrue: [ methodNode generateWithTempNames ] 
> +        ifFalse: [ methodNode generate ].
> +    ^method!
> 
> Item was added:
> + ----- Method: Compiler>>compiledMethodFor:in:to:notifying:ifFail:logged: (in category 'public access logging') -----
> + 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."
> + 
> +    | method |
> +    method := self
> +        compiledMethodFor: textOrStream
> +        in: aContext
> +        to: receiver
> +        notifying: aRequestor
> +        ifFail: [^failBlock value].
> +    logFlag ifTrue:
> +        [SystemChangeNotifier uniqueInstance evaluated: cue stringToLog context: aContext].
> +    ^method!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate: (in category 'public access') -----
> + evaluate: textOrString 
> +    "See 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!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:for: (in category 'public access') -----
> + evaluate: textOrString for: anObject
> +    "See 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!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:for:logged: (in category 'public access logging') -----
> + evaluate: textOrString for: anObject logged: logFlag 
> +    "See 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!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:for:notifying: (in category 'public access') -----
> + evaluate: textOrString for: anObject notifying: aController
> +    "Compile and execute the argument, textOrString with respect to the class 
> +    of anObject. If a compilation error occurs, notify aController."
> + 
> +    ^ self
> +        evaluate: textOrString
> +        in: nil
> +        to: anObject
> +        notifying: aController
> +        ifFail: [^nil]!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:for:notifying:logged: (in category 'public access logging') -----
> + 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
> +        evaluate: textOrString
> +        in: nil
> +        to: anObject
> +        notifying: aController
> +        ifFail: [^nil]
> +        logged: logFlag.!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:in:environment:notifying:ifFail:logged: (in category 'public access logging') -----
> + evaluate: textOrStream in: aContext environment: anEnvironment notifying: aRequestor ifFail: failBlock logged: logFlag
> +    "Compiles the sourceStream into a parse tree, then generates code into
> +     a method. If aContext is not nil, the text can refer to temporaries in that
> +     context (the Debugger uses this). If aRequestor is not nil, then it will receive
> +     a notify:at: message before the attempt to evaluate is aborted. Finally, the 
> +     compiled method is invoked from here via withArgs:executeMethod:, hence
> +     the system no longer creates Doit method litter on errors."
> +    ^self
> +        evaluateCue: (CompilationCue
> +            source: textOrStream
> +            context: aContext
> +            receiver: nil
> +            class: UndefinedObject
> +            environment: anEnvironment
> +            requestor: aRequestor)
> +        ifFail: failBlock
> +        logged: logFlag!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:in:notifying:logged: (in category 'public access logging') -----
> + evaluate: textOrString in: anEnvironment notifying: aController logged: logFlag 
> +    "Compile and execute the argument, textOrString in anEnvironment.
> +    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
> +        evaluate: textOrString
> +        in: nil
> +        environment: anEnvironment
> +        notifying: aController
> +        ifFail: [^nil]
> +        logged: logFlag!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:in:to: (in category 'public access') -----
> + evaluate: aString in: aContext to: aReceiver
> +    "evaluate aString in the given context, and return the result.  2/2/96 sw"
> +    ^self
> +        evaluate: aString
> +        in: aContext
> +        to: aReceiver
> +        notifying: nil
> +        ifFail: [^ #failedDoit]!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:in:to:environment:notifying:ifFail:logged: (in category 'public access logging') -----
> + evaluate: textOrStream in: aContext to: receiver environment: anEnvironment notifying: aRequestor ifFail: failBlock logged: logFlag
> +    "Same as #evaluate:in:to:notifying:ifFail:logged: but with an explicit environment"
> +    ^self
> +        evaluateCue: (CompilationCue
> +            source: textOrStream
> +            context: aContext
> +            receiver: receiver
> +            class: (self classForReceiver: receiver context: aContext)
> +            environment: anEnvironment
> +            requestor: aRequestor)
> +        ifFail: failBlock
> +        logged: logFlag!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:in:to:notifying:ifFail: (in category 'public access') -----
> + evaluate: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock
> +    "Compiles the sourceStream into a parse tree, then generates code into
> +     a method. If aContext is not nil, the text can refer to temporaries in that
> +     context (the Debugger uses this). If aRequestor is not nil, then it will receive
> +     a notify:at: message before the attempt to evaluate is aborted. Finally, the 
> +     compiled method is invoked from here via withArgs:executeMethod:, hence
> +     the system no longer creates Doit method litter on errors."
> +    
> +    | theClass |
> +    theClass := self classForReceiver: receiver context: aContext.
> +    ^self
> +        evaluateCue: (CompilationCue
> +            source: textOrStream
> +            context: aContext
> +            receiver: receiver
> +            class: theClass
> +            environment: theClass environment
> +            requestor: aRequestor)
> +        ifFail: failBlock!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:in:to:notifying:ifFail:logged: (in category 'public access logging') -----
> + evaluate: textOrStream in: aContext to: receiver notifying: aRequestor ifFail: failBlock logged: logFlag
> +    "Compiles the sourceStream into a parse tree, then generates code into
> +     a method. If aContext is not nil, the text can refer to temporaries in that
> +     context (the Debugger uses this). If aRequestor is not nil, then it will receive
> +     a notify:at: message before the attempt to evaluate is aborted. Finally, the 
> +     compiled method is invoked from here via withArgs:executeMethod:, hence
> +     the system no longer creates Doit method litter on errors."
> +    | theClass |
> +    theClass := self classForReceiver: receiver context: aContext.
> +    ^self
> +        evaluateCue: (CompilationCue
> +            source: textOrStream
> +            context: aContext
> +            receiver: receiver
> +            class: theClass
> +            environment: theClass environment
> +            requestor: aRequestor)
> +        ifFail: failBlock
> +        logged: logFlag!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:logged: (in category 'public access logging') -----
> + evaluate: textOrString logged: logFlag
> +    "See 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!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:notifying: (in category 'public access') -----
> + evaluate: textOrString notifying: aController
> +    "See evaluate:for:notifying:. Compilation is carried out 
> +    with respect to nil, i.e., no object."
> + 
> +    ^self evaluate: textOrString for: nil notifying: aController!
> 
> Item was added:
> + ----- Method: Compiler>>evaluate:notifying:logged: (in category 'public access logging') -----
> + evaluate: textOrString notifying: aController logged: logFlag 
> +    "See 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!
> 
> Item was added:
> + ----- Method: Compiler>>evaluateCue:ifFail: (in category 'private') -----
> + evaluateCue: aCue ifFail: failBlock
> +    "Compiles the cue source into a parse tree, then generates code into
> +    a method. Finally, the compiled method is invoked from here via    withArgs:executeMethod:, hence the system no longer creates Doit method
> +    litter on errors."
> + 
> +    | methodNode method value |
> +    methodNode := self compileCue: aCue noPattern: true ifFail: [^failBlock value].
> + 
> +    method := self interactive
> +                ifTrue: [methodNode generateWithTempNames]
> +                ifFalse: [methodNode generate].
> + 
> +    value := cue receiver
> +                withArgs: (cue context ifNil: [#()] ifNotNil: [{cue context}])
> +                executeMethod: method.
> +    ^ value
> + !
> 
> Item was added:
> + ----- Method: Compiler>>evaluateCue:ifFail:logged: (in category 'private') -----
> + evaluateCue: aCue ifFail: failBlock logged: logFlag
> +    "Compiles the cue source into a parse tree, then generates code into
> +    a method. Finally, the compiled method is invoked from here via    withArgs:executeMethod:, hence the system no longer creates Doit method
> +    litter on errors."
> + 
> +    | value |
> +    value := self evaluateCue: aCue ifFail: [^failBlock value].
> +    logFlag ifTrue:
> +        [SystemChangeNotifier uniqueInstance evaluated: cue stringToLog context: cue context].
> +    ^ value
> + !
> 
> Item was added:
> + ----- Method: Compiler>>format:in:notifying: (in category 'public access') -----
> + 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
> +        notifying: aRequestor.
> +    aNode := self formatNoPattern: false ifFail: [^ nil].
> + 
> +    "aSymbol == #colorPrint ifTrue:
> +        [^aNode asColorizedSmalltalk80Text]." "deprecating #colorPrint in favor of Shout --Ron Spengler"
> + 
> +    ^aNode decompileString!
> 
> Item was added:
> + ----- Method: Compiler>>format:in:notifying:decorated: (in category 'public access') -----
> + 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
> +        notifying: aRequestor.
> +    aNode := self formatNoPattern: false ifFail: [^ nil].
> +    ^ aBoolean
> +        ifTrue: [aNode decompileText]
> +        ifFalse: [aNode decompileString]!
> 
> Item was added:
> + ----- Method: Compiler>>formatNoPattern:environment: (in category 'public access') -----
> + formatNoPattern: textOrStream environment: env
> +    "Pretty-print a code snippet. Removes leading 'DoIt' and the '^' in the last statement. To be used in workspace-like tools."
> +    
> +    | aNode |
> +    self setCue: (CompilationCue
> +        source: textOrStream
> +        environment: env).
> +        
> +    aNode := self formatNoPattern: true ifFail: [^ nil].
> + 
> +    ^ (aNode decompileString lines allButFirst "DoIt" collect: [:ea |
> +        ea allButFirst "tab" in: [:result | (result beginsWith: '^ ') ifTrue: [result allButFirst: 2] ifFalse: [result]]])
> +            joinSeparatedBy: String cr!
> 
> Item was added:
> + ----- Method: Compiler>>formatNoPattern:ifFail: (in category 'private') -----
> + formatNoPattern: noPattern ifFail: failBlock
> +    ^(self parser
> +        parseCue: cue 
> +        noPattern: noPattern
> +        ifFail: [^failBlock value]) preen!
> 
> Item was added:
> + ----- Method: Compiler>>from:class:notifying: (in category 'private') -----
> + from: textOrStream class: aClass notifying: req
> +    self setCue:
> +        (CompilationCue
> +            source: textOrStream
> +            class: aClass
> +            requestor: req)
> + !
> 
> Item was added:
> + ----- Method: Compiler>>interactive (in category 'private') -----
> + interactive
> +    "The compilation is interactive if there is a requestor and that requestor does either not care or explicitly allow interactive error correction."
> +    
> +    ^ cue requestor notNil
> +        and: [(cue requestor respondsTo: #wantsInteractiveErrorCorrection) not
> +            or: [cue requestor perform: #wantsInteractiveErrorCorrection]]!
> 
> Item was added:
> + ----- Method: Compiler>>parse:in:notifying: (in category 'public access') -----
> + 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 notifying: req.
> +    ^self parser
> +        parseCue: cue
> +        noPattern: false
> +        ifFail: []!
> 
> Item was added:
> + ----- Method: Compiler>>parser (in category 'public access') -----
> + parser
> + 
> +    parser ifNil: [parser := (cue getClass ifNil: [self class]) newParser].
> +    ^parser!
> 
> Item was added:
> + ----- Method: Compiler>>parser: (in category 'public access') -----
> + parser: aParser
> + 
> +    parser := aParser!
> 
> Item was added:
> + ----- Method: Compiler>>parserClass: (in category 'public access') -----
> + parserClass: aParserClass
> + 
> +    parser := aParserClass new!
> 
> Item was added:
> + ----- Method: Compiler>>setCue: (in category 'private') -----
> + setCue: aCue
> +    cue := aCue!
> 
> Item was added:
> + ----- Method: Compiler>>translate:noPattern:ifFail: (in category 'private') -----
> + translate: ignored noPattern: noPattern ifFail: failBlock
> +    ^self translateNoPattern: noPattern ifFail: failBlock!
> 
> Item was added:
> + ----- Method: Compiler>>translate:noPattern:ifFail:parser: (in category 'public access') -----
> + translate: aStream noPattern: noPattern ifFail: failBlock parser: parser
> +    | tree |
> +    tree := parser
> +            parseCue: cue 
> +            noPattern: noPattern
> +            ifFail: [^ failBlock value].
> +    ^ tree!
> 
> Item was added:
> + ----- Method: Compiler>>translateNoPattern:ifFail: (in category 'private') -----
> + translateNoPattern: noPattern ifFail: failBlock
> +    ^self parser
> +        parseCue: cue 
> +        noPattern: noPattern
> +        ifFail: [^failBlock value]!
> 
> Item was added:
> + InstructionStream subclass: #Decompiler
> +    instanceVariableNames: 'constructor method instVars tempVars constTable stack statements lastPc exit caseExits lastJumpPc lastReturnPc limit hasValue blockStackBase numLocalTemps blockStartsToTempVars tempVarCount lastJumpIfPcStack tempReadCounts'
> +    classVariableNames: 'ArgumentFlag CascadeFlag CaseFlag IfNilFlag OtherwiseFlag'
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !Decompiler commentStamp: 'nice 2/3/2011 22:54' prior: 0!
> + I decompile a method in three phases:
> +    Reverser: postfix byte codes -> prefix symbolic codes (nodes and atoms)
> +    Parser: prefix symbolic codes -> node tree (same as the compiler)
> +    Printer: node tree -> text (done by the nodes)
> +    
> + 
> + instance vars:
> + 
> +    constructor <DecompilerConstructor> an auxiliary knowing how to generate Abstract Syntax Tree (node tree)
> +    method <CompiledMethod> the method being decompiled
> +    instVars <Array of: String> the instance variables of the class implementing method
> +    tempVars <String | (OrderedCollection of: String)> hold the names of temporary variables (if known)
> +        NOTE: POLYMORPHISM WILL BE RESOLVED IN #initSymbols:
> +    constTable <Collection of: ParseNode> parse node associated with byte encoded constants (nil true false 0 1 -1 etc...)
> +    stack <OrderedCollection of: (ParseNode | String | Integer) > multipurpose...
> +    statements <OrderedCollection of: ParseNode> the statements of the method being decompiled 
> +    lastPc <Integer>
> +    exit <Integer>
> +    caseExits <OrderedCollection of: Integer> - stack of exit addresses that have been seen in the branches of caseOf:'s
> +    lastJumpPc <Integer>
> +    lastReturnPc <Integer>
> +    limit <Integer>
> +    hasValue <Boolean>
> +    blockStackBase <Integer>
> +    numLocaltemps <Integer | Symbol> - number of temps local to a block; also a flag indicating decompiling a block
> +    blockStartsToTempVars <Dictionary key: Integer value: (OrderedCollection of: String)>
> +    tempVarCount <Integer> number of temp vars used by the method
> +    lastJumpIfPcStack <OrderedCollection of: Integer> the value of program counter just before the last encountered conditional jumps!
> 
> Item was added:
> + ----- Method: Decompiler class>>initialize (in category 'class initialization') -----
> + initialize
> + 
> +    CascadeFlag := 'cascade'.  "A unique object"
> +    CaseFlag := 'case'. "Ditto"
> +    OtherwiseFlag := 'otherwise'. "Ditto"
> +    ArgumentFlag := 'argument'.  "Ditto"
> +    IfNilFlag := 'ifNil'.  "Ditto"
> + 
> +    "Decompiler initialize"!
> 
> Item was added:
> + ----- Method: Decompiler>>blockForCaseTo: (in category 'control') -----
> + 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!
> 
> Item was added:
> + ----- Method: Decompiler>>blockReturnConstant: (in category 'instruction decoding') -----
> + blockReturnConstant: value
> + 
> +    self pushConstant: value; blockReturnTop!
> 
> Item was added:
> + ----- Method: Decompiler>>blockReturnTop (in category 'instruction decoding') -----
> + blockReturnTop
> +    "No action needed"!
> 
> Item was added:
> + ----- Method: Decompiler>>blockTo: (in category 'control') -----
> + blockTo: end
> +    "Decompile a range of code as in statementsTo:, but return a block node. NB: end is an exclusive index."
> +    | exprs block oldBase lastStatementOfBlockIsNil |
> +    oldBase := blockStackBase.
> +    blockStackBase := stack size.
> +    exprs := self statementsTo: end.
> +    lastStatementOfBlockIsNil := pc < method endPC and: [exprs notEmpty and: [exprs last == (constTable at: 4)]].
> +    lastStatementOfBlockIsNil ifTrue:
> +        [exprs := exprs allButLast].
> +    block := constructor codeBlock: exprs returns: lastReturnPc = lastPc.
> +    blockStackBase := oldBase.
> +    lastReturnPc := -1.  "So as not to mislead outer calls"
> +    ^block!
> 
> Item was added:
> + ----- Method: Decompiler>>case: (in category 'instruction decoding') -----
> + case: dist
> +    "statements = keyStmts CascadeFlag keyValueBlock ... keyStmts"
> + 
> +    | nextCase thenJump stmtStream elements b node cases otherBlock myExits |
> +    nextCase := pc + dist.
> + 
> +    "Now add CaseFlag & keyValueBlock to statements"
> +    statements addLast: stack removeLast.
> +    "Trick: put a flag on the stack.
> +    If it is the last case before otherwise: block, then
> +    - there won't be a dup of caseOf: receiver before sending =
> +    - there won't be a pop in the case handling block"
> +    stack addLast: OtherwiseFlag. "set for next pop"
> +    statements addLast: (self blockForCaseTo: nextCase).
> +        
> +    stack last == OtherwiseFlag
> +        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) == CaseFlag
> +                    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))].!
> 
> Item was added:
> + ----- Method: Decompiler>>checkForClosureCopy:arguments: (in category 'control') -----
> + 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!
> 
> Item was added:
> + ----- Method: Decompiler>>constructorForMethod: (in category 'private') -----
> + constructorForMethod: aMethod
> +    ^DecompilerConstructor new!
> 
> Item was added:
> + ----- Method: Decompiler>>convertToDoLoop: (in category 'private') -----
> + convertToDoLoop: blockBodyTempCounts
> +    "If statements contains the pattern
> +        var := startExpr.
> +        [var <= limit] whileTrue: [...statements... var := var + incConst]
> +    or
> +        var := startExpr.
> +        limit := limitExpr.
> +        [var <= limit] whileTrue: [...statements... var := var + incConst]
> +    then replace this by
> +        startExpr to: limit by: incConst do: [:var | ...statements...]
> +     and answer true."
> +    | whileStmt incrStmt initStmt limitStmt toDoStmt |
> +    whileStmt := statements last.
> +    incrStmt := whileStmt arguments first statements last.
> +    incrStmt isAssignmentNode ifFalse:
> +        [^false].
> +    (self startAndLimitFor: incrStmt variable from: stack into:
> +                            [:startExpr :limitExpr| initStmt := startExpr. limitStmt := limitExpr])
> +        ifTrue:
> +            [| limitInStatements |
> +             limitInStatements := limitStmt isNil
> +                                    and: [statements size > 1
> +                                    and: [self startAndLimitFor: incrStmt variable from: { stack last. (statements last: 2) first } into:
> +                                                [:startExpr :limitExpr| limitStmt := limitExpr]]].
> +            (toDoStmt := statements last toDoFromWhileWithCounts: blockBodyTempCounts init: initStmt limit: limitStmt) ifNil:
> +                [^false].
> +             limitInStatements
> +                ifTrue:
> +                    [stack
> +                        removeLast;
> +                        addLast: toDoStmt.
> +                     statements removeLast: 2]
> +                ifFalse:
> +                    [stack
> +                        removeLast: (limitStmt ifNil: [1] ifNotNil: [2]);
> +                        addLast: toDoStmt.
> +                     statements removeLast]]
> +        ifFalse:
> +            [(self startAndLimitFor: incrStmt variable from: statements allButLast into:
> +                            [:startExpr :limitExpr| initStmt := startExpr. limitStmt := limitExpr]) ifFalse:
> +                [^false].
> +             (toDoStmt := statements last toDoFromWhileWithCounts: blockBodyTempCounts init: initStmt limit: limitStmt) ifNil:
> +                [^false].
> +             statements
> +                removeLast: (limitStmt ifNil: [2] ifNotNil: [3]);
> +                addLast: toDoStmt].
> +    self markTemp: initStmt variable asOutOfScope: -1. "Flag arg as out of scope"
> +    initStmt variable beBlockArg.
> +    limitStmt ifNotNil:
> +        [self markTemp: limitStmt variable asOutOfScope: -2.
> +         toDoStmt arguments at: 1 put: limitStmt value]. "Flag limit as hidden"
> +    ^true!
> 
> Item was added:
> + ----- Method: Decompiler>>decompile:in: (in category '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) methodForDecompile!
> 
> Item was added:
> + ----- Method: Decompiler>>decompile:in:method: (in category 'public access') -----
> + 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)!
> 
> Item was added:
> + ----- Method: Decompiler>>decompile:in:method:using: (in category 'public access') -----
> + 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.
> +            lastJumpIfPcStack := OrderedCollection new.
> +            caseExits := OrderedCollection new.
> +            statements := OrderedCollection new: 20.
> +            numLocalTemps := 0.
> +            self method: method pc: method initialPC.
> +            "skip primitive error code store if necessary"
> +            (method primitive ~= 0 and: [self skipCallPrimitive; willStore]) ifTrue:
> +                [pc := pc + (method encoderClass bytecodeSize: self firstByte).
> +                 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 preen!
> 
> Item was added:
> + ----- Method: Decompiler>>decompileBlock: (in category 'public access') -----
> + decompileBlock: aBlock 
> +    "Decompile aBlock, returning the result as a BlockNode.
> +     Show temp names from source if available."
> +    "Decompiler new decompileBlock: [3 + 4]"
> +    "[3 + 4] decompile decompileString"
> +    aBlock method decompileWithTemps
> +        ifNil: [^nil]
> +        ifNotNil:
> +            [:methodNode|
> +             methodNode nodesDo:
> +                (aBlock isFullBlock
> +                    ifTrue: [[:node| (node pc isVariableBinding and: [node pc key == aBlock method]) ifTrue: [^node]]]
> +                    ifFalse: [[:node| node pc = aBlock startpc ifTrue: [^node]]])].
> +     ^self error: 'cannot find block node matching aBlock'!
> 
> Item was added:
> + ----- Method: Decompiler>>directedSuperSend:numArgs: (in category 'instruction decoding') -----
> + directedSuperSend: selector numArgs: numArgs
> +    stack removeLast. "Discard the pushed class."
> +    ^self send: selector super: true numArgs: numArgs!
> 
> Item was added:
> + ----- Method: Decompiler>>doClosureCopy:copiedValues: (in category 'control') -----
> + doClosureCopy: aCompiledBlock copiedValues: blockCopiedValues
> +    "implementation note: must be invoked on a copy because it modifies states"
> +    | savedPC blockArgs blockTemps blockTempsOffset block mark |
> +    numLocalTemps := aCompiledBlock numTemps - aCompiledBlock numArgs - blockCopiedValues size.
> +    blockTempsOffset := aCompiledBlock numArgs + blockCopiedValues size.
> +    (blockStartsToTempVars notNil "implies we were intialized with temp names."
> +     and: [blockStartsToTempVars includesKey: aCompiledBlock])
> +        ifTrue:
> +            [tempVars := blockStartsToTempVars at: aCompiledBlock]
> +        ifFalse:
> +            [blockArgs := (1 to: aCompiledBlock 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 + aCompiledBlock numArgs) printString].
> +            tempVars := blockArgs, blockCopiedValues, blockTemps].
> +    tempVarCount := tempVarCount + aCompiledBlock numArgs + numLocalTemps.
> +    lastJumpIfPcStack := OrderedCollection new.
> +    caseExits := OrderedCollection new.
> +    statements := OrderedCollection new: 20.
> +    savedPC := pc.
> +    self method: (method := aCompiledBlock) pc: aCompiledBlock initialPC.
> +    mark := stack size.
> +    block := self blockTo: aCompiledBlock endPC + 1.
> +    mark = stack size ifFalse: [self error: 'block did alter the stack'].
> +    ^((constructor
> +            codeArguments: (tempVars copyFrom: 1 to: aCompiledBlock numArgs)
> +            temps: (tempVars copyFrom: blockTempsOffset + 1 to: blockTempsOffset + numLocalTemps)
> +            block: block)
> +                pc: aCompiledBlock -> savedPC; "c.f. BytecodeEncoder>>pc"
> +                yourself).!
> 
> Item was added:
> + ----- Method: Decompiler>>doClosureCopyCopiedValues:numArgs:blockSize: (in category 'control') -----
> + doClosureCopyCopiedValues: blockCopiedValues numArgs: numArgs blockSize: blockSize
> +    | startpc savedTemps savedTempVarCount savedNumLocalTemps
> +      jump blockArgs blockTemps blockTempsOffset block |
> +    savedTemps := tempVars.
> +    savedTempVarCount := tempVarCount.
> +    savedNumLocalTemps := numLocalTemps.
> +    jump := blockSize + (startpc := pc).
> +    numLocalTemps := BlockLocalTempCounter
> +                            tempCountForBlockStartingAt: pc
> +                            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)
> +                            pc: startpc;
> +                            yourself).
> +    tempVars := savedTemps.
> +    tempVarCount := savedTempVarCount.
> +    numLocalTemps := savedNumLocalTemps!
> 
> Item was added:
> + ----- Method: Decompiler>>doDup (in category 'instruction decoding') -----
> + doDup
> +    stack last == CaseFlag
> +        ifTrue:
> +            ["We are in the process of decompiling a caseOf:"
> +            stack addLast: CaseFlag.
> +            ^self].
> +    stack last == CascadeFlag
> +        ifFalse:
> +            ["Save position and mark cascade"
> +            stack addLast: statements size.
> +            stack addLast: CascadeFlag].
> +    stack addLast: CascadeFlag!
> 
> Item was added:
> + ----- Method: Decompiler>>doPop (in category 'instruction decoding') -----
> + doPop
> + 
> +    stack isEmpty ifTrue:
> +        ["Ignore pop in first leg of ifNil for value"
> +        ^ self].
> +    stack last == OtherwiseFlag
> +        ifTrue: [stack removeLast]
> +        ifFalse: [statements addLast: stack removeLast].!
> 
> Item was added:
> + ----- Method: Decompiler>>doStore: (in category '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])!
> 
> Item was added:
> + ----- Method: Decompiler>>initSymbols: (in category 'initialize-release') -----
> + 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 mapFromBlockKeysIn: 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].
> +    tempReadCounts := Dictionary new!
> 
> Item was added:
> + ----- Method: Decompiler>>interpretNextInstructionFor: (in category 'private') -----
> + 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, '>'.
> +    (varNames indexOf: 'stack') 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 flush.
> +    ^super interpretNextInstructionFor: client!
> 
> Item was added:
> + ----- Method: Decompiler>>jump: (in category 'instruction decoding') -----
> + jump: dist
> +    | blockBody destPc nextPC |
> +    destPc := pc + dist.
> +    (lastJumpIfPcStack isEmpty or: [dist < 0 and: [destPc > lastJumpIfPcStack last]])
> +        ifTrue:
> +            ["Rule: aBackward jump not crossing a Bfp/Btp must be a repeat"
> +            nextPC := pc.
> +            pc := destPc.
> +            blockBody := self statementsTo: lastPc.
> +            blockBody size timesRepeat: [statements removeLast].
> +            pc := nextPC.
> +            statements addLast:
> +                (constructor
> +                    codeMessage: (constructor codeBlock: blockBody returns: false)
> +                    selector: (constructor
> +                                codeSelector: #repeat
> +                                code: #macro)
> +                    arguments: #()).
> +            ]
> +        ifFalse:
> +            [exit := destPc.
> +            lastJumpPc := lastPc]!
> 
> Item was added:
> + ----- Method: Decompiler>>jump:if: (in category 'instruction decoding') -----
> + jump: dist if: condition
> + 
> +    | savePc sign elsePc elseStart end cond ifExpr thenBlock elseBlock
> +      thenJump elseJump condHasValue isIfNil saveStack |
> +    lastJumpIfPcStack addLast: lastPc.
> +    stack last == CaseFlag ifTrue: [^ [self case: dist] ensure: [lastJumpIfPcStack removeLast]].
> +    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:
> +            [| blockBody blockArgs savedReadCounts blockBodyReadCounts selector |
> +             "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 searching for the node
> +              with the relevant pc."
> +            stack := saveStack.
> +            savedReadCounts := tempReadCounts copy.
> +            pc := thenJump.
> +            blockBody := self statementsTo: elsePc.
> +            blockBodyReadCounts := tempReadCounts.
> +            savedReadCounts keysAndValuesDo:
> +                [:temp :count|
> +                 blockBodyReadCounts at: temp put: (blockBodyReadCounts at: temp) - count].
> +            tempReadCounts := savedReadCounts.
> +            "discard unwanted statements from block"
> +            blockBody size - 1 timesRepeat: [statements removeLast].
> +            blockArgs := thenBlock statements = constructor codeEmptyBlock statements
> +                            ifTrue: [#()]
> +                            ifFalse: [{ thenBlock }].
> +            selector := blockArgs isEmpty
> +                            ifTrue: [sign ifTrue: [#whileFalse] ifFalse: [#whileTrue]]
> +                            ifFalse: [sign ifTrue: [#whileFalse:] ifFalse: [#whileTrue:]].
> +            statements addLast:
> +                (constructor
> +                    codeMessage: (constructor codeBlock: blockBody returns: false)
> +                    selector: (constructor codeSelector: selector code: #macro)
> +                    arguments: blockArgs).
> +            pc := elseStart.
> +            selector == #whileTrue: ifTrue:
> +                [self convertToDoLoop: blockBodyReadCounts]]
> +        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:
> +                            [(sign
> +                                ifTrue: [{elseBlock. thenBlock}]
> +                                ifFalse: [{thenBlock. elseBlock}]) in:
> +                                    [:args |
> +                                    (constructor
> +                                        decodeIfNilWithReceiver: ifExpr
> +                                        selector: #ifTrue:ifFalse:
> +                                        arguments: args
> +                                        tempReadCounts: tempReadCounts) ifNil:
> +                                            [constructor
> +                                                codeMessage: ifExpr
> +                                                selector: (constructor codeSelector: #ifTrue:ifFalse: code: #macro)
> +                                                arguments:     args]]].
> +            stack := saveStack.
> +            condHasValue
> +                ifTrue: [stack addLast: cond]
> +                ifFalse: [statements addLast: cond]].
> +    lastJumpIfPcStack removeLast.!
> 
> Item was added:
> + ----- Method: Decompiler>>mapFromBlockKeysIn:toTempVarsFrom:constructor: (in category 'initialize-release') -----
> + mapFromBlockKeysIn: aMethod toTempVarsFrom: schematicTempNamesString constructor: aDecompilerConstructor
> +    "Answer a (n Identity) Dictionary from block start key to sequence of TermpVarNode & RemoteTempVarNode"
> +    | startMap tempMap |
> +    "This rather odd construct is to avoid recursion if we used aMethod methodNode startKeysToBlockExtents,
> +     which will invoke this Decompiler if a method has no source."
> +    startMap := (DebuggerMethodMap
> +                    forMethod: aMethod
> +                    methodNode: nil) startKeysToBlockExtents.
> +    tempMap := aMethod
> +                    mapFromBlockKeys: (startMap keys asArray sort: [:a :b| (startMap at: a) first <= (startMap at: b) first])
> +                    toSchematicTemps: schematicTempNamesString.
> +    tempMap keysAndValuesDo:
> +        [:startKey :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"
> +            tempMap at: startKey put: tempVector]].
> +    ^tempMap!
> 
> Item was added:
> + ----- Method: Decompiler>>markTemp:asOutOfScope: (in category 'private') -----
> + markTemp: tempVarNode asOutOfScope: scopeFlag
> +    tempVarNode scope: scopeFlag.
> +    tempReadCounts removeKey: tempVarNode ifAbsent: []!
> 
> Item was added:
> + ----- Method: Decompiler>>methodRefersOnlyOnceToTemp: (in category 'private') -----
> + 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
> + !
> 
> Item was added:
> + ----- Method: Decompiler>>methodReturnConstant: (in category 'instruction decoding') -----
> + methodReturnConstant: value
> + 
> +    self pushConstant: value; methodReturnTop!
> 
> Item was added:
> + ----- Method: Decompiler>>methodReturnReceiver (in category 'instruction decoding') -----
> + methodReturnReceiver
> + 
> +    self pushReceiver; methodReturnTop!
> 
> Item was added:
> + ----- Method: Decompiler>>methodReturnTop (in category 'instruction decoding') -----
> + 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!
> 
> Item was added:
> + ----- Method: Decompiler>>popIntoLiteralVariable: (in category 'instruction decoding') -----
> + popIntoLiteralVariable: value
> + 
> +    self pushLiteralVariable: value; doStore: statements!
> 
> Item was added:
> + ----- Method: Decompiler>>popIntoReceiverVariable: (in category 'instruction decoding') -----
> + popIntoReceiverVariable: offset
> + 
> +    self pushReceiverVariable: offset; doStore: statements!
> 
> Item was added:
> + ----- Method: Decompiler>>popIntoRemoteTemp:inVectorAt: (in category 'instruction decoding') -----
> + popIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
> +    self pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex; doStore: statements!
> 
> Item was added:
> + ----- Method: Decompiler>>popIntoTemporaryVariable: (in category 'instruction decoding') -----
> + popIntoTemporaryVariable: offset
> +    | maybeTVTag tempVector start |
> +    maybeTVTag := stack last.
> +    ((maybeTVTag isMemberOf: Association)
> +     and: [maybeTVTag key == #pushNewArray]) ifTrue:
> +        [blockStartsToTempVars "implies we were intialized with temp names."
> +            ifNotNil: "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]])]
> +            ifNil: "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].
> +    stack addLast: (offset >= tempVars size
> +                        ifTrue: "Handle the case of chained LiteralVariableBinding assigments"
> +                            [stack at: (offset + 1 - tempVars size)]
> +                        ifFalse: "A regular argument or temporary"
> +                            [tempVars at: offset + 1]).
> +    self doStore: statements!
> 
> Item was added:
> + ----- Method: Decompiler>>popTo: (in category '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!
> 
> Item was added:
> + ----- Method: Decompiler>>pushActiveContext (in category 'instruction decoding') -----
> + pushActiveContext
> + 
> +    stack addLast: constructor codeThisContext!
> 
> Item was added:
> + ----- Method: Decompiler>>pushClosureCopyNumCopiedValues:numArgs:blockSize: (in category 'instruction decoding') -----
> + pushClosureCopyNumCopiedValues: numCopied numArgs: numArgs blockSize: blockSize
> +    | copiedValues |
> +    copiedValues := ((1 to: numCopied) collect: [:ign| stack removeLast]) reversed.
> +    self doClosureCopyCopiedValues: copiedValues numArgs: numArgs blockSize: blockSize!
> 
> Item was added:
> + ----- Method: Decompiler>>pushConsArrayWithElements: (in category 'instruction decoding') -----
> + pushConsArrayWithElements: numElements 
> +    | array |
> +    array := Array new: numElements.
> +    numElements to: 1 by: -1 do:
> +        [:i|
> +        array at: i put: stack removeLast].
> +    stack addLast: (constructor codeBrace: array)!
> 
> Item was added:
> + ----- Method: Decompiler>>pushConstant: (in category '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!
> 
> Item was added:
> + ----- Method: Decompiler>>pushFullClosure:numCopied: (in category 'instruction decoding') -----
> + pushFullClosure: aCompiledBlock numCopied: numCopied
> +    | copiedValues |
> +    copiedValues := ((1 to: numCopied) collect: [:ign| stack removeLast]) reversed.
> +    stack addLast: (self shallowCopy doClosureCopy: aCompiledBlock copiedValues: copiedValues)!
> 
> Item was added:
> + ----- Method: Decompiler>>pushLiteralVariable: (in category 'instruction decoding') -----
> + pushLiteralVariable: assoc
> + 
> +    stack addLast: (constructor codeAnyLitInd: assoc)!
> 
> Item was added:
> + ----- Method: Decompiler>>pushNewArrayOfSize: (in category 'instruction decoding') -----
> + pushNewArrayOfSize: size
> +    stack addLast: #pushNewArray -> (Array new: size)!
> 
> Item was added:
> + ----- Method: Decompiler>>pushReceiver (in category 'instruction decoding') -----
> + pushReceiver
> + 
> +    stack addLast: (constTable at: 1)!
> 
> Item was added:
> + ----- Method: Decompiler>>pushReceiverVariable: (in category 'instruction decoding') -----
> + 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!
> 
> Item was added:
> + ----- Method: Decompiler>>pushRemoteTemp:inVectorAt: (in category 'instruction decoding') -----
> + pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
> +    stack addLast: ((tempVars at: tempVectorIndex + 1) remoteTemps at: remoteTempIndex + 1)!
> 
> Item was added:
> + ----- Method: Decompiler>>pushSpecialConstant: (in category 'instruction decoding') -----
> + pushSpecialConstant: value
> +    ^self pushConstant: value!
> 
> Item was added:
> + ----- Method: Decompiler>>pushTemporaryVariable: (in category 'instruction decoding') -----
> + pushTemporaryVariable: offset
> +    | node |
> +    offset >= tempVars size
> +                ifTrue: "Handle the case of chained LiteralVariableBinding assigments"
> +                    [self halt.
> +                     node := stack at: offset + 1 - tempVars size]
> +                ifFalse: "A regular argument or temporary"
> +                    [node := tempVars at: offset + 1.
> +                     node isArg ifFalse: "count temp reads for the whileTrue: => to:do: transformation."
> +                        [tempReadCounts at: node put: (tempReadCounts at: node ifAbsent: [0]) + 1]].
> +    stack addLast: node!
> 
> Item was added:
> + ----- Method: Decompiler>>quickMethod (in category 'private') -----
> + 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'!
> 
> Item was added:
> + ----- Method: Decompiler>>send:super:numArgs: (in category 'instruction decoding') -----
> + send: selector super: superFlag numArgs: numArgs
> + 
> +    | args rcvr selNode msgNode messages |
> +    args := Array new: numArgs.
> +    (numArgs to: 1 by: -1) do:
> +        [:i | args at: i put: stack removeLast].
> +    rcvr := stack removeLast.
> +    superFlag ifTrue: [rcvr := constructor codeSuper].
> +    selNode := constructor codeAnySelector: selector.
> +    rcvr == CaseFlag
> +        ifTrue:
> +            [| cases stmtStream elements node b |
> +            selector == #= ifTrue:
> +                    [" = signals a case statement..."
> +                    statements addLast: args first.
> +                    stack addLast: rcvr. "restore CaseFlag"
> +                    ^ self].
> +            selector = #caseError ifFalse: [self error: 'unexpected message send while decompiling a caseOf:'].
> +            stmtStream := ReadStream on: (self popTo: stack removeLast).
> +            
> +            elements := OrderedCollection new.
> +            b := OrderedCollection new.
> +            [stmtStream atEnd] whileFalse:
> +                [(node := stmtStream next) == CaseFlag
> +                    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.
> +            
> +            stack addLast:
> +                (constructor
> +                    codeMessage: stack removeLast
> +                    selector: (constructor codeSelector: #caseOf: code: #macro)
> +                    arguments: (Array with: cases)).
> +            ^self].
> +    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 removeLast; addLast: CaseFlag; addLast: CaseFlag.    "Properly mark the case statement"
> +                        ^ self].
> +                    selector == #== ifTrue:
> +                        [" == signals an ifNil: for value..."
> +                        stack removeLast; removeLast.
> +                        rcvr := stack removeLast.
> +                        stack addLast: IfNilFlag;
> +                            addLast: (constructor
> +                                codeMessage: rcvr
> +                                selector: selNode
> +                                arguments: args).
> +                        ^ self]]
> +                ifFalse:
> +                    [(self willJumpIfTrue and: [selector == #==]) ifTrue:
> +                        [" == signals an ifNotNil: for value..."
> +                        stack removeLast; removeLast.
> +                        rcvr := stack removeLast.
> +                        stack addLast: IfNilFlag;
> +                            addLast: (constructor
> +                                codeMessage: rcvr
> +                                selector: selNode
> +                                arguments: args).
> +                        ^ self]].
> +            msgNode := constructor
> +                            codeCascadedMessage: selNode
> +                            arguments: args.
> +            stack last == CascadeFlag ifFalse:
> +                ["Last message of a cascade"
> +                statements addLast: msgNode.
> +                messages := self popTo: stack removeLast.  "Depth saved by first dup"
> +                msgNode := constructor
> +                                codeCascade: stack removeLast
> +                                messages: messages]]
> +        ifFalse:
> +            [msgNode := constructor
> +                        codeMessage: rcvr
> +                        selector: selNode
> +                        arguments: args].
> +    stack addLast: msgNode!
> 
> Item was added:
> + ----- Method: Decompiler>>sendSpecial:numArgs: (in category 'instruction decoding') -----
> + sendSpecial: selector numArgs: numArgs
> +    ^self send: selector super: false numArgs: numArgs!
> 
> Item was added:
> + ----- Method: Decompiler>>startAndLimitFor:from:into: (in category 'private') -----
> + startAndLimitFor: incrVar from: aStack into: binaryBlock
> +    "If incrVar matches the increment of a whileLoop at the end of statements
> +     evaluate binaryBlock with the init statement for incrVar and the init statement
> +     for the block's limit, if any, and answer true.  Otherwise answer false.  Used to
> +     help convert whileTrue: loops into to:[by:]do: loops."
> +    | guard initExpr limitInit size |
> +    ((size := aStack size) >= 1
> +     and: [(initExpr := aStack at: size) ~~ CaseFlag]
> +     and: [initExpr isAssignmentNode]) ifFalse:
> +        [^false].
> +    initExpr variable == incrVar ifTrue:
> +        [binaryBlock value: initExpr value: nil.
> +         ^true].
> +    limitInit := initExpr.
> +    (size >= 2
> +     and: [(initExpr := aStack at: size - 1) isAssignmentNode
> +     and: [initExpr variable == incrVar
> +     and: [(guard := statements last receiver) isBlockNode
> +     and: [guard statements size = 1
> +     and: [(guard := guard statements first) isMessageNode
> +     and: [guard receiver == incrVar
> +     and: [guard arguments first == limitInit variable]]]]]]]) ifTrue:
> +        [binaryBlock value: initExpr value: limitInit.
> +         ^true].
> +    ^false!
> 
> Item was added:
> + ----- Method: Decompiler>>statementsForCaseTo: (in category 'control') -----
> + 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 OtherwiseFlag 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 OtherwiseFlag"
> +    [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 == OtherwiseFlag
> +                ifFalse: [ statements addLast: stack removeLast] ].
> +    lastJumpPc = lastPc ifFalse: [exit := pc].
> +    caseExits add: exit.
> +    ^self popTo: blockPos!
> 
> Item was added:
> + ----- Method: Decompiler>>statementsTo: (in category '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."
> + 
> +    | encoderClass blockPos stackPos localLastPC |
> +    encoderClass := method encoderClass.
> +    blockPos := statements size.
> +    stackPos := stack size.
> +    [pc < end]
> +        whileTrue:
> +            [lastPc := localLastPC := pc.  limit := end.  "for performs"
> +             "If you want instrumentation replace the following statement with this one,
> +              and edit the implementation:
> +                self interpretNextInstructionFor: self"
> +            encoderClass interpretNextInstructionFor: self in: 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!
> 
> Item was added:
> + ----- Method: Decompiler>>storeIntoLiteralVariable: (in category 'instruction decoding') -----
> + storeIntoLiteralVariable: assoc
> + 
> +    self pushLiteralVariable: assoc; doStore: stack!
> 
> Item was added:
> + ----- Method: Decompiler>>storeIntoReceiverVariable: (in category 'instruction decoding') -----
> + storeIntoReceiverVariable: offset
> + 
> +    self pushReceiverVariable: offset; doStore: stack!
> 
> Item was added:
> + ----- Method: Decompiler>>storeIntoRemoteTemp:inVectorAt: (in category 'instruction decoding') -----
> + storeIntoRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex
> +    self pushRemoteTemp: remoteTempIndex inVectorAt: tempVectorIndex; doStore: stack!
> 
> Item was added:
> + ----- Method: Decompiler>>storeIntoTemporaryVariable: (in category 'instruction decoding') -----
> + storeIntoTemporaryVariable: offset
> +    stack addLast: (offset >= tempVars size
> +                        ifTrue: "Handle the case of chained LiteralVariableBinding assigments"
> +                            [stack at: (offset + 1 - tempVars size)]
> +                        ifFalse: "A regular argument or temporary"
> +                            [tempVars at: offset + 1]).
> +    self doStore: stack!
> 
> Item was added:
> + ----- Method: Decompiler>>tempAt: (in category 'public access') -----
> + tempAt: offset
> +    "Needed by BraceConstructor<PopIntoTemporaryVariable"
> + 
> +    ^tempVars at: offset + 1!
> 
> Item was added:
> + ----- Method: Decompiler>>withTempNames: (in category 'initialize-release') -----
> + 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!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    "I am not really a ParseNode.  Only here to access constants defined in parseNode."
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeAnyLitInd: (in category 'constructor') -----
> + codeAnyLitInd: association
> + 
> +    ^LiteralVariableNode new
> +        name: association key
> +        key: association
> +        index: nil
> +        type: LdLitIndType!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeAnyLiteral: (in category 'constructor') -----
> + codeAnyLiteral: value
> + 
> +    ^LiteralNode new
> +        key: value
> +        index: 0
> +        type: LdLitType!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeAnySelector: (in category 'constructor') -----
> + codeAnySelector: selector
> + 
> +    ^SelectorNode new
> +        key: selector
> +        index: nil
> +        type: SendType!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeArguments:temps:block: (in category 'constructor') -----
> + codeArguments: args temps: temps block: block 
> +    block
> +        arguments: args;
> +        temporaries: temps.
> +    ^block!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeAssignTo:value: (in category 'constructor') -----
> + codeAssignTo: variable value: expression
> + 
> +    ^AssignmentNode new variable: variable value: expression!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeBlock:returns: (in category 'constructor') -----
> + codeBlock: statements returns: returns
> +    ^ BlockNode statements: statements returns: returns!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeBrace: (in category 'constructor') -----
> + codeBrace: elements
> + 
> +    ^BraceNode new elements: elements!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeCascade:messages: (in category 'constructor') -----
> + codeCascade: receiver messages: messages
> + 
> +    ^ (BraceNode new matchBraceStreamReceiver: receiver messages: messages)
> +        ifNil: [CascadeNode new receiver: receiver messages: messages]!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeCascadedMessage:arguments: (in category 'constructor') -----
> + codeCascadedMessage: selector arguments: arguments
> + 
> +    ^self
> +        codeMessage: nil
> +        selector: selector
> +        arguments: arguments!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeConstants (in category '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])!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeEmptyBlock (in category 'constructor') -----
> + codeEmptyBlock
> +    ^ BlockNode withJust: NodeNil!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeInst: (in category 'constructor') -----
> + codeInst: index
> + 
> +    ^InstanceVariableNode new
> +        name: (instVars at: index + 1 ifAbsent: ['unknown', index asString])
> +        index: index + 1!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeMessage:selector:arguments: (in category 'constructor') -----
> + codeMessage: receiver selector: selector arguments: arguments
> +    | symbol |
> +    symbol := selector key.
> +    (self
> +        decodeLiteralVariableValueDereferenceWithReceiver: receiver
> +        selector: symbol
> +        arguments: arguments) ifNotNil: [:node| ^node].
> + 
> +    ^MessageNode new
> +            receiver: receiver selector: selector
> +            arguments: arguments
> +            precedence: symbol precedence!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeMethod:block:tempVars:primitive:class: (in category 'constructor') -----
> + codeMethod: selector block: block tempVars: vars primitive: primitive class: class
> + 
> +    | blockNode selectorNode visibleTemps invisibleTemps arguments temporaries properties |
> +    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.
> +    properties := method properties copy.
> +    (properties at: #onceCache ifAbsent: []) ifNotNil:
> +        [:onceCache|
> +         properties := properties copyWithout: (Association
> +                                                    key: #onceCache
> +                                                    value: onceCache)].
> +    blockNode := MethodNode new
> +        selector: selectorNode
> +        arguments: arguments
> +        precedence: selector precedence
> +        temporaries: temporaries
> +        block: block
> +        encoder: (method encoderClass new initScopeAndLiteralTables
> +                    temps: visibleTemps, invisibleTemps
> +                    literals: literalValues
> +                    class: class)
> +        primitive: primitive
> +        properties: properties.
> +    blockNode properties method: blockNode.
> +    ^blockNode!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeRemoteTemp:remoteTemps: (in category 'as yet unclassified') -----
> + codeRemoteTemp: index remoteTemps: tempVector
> + 
> +    ^(RemoteTempVectorNode new
> +        name: '_r', index printString
> +        index: index
> +        type: LdTempType
> +        scope: 0)
> +            remoteTemps: tempVector;
> +            yourself!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeSelector:code: (in category 'constructor') -----
> + codeSelector: sel code: code
> + 
> +    ^SelectorNode new key: sel code: code!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeSuper (in category 'constructor') -----
> + codeSuper
> + 
> +    ^NodeSuper!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeTemp: (in category 'constructor') -----
> + codeTemp: index
> + 
> +    ^ TempVariableNode new
> +        name: 't' , (index + 1) printString
> +        index: index
> +        type: LdTempType
> +        scope: 0!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeTemp:named: (in category 'constructor') -----
> + codeTemp: index named: tempName
> + 
> +    ^ TempVariableNode new
> +        name: tempName
> +        index: index
> +        type: LdTempType
> +        scope: 0!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>codeThisContext (in category 'constructor') -----
> + codeThisContext
> + 
> +    ^NodeThisContext!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>decodeIfNilWithReceiver:selector:arguments:tempReadCounts: (in category 'constructor') -----
> + decodeIfNilWithReceiver: receiver selector: selector arguments: arguments tempReadCounts: tempReadCounts
> +    
> +    | node temp |
> +    receiver ifNil: [ ^nil ].        "For instance, when cascading"
> +    selector == #ifTrue:ifFalse:
> +        ifFalse: [^ nil].
> +                
> +    (receiver isMessage: #==
> +                receiver: nil
> +                arguments: [:argNode | argNode == NodeNil])
> +        ifFalse: [^ nil].
> +        
> +    "Like #to:(by:)do:, support only local temps."
> +    (((temp := receiver ifNilTemporary) isNil or: [tempReadCounts includesKey: temp]) or: [
> +        "What about 'object ifNotNil: [:o | ]', which as not read the blockArg? Just check that there is no remote vector pointing to it."
> +        tempReadCounts keys noneSatisfy:
> +            [:otherTemp |
> +                otherTemp isIndirectTempVector
> +                    ifTrue: [otherTemp remoteTemps anySatisfy:
> +                        [:remoteTemp |
> +                        remoteTemp name = temp name]]
> +                    ifFalse: [otherTemp name = temp name]]
> +            ])
> +        ifFalse: [^ nil].
> +        
> +    node := (MessageNode new
> +            receiver: receiver
> +            selector: (SelectorNode new key: #ifTrue:ifFalse: code: #macro)
> +            arguments: arguments
> +            precedence: 3).
> + 
> +    "Reconfigure the message node to #ifNil:ifNotNil:. Note that original* instance variables keep their optimized format. See MessageNode >> #printIfNilNotNil:indent:."    
> +    node
> +        noteSpecialSelector: #ifNil:ifNotNil:;
> +        selector: (SelectorNode new key: #ifNil:ifNotNil:).
> +    
> +    temp ifNil: [^ node].
> +    temp isTemp ifFalse: [^ node].
> +    
> +    (arguments second isJust: NodeNil) not ifTrue:
> +        [temp beBlockArg.
> +        node arguments: {
> +            arguments first.
> +            arguments second copy arguments: { temp }; yourself }].
> +                
> +    ^ node!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>decodeLiteralVariableValueDereferenceWithReceiver:selector:arguments: (in category 'constructor') -----
> + decodeLiteralVariableValueDereferenceWithReceiver: receiver selector: selector arguments: arguments
> +    | varNode |
> +    (receiver notNil "cascades"
> +     and: [receiver isLiteralNode
> +     and: [receiver key isVariableBinding]]) ifFalse:
> +        [^nil].
> +    varNode := self codeAnyLitInd: receiver key.
> +    selector = #value ifTrue:
> +        [^varNode].
> +    ^selector = #value: ifTrue:
> +        [self codeAssignTo: varNode value: arguments first]!
> 
> Item was added:
> + ----- Method: DecompilerConstructor>>method:class:literals: (in category 'initialize-release') -----
> + method: aMethod class: aClass literals: literals
> + 
> +    method := aMethod.
> +    instVars := aClass allInstVarNames.
> +    nArgs := method numArgs.
> +    literalValues := literals!
> 
> Item was added:
> + ----- Method: Dictionary>>bindingOf: (in category '*Compiler') -----
> + bindingOf: varName
> + 
> +    ^self associationAt: varName ifAbsent: nil!
> 
> Item was added:
> + ----- Method: Dictionary>>bindingOf:ifAbsent: (in category '*Compiler') -----
> + bindingOf: varName ifAbsent: aBlock
> + 
> +    ^self associationAt: varName ifAbsent: aBlock!
> 
> Item was added:
> + ----- Method: Dictionary>>bindingsDo: (in category '*Compiler') -----
> + bindingsDo: aBlock
> +    ^self associationsDo: aBlock!
> 
> Item was added:
> + ParseNode subclass: #Encoder
> +    instanceVariableNames: 'scopeTable nTemps supered requestor class selector literalStream selectorSet litIndSet litSet sourceRanges globalSourceRanges addedExtraLiterals optimizedSelectors cue'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !Encoder commentStamp: 'cwp 12/26/2012 23:29' 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.!
> 
> Item was added:
> + ----- Method: Encoder>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    "I am not really a ParseNode.  Only here to access constants defined in parseNode."
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: Encoder>>allLiterals (in category 'results') -----
> + allLiterals
> +    addedExtraLiterals ifFalse:
> +        [addedExtraLiterals := true.
> +        "Put the optimized selectors in literals so as to browse senders more easily"
> +        optimizedSelectors := optimizedSelectors reject: [:e| literalStream originalContents hasLiteral: e].
> +        optimizedSelectors isEmpty ifFalse: [
> +            "Use one entry per literal if enough room, else make anArray"
> +            literalStream position + optimizedSelectors size + 2 >= self maxNumLiterals
> +                ifTrue: [self litIndex: optimizedSelectors asArray]
> +                ifFalse: [optimizedSelectors do: [:e | self litIndex: e]]].
> +        "Add a slot for selector or MethodProperties"
> +        self litIndex: nil.
> +        self litIndex: self associationForClass].
> +    ^literalStream contents!
> 
> Item was added:
> + ----- Method: Encoder>>associationForClass (in category 'results') -----
> + associationForClass
> +    | assoc |
> +    assoc := self environment associationAt: cue getClass name ifAbsent: [nil].
> +    ^assoc value == cue getClass
> +        ifTrue: [assoc]
> +        ifFalse: [Association new value: cue getClass]!
> 
> Item was added:
> + ----- Method: Encoder>>autoBind: (in category 'temps') -----
> + 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!
> 
> Item was added:
> + ----- Method: Encoder>>bindArg: (in category 'temps') -----
> + bindArg: name 
> +    "Declare an argument."
> +    | node |
> +    nTemps >= 15
> +        ifTrue: [^self notify: 'Too many arguments'].
> +    node := self bindTemp: name.
> +    ^ node nowHasDef nowHasRef!
> 
> Item was added:
> + ----- Method: Encoder>>bindBlockArg:within: (in category 'temps') -----
> + 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!
> 
> Item was added:
> + ----- Method: Encoder>>bindBlockTemp: (in category 'temps') -----
> + 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
> + !
> 
> Item was added:
> + ----- Method: Encoder>>bindBlockTemp:within: (in category 'temps') -----
> + 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!
> 
> Item was added:
> + ----- Method: Encoder>>bindTemp: (in category 'temps') -----
> + 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 already used in this method']
> +            ifFalse:[self warnAboutShadowed: name]].
> +    ^self reallyBind: name!
> 
> Item was added:
> + ----- Method: Encoder>>bindTemp:in: (in category 'temps') -----
> + 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 already used in this method']
> +            ifFalse:[Transcript 
> +                show: '(', name, ' is shadowed in "' , cue getClass printString , '>>' , methodSelector printString , '")']].
> +    ^self reallyBind: name!
> 
> Item was added:
> + ----- Method: Encoder>>bindUndeclaredTemp: (in category 'private') -----
> + bindUndeclaredTemp: name
> +    ^scopeTable at: name put: (self newUndeclaredTemp: name)!
> 
> Item was added:
> + ----- Method: Encoder>>cantStoreInto: (in category 'encoding') -----
> + cantStoreInto: varName
> + 
> +    ^StdVariables includesKey: varName!
> 
> Item was added:
> + ----- Method: Encoder>>classEncoding (in category '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."
> +    ^ cue getClass!
> 
> Item was added:
> + ----- Method: Encoder>>doItInContextName (in category 'encoding') -----
> + doItInContextName
> +    ^'ThisContext'!
> 
> Item was added:
> + ----- Method: Encoder>>encodeLiteral: (in category 'encoding') -----
> + encodeLiteral: object
> +    ^self
> +        name: object
> +        key: object
> +        class: LiteralNode
> +        type: LdLitType
> +        set: litSet!
> 
> Item was added:
> + ----- Method: Encoder>>encodeSelector: (in category 'encoding') -----
> + encodeSelector: aSelector
> + 
> +    ^self
> +        name: aSelector
> +        key: aSelector
> +        class: SelectorNode
> +        type: SendType
> +        set: selectorSet!
> 
> Item was added:
> + ----- Method: Encoder>>encodeVariable: (in category 'encoding') -----
> + encodeVariable: name
> +    ^ self encodeVariable: name sourceRange: nil ifUnknown: [ self undeclared: name ]!
> 
> Item was added:
> + ----- Method: Encoder>>encodeVariable:ifUnknown: (in category 'encoding') -----
> + encodeVariable: name ifUnknown: action
> +    ^self encodeVariable: name sourceRange: nil ifUnknown: action!
> 
> Item was added:
> + ----- Method: Encoder>>encodeVariable:sourceRange:ifUnknown: (in category 'encoding') -----
> + 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
> +            ifTrue: [action value]
> +            ifFalse: [self notify: 'out of scope']].
> +    ^varNode!
> 
> Item was added:
> + ----- Method: Encoder>>environment (in category 'encoding') -----
> + environment
> +    "Answer the environment of the current compilation context,
> +     be it in a class or global (e.g. a workspace)"
> +    ^cue environment!
> 
> Item was added:
> + ----- Method: Encoder>>fillDict:with:mapping:to: (in category '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)]!
> 
> Item was added:
> + ----- Method: Encoder>>fixTemp: (in category 'temps') -----
> + fixTemp: name
> +    | node |
> +    node := scopeTable at: name ifAbsent: [].
> +    (node isTemp and: [node isIndirectTempVector not]) ifFalse:
> +        [self error: 'can only fix a floating temp var'].
> +    node index: nTemps.
> +    nTemps := nTemps + 1.
> +    ^node!
> 
> Item was added:
> + ----- Method: Encoder>>floatTemp: (in category 'temps') -----
> + floatTemp: node
> +    (node == (scopeTable at: node name ifAbsent: [])
> +     and: [node isTemp
> +     and: [node index = (nTemps - 1)]]) ifFalse:
> +        [self error: 'can only float the last allocated temp var'].
> +    nTemps := nTemps - 1!
> 
> Item was added:
> + ----- Method: Encoder>>global:name: (in category 'private') -----
> + global: ref name: name
> + 
> +    ^self
> +        name: name
> +        key: ref
> +        class: LiteralVariableNode
> +        type: LdLitIndType
> +        set: litIndSet!
> 
> Item was added:
> + ----- Method: Encoder>>globalSourceRanges (in category 'source mapping') -----
> + globalSourceRanges
> + 
> +    ^ globalSourceRanges!
> 
> Item was added:
> + ----- Method: Encoder>>init:notifying: (in category 'initialize-release') -----
> + init: aCue notifying: anObject
> +    "The use of the variable requestor is a bit confusing here. This is
> +    *not* the original requestor, which is available through the cue.
> +    It's the Parser instance that is using the encoder."
> + 
> +    self setCue: aCue.
> +    requestor := anObject.
> +    nTemps := 0.
> +    supered := false.
> +    self initScopeAndLiteralTables.
> +    cue getClass 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])]].
> +    cue context ifNotNil:
> +        [| homeNode |
> +         homeNode := self bindArg: self doItInContextName.
> +         "0th temp = aContext passed as arg"
> +         cue context tempNames withIndexDo:
> +            [:variable :index|
> +            variable ~= self doItInContextName ifTrue:
> +                [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!
> 
> Item was added:
> + ----- Method: Encoder>>initScopeAndLiteralTables (in category 'initialize-release') -----
> + 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).
> +    addedExtraLiterals := false.
> +    optimizedSelectors := Set new!
> 
> Item was added:
> + ----- Method: Encoder>>interactive (in category 'private') -----
> + interactive
> +    "Answer true if compilation is interactive"
> + 
> +    ^requestor interactive!
> 
> Item was added:
> + ----- Method: Encoder>>litIndex: (in category 'encoding') -----
> + litIndex: literal
> +    | p |
> +    p := literalStream position.
> +    p = self maxNumLiterals ifTrue:
> +        [self notify: 'More than ', self maxNumLiterals printString, ' literals referenced.\You must split or otherwise simplify this method.\The ' withCRs, (self maxNumLiterals + 1) printString, 'th literal is: ', literal printString. ^nil].
> +    literal isLiteral ifTrue: "filters out BlockClosures, ExternalLibraryFunctions"
> +        [self setReadOnlyIfAppropriate: literal].
> +    "Would like to show where it is in the source code, but that info is hard to get."
> +    literalStream nextPut: literal.
> +    ^p!
> 
> Item was added:
> + ----- Method: Encoder>>literals (in category 'results') -----
> + literals
> +    "Should only be used for decompiling primitives"
> +    ^ literalStream contents!
> 
> Item was added:
> + ----- Method: Encoder>>lookupInPools:ifFound: (in category 'private') -----
> + lookupInPools: varName ifFound: assocBlock
> + 
> +    ^(Symbol lookup: varName)
> +        ifNil: [ false ]
> +        ifNotNil: [ :symbol |
> +            (cue bindingOf: symbol)
> +                ifNil: [ false ]
> +                ifNotNil: [:assoc|
> +                    assocBlock value: assoc.
> +                    true ]]!
> 
> Item was added:
> + ----- Method: Encoder>>lookupVariable:ifAbsent: (in category 'encoding') -----
> + lookupVariable: name ifAbsent: aBlock
> +    "Answer the binding of name in the scope table or aBlock's vaue if none.
> +     Do not bind and do not lookup in pools.  Used for correction, explanation etc"
> +    ^scopeTable at: name ifAbsent: aBlock!
> 
> Item was added:
> + ----- Method: Encoder>>maxIndexableLiterals (in category 'accessing') -----
> + maxIndexableLiterals
> +    "Answer the maximum number of literals supported by the receiver's
> +     bytecode set. This is a nominal value based on the Blue Book bytecode
> +     set; subclasses answer a more accurate value."
> +    ^63!
> 
> Item was added:
> + ----- Method: Encoder>>maxNumLiterals (in category 'accessing') -----
> + maxNumLiterals
> +    ^CompiledMethod maxNumLiterals min: self maxIndexableLiterals!
> 
> Item was added:
> + ----- Method: Encoder>>maxTemp (in category 'temps') -----
> + maxTemp
> + 
> +    ^nTemps!
> 
> Item was added:
> + ----- Method: Encoder>>methodNodeClass (in category 'accessing') -----
> + methodNodeClass
> +    ^MethodNode!
> 
> Item was added:
> + ----- Method: Encoder>>name:key:class:type:set: (in category 'private') -----
> + name: name key: key class: leafNodeClass type: type set: dict 
> +    ^dict at: key
> +        ifAbsentPut: 
> +            [leafNodeClass new 
> +                name: name
> +                key: key
> +                index: nil
> +                type: type]!
> 
> Item was added:
> + ----- Method: Encoder>>newTemp: (in category 'temps') -----
> + newTemp: name
> + 
> +    nTemps := nTemps + 1.
> +    ^ TempVariableNode new
> +        name: name
> +        index: nTemps - 1
> +        type: LdTempType
> +        scope: 0!
> 
> Item was added:
> + ----- Method: Encoder>>newUndeclaredTemp: (in category 'temps') -----
> + newUndeclaredTemp: name
> +    ^UndeclaredVariableNode new name: name!
> 
> Item was added:
> + ----- Method: Encoder>>noteOptimizedSelector: (in category 'encoding') -----
> + noteOptimizedSelector: aSymbol
> +    "Register a selector as being optimized.
> +    These optimized selectors will later be registered into the literals so that tools can easily browse senders."
> +    optimizedSelectors add: aSymbol!
> 
> Item was added:
> + ----- Method: Encoder>>noteSourceRange:forNode: (in category 'source mapping') -----
> + noteSourceRange: range forNode: node
> + 
> +    sourceRanges at: node put: range!
> 
> Item was added:
> + ----- Method: Encoder>>noteSuper (in category 'initialize-release') -----
> + noteSuper
> + 
> +    supered := true!
> 
> Item was added:
> + ----- Method: Encoder>>notify: (in category '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!
> 
> Item was added:
> + ----- Method: Encoder>>notify:at: (in category 'error handling') -----
> + notify: string at: location
> + 
> +    | req |
> +    requestor == nil
> +        ifFalse: 
> +            [req := requestor.
> +            self release.
> +            req notify: string at: location].
> +    ^false!
> 
> Item was added:
> + ----- Method: Encoder>>possibleNamesFor: (in category 'private') -----
> + possibleNamesFor: proposedName
> +    | results |
> +    results := cue getClass 
> +        possibleVariablesFor: proposedName 
> +        continuedFrom: nil.
> +    ^ proposedName correctAgainst: nil continuedFrom: results.
> + !
> 
> Item was added:
> + ----- Method: Encoder>>possibleVariablesFor: (in category 'private') -----
> + possibleVariablesFor: proposedVariable
> + 
> +    | results |
> +    results := proposedVariable correctAgainstDictionary: scopeTable
> +                                continuedFrom: nil.
> +    proposedVariable first canBeGlobalVarInitial ifTrue:
> +        [ results := cue getClass possibleVariablesFor: proposedVariable
> +                        continuedFrom: results ].
> +    ^ proposedVariable correctAgainst: nil continuedFrom: results.
> + !
> 
> Item was added:
> + ----- Method: Encoder>>rawSourceRanges (in category 'source mapping') -----
> + rawSourceRanges
> + 
> +    ^ sourceRanges !
> 
> Item was added:
> + ----- Method: Encoder>>reallyBind: (in category 'private') -----
> + reallyBind: name
> + 
> +    | node |
> +    node := self newTemp: name.
> +    scopeTable at: name put: node.
> +    ^node!
> 
> Item was added:
> + ----- Method: Encoder>>release (in category 'initialize-release') -----
> + release
> + 
> +    requestor := nil!
> 
> Item was added:
> + ----- Method: Encoder>>selector (in category 'accessing') -----
> + selector
> +    ^selector!
> 
> Item was added:
> + ----- Method: Encoder>>selector: (in category 'accessing') -----
> + selector: aSymbol
> +    selector := aSymbol!
> 
> Item was added:
> + ----- Method: Encoder>>setCue: (in category 'private') -----
> + setCue: aCue
> +    cue := aCue.
> +    
> +    "Also set legacy instance variables for methods that
> +    don't use cue yet"
> +    class := cue getClass.!
> 
> Item was added:
> + ----- Method: Encoder>>setReadOnlyIfAppropriate: (in category 'encoding') -----
> + setReadOnlyIfAppropriate: literal
> +    "If literal is not read-only and should be, set it to be read-only, along with any other such literals it may contain."
> +    (literal isReadOnlyObject
> +     or: [literal isVariableBinding]) ifFalse:
> +        [literal setIsReadOnlyObject: true.
> +         literal isArray ifTrue:
> +            [literal do: [:subLiteral| self setReadOnlyIfAppropriate: subLiteral]]]!
> 
> Item was added:
> + ----- Method: Encoder>>sharableLitIndex: (in category 'encoding') -----
> + sharableLitIndex: literal
> +    "Special access prevents multiple entries for post-allocated super send special selectors"
> +    1 to: literalStream position do:
> +        [:index|
> +        (literal literalEqual: (literalStream originalContents at: index)) ifTrue:
> +            [^index - 1]].
> +    ^self litIndex: literal!
> 
> Item was added:
> + ----- Method: Encoder>>sourceMap (in category 'source mapping') -----
> + sourceMap
> +    "Answer with a sorted set of associations (pc range)."
> + 
> +    ^sourceRanges associations
> +        replace: [ :association |    Association key: association key pc value: association value ];
> +        sort!
> 
> Item was added:
> + ----- Method: Encoder>>sourceRangeFor: (in category 'source mapping') -----
> + sourceRangeFor: node
> + 
> +    ^sourceRanges at: node!
> 
> Item was added:
> + ----- Method: Encoder>>tempNames (in category 'results') -----
> + tempNames 
> + 
> +    ^ self tempNodes collect:
> +        [:node | (node isMemberOf: MessageAsTempNode)
> +                    ifTrue: [scopeTable keyAtValue: node]
> +                    ifFalse: [node key]]!
> 
> Item was added:
> + ----- Method: Encoder>>tempNodes (in category 'results') -----
> + tempNodes
> + 
> +    | tempNodes |
> +    tempNodes := OrderedCollection new.
> +    scopeTable associationsDo:
> +        [:assn |
> +        assn value isArray
> +            ifTrue: [assn value do: [:temp| tempNodes add: temp]]
> +            ifFalse: [assn value isTemp ifTrue: [tempNodes add: assn value]]].
> +    ^tempNodes sort: [:n1 :n2 | n1 index <= n2 index]!
> 
> Item was added:
> + ----- Method: Encoder>>temps:literals:class: (in category 'initialize-release') -----
> + temps: tempVars literals: lits class: cl 
> +    "Initialize this encoder for decompilation."
> + 
> +    self setCue: (CompilationCue class: cl).
> +    supered := false.
> +    nTemps := tempVars size.
> +    tempVars do: [:node | scopeTable at: node name put: node].
> +    literalStream := WriteStream on: (Array new: lits size).
> +    literalStream nextPutAll: lits.
> +    sourceRanges := Dictionary new: 32.
> +    globalSourceRanges := OrderedCollection new: 32.!
> 
> Item was added:
> + ----- Method: Encoder>>tempsAndBlockArgs (in category 'results') -----
> + 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!
> 
> Item was added:
> + ----- Method: Encoder>>undeclared: (in category 'encoding') -----
> + undeclared: name 
> +    | sym |
> +    (requestor notNil and: [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: UndeclaredVariableNotification
> +            do: [:ex| ex resume: false]"
> +    sym := name asSymbol.
> +    ^ (UndeclaredVariableNotification new
> +        name: name
> +        selector: selector
> +        class: cue getClass) signal
> +        ifTrue:
> +            [ | undeclared assoc |
> +            undeclared := cue environment undeclared.
> +            assoc := [ undeclared add: (undeclared associationClass key: sym value: nil) ]
> +                on: AttemptToWriteReadOnlyGlobal
> +                do: [ : noti | noti resume: true ].
> +            self
> +                global: assoc
> +                name: sym ]
> +        ifFalse:
> +            [ self
> +                global: (Association key: sym)
> +                name: sym ]!
> 
> Item was added:
> + ----- Method: Encoder>>undeclaredTemps (in category 'results') -----
> + undeclaredTemps 
> +    ^(scopeTable select: [:var | var isVariableNode and: [var isUndeclared]]) values!
> 
> Item was added:
> + ----- Method: Encoder>>unusedTempNames (in category 'results') -----
> + 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!
> 
> Item was added:
> + ----- Method: Encoder>>warnAboutShadowed: (in category 'private') -----
> + warnAboutShadowed: name
> + 
> +    requestor addWarning: name,' is shadowed'.
> +    selector ifNil: [^ self].
> +    (ShadowedVariableNotification new
> +        name: name
> +        selector: selector
> +        class: cue getClass) signal.!
> 
> Item was added:
> + BytecodeEncoder subclass: #EncoderForSistaV1
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !EncoderForSistaV1 commentStamp: 'eem 3/10/2022 10:59' prior: 0!
> + EncoderForSistaV1 encodes a bytecode set for Smalltalk that lifts limits on the number of literals, branch distances, the number of temporary variables, and provides extended push integer and push character bytecodes.  The bytecode set also supports creating FullBlockClosures, closures whose method is separate from their home method's.  Bytecodes are ordered by length to make decoding easier.  Bytecodes marked with an * are extensible via a prefix extension bytecode.
> + 
> + N.B.  Extension bytecodes can only come before extensible bytecodes, and only if valid (one cannot extend a bytecode extensible by Ext A with an Ext B).  An extensible bytecode consumes (and zeros) its extension(s).  Hence the hidden implicit variables holding extensions are always zero except after a valid sequence of extension bytecodes.  The implication is that a bytecode interpreter should maintain the extension values in static variables initialized to zero at start-up, and live only from the start of a sequence of extension bytecodes to the end of the extended bytecode immediately following.
> + 
> + While the bytecode set lifts limits, it still assumes there are no more than 65535 literals (as of 2020 the CompiledCode header word imposes a 32,767 limit on number of literals), and no more than 256 stack slots (used for arguments, temporaries, and stack contents) in a Context.
> + 
> + EncoderForSistaV1 also includes an extended set of bytecodes for Sista, the Speculative Inlining Smalltalk Architecture, a project by Clément Bera and Eliot Miranda.  Scorch is an optimizer that exists in the Smalltalk image, /not/ in the VM,  and optimizes by substituting normal bytecoded methods by optimized bytecoded methods that may use special bytecodes for which the Cogit can generate faster code.  These bytecodes eliminate overheads such as bounds checks or polymorphic code (indexing Array, ByteArray, String etc).  But the bulk of the optimization performed is in inlining blocks and sends for the common path.  This bytecode set therefore differs from a normal Smalltalk set in providing a set of inlined primitives that do not validate their arguments that the compiler generates only when it can prove that the primitives' arguments are valid.
> + 
> + The basic scheme is that the Cogit generates code containing performance counters.  When these counters trip, a callback into the image is performed, at which point Scorch analyses some portion of the stack, looking at performance data for the methods on the stack, and optimises based on the stack and performance data.  Execution then resumes in the optimized code.
> + 
> + The Sista Cogit (e.g. SistaStackToRegisterMappingCogit) adds counters to conditional branches.  Each branch has an executed and a taken count.  On execution the executed count is decremented and if the count goes below zero the VM sends a message at a special index in the specialObjectsArray (as of writing, conditionalCounterTrippedOn:).  Then if the branch is taken the taken count is decremented.  The two counter values allow the Sista optimizer to collect basic block execution paths and to know what are the "hot" paths through execution that are worth agressively optimizing.  Since conditional branches are about 1/6 as frequent as sends, and since they can be used to determine the hot path through code, they are a better choice to count than, for example, method or block entry.
> + 
> + The VM provides a primitive that fills an Array with the state of the counters, and the state of each linked send in a method.  The optimizer obtains the branch and send data for a method via this primitive.
> + 
> + Instance Variables (inherited)
> + 
> + Here is the list of bytecodes.  An asterisk implies the bytecode takes either extA or extB extensions. Two asterisks imply it takes both extA and extB extensions.  A number in parentheses is a note.  See the notes at the end of the table.
> + 
> + 1 Byte Bytecodes
> +    code    (note)    binary            name
> +    0-15        0000 iiii            Push Receiver Variable #iiii
> +    16-31        0001 iiii            Push Literal Variable #iiii
> +    32-63        001 iiiii                Push Literal #iiiii
> +    64-71        01000 iii            Push Temp #iii
> +    72-75        010010 ii            Push Temp #ii + 8
> +    76            01001100            Push Receiver
> +    77            01001101            Push true
> +    78            01001110            Push false
> +    79            01001111            Push nil
> +    80            01010000            Push 0
> +    81            01010001            Push 1
> + *    82            01010010            Push thisContext, (then Extend B = 1 => push thisProcess)
> +    83            01010011            Duplicate Stack Top
> +    84-87        010101 ii            UNASSIGNED
> +    88-91        010110 ii            Return Receiver/true/false/nil
> +    92            01011100            Return top
> +    93            01011101            BlockReturn nil
> + *    94            01011110            BlockReturn Top [* return from enclosing block N, N = Extend A, then jump by Ext B ]
> + *    95            01011111            Nop
> +    96-111        0110 iiii            Send Arithmetic Message #iiii (+ - < > <= >= = ~= * / \\ @ bitShift: // bitAnd: bitOr:)
> +    112-119    01110 iii            Send Special Message #iii + 0 (at: at:put: size next nextPut: atEnd == class)
> +    120-127    01111 iii            Send Special Message #iii + 8 (~~ value value: do: new new: x y)
> +    128-143    1000 iiii            Send Literal Selector #iiii With 0 Argument
> +    144-159    1001 iiii            Send Literal Selector #iiii With 1 Arguments
> +    160-175    1010 iiii            Send Literal Selector #iiii With 2 Arguments
> +    176-183    10110 iii            Jump iii + 1 (i.e., 1 through 8)
> +    184-191    10111 iii            Pop and Jump 0n True iii +1 (i.e., 1 through 8)
> +    192-199    11000 iii            Pop and Jump 0n False iii +1 (i.e., 1 through 8)
> +    200-207    11001 iii            Pop and Store Receiver Variable #iii
> +    208-215    11010 iii            Pop and Store Temporary Variable #iii
> +    216        11011000            Pop Stack Top
> +    217    (5)    11011001            Unconditional trap
> +    218-219    1101101 i            UNASSIGNED
> +    220-223    110111 ii            UNASSIGNED
> + 
> + 2 Byte Bytecodes
> + *    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A) A is an unsigned extension.
> + *    225        11100001    bbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B) B is a signed extension.
> + *    226        11100010    iiiiiiii        Push Receiver Variable #iiiiiiii (+ Extend A * 256)
> + *    227        11100011    iiiiiiii        Push Literal Variable #iiiiiiii (+ Extend A * 256)
> + *    228        11100100    iiiiiiii        Push Literal #iiiiiiii (+ Extend A * 256)
> +    229        11100101    iiiiiiii        Push Temporary Variable #iiiiiiii
> +    230        11100110    iiiiiiii        UNASSIGNED (was pushNClosureTemps)
> +    231        11100111    jkkkkkkk    Push (Array new: kkkkkkk) (j = 0)
> +                                    &    Pop kkkkkkk elements into: (Array new: kkkkkkk) (j = 1)
> + *    232        11101000    iiiiiiii        Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, d=0, s=1)
> + *    233        11101001    iiiiiiii        Push Character #iiiiiiii (+ Extend A * 256)
> + **    234        11101010    iiiiijjj        Send Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments
> + **    235    (1)    11101011    iiiiijjj    ExtendB < 64
> +                                        ifTrue: [Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments]
> +                                        ifFalse: [Send To Superclass of Stacked Class Literal Selector #iiiii (+ Extend A * 32) with jjj (+ (Extend B bitAnd: 63) * 8) Arguments]
> +    236        11101100    iiiiiiii        UNASSIGNED
> + *    237        11101101    iiiiiiii        Jump #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, d=0, s=1)
> + **    238    (4)    11101110    iiiiiiii        Pop and Jump 0n True #iiiiiiii (+ Extend B * 256, where Extend B >= 0)
> + **    239    (4)    11101111    iiiiiiii        Pop and Jump 0n False #iiiiiiii (+ Extend B * 256, where Extend B >= 0)
> + **    240    (3)    11110000    iiiiiiii        Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256) 
> + **    241    (3)    11110001    iiiiiiii        Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256) 
> +    242        11110010    iiiiiiii        Pop and Store Temporary Variable #iiiiiiii
> + **    243    (3)    11110011    iiiiiiii        Store Receiver Variable #iiiiiii (+ Extend A * 256) 
> + **    244    (3)    11110100    iiiiiiii        Store Literal Variable #iiiiiiii (+ Extend A * 256) 
> +    245        11110110    iiiiiiii        Store Temporary Variable #iiiiiiii
> +    246-247    1111011 i    xxxxxxxx    UNASSIGNED
> + 
> + 3 Byte Bytecodes
> +    248    (2)    11111000    iiiiiiii        mssjjjjj        Call Primitive #iiiiiiii + (jjjjj * 256) 
> +                                m=1 means inlined primitive, no hard return after execution. 
> +                                ss defines the unsafe operation set used to encode the operations. 
> +                                (ss = 0 means sista unsafe operations, ss = 01 means lowcode operations, other numbers are as yet used)
> +                                Lowcode inlined primitives may have extensions.
> + *    249        11111001    xxxxxxxx    siyyyyyy    Push Closure Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy receiverOnStack: s = 1 ignoreOuterContext: i = 1
> + **    250        11111010    eeiiikkk        jjjjjjjj        Push Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize jjjjjjjj (+ExtB*256). ee = num extensions
> +    251        11111011    kkkkkkkk    sjjjjjjj        Push Temp At kkkkkkkk In Temp Vector At: jjjjjjj, s = 1 implies remote inst var access instead of remote temp vector access 
> + *    252    (3)    11111100    kkkkkkkk    sjjjjjjj        Store Temp At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst var access instead of remote temp vector access 
> + *    253    (3)    11111101    kkkkkkkk    sjjjjjjj        Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst var access instead of remote temp vector access
> + **    254    (5)    11111110    kkkkkkkk    jjjjjjjj        branch If Not Instance Of Behavior/Array Of Behavior literal kkkkkkkk (+ Extend A * 256, where Extend A >= 0) distance jjjjjjjj (+ Extend B * 256, where Extend B >= 0 and <= 127)
> + **    254    (5)    11111110    kkkkkkkk    jjjjjjjj        branch If Instance Of Behavior/Array Of Behavior literal kkkkkkkk (+ Extend A * 256, where Extend A >= 0) distance jjjjjjjj (+ (Extend B bitAnd: 127) * 256, where Extend B >= 128 and <= 255)
> + *    255        11111111    xxxxxxxx    jjjjjjjj        UNASSIGNED
> + 
> + (1) Bytecode 235 is a super send bytecode that starts the lookup in the superclass of some class.  It has two forms, "normal" and "directed". In the normal form, the class is the value of the method's methodClassAssociation which must be the last literal.  In the directed form the class is the class on top of stack.
> + 
> + (2) The Call Primitive Bytecode (see below) specifies either a primitive in the primitive table (m=0) or an inlined primitive (m=1). Non-inlined primitives from the primitive table have index (jjjjjjj * 256) + iiiiiiii and return from the method if they succeed.  This bytecode is only valid as the first bytecode of a method.  Inline primitives have index (jjjjjjj * 256) + iiiiiiii, cannot fail, and do not return when they succeed, yielding a result (typically on top of stack after popping their arguments, but possibly in a byte data stack, for example for unboxed floating-point primitives).
> + 
> + (3) ExtB lowest bit implies no store check is needed, ExtB second bit implies the object may be a context, ExtB third bit implies no immutability/read-only check is needed, other bits in the extension are unused.
> + 
> + (4) ExtA = 1 implies no mustBeBoolean trampoline is needed, other bits in the extension are unused
> + 
> + (5) these are Scorch/Sista bytecodes generated by an optimizing compiler and not used in normal Smalltalk code.
> + 
> + 
> + The CallPrimitive bytecode is divided into two halves, those for normal primtiives, occurring at the beginning of a method, and those for inline primitives, anywhere within the body of a method.  This is a three byte bytecode, the first byte being 248, and the second byte being a big-endian 16-bit primitive index. If the top bit of the first byte of the primitive index is 1 then this is a normal primitive invocation.  If it is zero then the remaining 15 bits define 32k primitives, organized as four 8k "pages".  The first page is used for and reserved by the Sista optimizing compiler.  The second page is usd for and reserved by the Lowcode FFI marshalling primitive set.  The other two sets are unspecified and unused.
> + 
> + Here is the specification of the Sista unsafe instructions (unsafe operations, set 00). The lowcode set uses external specifications.
> + We sort the inline primitive operations by arity.  Nullary primitives occupy the 0-999 range. Unary primitives occupy the 1-1999 range, up until 8 args. 8191 instructions can be encoded in each unsafe operation set, instructions from 0 to 7 arguments can have 1000 different instructions each, while 8 args instructions can have 192 different instructions.
> + 
> + Sista defines the following inlined primitives (CallPrimitive iiiiiiii 100jjjjj, n = jjjjjiiiiiiii)
> + 1000    class
> + 1001    pointer numSlots
> + 1002    pointer basicSize
> + 1003    byte8Type format numBytes (includes CompiledMethod)
> + 1004    short16Type format numShorts
> + 1005    word32Type format numWords
> + 1006    doubleWord64Type format numDoubleWords
> +    
> + 1010    ensure number of bytes available.
> + 1011    fixed-sized new. (objects with 0 to n inst vars)
> +    
> + 1020    identityHash (non-immediate, non-Behavior)
> + 1021    identityHash (SmallInteger)
> + 1022    identityHash (Character)
> + 1023    identityHash (SmallFloat64)
> + 1024    identityHash (Behavior, has hash?)
> + 
> + 1030    immediateAsInteger (Character)
> + 1031    immediateAsInteger (SmallFloat64)
> + 1035    immediateAsFloat    (Smallinteger)
> +    
> + 2000    SmallInteger #+.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2001    SmallInteger #-.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2002    SmallInteger #*.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2003    SmallInteger #/.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2004    SmallInteger #//.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2005    SmallInteger #\\.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2006    SmallInteger #quo:.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 
> + 2011    Variable-sized pointers new (new:). Array, etc.
> + 2012    Variable-sized byte new (new:). ByteArray, ByteString, etc.
> + 2013    Variable-sized 16-bit new (new:). DoubleByteArray, etc.
> + 2014    Variable-sized 32-bit new (new:). Bitmap, FloatArray, etc.
> + 2015    Variable-sized 64-bit new (new:). DoubleWordArray, etc.
> + 
> + 2016    SmallInteger #bitAnd:.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2017    SmallInteger #bitOr:.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2018    SmallInteger #bitXor:.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2019    SmallInteger #bitShiftLeft:.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 2020    SmallInteger #bitShiftRight:.  Both arguments are SmallIntegers and the result fits in a SmallInteger (* depends on word size)
> + 
> + 2032    SmallInteger #>.  Both arguments are SmallIntegers
> + 2033    SmallInteger #<.  Both arguments are SmallIntegers
> + 2034    SmallInteger #>=.  Both arguments are SmallIntegers
> + 2035    SmallInteger #<=.  Both arguments are SmallIntegers
> + 2036    SmallInteger #=.  Both arguments are SmallIntegers
> + 2037    SmallInteger #~=.  Both arguments are SmallIntegers
> + 
> + 2064    Pointer Object>>at:.        The receiver is guaranteed to be a pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger
> + 2065    Byte Object>>at:.            The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The result is a SmallInteger.
> + 2066    16-bit Word Object>>at:.            The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The result is a SmallInteger.
> + 2067    32-bit DoubleWord Object>>at:.            The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The result is a SmallInteger or a LargePositiveInteger.
> + 2068    64-bit QuadWord Object>>at:.    The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The result is a SmallInteger or a LargePositiveInteger.
> + 
> + The following instructions can have the ExtB check flag (See (3)).
> + 3000    Pointer Object>>at:put:.            The receiver is guaranteed to be a pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger
> + 3001    Byte Object>>at:put:.            The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 8 bits.
> + 3002    Word Object>>at:put:.            The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 16 bits.
> + 3003    DoubleWord Object>>at:put:.    The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 32 bits.
> + 3004    QuadWord Object>>at:put:.        The receiver is guaranteed to be a non-pointer object.  The 0-relative (1-relative?) index is an in-range SmallInteger.  The argument is a SmallInteger.  The primitive stores the least significant 64 bits.
> +            
> + 3021    Byte Object >> equals:length:    The receiver and the arguments are both byte objects and have both the same size (length). The length argument is a smallinteger. Answers true if all fields are equal, false if not. Comparison is bulked to word comparison.
> + 
> + 4000    Pointer Object>> fillFrom:to:with: The receiver is a Pointer object. the middle two arguments are smallintegers. Last argument is any object. Fills the object in between the two indexes with last argument. Receiver is guaranteed to be mutable. The pointer accesses are raw (no inst var check). If ExtB is set to 1, no store check is present. Else a single store check is done for the bulk operation. Answers the receiver.
> +    
> + 5000    Pointer Object>> replaceFrom:to:with:startingAt: Src and dest are pointer objects. ScrPos, scrLast and destLast are smallintegers. Receiver is guaranteed to be mutable.  Both ranges are in-bounds. The pointer accesses are raw (no inst var check). As for the normal primitive, the copy is linear. Answers the receiver.
> + 
> + 
> + Lowcode defines inlined primitives for the range CallPrimitive iiiiiiii 101jjjjj, n = jjjjjiiiiiiii.!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>bindingReadScanBlockFor:using: (in category 'compiled method support') -----
> + bindingReadScanBlockFor: litVarIndex using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for reads of the value of the binding with zero-relative index litVarIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> + 
> +    "    16-31        0001 i i i i                Push Literal Variable #iiii
> +     *    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +     *    227        11100011    i i i i i i i i    Push Literal Variable #iiiiiiii (+ Extend A * 256)"
> +    | extension |
> +    extension := 0.
> +    ^[:b| | prevext |
> +       prevext := extension.
> +       extension := b = 224 ifTrue: [scanner followingByte bitShift: 8] ifFalse: [0].
> +       (b < 32 and: [b >= 16 and: [b - 16 = litVarIndex]])
> +        or: [b = 227
> +            and: [scanner followingByte + prevext = litVarIndex]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>bindingWriteScanBlockFor:using: (in category 'compiled method support') -----
> + bindingWriteScanBlockFor: litVarIndex using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for writes of the value of the binding with zero-relative index litVarIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> + 
> +    "*    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +     *    241        11110001    iiiiiiii        Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256)
> +     *    244        11110100    iiiiiiii        Store Literal Variable #iiiiiiii (+ Extend A * 256)"
> +    | extension |
> +    extension := 0.
> +    ^[:b| | prevext |
> +       prevext := extension.
> +       extension := b = 224 ifTrue: [scanner followingByte bitShift: 8] ifFalse: [0].
> +       (b = 241 or: [b = 244])
> +       and: [scanner followingByte + prevext = litVarIndex]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>blockMethodOrNilFor:in:at: (in category 'instruction stream support') -----
> + blockMethodOrNilFor: anInstructionStream in: method at: pc
> +    "If anInstructionStream is at a block creation bytecode then answer the block's
> +     CompiledBlock, otherwise answer nil.
> + 
> +     The complication is that for convenience we allow the pc to point to the
> +     raw send bytecode after its extension(s), or at the extension(s) preceding it.
> +    249        11111001    xxxxxxxx    siyyyyyy    push Closure Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy receiverOnStack: s = 1 ignoreOuterContext: i = 1"
> + 
> +    | byte |
> +    byte := method at: pc.
> +    byte = 249 ifTrue:
> +        ["it could be extended..."
> +         ^self extensionsFor: pc in: method into:
> +            [:extA :extB :nExtBytes|
> +             method literalAt: (method at: pc + nExtBytes + 1) + (extA bitShift: 8) + 1]].
> +    ^byte = 16rE0 ifTrue:
> +        [self extensionsAt: pc in: method into:
> +            [:extA :extB :nExtBytes|
> +            (method at: pc + nExtBytes) = 249 ifTrue:
> +                [method literalAt: (method at: pc + nExtBytes + 1) + (extA bitShift: 8) + 1]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>bytecodeSize: (in category 'instruction stream support') -----
> + bytecodeSize: bytecode
> +    "Answer the number of bytes in the bytecode."
> +    bytecode < 224 ifTrue: [^1].
> +    bytecode < 248 ifTrue: [^2].
> +    ^3!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>callPrimitiveCode (in category 'bytecode decoding') -----
> + callPrimitiveCode
> +    "Answer the call primitive bytecode, if it exists in the encoder's bytecode set, or nil if not.
> +     248    11111000    iiiiiiii    mjjjjjjj    Call Primitive #iiiiiiii + (jjjjjjj * 256) m=1 means inlined primitive, no hard return after execution."
> +    ^248!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>canBeSpecialLiteral: (in category 'testing') -----
> + canBeSpecialLiteral: aLiteral
> +    "This check can be used to prevent unnecessary use of #scanBlockOrNilForLiteral:."
> + 
> +    aLiteral isVariableBinding ifTrue: [^false]. "a common case; don't waste time analysing..."
> +    
> +    aLiteral isSymbol ifTrue: [^ Smalltalk specialSelectors identityIncludes: aLiteral].
> +    aLiteral isCharacter ifTrue: [^ aLiteral asInteger <= 65535].
> +    aLiteral isInteger ifTrue: [^ aLiteral between: -32768 and: 32767].
> + 
> +    aLiteral == true ifTrue: [^ true].
> +    aLiteral == false ifTrue: [^ true].
> +    aLiteral == nil ifTrue: [^ true].
> + 
> +    ^ false!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>createClosureCode (in category 'bytecode decoding') -----
> + createClosureCode
> +    "Answer the create closure bytecode, if it exists in the encoder's bytecode set, or nil if not.
> +     Actually this code is that for a closure whose bytecodes are nested within its home method's."
> + 
> +    ^250!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>createClosureScanBlock (in category 'compiled method support') -----
> + createClosureScanBlock
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for block closure creation bytecodes.  Note that with this interface we can't answer
> +     true for the extension in front of a push closure bytecode and so the interface may
> +     have to change at some point."
> + 
> +    "*    224    11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +     *    225    11100001    bbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B)
> +    **    249    11111001    xxxxxxxx    siyyyyyy    push Closure Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy receiverOnStack: s = 1 ignoreOuterContext: i = 1
> +     **    250    11111010    eeiiikkk        jjjjjjjj        Push Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize jjjjjjjj (+ExtB*256). ee = num extensions"
> +    ^[:b| b >= 249 and: [b <= 250]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>extensionsAt:in:into: (in category 'compiled method support') -----
> + extensionsAt: bcpc in: method into: aTrinaryBlock
> +    "If the bytecode at pc is an extension then evaluate aBinaryBlock with the values of extA and extB and number of extension *bytes*.
> +     If the bytecode at pc is not extended then evaluate aBinaryBlock with 0 and 0.
> +    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +    225        11100001    bbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B)"
> +  
> +    | scanpc byte extByte extA extB |
> +    scanpc := bcpc.
> +    "There may be an extension (it could be a false positive).  We must scan as fast as possible..."
> +    extA := extB := 0.
> +    [byte := method at: scanpc.
> +     byte >= 224 and: [byte <= 225]] whileTrue: 
> +        [extByte := method at: scanpc + 1.
> +         scanpc := scanpc + 2.
> +         byte = 224
> +            ifTrue:
> +                [extA := (extA bitShift: 8) + extByte]
> +            ifFalse:
> +                [extB := (extB = 0 and: [extByte > 127])
> +                    ifTrue: [extByte - 256]
> +                    ifFalse: [(extB bitShift: 8) + extByte]]].
> +    ^aTrinaryBlock value: extA value: extB value: scanpc - bcpc
> + 
> + 
> + "Why use
> +    byte >= 224 and: [byte <= 225]
> +  and not
> +    (byte bitAnd: 16rFE) = 16rE0
> +  ?
> +  | n |
> +  n := 100000000.
> +  #(0 224) collect:
> +    [:byte|
> +    { Time millisecondsToRun: [1 to: n do: [:i| (byte >= 224 and: [byte <= 225]) ifTrue: []]].
> +       Time millisecondsToRun: [1 to: n do: [:i| (byte bitAnd: 16rFE) = 16rE0 ifTrue: []]] }] #(#(297 599) #(702 671))"!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>instVarReadScanBlockFor:using: (in category 'compiled method support') -----
> + instVarReadScanBlockFor: varIndexCode using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for reads of the inst var with zero-relative index varIndexCode.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> + 
> +    "    0-15        0000 i i i i                Push Receiver Variable #iiii
> +    *    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +    *    226        11100010    i i i i i i i i    Push Receiver Variable #iiiiiiii (+ Extend A * 256)"
> +    | extension |
> +    extension := 0.
> +    ^[:b| | prevext |
> +       prevext := extension.
> +       extension := b = 224 ifTrue: [scanner followingByte bitShift: 8] ifFalse: [0].
> +       (b < 16 and: [b = varIndexCode])
> +        or: [b = 226
> +            and: [scanner followingByte + prevext = varIndexCode]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>instVarWriteScanBlockFor:using: (in category 'compiled method support') -----
> + instVarWriteScanBlockFor: varIndexCode using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for writes of the inst var with zero-relative index varIndexCode.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> + 
> +    "    200-207    11001 iii            Pop and Store Receiver Variable #iii
> +    *    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +    *    240        11110000    iiiiiiii        Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256)
> +    *    243        11110011    iiiiiiii        Store Receiver Variable #iiiiiii (+ Extend A * 256)"
> +    | extension |
> +    extension := 0.
> +    ^[:b| | prevext |
> +       prevext := extension.
> +       extension := b = 224 ifTrue: [scanner followingByte bitShift: 8] ifFalse: [0].
> +       (b >= 200
> +        and: [b < 208
> +        and: [b - 200 = varIndexCode]])
> +       or: [(b = 240 or: [b = 243])
> +          and: [scanner followingByte + prevext = varIndexCode]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>interpretJumpIfCondIn: (in category 'compiled method support') -----
> + interpretJumpIfCondIn: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct conditional jump decoder for the instruction set."
> +    ^anInstructionStream interpretSistaV1JumpIfCond!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>interpretJumpIn: (in category 'compiled method support') -----
> + interpretJumpIn: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct unconditional jump decoder for the instruction set."
> +    ^anInstructionStream interpretSistaV1Jump!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>interpretNextInstructionFor:in: (in category 'instruction stream support') -----
> + interpretNextInstructionFor: aClient in: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct instruction set decoder."
> +    ^anInstructionStream interpretNextSistaV1InstructionFor: aClient!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isBlockReturnAt:in: (in category 'instruction stream support') -----
> + isBlockReturnAt: pc in: method
> +    "Answer whether the bytecode at pc is a return from block."
> +    "    93            01011101            BlockReturn nil
> +     *    94            01011110            BlockReturn Top [* return from enclosing block N, N = Extend A, then jump by Ext B ]"
> +    ^(self nonExtensionBytecodeAt: pc in: method) between: 93 and: 94!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isBranchIfFalseAt:in: (in category 'instruction stream support') -----
> + isBranchIfFalseAt: pc in: method
> +    "Answer whether the bytecode at pc is a conditional branch-if-false."
> + 
> +    "    192-199    11000 iii                Pop and Jump 0n False iii +1 (i.e., 1 through 8)
> +     *    239        11101111    iiiiiiii        Pop and Jump 0n False #iiiiiiii (+ Extend B * 256, where Extend B >= 0)"
> +    | byte |
> +    byte := self nonExtensionBytecodeAt: pc in: method.
> +    ^byte >= 192 and: [byte <= 199 or: [byte = 239]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isBranchIfTrueAt:in: (in category 'instruction stream support') -----
> + isBranchIfTrueAt: pc in: method
> +    "Answer whether the bytecode at pc is a conditional branch-if-true."
> + 
> +    "    184-191    10111 iii                Pop and Jump 0n True iii +1 (i.e., 1 through 8)
> +     *    238        11101110    iiiiiiii        Pop and Jump 0n True #iiiiiiii (+ Extend B * 256, where Extend B >= 0))"
> +    | byte |
> +    byte := self nonExtensionBytecodeAt: pc in: method.
> +    ^byte >= 184 and: [byte <= 191 or: [byte = 238]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isExtension: (in category 'instruction stream support') -----
> + isExtension: bytecode
> +    "Answer if the bytecode is an extension bytecode, i.e. one that extends
> +     the range of the following bytecode."
> +    ^bytecode >= 16rE0 and: [bytecode <= 16rE1]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isJumpAt:in: (in category 'instruction stream support') -----
> + isJumpAt: pc in: method
> +    "Answer whether the bytecode at pc is an (unconditional) jump."
> + 
> +    "    176-183    10110 iii                Jump iii + 1 (i.e., 1 through 8)
> +     *    225        11100001    bbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B)
> +     *    237        11101101    iiiiiiii        Jump #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> +    | byte |
> +    byte := self nonExtensionBytecodeAt: pc in: method.
> +    ^byte >= 176 and: [byte <= 183 or: [byte = 237]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isJustPopAt:in: (in category 'instruction stream support') -----
> + isJustPopAt: pc in: method
> +    "Answer whether the bytecode at pc is a pop."
> + 
> +    ^(method at: pc) = 216 "216        11011000            Pop Stack Top"!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isRealSendAt:in: (in category 'instruction stream support') -----
> + isRealSendAt: pc in: method
> +    "Answer whether the bytecode at pc is a real message-send, not blockCopy:."
> + 
> +    ^self isSendAt: pc in: method!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isReturnAt:in: (in category 'instruction stream support') -----
> + isReturnAt: pc in: method
> +    "Answer whether the bytecode at pc is a return from block."
> +    "    88-91        010110 ii            Return Receiver/true/false/nil
> +        92            01011100            Return top
> +        93            01011101            BlockReturn nil
> +     *    94            01011110            BlockReturn Top [* return from enclosing block N, N = Extend A, then jump by Ext B ]"
> +    ^(self nonExtensionBytecodeAt: pc in: method) between: 88 and: 94!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isReturnSelfFromMethodAt:in: (in category 'instruction stream support') -----
> + isReturnSelfFromMethodAt: pc in: method
> +    "Answer whether the bytecode at pc is a return self from method."
> + 
> +    ^(method at: pc) = 88!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isReturnTopFromMethodAt:in: (in category 'instruction stream support') -----
> + isReturnTopFromMethodAt: pc in: method
> +    "Answer whether the bytecode at pc is a return stack top from method."
> + 
> +    ^(method at: pc) = 92!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isSendAt:in: (in category 'instruction stream support') -----
> + isSendAt: pc in: method
> +    "Answer whether the bytecode at pc is a message-send."
> + 
> +    "    96-111        0110 iiii            Send Arithmetic Message #iiii #(#+ #- #< #> #'<=' #'>=' #= #'~=' #* #/ #'\\' #@ #bitShift: #'//' #bitAnd: #bitOr:)
> +        112-119    01110 iii            Send Special Message #iii #(#at: #at:put: #size #next #nextPut: #atEnd #'==' class)
> +        120        01111000            UNASSIGNED (was: blockCopy:)
> +        121        01111001            Send Special Message #value
> +        122-123    0111101 i            Send Special Message #i #(#value: #do:)
> +        124-127    011111 ii            Send Special Message #ii #(#new #new: #x #y))
> +        128-143    1000 iiii            Send Literal Selector #iiii With 0 Argument
> +        144-159    1001 iiii            Send Literal Selector #iiii With 1 Arguments
> +        160-175    1010 iiii            Send Literal Selector #iiii With 2 Arguments
> +     **    234        11101010    iiiiijjj    Send Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments
> +     **    235        11101011    iiiiijjj    Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> + 
> +    | byte |
> +    byte := self nonExtensionBytecodeAt: pc in: method.
> +    ^byte >= 96
> +      and: [byte <= 175
> +         or: [byte >= 234 and: [byte <= 235]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isStoreAt:in: (in category 'instruction stream support') -----
> + isStoreAt: pc in: method
> +    "Answer whether the bytecode at pc is a store or store-pop."
> + 
> +    "    200-207    11001 iii                        Pop and Store Receiver Variable #iii
> +        208-215    11010 iii                        Pop and Store Temporary Variable #iii
> +     *    224        11100000    aaaaaaaa            Extend A (Ext A = Ext A prev * 256 + Ext A)
> +     *    240        11110000    iiiiiiii                Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256)
> +     *    241        11110001    iiiiiiii                Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256)
> +        242        11110010    iiiiiiii                Pop and Store Temporary Variable #iiiiiiii
> +     *    243        11110011    iiiiiiii                Store Receiver Variable #iiiiiii (+ Extend A * 256)
> +     *    244        11110100    iiiiiiii                Store Literal Variable #iiiiiiii (+ Extend A * 256)
> +        245        11110110    iiiiiiii                Store Temporary Variable #iiiiiiii
> + 
> +        252        11111100    kkkkkkkk    jjjjjjjj    Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj
> +        253        11111101    kkkkkkkk    jjjjjjjj    Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
> + 
> +    | byte |
> +    byte := self nonExtensionBytecodeAt: pc in: method.
> +    ^byte >= 200
> +      and: [byte <= 215
> +         or: [(byte between: 240 and: 245)
> +         or: [(byte between: 252 and: 253)]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isStorePopAt:in: (in category 'instruction stream support') -----
> + isStorePopAt: pc in: method
> +    "Answer whether the bytecode at pc is a store or store-pop."
> + 
> +    "    200-207    11001 iii                        Pop and Store Receiver Variable #iii
> +        208-215    11010 iii                        Pop and Store Temporary Variable #iii
> +     *    224        11100000    aaaaaaaa            Extend A (Ext A = Ext A prev * 256 + Ext A)
> +     *    240        11110000    iiiiiiii                Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256)
> +     *    241        11110001    iiiiiiii                Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256)
> +        242        11110010    iiiiiiii                Pop and Store Temporary Variable #iiiiiiii
> + 
> +        253        11111101    kkkkkkkk    jjjjjjjj    Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjjj"
> + 
> +    | byte |
> +    byte := self nonExtensionBytecodeAt: pc in: method.
> +    ^byte >= 200
> +      and: [byte <= 215
> +         or: [(byte between: 240 and: 242)
> +         or: [byte = 253]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isSyntheticStoreAt:in:for: (in category 'instruction stream support') -----
> + isSyntheticStoreAt: pc in: method for: anInstructionStream
> +    "Answer whether the bytecode at pc is a store or store-pop of an indirect temp vector,
> +     which implement mutable closed-over variables in the the closure implementation.
> +     Stores into temp vectors are not real stores.  N.B. pcPreviousTo:in:for: is slow, so filter
> +     out any preceding bytecodes other than what looks like a pushNewArrayCode.  But the
> +     pcPreviousTo:in:for: is still necessary, since the presence of a pcPreviousTo:in:for: in the
> +     right place is potentially ambiguous, possibly part of a different bytecode sequence."
> + 
> +    ^(self isTempStoreAt: pc in: method)
> +      and: [pc - 2 >= method initialPC
> +      and: [(method at: pc - 2) = self pushNewArrayCode
> +      and: [(method at: pc - 1) <= 127
> +      and: [pc - 2 = (self pcPreviousTo: pc in: method for: anInstructionStream)]]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>isTempStoreAt:in: (in category 'instruction stream support') -----
> + isTempStoreAt: pc in: method
> +    "Answer if the bytecode at pc is a store or store-pop into a temporary variable.
> +     208-215    11010 iii            Pop and Store Temporary Variable #iii
> +     242        11110010    iiiiiiii        Pop and Store Temporary Variable #iiiiiiii
> +     245        11110110    iiiiiiii        Store Temporary Variable #iiiiiiii"
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^byte >= 208
> +      and: [byte <= 215
> +            or: [byte = 242 or: [byte = 245]]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>markerOrNilFor: (in category 'compiled method support') -----
> + markerOrNilFor: aMethod
> +    "If aMethod is a marker method, answer the symbol used to mark it.  Otherwise
> +     answer nil.  What is a marker method?  It is method with body like 
> +        'self subclassResponsibility' or '^ self subclassResponsibility' 
> +     used to indicate ('mark') a special property.
> + 
> +    Marker methods compile to two bytecode forms, this:
> +        self
> +        send: <literal 1>
> +        pop
> +        returnSelf
> +    or this:
> +        self
> +        send: <literal 1>
> +        returnTop"
> +    | expectedHeaderPlusLliteralSize e byte |
> +    expectedHeaderPlusLliteralSize := Smalltalk wordSize * 4.
> +    ^(((e := aMethod endPC - expectedHeaderPlusLliteralSize) = 3 or: [e = 4]) 
> +      and: [aMethod numLiterals = 3
> +      and: [(aMethod at: expectedHeaderPlusLliteralSize + 1) = 16r4C "push self"
> +      and: [(aMethod at: expectedHeaderPlusLliteralSize + 2) = 16r80 "send"
> +      and: [(byte := aMethod at: expectedHeaderPlusLliteralSize + 3) = 16rD8 "pop" or: [byte = 16r5C "returnTop"]]]]])
> +        ifTrue: [aMethod literalAt: 1]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>method:refersInBytecodeToLiteral:specialSelectorIndex: (in category 'scanning') -----
> + method: method refersInBytecodeToLiteral: aLiteral specialSelectorIndex: specialOrNil
> +    "Answer if method refers to the literal aLiteral in the bytecode, as opposed to in its literal frame."
> + 
> +    "    77            01001101                Push true
> +        78            01001110                Push false
> +        79            01001111                Push nil
> +        80            01010000                Push 0
> +        81            01010001                Push 1
> +        88-91        010110 ii                Return Receiver/true/false/nil
> +        93            01011101                BlockReturn nil
> +        96-111        0110 iiii                Send Arithmetic Message #iiii #(#+ #- #< #> #'<=' #'>=' #= #'~=' #* #/ #'\\' #@ #bitShift: #'//' #bitAnd: #bitOr:)
> +        112-119    01110 iii                Send Special Message #iii #(#at: #at:put: #size #next #nextPut: #atEnd #'==' class)
> +        120        01111000                UNASSIGNED (was: blockCopy:)
> +        121        01111001                Send Special Message #value
> +        122-123    0111101 i                Send Special Message #i #(#value: #do:)
> +        124-127    011111 ii                Send Special Message #ii #(#new #new: #x #y))
> +    *    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +    *    225        11100001    sbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B)
> +    *    232        11101000    iiiiiiii        Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)
> +    *    233        11101001    iiiiiiii        Push Character #iiiiiiii (+ Extend B * 256)
> +        249        11111001    xxxxxxxx    syyyyyyy    Reserved for Push Float"
> +    | byte extended scanner |
> +    specialOrNil ifNotNil:
> +        [byte := specialOrNil + 95.
> +        ^(InstructionStream on: method) scanFor: [:b| b = byte]].
> +    extended := false.
> +    aLiteral isInteger ifTrue:
> +        [(aLiteral >= -32768 and: [aLiteral <= 32767]) ifFalse: [^false].
> +         scanner := InstructionStream on: method.
> +         (aLiteral >= 0 and: [aLiteral <= 255]) ifTrue:
> +            [aLiteral <= 1 ifTrue:
> +                [byte := aLiteral + 80.
> +                 ^scanner scanFor: [:b| b = byte]].
> +             ^scanner scanFor:
> +                [:b|
> +                (b = 232
> +                 and: [extended not
> +                 and: [scanner followingByte = aLiteral]])
> +                or: [extended := b = 225.
> +                    false]]].
> +         byte := (aLiteral bitShift: -8) bitAnd: 255.
> +        ^scanner scanFor:
> +            [:b|
> +            (b = 232
> +             and: [extended
> +             and: [scanner followingByte = (aLiteral bitAnd: 255)]])
> +            or: [extended := b = 225 and: [scanner followingByte = byte].
> +                false]]].
> +    aLiteral isCharacter ifTrue:
> +        [aLiteral asciiValue <= 65535 ifFalse: [^false].
> +         scanner := InstructionStream on: method.
> +         aLiteral asciiValue <= 255 ifTrue:
> +            [^scanner scanFor:
> +                [:b|
> +                (b = 233
> +                 and: [extended not
> +                 and: [scanner followingByte = aLiteral]])
> +                or: [extended := b = 225.
> +                    false]]].
> +         byte := (aLiteral bitShift: -8) bitAnd: 255.
> +        ^scanner scanFor:
> +            [:b|
> +            (b = 233
> +             and: [extended
> +             and: [scanner followingByte = (aLiteral bitAnd: 255)]])
> +            or: [extended := b = 225 and: [scanner followingByte = byte].
> +                false]]].
> +    aLiteral == nil ifTrue:
> +        [^(InstructionStream on: method) scanFor: [:b| b = 79 or: [b = 91 or: b = 93]]].
> +    aLiteral == true ifTrue:
> +        [^(InstructionStream on: method) scanFor: [:b| b = 77 or: [b = 89]]].
> +    aLiteral == false ifTrue:
> +        [^(InstructionStream on: method) scanFor: [:b| b = 78 or: [b = 90]]].
> +    
> +    ^false!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>nonExtensionBytecodeAt:in: (in category 'instruction stream support') -----
> + nonExtensionBytecodeAt: pc in: method
> +    "Answer the actual bytecode at pc in method, skipping past any preceding extensions."
> +    | thePC bytecode |
> +    thePC := pc.
> +    [self isExtension: (bytecode := method at: thePC)] whileTrue:
> +        [thePC := thePC + (self bytecodeSize: bytecode)].
> +    ^bytecode!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>nopCode (in category 'bytecode decoding') -----
> + nopCode
> +    "Answer the call primitive bytecode, if it exists in the encoder's bytecode set, or nil if not.
> +     95            01011111            Nop"
> +    ^95!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category 'bytecode decoding') -----
> + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method
> +    "Answer the pc of the push closure bytecode whose block starts at startpc in method.
> +     May need to back up to include extension bytecodes."
> + 
> +    "*    224        11100000    aaaaaaaa            Extend A (Ext A = Ext A prev * 256 + Ext A)
> +     *    225        11100001    bbbbbbbb            Extend B (Ext B = Ext B prev * 256 + Ext B)
> +     **    250        11111010    eeiiikkk        jjjjjjjj    Push Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize jjjjjjjj (+ExtB*256). ee = num extensions"
> +    | numExtensions |
> +    self assert: (method at: startpc - 3) = 250.
> +    numExtensions := (method at: startpc - 2) >> 6.
> +    ^startpc - 3 - (numExtensions * 2)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>pushClosureBytecodeSize (in category 'bytecode decoding') -----
> + pushClosureBytecodeSize
> +    "Answer the size of the push closure bytecode.
> +     **    250        11111010    eeiiikkk        jjjjjjjj    Push Closure Num Copied iii (+ExtA//16*8) Num Args kkk (+ ExtA\\16*8) BlockSize jjjjjjjj (+ExtB*256). ee = num extensions"
> +    ^3!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>pushNewArrayCode (in category 'bytecode decoding') -----
> + pushNewArrayCode
> +    "231        11100111    jkkkkkkk    Push (Array new: kkkkkkk) (j = 0)
> +                                    &    Pop kkkkkkk elements into: (Array new: kkkkkkk) (j = 1)"
> +    ^231!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>pushNilCode (in category 'bytecode decoding') -----
> + pushNilCode
> +    "Answer the pushNil bytecode.
> +     79            01001111            Push nil"
> +    ^79!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>scanBlockOrNilForLiteral: (in category 'scanning') -----
> + scanBlockOrNilForLiteral: aLiteral
> +    "Answer a block argument for CompiledMethod>>#scanFor: that answers
> +     if the method refers to the literal implicitly via a special bytecode.
> +     If the literal is not accessible via a special bytecode, answer nil."
> +    | value hi lo unextended |
> + 
> +    "96-111    0110 iiii            Send Arithmetic Message #iiii (+ - < > <= >= = ~= * / \\ @ bitShift: // bitAnd: bitOr:)
> +     112-119    01110 iii            Send Special Message #iii + 0 (at: at:put: size next nextPut: atEnd == class)"
> +    aLiteral isSymbol ifTrue:
> +        [value := 96 + ((Smalltalk specialSelectors indexOf: aLiteral ifAbsent: [^nil]) // 2).
> +         ^[:byte| byte = value]].
> + 
> +    "80            01010000            Push 0
> +     81            01010001            Push 1
> +     232        11101000    iiiiiiii    Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, d=0, s=1)"
> +    aLiteral isInteger ifTrue:
> +        [aLiteral >= 0 ifTrue:
> +            [aLiteral <= 1 ifTrue:
> +                [value := aLiteral + 80.
> +                 ^[:byte| byte = value]].
> +             aLiteral <= 255 ifTrue:
> +                [unextended := true. "Don't be fooled by extended cases with the same least significant byte!!"
> +                 ^[:b1 :b2| | found |
> +                    found := b1 = 232 and: [b2 = aLiteral and: [unextended]].
> +                    unextended := b1 ~= 16rE1.
> +                    found]]].
> +         (aLiteral between: -32768 and: 32767) ifFalse: [^nil].
> +         lo := aLiteral bitAnd: 255.
> +         hi := (aLiteral bitShift: -8) bitAnd: 255.
> +         ^[:b1 :b2 :b3 :b4| b1 = 16rE1 and: [b2 = hi and: [b3 = 232 and: [b4 = lo]]]]].
> + 
> +    "233        11101001    iiiiiiii    Push Character #iiiiiiii (+ Extend B * 256)"
> +    aLiteral isCharacter ifTrue:
> +        [(value := aLiteral asInteger) <= 255 ifTrue:
> +            [unextended := true. "Don't be fooled by extended cases with the same least significant byte!!"
> +             ^[:b1 :b2| | found |
> +                found := b1 = 233 and: [b2 = value and: [unextended]].
> +                unextended := b1 ~= 16rE1.
> +                found]].
> +         ^value <= 65535 ifTrue:
> +            [lo := value bitAnd: 255.
> +             hi := (value bitShift: -8) bitAnd: 255.
> +             [:b1 :b2 :b3 :b4| b1 = 16rE1 and: [b2 = hi and: [b3 = 233 and: [b4 = lo]]]]]].
> + 
> +    "77            01001101            Push true
> +     78            01001110            Push false
> +     79            01001111            Push nil
> +     88-91        010110 ii            Return Receiver/true/false/nil
> +     93            01011101            BlockReturn nil"
> +    aLiteral == true ifTrue:
> +        [^[:byte| byte = 77 or: [byte = 89]]].
> +    aLiteral == false ifTrue:
> +        [^[:byte| byte = 78 or: [byte = 90]]].
> +    aLiteral == nil ifTrue:
> +        [^[:byte| byte = 79 or: [byte = 91 or: [byte = 93]]]].
> +    ^nil!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>selectorToSendOrItselfFor:in:at: (in category 'instruction stream support') -----
> + selectorToSendOrItselfFor: anInstructionStream in: method at: pc
> +    "If anInstructionStream is at a send bytecode then answer the send's selector,
> +     otherwise answer anInstructionStream itself.  The rationale for answering
> +     anInstructionStream instead of, say, nil, is that potentially any existing object
> +     can be used as a selector, but since anInstructionStream postdates the method,
> +     it can't be one of them.
> + 
> +     The complication is that for convenience we allow the pc to point to the
> +     raw send bytecode after its extension(s), or at the extension(s) preceding it.
> +    96-111        0110 iiii            Send Arithmetic Message #iiii (+ - < > <= >= = ~= * / \\ @ bitShift: // bitAnd: bitOr:)
> +    112-119    01110 iii            Send Special Message #iii + 0 (at: at:put: size next nextPut: atEnd == class)
> +    120-127    01111 iii            Send Special Message #iii + 8 (~~ value value: do: new new: x y)
> +    128-143    1000 iiii            Send Literal Selector #iiii With 0 Argument
> +    144-159    1001 iiii            Send Literal Selector #iiii With 1 Arguments
> +    160-175    1010 iiii            Send Literal Selector #iiii With 2 Arguments
> +    *    224    11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +    *    225    11100001    bbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B)
> +    **    234    11101010    iiiiijjj        Send Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments
> +    **    235    11101011    iiiiijjj    ExtendB < 64
> +                                        ifTrue: [Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments]
> +                                        ifFalse: [Send To Superclass of Stacked Class Literal Selector #iiiii (+ Extend A * 32) with jjj (+ (Extend B bitAnd: 63) * 8) Arguments"
> + 
> +    | byte |
> +    byte := method at: pc.
> +    byte < 96 ifTrue:
> +        [^anInstructionStream].
> +    byte <= 175 ifTrue: 
> +        ["special byte or short send"
> +         ^byte >= 128
> +            ifTrue: [method literalAt: (byte bitAnd: 15) + 1]
> +            ifFalse: [Smalltalk specialSelectorAt: byte - 95]].
> +    byte < 234 ifTrue: "need to check for either extension cuz order of extensions is not restricted. so extB could precede extA"
> +        [(byte >= 224 and: [byte <= 225]) ifTrue:
> +            [^self extensionsAt: pc in: method into:
> +                [:extA :extB :nExtBytes| | byteAfter index |
> +                byteAfter := method at: pc + nExtBytes.
> +                (byteAfter >= 234 and: [byteAfter <= 235])
> +                    ifTrue:
> +                        [index := ((method at: pc + nExtBytes + 1) bitShift: -3) + (extA bitShift: 5).
> +                         method literalAt: index + 1]
> +                    ifFalse: [anInstructionStream]]].
> +        ^anInstructionStream].
> +    byte > 235 ifTrue:
> +        [^anInstructionStream].
> +    "they could be extended..."
> +    ^self extensionsFor: pc in: method into:
> +        [:extA :extB :nExtBytes| | index |
> +         index := ((method at: pc + 1) bitShift: -3) + (extA bitShift: 5).
> +         method literalAt: index + 1]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>stackDeltaForPrimitive:in: (in category 'bytecode decoding') -----
> + stackDeltaForPrimitive: primitiveIndex in: method
> +    "Answer the stack delta for the callPrimitive: bytecode (see my class comment).
> +     There is no delta for non-inlined primitives (its implicitly 0 - method numArgs).
> +     Inlined primitives are grouped by the thousand by argument count, 32 args max ;-)."
> +    ^primitiveIndex < 32678
> +        ifTrue: [0]
> +        ifFalse: [primitiveIndex - 32768 // 1000]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>superSendScanBlockUsing: (in category 'instruction stream support') -----
> + superSendScanBlockUsing: scanner
> +    "Answer a block argument for InstructionStream>>scanFor:
> +     that answers true for super sends."
> + 
> +    "*    224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +     *    225        11100001    sbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B)
> +     **    235        11101011    iiiiijjj        Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> +                    
> +    ^[:instr | instr = 235]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>supportsClosures (in category 'compiled method support') -----
> + supportsClosures
> +    "Answer if the instruction set supports closures (contains
> +     closure creation and indirect temp access bytecodes)."
> + 
> +    ^true!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1 class>>unusedBytecode (in category 'bytecode decoding') -----
> + unusedBytecode
> +    "Answer the opcode of a single-byte unused bytecode, if it exists in the encoder's bytecode set, or nil if not."
> +    ^223!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>computeMethodHeaderForNumArgs:numTemps:numLits:primitive: (in category 'method generation') -----
> + computeMethodHeaderForNumArgs: numArgs numTemps: numTemps numLits: numLits primitive: primitiveIndex
> +    numTemps > 63 ifTrue:
> +        [^self error: 'Cannot compile -- too many temporary variables'].    
> +    numLits > 65535 ifTrue:
> +        [^self error: 'Cannot compile -- too many literals'].
> +    ^SmallInteger minVal "sign bit is the flag for the alternative bytecode set"
> +    + (numArgs bitShift: 24)
> +    + (numTemps bitShift: 18)
> +    "+ (largeBit bitShift: 17)" "largeBit gets filled in later"
> +    + numLits
> +    + (primitiveIndex > 0 ifTrue: [1 bitShift: 16] ifFalse: [0])!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genBranchPopFalse: (in category 'bytecode generation') -----
> + genBranchPopFalse: distance
> +    (distance > 0 and: [distance < 9]) ifTrue:
> +        ["192-199    11000 iii            Pop and Jump 0n False iii + 1 (i.e., 1 through 8)"
> +         stream nextPut: 191 + distance.
> +         ^self].
> +    ^self genBranchPopFalseLong: distance!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genBranchPopFalseLong: (in category 'bytecode generation') -----
> + genBranchPopFalseLong: distance
> +    "239        11101111    iiiiiiii        Pop and Jump 0n False #iiiiiiii (+ Extend B * 256, where Extend B >= 0)    "
> +    | distanceMod256 |
> +    (distance < 0 or: [distance > 32767]) ifTrue:
> +        [^self outOfRangeError: 'distance' index: distance range: 0 to: 32767].
> +    distanceMod256 := (distance < 0 or: [distance > 255])
> +                            ifTrue:
> +                                [self genUnsignedSingleExtendB: (distance bitShift: -8).
> +                                 distance bitAnd: 255]
> +                            ifFalse: [distance].
> +    stream
> +        nextPut: 239;
> +        nextPut: distanceMod256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genBranchPopTrue: (in category 'bytecode generation') -----
> + genBranchPopTrue: distance
> +    (distance > 0 and: [distance < 9]) ifTrue:
> +        ["184-191    10111 iii            Pop and Jump 0n True iii + 1 (i.e., 1 through 8)"
> +         stream nextPut: 183 + distance.
> +         ^self].
> +    ^self genBranchPopTrueLong: distance!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genBranchPopTrueLong: (in category 'bytecode generation') -----
> + genBranchPopTrueLong: distance
> +    "238        11101110    iiiiiiii        Pop and Jump 0n True #iiiiiiii (+ Extend B * 256, where Extend B >= 0)"
> +    | distanceMod256 |
> +    (distance < 0 or: [distance > 32767]) ifTrue:
> +        [^self outOfRangeError: 'distance' index: distance range: 0 to: 32767].
> +    (distance > 0 and: [distance < 9]) ifTrue:
> +        ["184-191    10111 iii            Pop and Jump 0n True iii + 1 (i.e., 1 through 8)"
> +         stream nextPut: 183 + distance.
> +         ^self].
> +    distanceMod256 := (distance < 0 or: [distance > 255])
> +                            ifTrue:
> +                                [self genUnsignedSingleExtendB: (distance bitShift: -8).
> +                                 distance bitAnd: 255]
> +                            ifFalse: [distance].
> +    stream
> +        nextPut: 238;
> +        nextPut: distanceMod256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genCallInlinePrimitive: (in category 'bytecode generation') -----
> + genCallInlinePrimitive: primitiveIndex
> +    "    248    (2)    11111000    iiiiiiii        mssjjjjj        Call Primitive #iiiiiiii + (jjjjj * 256) 
> +                                m=1 means inlined primitive, no hard return after execution. 
> +                                ss defines the unsafe operation set used to encode the operations. 
> +                                (ss = 0 means sista unsafe operations, ss = 01 means lowcode operations, other numbers are not used)"
> +    "N.B. We could have made CallPrimitive a 2-byte code taking an extension, but that would
> +     complicate the VM's determination of the primitive number and the primitive error code
> +     store since the extension, being optional, would make the sequence variable length."
> +    (primitiveIndex < 1 or: [primitiveIndex > 32767]) ifTrue:
> +        [self outOfRangeError: 'primitive index' index: primitiveIndex range: 1 to: 32767].
> +    stream
> +        nextPut: 248;
> +        nextPut: (primitiveIndex bitAnd: 255);
> +        nextPut: (primitiveIndex bitShift: -8) + 128!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genCallPrimitive: (in category 'bytecode generation') -----
> + genCallPrimitive: primitiveIndex
> +    "248    (2)    11111000    iiiiiiii        mssjjjjj        Call Primitive #iiiiiiii + (jjjjj * 256) 
> +                                m=1 means inlined primitive, no hard return after execution. 
> +                                ss defines the unsafe operation set used to encode the operations. 
> +                                (ss = 0 means sista unsafe operations, ss = 01 means lowcode operations, other numbers are not used)"
> +    "N.B. We could have made CallPrimitive a 2-byte code taking an extension, but that would
> +     complicate the VM's determination of the primitive number and the primitive error code
> +     store since the extension, being optional, would make the sequence variable length."
> +    (primitiveIndex < 1 or: [primitiveIndex > 32767]) ifTrue:
> +        [self outOfRangeError: 'primitive index' index: primitiveIndex range: 1 to: 32767].
> +    stream
> +        nextPut: 248;
> +        nextPut: (primitiveIndex bitAnd: 255);
> +        nextPut: (primitiveIndex bitShift: -8)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genDup (in category 'bytecode generation') -----
> + genDup
> +    "83            01010011            Duplicate Stack Top"
> +    stream nextPut: 83!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genInlineSmallIntegerAdd (in category 'in-line primitive generation') -----
> + genInlineSmallIntegerAdd
> +    ^self genCallInlinePrimitive: 0!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genJump: (in category 'bytecode generation') -----
> + genJump: distance
> +    (distance > 0 and: [distance < 9]) ifTrue:
> +        ["176-183    10110 iii            Jump iii + 1 (i.e., 1 through 8)"
> +         stream nextPut: 175 + distance.
> +         ^self].
> +    "237        11101101    iiiiiiii        Jump #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> +    ^self genJumpLong: distance!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genJumpLong: (in category 'bytecode generation') -----
> + genJumpLong: distance
> +    "237        11101101    iiiiiiii        Jump #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> +    (distance between: -32768 and: 32767) ifFalse:
> +        [^self outOfRangeError: 'index' index: distance range: -32768 to: 32767].
> +    (distance < 0 or: [distance > 255]) ifTrue:
> +        [self genSignedSingleExtendB: (distance bitShift: -8)].
> +    stream
> +        nextPut: 237;
> +        nextPut: (distance bitAnd: 255)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genNop (in category 'bytecode generation') -----
> + genNop
> +    "95            01011111            Nop"
> +    stream nextPut: 95!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPop (in category 'bytecode generation') -----
> + genPop
> +    "216        11011000            Pop Stack Top"
> +    stream nextPut: 216!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushCharacter: (in category 'bytecode generation') -----
> + genPushCharacter: aCharacterOrCode
> +    "233        11101001    i i i i i i i i    Push Character #iiiiiiii (+ Extend A * 256)"
> +    "Why restrict the range to 16 bits when we could encode arbitrary 32-bit Characters?
> +     Well, 16 bits requires 4 bytes (extA + byte, 233 + byte) and so beyond this range we
> +     lose space verses a single-byte pushLiteral and a 4 byte Character literal on 32-bits.
> +     And generating the same bytecode on 64-bit and 32-bit versions is important if we
> +     want to be able to load binary code from one to the other (e.g. via Fuel)."
> +    | code |
> +    code := aCharacterOrCode isInteger ifTrue: [aCharacterOrCode] ifFalse: [aCharacterOrCode asInteger].
> +    (code < 0 or: [code > 65535]) ifTrue:
> +        [^self outOfRangeError: 'character' index: code range: 0 to: 65535].
> +    (code > 255) ifTrue:
> +        [self genUnsignedSingleExtendA: (code bitShift: -8)].
> +    stream
> +        nextPut: 233;
> +        nextPut: (code bitAnd: 255)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushClosureCopyNumCopiedValues:numArgs:jumpSize: (in category 'bytecode generation') -----
> + genPushClosureCopyNumCopiedValues: numCopied numArgs: numArgs jumpSize: jumpSize
> +    "250        11111010 eeiiikkk        jjjjjjjj        Push Closure Num Copied iii (+ Ext A // 16 * 8) Num Args kkk (+ Ext A \\ 16 * 8) BlockSize jjjjjjjj (+ Ext B * 256). ee = num extensions"
> +    "Including numExtensions makes decoding the bytecode quicker since it obviates having to scan from the beginning of a method."
> +    | numExtensions numCopiedMod8 numArgsMod8 extA |
> +    (jumpSize < 0 or: [jumpSize > 65535]) ifTrue:
> +        [^self outOfRangeError: 'block size' index: jumpSize range: 0 to: 65535].
> +    (numCopied < 0 or: [numCopied > 127]) ifTrue:
> +        [^self outOfRangeError: 'num copied' index: numCopied range: 0 to: 127].
> +    (numArgs < 0 or: [numArgs > 127]) ifTrue:
> +        [^self outOfRangeError: 'num args' index: numArgs range: 0 to: 127].
> +    extA := numExtensions := 0.
> +    (numArgsMod8 := numArgs) > 7 ifTrue:
> +        [extA := numArgs // 8.
> +         numArgsMod8 := numArgsMod8 \\ 8].
> +    (numCopiedMod8 := numCopied) > 7 ifTrue:
> +        [extA := extA + (numCopied // 8 * 16).
> +         numCopiedMod8 := numCopiedMod8 \\ 8].
> +    extA ~= 0 ifTrue:
> +        [self genUnsignedSingleExtendA: extA.
> +         numExtensions := 1].
> +    jumpSize > 255 ifTrue:
> +        [numExtensions := numExtensions + 1.
> +         self genUnsignedSingleExtendB: jumpSize // 256].
> +    stream
> +        nextPut: 250;
> +        nextPut: (numExtensions bitShift: 6) + (numCopiedMod8 bitShift: 3) + numArgsMod8;
> +        nextPut: (jumpSize bitAnd: 16rFF)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushConsArray: (in category 'bytecode generation') -----
> + genPushConsArray: size
> +    (size < 0 or: [size > 127]) ifTrue:
> +        [^self outOfRangeError: 'size' index: size range: 0 to: 127].
> +    "231        11100111    jkkkkkkk    Push (Array new: kkkkkkk) (j = 0)
> +                                    &    Pop kkkkkkk elements into: (Array new: kkkkkkk) (j = 1)"
> +    stream
> +        nextPut: 231;
> +        nextPut: size + 128!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushFullClosure:numCopied: (in category 'bytecode generation') -----
> + genPushFullClosure: compiledBlockLiteralIndex numCopied: numCopied
> +    "By default the closure will have an outer context and the receiver will be fetched from the current context"
> +    self genPushFullClosure: compiledBlockLiteralIndex numCopied: numCopied receiverOnStack: false ignoreOuterContext: false!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushFullClosure:numCopied:receiverOnStack:ignoreOuterContext: (in category 'bytecode generation') -----
> + genPushFullClosure: compiledBlockLiteralIndex numCopied: numCopied receiverOnStack: receiverOnStack ignoreOuterContext: ignoreOuterContext
> +    "*    249        11111001    xxxxxxxx    siyyyyyy    push Closure Compiled block literal index xxxxxxxx (+ Extend A * 256) numCopied yyyyyy receiverOnStack: s = 1 ignoreOuterContext: i = 1"
> +    | extendedIndex |
> +    (numCopied < 0 or: [numCopied > 64]) ifTrue:
> +        [self outOfRangeError: 'num copied' index: numCopied range: 1 to: 64].
> +    (compiledBlockLiteralIndex < 0 or: [compiledBlockLiteralIndex > 32767]) ifTrue:
> +        [^self outOfRangeError: 'index' index: compiledBlockLiteralIndex range: 0 to: 32767].
> +    (extendedIndex := compiledBlockLiteralIndex) > 255 ifTrue:
> +        [self genUnsignedSingleExtendA: extendedIndex // 256.
> +         extendedIndex := extendedIndex \\ 256].
> +    stream
> +        nextPut: 249;
> +        nextPut: extendedIndex;
> +        nextPut: receiverOnStack asBit << 7 + (ignoreOuterContext asBit << 6) + numCopied!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushInstVar: (in category 'bytecode generation') -----
> + genPushInstVar: instVarIndex
> +    (instVarIndex between: 0 and: 15) ifTrue:
> +        ["0-15    0000iiii    Push Receiver Variable #iiii"
> +         stream nextPut: 0 + instVarIndex.
> +         ^self].
> +    self genPushInstVarLong: instVarIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushInstVarLong: (in category 'bytecode generation') -----
> + genPushInstVarLong: instVarIndex
> +    "226        11100010    i i i i i i i i    Push Receiver Variable #iiiiiiii (+ Extend A * 256)"
> +    "See also MaybeContextInstanceVariableNode"
> +    (instVarIndex < 0 or: [instVarIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 65535].
> +    instVarIndex > 255 ifTrue:
> +        [self genUnsignedSingleExtendA: instVarIndex // 256].
> +    stream
> +        nextPut: 226;
> +        nextPut: instVarIndex \\ 256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushInteger: (in category 'bytecode generation') -----
> + genPushInteger: anInteger
> +    "80            01010000                Push 0
> +     81            01010001                Push 1
> +     232        11101000    i i i i i i i i    Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)"
> +    "Why restrict the range to 16 bits when we could encode arbitrarily large integers?
> +     Well, 16 bits requires 4 bytes (extB + byte, 78 + byte) and so beyond this range we lose space
> +     verses a single-byte pushLiteral and a 4 byte integer literal on 32-bits.  And generating the same
> +     bytecode on 64-bit and 32-bit is important if we want to be able to load binary code from one to
> +     the other (e.g. via Fuel)."
> +    anInteger = 0 ifTrue:
> +        [stream nextPut: 80.
> +         ^self].
> +    anInteger = 1 ifTrue:
> +        [stream nextPut: 81.
> +         ^self].
> +    (anInteger < -32768 or: [anInteger > 32767]) ifTrue:
> +        [^self outOfRangeError: 'integer' index: anInteger range: -32768 to: 32767].
> +    (anInteger < 0 or: [anInteger > 255]) ifTrue:
> +        [self genSignedSingleExtendB: (anInteger bitShift: -8)].
> +    stream
> +        nextPut: 232;
> +        nextPut: (anInteger bitAnd: 255)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushLiteral: (in category 'bytecode generation') -----
> + genPushLiteral: literalIndex
> +    | extendedIndex |
> +    (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: literalIndex range: 0 to: 65535].
> +    literalIndex < 32 ifTrue: 
> +        ["32-63    001iiiii    Push Literal #iiiii"
> +         stream nextPut: 32 + literalIndex.
> +         ^self].
> +    "228        11100100    i i i i i i i i    Push Literal #iiiiiiii (+ Extend A * 256)"
> +    (extendedIndex := literalIndex) > 255 ifTrue:
> +        [self genUnsignedSingleExtendA: extendedIndex // 256.
> +         extendedIndex := extendedIndex \\ 256].
> +    stream
> +        nextPut: 228;
> +        nextPut: extendedIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushLiteralVar: (in category 'bytecode generation') -----
> + genPushLiteralVar: literalIndex
> +    | extendedIndex |
> +    (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: literalIndex range: 0 to: 65535].
> +    literalIndex < 16 ifTrue: 
> +        ["16-31        0001 i i i i        Push Literal Variable #iiii"
> +         stream nextPut: 16 + literalIndex.
> +         ^self].
> +    "227        11100011    i i i i i i i i    Push Literal Variable #iiiiiiii (+ Extend A * 256)"
> +    (extendedIndex := literalIndex) > 255 ifTrue:
> +        [self genUnsignedSingleExtendA: extendedIndex // 256.
> +         extendedIndex := extendedIndex \\ 256].
> +    stream
> +        nextPut: 227;
> +        nextPut: extendedIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushNewArray: (in category 'bytecode generation') -----
> + genPushNewArray: size
> +    (size < 0 or: [size > 127]) ifTrue:
> +        [^self outOfRangeError: 'size' index: size range: 0 to: 127].
> +    "231        11100111    jkkkkkkk    Push (Array new: kkkkkkk) (j = 0)
> +                                    &    Pop kkkkkkk elements into: (Array new: kkkkkkk) (j = 1)"
> +    stream
> +        nextPut: 231;
> +        nextPut: size!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushReceiver (in category 'bytecode generation') -----
> + genPushReceiver
> +    "76            01001100        Push Receiver"
> +    stream nextPut: 76!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushRemoteTemp:inVectorAt: (in category 'bytecode generation') -----
> + genPushRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> +    "251        11111011    kkkkkkkk    sjjjjjjj        Push Temp At kkkkkkkk In Temp Vector At: jjjjjjj, s = 1 implies remote inst var access instead of remote temp vector access"
> +    (tempIndex < 0 or: [tempIndex >= 256]) ifTrue:
> +        [^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
> +    (tempVectorIndex < 0 or: [tempVectorIndex >= 128]) ifTrue:
> +        [^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 127].
> +    stream
> +        nextPut: 251;
> +        nextPut: tempIndex;
> +        nextPut: tempVectorIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushSpecialLiteral: (in category 'bytecode generation') -----
> + genPushSpecialLiteral: aLiteral
> +    "77            01001101            Push true
> +     78            01001110            Push false
> +     79            01001111            Push nil
> +     80            01010000            Push 0
> +     81            01010001            Push 1
> +     232        11101000    iiiiiiii        Push Integer #iiiiiiii (+ Extend B * 256, where bbbbbbbb = sddddddd, e.g. -32768 = i=0, a=0, s=1)
> +     233        11101001    i i i i i i i i    Push Character #iiiiiiii (+ Extend B * 256)"
> +    | index |
> +    aLiteral isInteger ifTrue:
> +        [aLiteral == 0 ifTrue:
> +            [stream nextPut: 80.
> +             ^self].
> +         aLiteral == 1 ifTrue:
> +            [stream nextPut: 81.
> +             ^self].
> +         ^self genPushInteger: aLiteral].
> +    aLiteral isCharacter ifTrue:
> +        [^self genPushCharacter: aLiteral].
> +    index := #(true false nil)
> +                    indexOf: aLiteral
> +                    ifAbsent: [^self error: 'push special literal: ', aLiteral printString,  ' is not one of true false nil'].
> +    stream nextPut: 76 + index!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushTemp: (in category 'bytecode generation') -----
> + genPushTemp: tempIndex
> +    (tempIndex < 0 or: [tempIndex > 63]) ifTrue:
> +        [^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
> +    tempIndex < 12 ifTrue: 
> +        ["64-71        01000 i i i        Push Temporary Variable #iii
> +           72-75    010010 i i        Push Temporary Variable #ii + 8"
> +         stream nextPut: 64 + tempIndex.
> +         ^self].
> +    "229        11100101    i i i i i i i i    Push Temporary Variable #iiiiiiii"
> +    stream
> +        nextPut: 229;
> +        nextPut: tempIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genPushThisContext (in category 'bytecode generation') -----
> + genPushThisContext
> +    "82            01010010            Push thisContext, (then e.g. Extend B 1 = push thisProcess)"
> +    stream nextPut: 82!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genReturnNilToCaller (in category 'bytecode generation') -----
> + genReturnNilToCaller
> +    "93            01011101            BlockReturn nil [* return from enclosing block N, ExtA]"
> +    "If extended, the least significant bit of the extension determines if we return to the caller or not
> +     and the most significant bits determine how many levels of the static chain to return from.
> +        ExtA = iiiiiiij
> +        iiiiiii=0,j=0    =>    return to caller
> +        iiiiiii=0,j=1    =>    illegal
> +        iiiiiii=1,j=0    =>    return to outerContext
> +        iiiiiii=1,j=1    =>    return to outerContext sender/return from outerContext
> +        iiiiiii=2,j=0    =>    return to outerContext outerContext
> +        iiiiiii=2,j=1    =>    return to outerContext outerContext sender/return from outerContext outerContext
> +        etc"
> + 
> +    stream nextPut: 93!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genReturnReceiver (in category 'bytecode generation') -----
> + genReturnReceiver
> +    "88-91        010110 ii            Return Receiver/true/false/nil"
> +    stream nextPut: 88!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genReturnSpecialLiteral: (in category 'bytecode generation') -----
> + genReturnSpecialLiteral: aLiteral
> +    "88-91        010110 ii            Return Receiver/true/false/nil"
> +    | 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: 88 + index!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genReturnTop (in category 'bytecode generation') -----
> + genReturnTop
> +    "92        1011100        Return Stack Top From Message"
> +    stream nextPut: 92!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genReturnTopToCaller (in category 'bytecode generation') -----
> + genReturnTopToCaller
> +    "94        01011110        Return Stack Top From Block [* return from enclosing block N, ExtA]"
> +    "If extended, the least significant bit of the extension determines if we return to the caller or not
> +     and the most significant bits determine how many levels of the static chain to return from.
> +        ExtA = iiiiiiij
> +        iiiiiii=0,j=0    =>    return to caller
> +        iiiiiii=0,j=1    =>    illegal
> +        iiiiiii=1,j=0    =>    return to outerContext
> +        iiiiiii=1,j=1    =>    return to outerContext sender/return from outerContext
> +        iiiiiii=2,j=0    =>    return to outerContext outerContext
> +        iiiiiii=2,j=1    =>    return to outerContext outerContext sender/return from outerContext outerContext
> +        etc"
> + 
> +    stream nextPut: 94!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genSend:numArgs: (in category 'bytecode generation') -----
> + genSend: selectorLiteralIndex numArgs: nArgs
> +    | extendedIndex extendedNArgs |
> +    (selectorLiteralIndex < 0 or: [selectorLiteralIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'selectorLiteralIndex' index: selectorLiteralIndex range: 0 to: 65535].
> +    (nArgs < 0 or: [nArgs > 31]) ifTrue:
> +        [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31 "!!!!"].
> +    (selectorLiteralIndex < 16 and: [nArgs < 3]) ifTrue: 
> +        ["128-143    1000 iiii            Send Literal Selector #iiii With 0 Argument
> +          144-159    1001 iiii            Send Literal Selector #iiii With 1 Arguments
> +          160-175    1010 iiii            Send Literal Selector #iiii With 2 Arguments"
> +         stream nextPut: 128 + (nArgs * 16) + selectorLiteralIndex.
> +         ^self].
> +    (extendedIndex := selectorLiteralIndex) > 31 ifTrue:
> +        [self genUnsignedMultipleExtendA: extendedIndex // 32.
> +         extendedIndex := extendedIndex \\ 32].
> +    (extendedNArgs := nArgs) > 7 ifTrue:
> +        [self genUnsignedSingleExtendB: extendedNArgs // 8.
> +         extendedNArgs := extendedNArgs \\ 8].
> +    "234        11101010    i i i i i j j j    Send Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> +    stream
> +        nextPut: 234;
> +        nextPut: extendedNArgs + (extendedIndex * 8)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genSendDirectedSuper:numArgs: (in category 'bytecode generation') -----
> + genSendDirectedSuper: selectorLiteralIndex numArgs: nArgs
> +    | extendedIndex |
> +    (selectorLiteralIndex < 0 or: [selectorLiteralIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'selectorLiteralIndex' index: selectorLiteralIndex range: 0 to: 65535].
> +    (nArgs < 0 or: [nArgs > 31]) ifTrue:
> +        [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31 "!!!!"].
> +    (extendedIndex := selectorLiteralIndex) > 31 ifTrue:
> +        [self genUnsignedMultipleExtendA: extendedIndex // 32.
> +         extendedIndex := extendedIndex \\ 32].
> +    "Bit 6 of the ExtB byte is the directed send flag.  Bit 6 allows for future expansion to up to 255 args."
> +    self genUnsignedSingleExtendB: nArgs // 8 + 64.
> +    "235        11101011    iiiiijjj        Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> +    stream
> +        nextPut: 235;
> +        nextPut: nArgs \\ 8 + (extendedIndex * 8)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genSendSpecial:numArgs: (in category 'bytecode generation') -----
> + genSendSpecial: specialSelectorIndex numArgs: nArgs
> +    self assert: (specialSelectorIndex between: 1 and: Smalltalk specialSelectorSize).
> +    self assert: nArgs = (Smalltalk specialNargsAt: specialSelectorIndex).
> +    "Special selector sends.
> +        96-111        0110 iiii            Send Arithmetic Message #iiii #(#+ #- #< #> #'<=' #'>=' #= #'~=' #* #/ #'\\' #@ #bitShift: #'//' #bitAnd: #bitOr:)
> +        112-119    01110 iii            Send Special Message #iii #(#at: #at:put: #size ? ? ? #'==' class ? value value: ? ? ? ? ?)"
> + 
> +    stream nextPut: specialSelectorIndex + 95!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genSendSuper:numArgs: (in category 'bytecode generation') -----
> + genSendSuper: selectorLiteralIndex numArgs: nArgs
> +    | extendedIndex extendedNArgs |
> +    (selectorLiteralIndex < 0 or: [selectorLiteralIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'selectorLiteralIndex' index: selectorLiteralIndex range: 0 to: 65535].
> +    (nArgs < 0 or: [nArgs > 31]) ifTrue:
> +        [^self outOfRangeError: 'numArgs' index: nArgs range: 0 to: 31 "!!!!"].
> +    (extendedIndex := selectorLiteralIndex) > 31 ifTrue:
> +        [self genUnsignedMultipleExtendA: extendedIndex // 32.
> +         extendedIndex := extendedIndex \\ 32].
> +    (extendedNArgs := nArgs) > 7 ifTrue:
> +        [self genUnsignedSingleExtendB: extendedNArgs // 8.
> +         extendedNArgs := extendedNArgs \\ 8].
> +    "235        11101011    iiiiijjj        Send To Superclass Literal Selector #iiiii (+ Extend A * 32) with jjj (+ Extend B * 8) Arguments"
> +    stream
> +        nextPut: 235;
> +        nextPut: extendedNArgs + (extendedIndex * 8)!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genSignedSingleExtendB: (in category 'bytecode generation') -----
> + genSignedSingleExtendB: extendedIndex
> +    (extendedIndex between: -128 and: 127) ifFalse:
> +        [^self outOfRangeError: 'index' index: extendedIndex range: -128 to: 127].
> +    "225        11100001    sbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B)"
> +    stream
> +        nextPut: 225;
> +        nextPut: (extendedIndex >= 0 ifTrue: [extendedIndex] ifFalse: [extendedIndex + 256]) !
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStoreInstVar: (in category 'bytecode generation') -----
> + genStoreInstVar: instVarIndex
> +    "243        11110011    iiiiiiii        Store Receiver Variable #iiiiiii (+ Extend A * 256)"
> +    self genStoreInstVarLong: instVarIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStoreInstVarLong: (in category 'bytecode generation') -----
> + genStoreInstVarLong: instVarIndex
> +    "243        11110011    iiiiiiii        Store Receiver Variable #iiiiiii (+ Extend A * 256)"
> +    (instVarIndex < 0 or: [instVarIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 65535].
> +    instVarIndex > 255 ifTrue:
> +        [self genUnsignedSingleExtendA: instVarIndex // 256].
> +    stream
> +        nextPut: 243;
> +        nextPut: instVarIndex \\ 256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStoreLiteralVar: (in category 'bytecode generation') -----
> + genStoreLiteralVar: literalIndex
> +    "244        11110100    iiiiiiii        Store Literal Variable #iiiiiiii (+ Extend A * 256)"
> +    (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: literalIndex range: 0 to: 65535].
> +    literalIndex > 255 ifTrue: 
> +        [self genUnsignedSingleExtendA: literalIndex // 256].
> +    stream
> +        nextPut: 244;
> +        nextPut: literalIndex \\ 256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStorePopInstVar: (in category 'bytecode generation') -----
> + genStorePopInstVar: instVarIndex
> +    "200-207    11001 iii            Pop and Store Receiver Variable #iii
> +     240        11110000    iiiiiiii    Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256)"
> +    (instVarIndex < 0 or: [instVarIndex > 7]) ifTrue:
> +        [^self genStorePopInstVarLong: instVarIndex].
> +    stream nextPut: 200 + instVarIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStorePopInstVarLong: (in category 'bytecode generation') -----
> + genStorePopInstVarLong: instVarIndex
> +    "240        11110000    iiiiiiii        Pop and Store Receiver Variable #iiiiiii (+ Extend A * 256)"
> +    (instVarIndex < 0 or: [instVarIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: instVarIndex range: 0 to: 65535].
> +    instVarIndex > 255 ifTrue:
> +        [self genUnsignedSingleExtendA: instVarIndex // 256].
> +    stream
> +        nextPut: 240;
> +        nextPut: instVarIndex \\ 256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStorePopLiteralVar: (in category 'bytecode generation') -----
> + genStorePopLiteralVar: literalIndex
> +    "241        11110001    iiiiiiii        Pop and Store Literal Variable #iiiiiiii (+ Extend A * 256)"
> +    (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: literalIndex range: 0 to: 65535].
> +    literalIndex > 255 ifTrue: 
> +        [self genUnsignedSingleExtendA: literalIndex // 256].
> +    stream
> +        nextPut: 241;
> +        nextPut: literalIndex \\ 256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStorePopRemoteTemp:inVectorAt: (in category 'bytecode generation') -----
> + genStorePopRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> +    "*    253    (3)    11111101    kkkkkkkk    sjjjjjjj        Pop and Store Temp At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst var access instead of remote temp vector access"
> +    (tempIndex < 0 or: [tempIndex >= 256]) ifTrue:
> +        [^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
> +    (tempVectorIndex < 0 or: [tempVectorIndex >= 128]) ifTrue:
> +        [^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 127].
> +    stream
> +        nextPut: 253;
> +        nextPut: tempIndex;
> +        nextPut: tempVectorIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStorePopTemp: (in category 'bytecode generation') -----
> + genStorePopTemp: tempIndex
> +    "208-215    11010 iii            Pop and Store Temporary Variable #iii
> +     242        11110010    iiiiiiii    Pop and Store Temporary Variable #iiiiiiii"
> +    (tempIndex < 0 or: [tempIndex > 63]) ifTrue:
> +        [^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
> +    tempIndex < 8 ifTrue:
> +        [stream nextPut: 208 + tempIndex.
> +         ^self].
> +    stream
> +        nextPut: 242;
> +        nextPut: tempIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStoreRemoteTemp:inVectorAt: (in category 'bytecode generation') -----
> + genStoreRemoteTemp: tempIndex inVectorAt: tempVectorIndex
> +    "*252    (3)    11111100    kkkkkkkk    sjjjjjjj        Store Temp At kkkkkkkk In Temp Vector At: jjjjjjj s = 1 implies remote inst var access instead of remote temp vector access"
> +    (tempIndex < 0 or: [tempIndex >= 256]) ifTrue:
> +        [^self outOfRangeError: 'remoteTempIndex' index: tempIndex range: 0 to: 255].
> +    (tempVectorIndex < 0 or: [tempVectorIndex >= 128]) ifTrue:
> +        [^self outOfRangeError: 'tempVectorIndex' index: tempVectorIndex range: 0 to: 127].
> +    stream
> +        nextPut: 252;
> +        nextPut: tempIndex;
> +        nextPut: tempVectorIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genStoreTemp: (in category 'bytecode generation') -----
> + genStoreTemp: tempIndex
> +    "245        11110110    iiiiiiii        Store Temporary Variable #iiiiiiii"
> +    (tempIndex < 0 or: [tempIndex > 63]) ifTrue:
> +        [^self outOfRangeError: 'index' index: tempIndex range: 0 to: 63].
> +    stream
> +        nextPut: 245;
> +        nextPut: tempIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genTrapIfNotInstanceOf: (in category 'bytecode generation') -----
> + genTrapIfNotInstanceOf: literalIndex
> +    "*    236        11101100    iiiiiiii        Trap If Not Instance Of Behavior/Array Of Behavior #iiiiiiii (+ Extend A * 256, where Extend A >= 0)"
> + 
> +    | extendedIndex |
> +    (literalIndex < 0 or: [literalIndex > 65535]) ifTrue:
> +        [^self outOfRangeError: 'index' index: literalIndex range: 0 to: 65536].
> +    (extendedIndex := literalIndex) > 255 ifTrue:
> +        [self genUnsignedSingleExtendA: extendedIndex // 256.
> +         extendedIndex := extendedIndex \\ 256].
> +    stream
> +        nextPut: 236;
> +        nextPut: extendedIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genUnsignedMultipleExtendA: (in category 'bytecode generation') -----
> + genUnsignedMultipleExtendA: extendedIndex
> +    "224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)"
> +    extendedIndex > 255 ifTrue:
> +        [self genUnsignedMultipleExtendA: extendedIndex // 256].
> +    stream
> +        nextPut: 224;
> +        nextPut: extendedIndex \\ 256!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genUnsignedSingleExtendA: (in category 'bytecode generation') -----
> + genUnsignedSingleExtendA: extendedIndex
> +    (extendedIndex between: 0 and: 255) ifFalse:
> +        [^self outOfRangeError: 'index' index: extendedIndex range: 0 to: 255].
> +    "224        11100000    aaaaaaaa    Extend A (Ext A = Ext A prev * 256 + Ext A)
> +    ExtA is normally unsigned."
> +    stream
> +        nextPut: 224;
> +        nextPut: extendedIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>genUnsignedSingleExtendB: (in category 'bytecode generation') -----
> + genUnsignedSingleExtendB: extendedIndex
> +    (extendedIndex between: 0 and: 255) ifFalse:
> +        [^self outOfRangeError: 'index' index: extendedIndex range: 0 to: 255].
> +    "225        11100001    sbbbbbbb    Extend B (Ext B = Ext B prev * 256 + Ext B).
> +    ExtB is normally signed"
> +    stream
> +        nextPut: 225;
> +        nextPut: extendedIndex!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>isSpecialLiteralForPush: (in category 'special literal encodings') -----
> + isSpecialLiteralForPush: literal
> +    ^literal isInteger
> +        ifFalse:
> +            [literal isCharacter
> +                ifFalse:
> +                    [false == literal
> +                     or: [true == literal
> +                     or: [nil == literal]]]
> +                ifTrue:
> +                    [Smalltalk interpreterVMMakerVersion >= 3174
> +                        ifTrue:
> +                            [literal asInteger between: 0 and: 65535]
> +                        ifFalse:
> +                            ["Restrict character range due to VM bug at character value reconstruction
> +                              See https://github.com/OpenSmalltalk/opensmalltalk-vm/issues/618"
> +                             literal asInteger between: 0 and: 16rFF]]]
> +        ifTrue:
> +            [literal between: -32768 and: 32767]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>isSpecialLiteralForReturn: (in category 'special literal encodings') -----
> + isSpecialLiteralForReturn: literal
> +    ^literal == false
> +      or: [literal == true
> +      or: [literal == nil]]!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>maxIndexableLiterals (in category 'accessing') -----
> + maxIndexableLiterals
> +    "Answer the maximum number of literals supported by the receiver's
> +     bytecode set."
> +    ^65536!
> 
> Item was added:
> + ----- Method: EncoderForSistaV1>>supportsFullBlocks (in category 'testing') -----
> + supportsFullBlocks
> +    "Answer if the instruction set supports full closures (closure creation from
> +     specfic methods instead of bytecodes embedded in an outer home method)."
> + 
> +    ^true!
> 
> Item was added:
> + BytecodeEncoder subclass: #EncoderForV3
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !EncoderForV3 commentStamp: 'eem 1/18/2019 12:38' prior: 0!
> + I add behaviour to Encoder to size and emit bytecodes for the Squeak V3.x VM bytecode set, a close variant of the original Smalltalk-80 bytecode set defined in the Blue Book.
> + 
> +    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
> +    112-119    01110iii    Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]
> +    120-123    011110ii    Return (receiver, true, false, nil) [ii] From Message
> +    124-125    0111110i    Return Stack Top From (Message, Block) [i]
> +    (126-127 unassigned)
> +    128        10000000 jjkkkkkk    Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk
> +    129        10000001 jjkkkkkk    Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> +    130        10000010 jjkkkkkk    Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> +    131        10000011 jjjkkkkk    Send Literal Selector #kkkkk With jjj Arguments
> +    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 (for sends jjjjj = numArgs)
> +    133        10000101 jjjkkkkk    Send Literal Selector #kkkkk To Superclass With jjj Arguments
> +    134        10000110 jjkkkkkk    Send Literal Selector #kkkkkk With jj Arguments
> +    135        10000111    Pop Stack Top
> +    136        10001000    Duplicate Stack Top
> +    137        10001001    Push Active Context
> +    (138-143 unassigned)
> +    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)
> +    160-167    10100iii jjjjjjjj    Jump(iii - 4) *256+jjjjjjjj
> +    168-171    101010ii jjjjjjjj    Pop and Jump On True ii *256+jjjjjjjj
> +    172-175    101011ii jjjjjjjj    Pop and Jump On False ii *256+jjjjjjjj
> +    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
> + !
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>bindingReadScanBlockFor:using: (in category 'compiled method support') -----
> + bindingReadScanBlockFor: bindingLitIndex using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for reads of the value of the binding with zero-relative index litVarIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    ^[:b|
> +       b >= 64
> +       and: [b <= 95
> +            ifTrue: [b - 64 = bindingLitIndex]
> +            ifFalse:
> +                [b = 128
> +                    ifTrue: [scanner followingByte - 192 = bindingLitIndex]
> +                    ifFalse:
> +                        [b = 132
> +                         and: [(scanner followingByte between: 128 and: 159)
> +                         and: [scanner thirdByte = bindingLitIndex]]]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>bindingWriteScanBlockFor:using: (in category 'compiled method support') -----
> + bindingWriteScanBlockFor: bindingLitIndex using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for writes of the value of the binding with zero-relative index bindingLitIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    ^[:b|
> +      (b = 129 or: [b = 130])
> +        ifTrue: [scanner followingByte - 192 = bindingLitIndex]
> +        ifFalse:
> +            [b = 132
> +             and: [scanner followingByte >= 224
> +             and: [scanner thirdByte = bindingLitIndex]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>bytecodeSize: (in category 'instruction stream support') -----
> + bytecodeSize: bytecode
> +    "Answer the number of bytes in the bytecode."
> +    bytecode <= 125 ifTrue:
> +        [^1].
> +    bytecode >= 176 ifTrue:
> +        [^1].
> +    bytecode >= 160 ifTrue: "long jumps"
> +        [^2].
> +    bytecode >= 144 ifTrue: "short jumps"
> +        [^1].
> +    "extensions"
> +    bytecode >= 128 ifTrue:
> +        [^#(2 2 2 2 3 2 2 1 1 1 nil nil nil nil nil nil) at: bytecode - 127].
> +    ^nil!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>canBeSpecialLiteral: (in category 'testing') -----
> + canBeSpecialLiteral: aLiteral
> +    "This check can be used to prevent unnecessary use of #scanBlockOrNilForLiteral:."
> + 
> +    aLiteral isVariableBinding ifTrue: [^false]. "a common case; don't waste time analysing..."
> + 
> +    aLiteral isSymbol ifTrue: [^ Smalltalk specialSelectors identityIncludes: aLiteral].
> +    aLiteral isInteger ifTrue: [^ aLiteral between: -1 and: 2].
> + 
> +    aLiteral == true ifTrue: [^ true].
> +    aLiteral == false ifTrue: [^ true].
> +    aLiteral == nil ifTrue: [^ true].
> + 
> +    ^ false!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>createClosureScanBlock (in category 'compiled method support') -----
> + createClosureScanBlock
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for block closure creation bytecodes."
> +    ^[:b| false]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>extensionsAt:in:into: (in category 'instruction stream support') -----
> + extensionsAt: pc in: aCompiledMethod into: trinaryBlock
> +    "If the bytecode at pc is an extension then evaluate aTrinaryBlock
> +     with the values of extA and extB and number of extension *bytes*.
> +     If the bytecode at pc is not an extension then evaluate with 0, 0, 0.
> +     There are no extensions in the SqueakV3/Smalltalk-80 bytecode set, so..." 
> +    ^trinaryBlock value: 0 value: 0 value: 0!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>extensionsFor:in:into: (in category 'instruction stream support') -----
> + extensionsFor: pc in: aCompiledMethod into: trinaryBlock
> +    "If the bytecode at pc is an extension, or if the bytecode at pc is preceded by extensions,
> +     then evaluate aTrinaryBlock with the values of extA and extB and number of extension *bytes*.
> +     If the bytecode at pc is neither an extension or extended then evaluate with 0, 0, 0.
> +     There are no extensions in the SqueakV3/Smalltalk-80 bytecode set, so..." 
> +    ^trinaryBlock value: 0 value: 0 value: 0!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>instVarReadScanBlockFor:using: (in category 'compiled method support') -----
> + instVarReadScanBlockFor: varIndexCode using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for reads of the inst var with zero-relative index varIndexCode.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    ^[:b|
> +       b < 16
> +        ifTrue: [b = varIndexCode]
> +        ifFalse:
> +            [b = 128
> +                ifTrue: [scanner followingByte = varIndexCode and: [varIndexCode <= 63]]
> +                ifFalse:
> +                    [b = 132
> +                     and: [(scanner followingByte between: 64 and: 95)
> +                     and: [scanner thirdByte = varIndexCode]]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>instVarWriteScanBlockFor:using: (in category 'compiled method support') -----
> + instVarWriteScanBlockFor: varIndexCode using: scanner
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for writes of the inst var with zero-relative index varIndexCode.
> +     N.B. Don't assume the compiler uses the most compact encoding available."
> +    ^[:b|
> +       b >= 96
> +       and: [b <= 103
> +            ifTrue: [b - 96 = varIndexCode]
> +            ifFalse:
> +                [(b = 129 or: [b = 130])
> +                    ifTrue: [scanner followingByte = varIndexCode and: [varIndexCode <= 63]]
> +                    ifFalse:
> +                        [b = 132
> +                         and: [(scanner followingByte between: 160 and: 223)
> +                         and: [scanner thirdByte = varIndexCode]]]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>interpretJumpIfCondIn: (in category 'instruction stream support') -----
> + interpretJumpIfCondIn: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct conditional jump decoder for the instruction set."
> +    ^anInstructionStream interpretV3JumpIfCond!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>interpretJumpIn: (in category 'instruction stream support') -----
> + interpretJumpIn: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct jump interpreter for the instruction set."
> +    ^anInstructionStream interpretV3Jump!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>interpretNextInstructionFor:in: (in category 'instruction stream support') -----
> + interpretNextInstructionFor: aClient in: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct instruction set decoder."
> +    ^anInstructionStream interpretNextV3InstructionFor: aClient!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isBlockReturnAt:in: (in category 'instruction stream support') -----
> + isBlockReturnAt: pc in: method
> +    "Answer whether the bytecode at pc is a return from block."
> + 
> +    ^(method at: pc) = 125!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isBranchIfFalseAt:in: (in category 'instruction stream support') -----
> + isBranchIfFalseAt: pc in: method
> +    "Answer whether the bytecode at pc is a conditional branch-if-false."
> +    | bytecode |
> +    bytecode := method at: pc.
> +    ^(bytecode between: 152 and: 159) or: [bytecode between: 172 and: 175]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isBranchIfTrueAt:in: (in category 'instruction stream support') -----
> + isBranchIfTrueAt: pc in: method
> +    "Answer whether the bytecode at pc is a conditional branch-if-true."
> +    ^(method at: pc) between: 168 and: 171!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isExtension: (in category 'instruction stream support') -----
> + isExtension: bytecode
> +    "Answer if the bytecode is an extension bytecode, i.e. one that extends the
> +     range of the following bytecode.  The Smalltalk-80/V3 sets don't use extensions."
> +    ^false!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isJumpAt:in: (in category 'instruction stream support') -----
> + isJumpAt: pc in: method
> +    "Answer whether the bytecode at pc is an (unconditional) jump."
> +    | bytecode |
> +    bytecode := method at: pc.
> +    ^(bytecode between: 144 and: 151) or: [bytecode between: 160 and: 167]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isJustPopAt:in: (in category 'instruction stream support') -----
> + isJustPopAt: pc in: method
> +    "Answer whether the bytecode at pc is a pop."
> + 
> +    ^(method at: pc) = 135    "135        10000111    Pop Stack Top"!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isRealSendAt:in: (in category 'instruction stream support') -----
> + isRealSendAt: pc in: method
> +    "Answer whether the bytecode at pc is a real message-send, not blockCopy:."
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^byte >= 176            "special send or short send"
> +      or: [byte >= 131
> +         and: [byte <= 134    "long sends"    
> +         and: [byte ~= 132    "double extended do anything"
> +            or: [(method at: pc + 1) // 32 <= 1]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isReturnAt:in: (in category 'instruction stream support') -----
> + isReturnAt: pc in: method
> +    "Answer whether the bytecode at pc is a return."
> + 
> +    ^(method at: pc) between: 120 and: 125!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isReturnSelfFromMethodAt:in: (in category 'instruction stream support') -----
> + isReturnSelfFromMethodAt: pc in: method
> +    "Answer whether the bytecode at pc is a return self from method."
> + 
> +    ^(method at: pc) = 120!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isReturnTopFromMethodAt:in: (in category 'instruction stream support') -----
> + isReturnTopFromMethodAt: pc in: method
> +    "Answer whether the bytecode at pc is a return stack top from method."
> + 
> +    ^(method at: pc) = 124!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isSendAt:in: (in category 'instruction stream support') -----
> + isSendAt: pc in: method
> +    "Answer whether the bytecode at pc is a message-send."
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^byte >= 176            "special send or short send"
> +     or: [byte >= 131
> +         and: [byte <= 134    "long sends"    
> +         and: [byte ~= 132    "double extended do anything"
> +            or: [(method at: pc + 1) // 32 <= 1]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isStoreAt:in: (in category 'instruction stream support') -----
> + isStoreAt: pc in: method
> +    "Answer whether the bytecode at pc is a store or store-pop."
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^(byte between: 96 and: 132)
> +        and: [byte <= 111                "96 103    storeAndPopReceiverVariableBytecode"
> +                                        "104 111    storeAndPopTemporaryVariableBytecode"
> +            or: [byte >= 129            "129        extendedStoreBytecode"
> +                and: [byte <= 130        "130        extendedStoreAndPopBytecode"
> +                    or: [byte = 132        "132        doubleExtendedDoAnythingBytecode"
> +                        and: [(method at: pc+1) >= 160]]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isStorePopAt:in: (in category 'instruction stream support') -----
> + isStorePopAt: pc in: method
> +    "Answer whether the bytecode at pc is a store-pop."
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^(byte between: 96 and: 111)    "96 103    storeAndPopReceiverVariableBytecode"
> +                                    "104 111    storeAndPopTemporaryVariableBytecode"
> +      or: [byte = 130]                "130        extendedStoreAndPopBytecode"!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isSyntheticStoreAt:in:for: (in category 'instruction stream support') -----
> + isSyntheticStoreAt: pc in: method for: anInstructionStream
> +    "Answer whether the bytecode at pc is a store or store-pop of an indirect temp vector,
> +     which implement mutable closed-over variables in the the closure implementation.
> +     Stores into temp vectors are not real stores."
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>isTempStoreAt:in: (in category 'instruction stream support') -----
> + isTempStoreAt: pc in: method
> +    "Answer whether the bytecode at pc is a store or store-pop into a temporary variable.
> +     104-111    01101iii    Pop and Store Temporary Location #iii
> +     129        10000001 jjkkkkkk    Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> +     130        10000010 jjkkkkkk    Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk"
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^byte >= 104
> +      and: [byte <= 111
> +            or: [byte <= 130 and: [byte >= 129 and: [(method at: pc + 1) >> 6 = 1]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>markerOrNilFor: (in category 'compiled method support') -----
> + markerOrNilFor: aMethod
> +    "If aMethod is a marker method, answer the symbol used to mark it.  Otherwise
> +     answer nil.  What is a marker method?  It is method with body like 
> +        'self subclassResponsibility' or '^ self subclassResponsibility' 
> +     used to indicate ('mark') a special property.
> + 
> +    Marker methods compile to two bytecode forms, this:
> +        self
> +        send: <literal 1>
> +        pop
> +        returnSelf
> +    or this:
> +        self
> +        send: <literal 1>
> +        returnTop"
> +    | expectedHeaderPlusLliteralSize e byte |
> +    expectedHeaderPlusLliteralSize := Smalltalk wordSize * 4.
> +    ^(((e := aMethod endPC - expectedHeaderPlusLliteralSize) = 3 or: [e = 4]) 
> +      and: [aMethod numLiterals = 3
> +      and: [(aMethod at: expectedHeaderPlusLliteralSize + 1) = 16r70 "push self"
> +      and: [(aMethod at: expectedHeaderPlusLliteralSize + 2) = 16rD0 "send"
> +      and: [(byte := aMethod at: expectedHeaderPlusLliteralSize + 3) = 16r87 "pop" or: [byte = 16r7C "returnTop"]]]]])
> +        ifTrue: [aMethod literalAt: 1]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>method:readsField: (in category 'scanning') -----
> + method: method readsField: varIndex
> +    "Answer if method loads the instance variable indexed by varIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available.
> +    0-15        0000iiii    Push Receiver Variable #iiii
> +    128        10000000 jjkkkkkk    Push (Receiver Variable, Temporary Location, Literal Constant, Literal Variable) [jj] #kkkkkk
> +    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 (for sends jjjjj = numArgs)"
> +    | varIndexCode scanner |
> +    varIndexCode := varIndex - 1.
> +    method isReturnField ifTrue:
> +        [^method returnField = varIndexCode].
> +    ^(scanner := InstructionStream on: method) scanFor:
> +        [:b|
> +        b < 16
> +            ifTrue: [b = varIndexCode]
> +            ifFalse:
> +                [b = 128
> +                    ifTrue: [scanner followingByte = varIndexCode and: [varIndexCode <= 63]]
> +                    ifFalse:
> +                        [b = 132
> +                         and: [(scanner followingByte between: 64 and: 95)
> +                         and: [scanner thirdByte = varIndexCode]]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>method:writesField: (in category 'scanning') -----
> + method: method writesField: varIndex
> +    "Answer if method stores into the instance variable indexed by varIndex.
> +     N.B. Don't assume the compiler uses the most compact encoding available.
> +    96-103    01100iii    Pop and Store Receiver Variable #iii
> +    129        10000001 jjkkkkkk    Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> +    130        10000010 jjkkkkkk    Pop and Store (Receiver Variable, Temporary Location, Illegal, Literal Variable) [jj] #kkkkkk
> +    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 (for sends jjjjj = numArgs)"
> +    | varIndexCode scanner |
> +    method isQuick ifTrue: [^false].
> +    varIndexCode := varIndex - 1.
> +    ^(scanner := InstructionStream on: method) scanFor:
> +        [:b|
> +        b >= 96
> +        and: [b <= 103
> +                ifTrue: [b - 96 = varIndexCode]
> +                ifFalse:
> +                    [(b = 129 or: [b = 130])
> +                        ifTrue: [scanner followingByte = varIndexCode and: [varIndexCode <= 63]]
> +                        ifFalse:
> +                            [b = 132
> +                             and: [(scanner followingByte between: 160 and: 223)
> +                             and: [scanner thirdByte = varIndexCode]]]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>nonExtensionBytecodeAt:in: (in category 'instruction stream support') -----
> + nonExtensionBytecodeAt: pc in: method
> +    "Answer the actual bytecode at pc in method, skipping past any preceding extensions."
> +    ^method at: pc!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>pushNilCode (in category 'bytecode decoding') -----
> + pushNilCode
> +    "Answer the pushNil bytecode.
> +     112-119    01110iii    Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]"
> +    ^115!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>scanBlockOrNilForLiteral: (in category 'scanning') -----
> + scanBlockOrNilForLiteral: aLiteral
> +    "Answer a block argument for CompiledMethod>>#scanFor: that answers
> +     if the method refers to the literal implicitly via a special bytecode.
> +     If the literal is not accessible via a special bytecode, answer nil."
> +    | value |
> +    "176-191    1011iiii    Send Arithmetic Message #iiii
> +     192-207    1100iiii    Send Special Message #iiii"
> +    (aLiteral isSymbol or: [aLiteral isInteger]) ifTrue:
> +        [value := aLiteral isSymbol
> +                    ifTrue: [176 + ((Smalltalk specialSelectors indexOf: aLiteral ifAbsent: [^nil]) // 2)]
> +                    ifFalse: [(aLiteral between: -1 and: 2) ifFalse: [^nil].
> +                            aLiteral + 117].
> +         ^[:byte| byte = value]].
> +    "112-119    01110iii    Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]
> +     120-123    011110ii    Return (receiver, true, false, nil) [ii] From Message"
> +    aLiteral == true ifTrue:
> +        [^[:byte| byte = 113 or: [byte = 121]]].
> +    aLiteral == false ifTrue:
> +        [^[:byte| byte = 114 or: [byte = 122]]].
> +    aLiteral == nil ifTrue:
> +        [^[:byte| byte = 115 or: [byte = 123]]].
> +    ^nil!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>selectorToSendOrItselfFor:in:at: (in category 'instruction stream support') -----
> + selectorToSendOrItselfFor: anInstructionStream in: method at: pc
> +    "If anInstructionStream is at a send bytecode then answer the send's selector,
> +     otherwise answer anInstructionStream itself.  The rationale for answering
> +     anInstructionStream instead of, say, nil, is that potentially any existing object
> +     can be used as a selector, but since anInstructionStream postdates the method,
> +     it can't be one of them."
> + 
> +    | byte byte2 |
> +    byte := method at: pc.
> +    byte < 131 ifTrue: [^anInstructionStream].
> +    byte >= 176
> +        ifTrue: 
> +            ["special byte or short send"
> +            byte >= 208
> +                ifTrue: [^method literalAt: (byte bitAnd: 15) + 1]
> +                ifFalse: [^Smalltalk specialSelectorAt: byte - 176 + 1]]
> +        ifFalse: 
> +            [byte <= 134 ifTrue: 
> +                [byte2 := method at: pc + 1.
> +                 byte = 131 ifTrue: [^method literalAt: byte2 \\ 32 + 1].
> +                 byte = 132 ifTrue: [byte2 < 64 ifTrue: [^method literalAt: (method at: pc + 2) + 1]].
> +                 byte = 133 ifTrue: [^method literalAt: byte2 \\ 32 + 1].
> +                 byte = 134 ifTrue: [^method literalAt: byte2 \\ 64 + 1]]].
> +    ^anInstructionStream!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>superSendScanBlockUsing: (in category 'compiled method support') -----
> + superSendScanBlockUsing: scanner
> +    "Answer a block argument for InstructionStream>>scanFor:
> +     that answers true for super sends."
> +    ^[:instr |
> +       instr = 16r85
> +       or: [instr = 16r84
> +        and: [scanner followingByte between: 16r20 and: 16r3F]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>supportsClosures (in category 'compiled method support') -----
> + supportsClosures
> +    "Answer if the instruction set supports closures (contains
> +     closure creation and indirect temp access bytecodes)."
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: EncoderForV3 class>>unusedBytecode (in category 'bytecode decoding') -----
> + unusedBytecode
> +    "Answer the opcode of a single-byte unused bytecode, if it exists in the encoder's bytecode set, or nil if not."
> +    ^126!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genBranchPopFalse: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genBranchPopTrue: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genDup (in category 'bytecode generation') -----
> + genDup
> +    "See BlueBook page 596"
> +    "136    10001000    Duplicate Stack Top"
> +    stream nextPut: 136!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genJump: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genJumpLong: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPop (in category 'bytecode generation') -----
> + genPop
> +    "See BlueBook page 596"
> +    "135    10000111    Pop Stack Top"
> +    stream nextPut: 135!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushInstVar: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushInstVarLong: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushLiteral: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushLiteralVar: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushReceiver (in category 'bytecode generation') -----
> + genPushReceiver
> +    "See BlueBook page 596"
> +    "112-119    01110iii    Push (receiver, true, false, nil, -1, 0, 1, 2) [iii]"
> +    stream nextPut: 112!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushSpecialLiteral: (in category 'bytecode generation') -----
> + 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.
> +    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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushTemp: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushTempLong: (in category 'bytecode generation') -----
> + genPushTempLong: tempIndex
> +    "See BlueBook page 596"
> +    (tempIndex >= 0 and: [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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genPushThisContext (in category 'bytecode generation') -----
> + genPushThisContext
> +    "See BlueBook page 596"
> +    "137    10001001    Push Active Context"
> +    stream nextPut: 137!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genReturnReceiver (in category 'bytecode generation') -----
> + genReturnReceiver
> +    "See BlueBook page 596"
> +    "120-123    011110ii    Return (receiver, true, false, nil) [ii] From Message"
> +    stream nextPut: 120!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genReturnSpecialLiteral: (in category 'bytecode generation') -----
> + genReturnSpecialLiteral: aLiteral
> +    "120-123    011110ii    Return (receiver, true, false, nil) [ii] From Message"
> +    | index |
> +    index := #(true false nil) indexOf: aLiteral.
> +    index = 0 ifTrue:
> +        [^self error: 'return special literal: ', aLiteral printString,  ' is not one of true false nil'].
> +    stream nextPut: 120 + index!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genReturnTop (in category 'bytecode generation') -----
> + genReturnTop
> +    "See BlueBook page 596"
> +    "124-125    0111110i    Return Stack Top From (Message, Block) [i]"
> +    stream nextPut: 124!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genReturnTopToCaller (in category 'bytecode generation') -----
> + genReturnTopToCaller
> +    "See BlueBook page 596"
> +    "124-125    0111110i    Return Stack Top From (Message, Block) [i]"
> +    stream nextPut: 125!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genSend:numArgs: (in category 'bytecode generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genSendSpecial:numArgs: (in category 'bytecode generation') -----
> + genSendSpecial: specialSelectorIndex numArgs: nArgs
> +    "See BlueBook page 596"
> +    self assert: (specialSelectorIndex between: 1 and: Smalltalk specialSelectorSize).
> +    self assert: nArgs = (Smalltalk specialNargsAt: specialSelectorIndex).
> +    "Special selector sends.
> +        176-191    1011iiii    Send Arithmetic Message #iiii
> +        192-207    1100iiii    Send Special Message #iiii"
> +    stream nextPut: specialSelectorIndex + 175!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genSendSuper:numArgs: (in category 'bytecode generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStoreInstVar: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStoreInstVarLong: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStoreLiteralVar: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStorePopInstVar: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStorePopInstVarLong: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStorePopLiteralVar: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStorePopTemp: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>genStoreTemp: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3>>if:isSpecialLiteralForPush: (in category 'special literal encodings') -----
> + 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]!
> 
> Item was added:
> + ----- Method: EncoderForV3>>if:isSpecialLiteralForReturn: (in category 'special literal encodings') -----
> + 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]!
> 
> Item was added:
> + ----- Method: EncoderForV3>>isSpecialLiteralForPush: (in category 'special literal encodings') -----
> + isSpecialLiteralForPush: literal
> +    ^literal isInteger
> +        ifFalse:
> +            [false == literal
> +             or: [true == literal
> +             or: [nil == literal]]]
> +        ifTrue: [literal between: -1 and: 2]!
> 
> Item was added:
> + ----- Method: EncoderForV3>>isSpecialLiteralForReturn: (in category 'special literal encodings') -----
> + isSpecialLiteralForReturn: literal
> +    ^literal == false
> +      or: [literal == true
> +      or: [literal == nil]]!
> 
> Item was added:
> + ----- Method: EncoderForV3>>maxIndexableLiterals (in category 'bytecode generation') -----
> + maxIndexableLiterals
> +    "This bytecode set can index up to 256 literals."
> +    ^256!
> 
> Item was added:
> + ----- Method: EncoderForV3>>supportsFullBlocks (in category 'testing') -----
> + supportsFullBlocks
> +    "Answer if the instruction set supports full closures (closure creation from
> +     specfic methods instead of bytecodes embedded in an outer home method)."
> +    
> +    ^false!
> 
> Item was added:
> + EncoderForV3 subclass: #EncoderForV3PlusClosures
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !EncoderForV3PlusClosures commentStamp: 'eem 2/29/2016 00:07' 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)
> +    139   10001011 kkkkkkkk jjjjjjjj    Invoke primitive number jjjjjjjjkkkkkkkk
> +    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.!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>bytecodeSize: (in category 'instruction stream support') -----
> + bytecodeSize: bytecode
> +    "Answer the number of bytes in the bytecode."
> +    bytecode <= 125 ifTrue:
> +        [^1].
> +    bytecode >= 176 ifTrue:
> +        [^1].
> +    bytecode >= 160 ifTrue: "long jumps"
> +        [^2].
> +    bytecode >= 144 ifTrue: "short jumps"
> +        [^1].
> +    "extensions"
> +    bytecode >= 128 ifTrue:
> +        [^#(2 2 2 2 3 2 2 1 1 1 2 3 3 3 3 4) at: bytecode - 127].
> +    ^nil!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>callPrimitiveCode (in category 'bytecode decoding') -----
> + callPrimitiveCode
> +    "139    11101111    iiiiiiii jjjjjjjj    Call Primitive #iiiiiiii + (jjjjjjjj * 256)"
> +    ^139!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>createClosureCode (in category 'bytecode decoding') -----
> + createClosureCode
> +    "Answer the create closure bytecode, if it exists in the encoder's bytecode set, or nil if not.
> +     Actually this code is that for a closure whose bytecodes are nested within its home method's."
> +    ^143!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>createClosureScanBlock (in category 'compiled method support') -----
> + createClosureScanBlock
> +    "Answer a block argument for InstructionStream>>scanFor: that answers true
> +     for block closure creation bytecodes."
> +    ^[ :bc | bc = 143]!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>interpretNextInstructionFor:in: (in category 'instruction stream support') -----
> + interpretNextInstructionFor: aClient in: anInstructionStream
> +    "Double-dispatch through the encoder to select the correct instruction set decoder."
> +    ^anInstructionStream interpretNextV3ClosuresInstructionFor: aClient!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>isStoreAt:in: (in category 'instruction stream support') -----
> + isStoreAt: pc in: method
> +    "Answer whether the bytecode at pc is a store or store-pop."
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^(byte between: 96 and: 142)
> +        and: [byte <= 111                "96 103    storeAndPopReceiverVariableBytecode"
> +                                        "104 111    storeAndPopTemporaryVariableBytecode"
> +            or: [byte >= 129            "129        extendedStoreBytecode"
> +                and: [byte <= 130        "130        extendedStoreAndPopBytecode"
> +                    or: [(byte = 132    "132        doubleExtendedDoAnythingBytecode"
> +                        and: [(method at: pc+1) >= 160])
> +                    or: [byte = 141        "141        storeRemoteTempLongBytecode"
> +                    or: [byte = 142        "142        storeAndPopRemoteTempLongBytecode"]]]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>isStorePopAt:in: (in category 'instruction stream support') -----
> + isStorePopAt: pc in: method
> +    "Answer whether the bytecode at pc is a store-pop."
> + 
> +    | byte |
> +    byte := method at: pc.
> +    ^(byte between: 96 and: 111)    "96 103    storeAndPopReceiverVariableBytecode"
> +                                    "104 111    storeAndPopTemporaryVariableBytecode"
> +      or: [byte = 130                "130        extendedStoreAndPopBytecode"
> +      or: [byte = 142]]                "142        storeAndPopRemoteTempLongBytecode"!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>isSyntheticStoreAt:in:for: (in category 'instruction stream support') -----
> + isSyntheticStoreAt: pc in: method for: anInstructionStream
> +    "Answer whether the bytecode at pc is a store or store-pop of an indirect temp vector,
> +     which implement mutable closed-over variables in the the closure implementation.
> +     Stores into temp vectors are not real stores.  N.B. pcPreviousTo:in:for: is slow, so filter
> +     out any preceding bytecodes other than what looks like a pushNewArrayCode.  But the
> +     pcPreviousTo:in:for: is still necessary, since the presence of a pcPreviousTo:in:for: in the
> +     right place is potentially ambiguous, possibly part of a different bytecode seqence."
> + 
> +    ^(self isTempStoreAt: pc in: method)
> +      and: [pc - 2 >= method initialPC
> +      and: [(method at: pc - 2) = self pushNewArrayCode
> +      and: [(method at: pc - 1) <= 127
> +      and: [pc - 2 = (self pcPreviousTo: pc in: method for: anInstructionStream)]]]]!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>pcFollowingBlockAt:in: (in category 'bytecode decoding') -----
> + pcFollowingBlockAt: pc in: method
> +    "Assuming the pc is that of a block creation bytecode, answer the pc immediately following the block,
> +     i.e. the next pc after the block creation."
> +    self assert: (method at: pc) = self createClosureCode.
> +    ^(method at: pc + 2) * 256 + (method at: pc + 3) + pc + 4!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>pcOfBlockCreationBytecodeForBlockStartingAt:in: (in category 'bytecode decoding') -----
> + pcOfBlockCreationBytecodeForBlockStartingAt: startpc in: method
> +    "Answer the pc of the push closure bytecode whose block starts at startpc in method.
> +     143   10001111 llllkkkk jjjjjjjj iiiiiiii    Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii"
> +    ^startpc - 4!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>pushClosureBytecodeSize (in category 'bytecode decoding') -----
> + pushClosureBytecodeSize
> +    "Answer the size of the push closure bytecode.
> +     143   10001111 llllkkkk jjjjjjjj iiiiiiii    Push Closure Num Copied llll Num Args kkkk BlockSize jjjjjjjjiiiiiiii"
> +    ^4!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>pushNewArrayCode (in category 'bytecode decoding') -----
> + pushNewArrayCode
> +    "138   10001010 jkkkkkkk        Push (Array new: kkkkkkk) (j = 0)
> +                                or    Pop kkkkkkk elements into: (Array new: kkkkkkk) (j = 1)"
> +    ^138!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures class>>supportsClosures (in category 'compiled method support') -----
> + supportsClosures
> +    "Answer if the instruction set supports closures (contains
> +     closure creation and indirect temp access bytecodes)."
> + 
> +    ^true!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>genCallPrimitive: (in category 'bytecode generation') -----
> + genCallPrimitive: primitiveIndex
> +    "139    11101111    iiiiiiii jjjjjjjj    Call Primitive #iiiiiiii + (jjjjjjjj * 256)"
> +    (primitiveIndex < 1 or: [primitiveIndex > 65535]) ifTrue:
> +        [self outOfRangeError: 'primitive index' index: primitiveIndex range: 1 to: 65535].
> +    stream
> +        nextPut: 139;
> +        nextPut: (primitiveIndex bitAnd: 255);
> +        nextPut: (primitiveIndex bitShift: -8)!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>genPushClosureCopyNumCopiedValues:numArgs:jumpSize: (in category 'bytecode generation') -----
> + 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)!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>genPushConsArray: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>genPushNewArray: (in category 'bytecode generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>genPushRemoteTemp:inVectorAt: (in category 'bytecode generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>genStorePopRemoteTemp:inVectorAt: (in category 'bytecode generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>genStoreRemoteTemp:inVectorAt: (in category 'bytecode generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: EncoderForV3PlusClosures>>supportsClosureOpcodes (in category 'testing') -----
> + supportsClosureOpcodes
> +    ^true!
> 
> Item was added:
> + VariableNode subclass: #FieldNode
> +    instanceVariableNames: 'fieldDef rcvrNode readNode writeNode'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !FieldNode commentStamp: 'eem 5/24/2017 10:26' prior: 0!
> + FieldNode handles field access in Tweak, e.g. self fieldName := foo => self fieldName: foo.!
> 
> Item was added:
> + ----- Method: FieldNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitFieldNode: self!
> 
> Item was added:
> + ----- Method: FieldNode>>assignmentCheck:at: (in category 'testing') -----
> + assignmentCheck: encoder at: location
> +    (encoder cantStoreInto: name) ifTrue: [^location].
> +    fieldDef toSet ifNil:[
> +        encoder interactive ifTrue:[^location].
> +        fieldDef := fieldDef shallowCopy assignDefaultSetter.
> +    ].
> +    ^-1!
> 
> Item was added:
> + ----- Method: FieldNode>>emitCodeForEffect:encoder: (in category 'code generation') -----
> + emitCodeForEffect: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: FieldNode>>emitCodeForLoad:forValue:encoder: (in category 'code generation') -----
> + emitCodeForLoad: stack forValue: forValue encoder: encoder
> +    rcvrNode emitCodeForValue: stack encoder: encoder.
> +    fieldDef accessKey ifNotNil:
> +        [super emitCodeForValue: stack encoder: encoder]!
> 
> Item was added:
> + ----- Method: FieldNode>>emitCodeForStore:encoder: (in category 'code generation') -----
> + 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.
> +    ].!
> 
> Item was added:
> + ----- Method: FieldNode>>emitCodeForStorePop:encoder: (in category 'code generation') -----
> + emitCodeForStorePop: stack encoder: encoder
> +    self emitCodeForStore: stack encoder: encoder.
> +    encoder genPop.
> +    stack pop: 1.!
> 
> Item was added:
> + ----- Method: FieldNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + 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.
> +    ].!
> 
> Item was added:
> + ----- Method: FieldNode>>encodeReceiverOn: (in category 'code generation') -----
> + encodeReceiverOn: encoder
> +    "encode the receiver node"
> +    rcvrNode := encoder encodeVariable: 'self'.!
> 
> Item was added:
> + ----- Method: FieldNode>>fieldDef (in category 'accessing') -----
> + fieldDef
> +    ^fieldDef!
> 
> Item was added:
> + ----- Method: FieldNode>>fieldDefinition: (in category 'initialize-release') -----
> + fieldDefinition: fieldDefinition
> +    self name: fieldDefinition name key: fieldDefinition index: nil type: LdLitType!
> 
> Item was added:
> + ----- Method: FieldNode>>name:key:index:type: (in category 'initialize-release') -----
> + name: varName key: objRef index: i type: type
> +    fieldDef := objRef.
> +    ^super name: varName key: objRef key index: nil type: LdLitType!
> 
> Item was added:
> + ----- Method: FieldNode>>resetFromCopy: (in category 'code generation') -----
> + resetFromCopy: aFieldNode
> +    "Reset the state of the recever to match that of the argument.
> +     This is used to reset nodes that may have been repurposed
> +     while generatig the compiled method for a full block."
> + 
> +    self assert: (fieldDef == aFieldNode fieldDef
> +                and: [rcvrNode == (aFieldNode instVarNamed: 'rcvrNode')
> +                and: [readNode == (aFieldNode instVarNamed: 'readNode')
> +                and: [writeNode == (aFieldNode instVarNamed: 'writeNode')]]]).
> +    super resetFromCopy: aFieldNode!
> 
> Item was added:
> + ----- Method: FieldNode>>sizeCodeForEffect: (in category 'code generation') -----
> + sizeCodeForEffect: encoder
> +    ^0!
> 
> Item was added:
> + ----- Method: FieldNode>>sizeCodeForStore: (in category 'code generation') -----
> + 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)!
> 
> Item was added:
> + ----- Method: FieldNode>>sizeCodeForStorePop: (in category 'code generation') -----
> + sizeCodeForStorePop: encoder
> +    ^(self sizeCodeForStore: encoder) + encoder sizePop!
> 
> Item was added:
> + ----- Method: FieldNode>>sizeCodeForValue: (in category 'code generation') -----
> + 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)!
> 
> Item was added:
> + ParseNode subclass: #FutureNode
> +    instanceVariableNames: 'receiver originalSelector futureSelector futureDelta futureArgs effectNode valueNode'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !FutureNode commentStamp: 'jcg 12/17/2009 02:03' prior: 0!
> + Compile-time transformation of #future and #future: messages.  Use is best described through examples:
> + 
> +    receiver future doSomething: arg1 withArgs: arg2.
> +    (receiver future: 2000) doSomethingElse
> + 
> + The first means to immediately schedule #doSomething:withArgs: for asyncronous evaluation.  The second means to wait 2000 milliseconds before scheduling #doSomethingElse for asynchronous evaluation.
> + 
> + These are transformed into either #futureDo:at:args: or #futureSend:at:args:, depending on whether the result is used.  Let's look at a few examples.
> + 
> +    [receiver future foo. 2+2] value.
> +    true ifTrue: [^receiver future foo].
> +    arraySize := receiver future getArray wait size.
> +    
> + In the first case, the result is never used, so the message #futureDo:at:args: is generated.  In the second case, the result is answered from the current method.  Since we don't do any cross-method analysis, we have to assume that the result is needed for a later computation.  The result is provided in the form of a Promise, which will resolve to a value when the asynchronous evaluation has completed.  Creating and resolving this Promise is the responsibility of #futureSend:at:args:, which is generated instead of #futureDo:at:args: when code-analysis indicates that the result of the message might be used.  The third example is another one where #futureSend:at:args: is generated.
> + 
> + See the default implementations of #futureDo:at:args: and #futureSend:at:args: in Object.  Subclasses are free to override the default implementations to achieve specific effects.  For example, this functionality originated in the Croquet class TFarRef.  If you have a TFarRef to a replicated object, then sending 'aTFarRef future foo' results in a message being sent over the network to each replica of the object referenced by aTFarRef.  We might also use far-refs, for example, to send a message to an object in another Hydra object-memory.!
> 
> Item was added:
> + ----- Method: FutureNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitFutureNode: self!
> 
> Item was added:
> + ----- Method: FutureNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> +    { receiver. futureDelta }, (futureArgs ifNil: [#()]) do:
> +        [:node|
> +        node == nil ifFalse:
> +            [node analyseTempsWithin: scopeBlock rootNode: rootNode assignmentPools: assignmentPools]]!
> 
> Item was added:
> + ----- Method: FutureNode>>emitCodeForBlockValue:encoder: (in category 'code generation') -----
> + emitCodeForBlockValue: stack encoder: encoder
> +    "Generate code for evaluating the last statement in a block."
> +    ^effectNode emitCodeForValue: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: FutureNode>>emitCodeForEffect:encoder: (in category 'code generation') -----
> + emitCodeForEffect: stack encoder: encoder
> +    ^effectNode emitCodeForEffect: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: FutureNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    ^valueNode emitCodeForValue: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: FutureNode>>futureMessage:arguments:from:sourceRange: (in category 'initialize-release') -----
> + futureMessage: selName arguments: args  from: encoder sourceRange: range
> +    futureSelector := selName.
> +    futureArgs := args.
> +    ^self!
> 
> Item was added:
> + ----- Method: FutureNode>>futureSelector (in category 'accessing') -----
> + futureSelector
> +    ^futureSelector!
> 
> Item was added:
> + ----- Method: FutureNode>>isFutureNode (in category 'testing') -----
> + isFutureNode
> +    ^true!
> 
> Item was added:
> + ----- Method: FutureNode>>originalSelector (in category 'accessing') -----
> + originalSelector
> +    ^originalSelector!
> 
> Item was added:
> + ----- Method: FutureNode>>receiver (in category 'accessing') -----
> + receiver
> +    ^receiver!
> 
> Item was added:
> + ----- Method: FutureNode>>receiver:selector:arguments:precedence:from:sourceRange: (in category 'initialize-release') -----
> + receiver: rcvr selector: selector arguments: args precedence: p from: encoder sourceRange: range
> +    receiver := rcvr.
> +    originalSelector := selector.
> +    originalSelector == #future: ifTrue:[futureDelta := args first].
> +    encoder noteSourceRange: range forNode: self.!
> 
> Item was added:
> + ----- Method: FutureNode>>sizeCodeForBlockValue: (in category 'code generation') -----
> + sizeCodeForBlockValue: encoder
> +    receiver == NodeSuper ifTrue: [^self error: 'Futures cannot send to future'].
> +    (futureArgs isNil or: [futureSelector isNil]) ifTrue:
> +        [^self error: 'Futures must be sent messages'].
> +    encoder sharableLitIndex: originalSelector. "to find its senders"
> +    futureDelta ifNil:[futureDelta := encoder encodeLiteral: 0].
> +    effectNode := MessageNode new
> +        receiver: receiver
> +        selector: #futureDo:at:args:
> +        arguments: (Array 
> +            with: (encoder encodeLiteral: futureSelector) 
> +            with: futureDelta
> +            with: (BraceNode new elements: futureArgs))
> +        precedence: 3 
> +        from: encoder.
> +    ^effectNode sizeCodeForValue: encoder!
> 
> Item was added:
> + ----- Method: FutureNode>>sizeCodeForEffect: (in category 'code generation') -----
> + sizeCodeForEffect: encoder
> +    receiver == NodeSuper ifTrue: [^self error: 'Futures cannot send to future'].
> +    (futureArgs isNil or: [futureSelector isNil]) ifTrue:
> +        [^self error: 'Futures must be sent messages'].
> +    encoder sharableLitIndex: originalSelector. "to find its senders"
> +    futureDelta ifNil:[futureDelta := encoder encodeLiteral: 0].
> +    effectNode := MessageNode new
> +        receiver: receiver
> +        selector: #futureDo:at:args:
> +        arguments: (Array 
> +            with: (encoder encodeLiteral: futureSelector) 
> +            with: futureDelta
> +            with: (BraceNode new elements: futureArgs))
> +        precedence: 3 
> +        from: encoder.
> +    ^effectNode sizeCodeForEffect: encoder!
> 
> Item was added:
> + ----- Method: FutureNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    receiver == NodeSuper ifTrue: [^self error: 'Futures cannot send to future'].
> +    (futureArgs isNil or: [futureSelector isNil]) ifTrue:
> +        [^self error: 'Futures must be sent messages'].
> +    encoder sharableLitIndex: originalSelector. "to find its senders"
> +    futureDelta ifNil:[futureDelta := encoder encodeLiteral: 0].
> +    valueNode := MessageNode new
> +        receiver: receiver
> +        selector: #futureSend:at:args:
> +        arguments: (Array 
> +            with: (encoder encodeLiteral: futureSelector) 
> +            with: futureDelta
> +            with: (BraceNode new elements: futureArgs))
> +        precedence: 3 
> +        from: encoder.
> +    ^valueNode sizeCodeForValue: encoder!
> 
> Item was added:
> + VariableNode subclass: #InstanceVariableNode
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitInstanceVariableNode: self!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>emitCodeForStore:encoder: (in category 'code generation') -----
> + emitCodeForStore: stack encoder: encoder
> +    encoder genStoreInstVar: index!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>emitCodeForStorePop:encoder: (in category 'code generation') -----
> + emitCodeForStorePop: stack encoder: encoder
> +    encoder genStorePopInstVar: index.
> +    stack pop: 1!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    stack push: 1.
> +    ^encoder genPushInstVar: index!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>name:index: (in category 'initialize-release') -----
> + name: varName index: varIndex
> +    ^self name: varName index: varIndex-1 type: LdInstType!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>sizeCodeForStore: (in category 'code generation') -----
> + sizeCodeForStore: encoder
> +    ^encoder sizeStoreInstVar: index!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>sizeCodeForStorePop: (in category 'code generation') -----
> + sizeCodeForStorePop: encoder
> +    ^encoder sizeStorePopInstVar: index!
> 
> Item was added:
> + ----- Method: InstanceVariableNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    ^encoder sizePushInstVar: index!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: LeafNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> +    "This is a no-op except in TempVariableNode"
> +    ^self!
> 
> Item was added:
> + ----- Method: LeafNode>>code (in category 'code generation') -----
> + code
> + 
> +    ^ code!
> 
> Item was added:
> + ----- Method: LeafNode>>code:type: (in category 'private') -----
> + code: index type: type
> + 
> +    index isNil 
> +        ifTrue: [^type negated].
> +    (CodeLimits at: type) > index 
> +        ifTrue: [^(CodeBases at: type) + index].
> +    ^type * 256 + index!
> 
> Item was added:
> + ----- Method: LeafNode>>emitCodeForEffect:encoder: (in category 'code generation') -----
> + emitCodeForEffect: stack encoder: encoder
> + 
> +    ^self!
> 
> Item was added:
> + ----- Method: LeafNode>>emitCodeForLoad:forValue:encoder: (in category 'code generation') -----
> + emitCodeForLoad: stack forValue: forValue encoder: encoder
> +    "Default is to do nothing.
> +     Subclasses may need to override."!
> 
> Item was added:
> + ----- Method: LeafNode>>index (in category 'accessing') -----
> + index
> +    "Answer the index of the receiver, which has various uses depending on the class of the receiver."
> + 
> +    ^index!
> 
> Item was added:
> + ----- Method: LeafNode>>key (in category 'accessing') -----
> + key
> + 
> +    ^key!
> 
> Item was added:
> + ----- Method: LeafNode>>key:code: (in category 'initialize-release') -----
> + key: object code: byte
> + 
> +    key := object.
> +    code := byte!
> 
> Item was added:
> + ----- Method: LeafNode>>key:index:type: (in category 'initialize-release') -----
> + key: object index: i type: type
> + 
> +    key := object.
> +    code := (self code: i type: type).
> +    index := i!
> 
> Item was added:
> + ----- Method: LeafNode>>name:key:code: (in category 'initialize-release') -----
> + name: ignored key: object code: byte
> + 
> +    key := object.
> +    code := byte!
> 
> Item was added:
> + ----- Method: LeafNode>>reserve: (in category 'code generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: LeafNode>>resetFromCopy: (in category 'code generation') -----
> + resetFromCopy: aLeafNode
> +    "Reset the state of the recever to match that of the argument.
> +     This is used to reset nodes that may have been repurposed
> +     while generatig the compiled method for a full block."
> + 
> +    self assert: key == aLeafNode key.
> +    code := aLeafNode code.
> +    index := aLeafNode index!
> 
> Item was added:
> + ----- Method: LeafNode>>sizeCodeForEffect: (in category 'code generation') -----
> + sizeCodeForEffect: encoder
> + 
> +    ^0!
> 
> Item was added:
> + ----- Method: LeafNode>>sizeCodeForLoad:forValue: (in category 'code generation') -----
> + sizeCodeForLoad: encoder forValue: forValue
> +    "Default is to do nothing.
> +     Subclasses may need to override."
> +    ^0!
> 
> Item was added:
> + ----- Method: LeafNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: LeafNode>>veryDeepFixupWith: (in category 'copying') -----
> + 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]).
> + !
> 
> Item was added:
> + ----- Method: LeafNode>>veryDeepInner: (in category 'copying') -----
> + 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.
> + !
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: LiteralNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitLiteralNode: self!
> 
> Item was added:
> + ----- Method: LiteralNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    stack push: 1.
> +    (encoder isSpecialLiteralForPush: key)
> +        ifTrue: [encoder genPushSpecialLiteral: key]
> +        ifFalse: [encoder genPushLiteral: index]!
> 
> Item was added:
> + ----- Method: LiteralNode>>eval (in category 'evaluation') -----
> + 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!
> 
> Item was added:
> + ----- Method: LiteralNode>>isConstantNumber (in category 'testing') -----
> + isConstantNumber
> +    ^ key isNumber!
> 
> Item was added:
> + ----- Method: LiteralNode>>isLiteralNode (in category 'testing') -----
> + isLiteralNode
> + 
> +    ^ true!
> 
> Item was added:
> + ----- Method: LiteralNode>>isSpecialConstant (in category 'testing') -----
> + isSpecialConstant
> +    ^ code between: LdTrue and: LdMinus1+3!
> 
> Item was added:
> + ----- Method: LiteralNode>>literalValue (in category 'testing') -----
> + literalValue
> + 
> +    ^key!
> 
> Item was added:
> + ----- Method: LiteralNode>>name:key:index:type: (in category 'initialize-release') -----
> + name: literal key: object index: i type: type
> +    "For compatibility with Encoder>>name:key:class:type:set:"
> +    ^self key: object index: i type: type!
> 
> Item was added:
> + ----- Method: LiteralNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level
> + 
> +    key isVariableBinding ifTrue:
> +        [key key isNil
> +            ifTrue:
> +                [aStream nextPutAll: '###'; nextPutAll: key value soleInstance name]
> +            ifFalse:
> +                [aStream nextPutAll: '##'; nextPutAll: key key].
> +        ^self].
> +    key isLiteral ifTrue:
> +        [key printAsLiteralOn: aStream.
> +         ^self].
> +    (key isCompiledCode and: [key isCompiledBlock]) ifTrue:
> +        [key printOn: aStream.
> +         ^self].
> +    key storeOn: aStream!
> 
> Item was added:
> + ----- Method: LiteralNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: LiteralNode>>reserve: (in category 'code generation') -----
> + reserve: encoder 
> +    "If this is a yet unused literal of type -code, reserve it."
> + 
> +    code < 0 ifTrue:
> +        [index := key isVariableBinding "true if sending value[:] to a special binding"
> +                    ifTrue: [encoder sharableLitIndex: key]
> +                    ifFalse: [encoder litIndex: key].
> +         code := self code: index type: 0 - code]!
> 
> Item was added:
> + ----- Method: LiteralNode>>resetForBlockGeneration (in category 'code generation') -----
> + resetForBlockGeneration
> +    "Reset the receiver to an unassigned state such that its index
> +     in the encoder's literalStream is as yet to be determined."
> +    code := LdLitType negated.
> +    index := nil!
> 
> Item was added:
> + ----- Method: LiteralNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    self reserve: encoder.
> +    ^(encoder isSpecialLiteralForPush: key)
> +        ifTrue: [encoder sizePushSpecialLiteral: key]
> +        ifFalse: [encoder sizePushLiteral: index]!
> 
> Item was added:
> + VariableNode subclass: #LiteralVariableNode
> +    instanceVariableNames: 'readNode writeNode'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitLiteralVariableNode: self!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>assignmentCheck:at: (in category 'testing') -----
> + assignmentCheck: encoder at: location
> +    ^(key isVariableBinding and: [key canAssign not])
> +        ifTrue: [location]
> +        ifFalse: [-1]!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>emitCodeForLoad:forValue:encoder: (in category 'code generation') -----
> + emitCodeForLoad: stack forValue: forValue encoder: encoder
> +    "If a normal literal variable (not sending value:), do nothing.
> +     If for value (e.g. v := Binding := expr) do nothing; the work will be done in emitCodeForStore:encoder:.
> +     If not for value then indeed load.  The rest of the work will be done in  emitCodeForStorePop:encoder:."
> +    (writeNode isNil or: [forValue]) ifTrue: [^self].
> +    encoder genPushLiteral: index.
> +    stack push: 1!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>emitCodeForStore:encoder: (in category 'code generation') -----
> + emitCodeForStore: stack encoder: encoder
> +    | exprOffset |
> +    writeNode ifNil: [^encoder genStoreLiteralVar: index].
> +    "On entry the stack has only the expression.  Push the binding,
> +     duplicate the expression, send #value: and pop.
> +     The various value: methods on Association ReadOnlyVariableBinding
> +     etc _do not_ return the value assigned; they return the receiver.  If they
> +     did we could generate much simpler code, e.g.
> +        encoder genPushLiteral: index.
> +        stack push: 1.
> +        writeNode emitCode: stack args: 1 encoder: encoder super: false"
> +    exprOffset := stack position - 1.
> +    encoder genPushLiteral: index.
> +    stack push: 1.
> +    encoder genPushTempLong: exprOffset.
> +    stack push: 1.
> +    writeNode
> +        emitCode: stack
> +        args: 1
> +        encoder: encoder
> +        super: false.
> +    stack pop: 1.
> +    encoder genPop!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>emitCodeForStorePop:encoder: (in category 'code generation') -----
> + emitCodeForStorePop: stack encoder: encoder
> +    writeNode ifNil:
> +        [stack pop: 1.
> +         ^encoder genStorePopLiteralVar: index].
> +    writeNode
> +        emitCode: stack
> +        args: 1
> +        encoder: encoder
> +        super: false.
> +    stack pop: 1.
> +    encoder genPop!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    ^readNode
> +        ifNil: [stack push: 1.
> +            encoder genPushLiteralVar: index]
> +        ifNotNil: [readNode emitCodeForValue: stack encoder: encoder]!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>resetForBlockGeneration (in category 'code generation') -----
> + resetForBlockGeneration
> +    "Reset the receiver to an unassigned state such that its index
> +     in the encoder's literalStream is as yet to be determined."
> +    code := LdLitIndType negated.
> +    index := nil!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>resetFromCopy: (in category 'code generation') -----
> + resetFromCopy: aLiteralVariableNode
> +    "Reset the state of the recever to match that of the argument.
> +     This is used to reset nodes that may have been repurposed
> +     while generatig the compiled method for a full block."
> + 
> +    self assert: (readNode == (aLiteralVariableNode instVarNamed: 'readNode')
> +                and: [writeNode == (aLiteralVariableNode instVarNamed: 'writeNode')]).
> +    super resetFromCopy: aLiteralVariableNode!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>sizeCodeForLoad:forValue: (in category 'code generation') -----
> + sizeCodeForLoad: encoder forValue: forValue
> +    self reserve: encoder.
> +    ^(key isVariableBinding and: [key isSpecialWriteBinding and: [forValue not]])
> +        ifTrue: [encoder sizePushLiteral: index]
> +        ifFalse: [0]!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>sizeCodeForStore: (in category 'code generation') -----
> + sizeCodeForStore: encoder
> +    self reserve: encoder.
> +    (key isVariableBinding and: [key isSpecialWriteBinding]) ifFalse:
> +        [^encoder sizeStoreLiteralVar: index].
> +    writeNode := encoder encodeSelector: #value:.
> +    "On entry the stack has only the expression.  Push the binding,
> +     duplicate the expression, send #value: and pop."
> +    ^(encoder sizePushLiteral: index)
> +      + (encoder sizePushTempLong: 0) "we don't know yet, hence long, sigh..."
> +      + (writeNode sizeCode: encoder args: 1 super: false)
> +      + encoder sizePop!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>sizeCodeForStorePop: (in category 'code generation') -----
> + sizeCodeForStorePop: encoder
> +    self reserve: encoder.
> +    ^(key isVariableBinding and: [key isSpecialWriteBinding])
> +        ifTrue: [    writeNode := encoder encodeSelector: #value:.
> +                ^ (writeNode sizeCode: encoder args: 1 super: false)
> +                  + encoder sizePop]
> +        ifFalse: [encoder sizeStorePopLiteralVar: index]!
> 
> Item was added:
> + ----- Method: LiteralVariableNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    self reserve: encoder.
> +    (key isVariableBinding and: [key isSpecialReadBinding]) 
> +        ifFalse:
> +            [^encoder sizePushLiteralVar: index].
> +    readNode := MessageNode new 
> +        receiver: (encoder encodeLiteral: key)
> +        selector: (encoder encodeSelector: #value)
> +        arguments: #()
> +        precedence: #value precedence.
> +    ^readNode sizeCodeForValue: encoder!
> 
> Item was added:
> + 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 rea
> d to fetch the index.!
> 
> Item was added:
> + ----- Method: MaybeContextInstanceVariableNode>>code (in category 'accessing') -----
> + code
> +    "Answer a bogus code to avoid creating quick methods.
> +     See MethodNode>>generate:ifQuick:"
> +    ^LoadLong!
> 
> Item was added:
> + ----- Method: MaybeContextInstanceVariableNode>>emitCodeForStore:encoder: (in category 'code generation') -----
> + emitCodeForStore: stack encoder: encoder
> +    encoder genStoreInstVarLong: index!
> 
> Item was added:
> + ----- Method: MaybeContextInstanceVariableNode>>emitCodeForStorePop:encoder: (in category 'code generation') -----
> + emitCodeForStorePop: stack encoder: encoder
> +    encoder genStorePopInstVarLong: index.
> +    stack pop: 1!
> 
> Item was added:
> + ----- Method: MaybeContextInstanceVariableNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    stack push: 1.
> +    ^encoder genPushInstVarLong: index!
> 
> Item was added:
> + ----- Method: MaybeContextInstanceVariableNode>>sizeCodeForStore: (in category 'code generation') -----
> + sizeCodeForStore: encoder
> +    ^encoder sizeStoreInstVarLong: index!
> 
> Item was added:
> + ----- Method: MaybeContextInstanceVariableNode>>sizeCodeForStorePop: (in category 'code generation') -----
> + sizeCodeForStorePop: encoder
> +    ^encoder sizeStorePopInstVarLong: index!
> 
> Item was added:
> + ----- Method: MaybeContextInstanceVariableNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    ^encoder sizePushInstVarLong: index!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: MessageAsTempNode>>asStorableNode: (in category 'access to remote temps') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageAsTempNode>>code (in category 'access to remote temps') -----
> + code
> +    "Allow synthetic temp nodes to be sorted by code"
> +    ^ arguments first literalValue!
> 
> Item was added:
> + ----- Method: MessageAsTempNode>>emitCodeForStorePop:encoder: (in category 'code generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageAsTempNode>>sizeCodeForStorePop: (in category 'code generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageAsTempNode>>store:from: (in category 'access to remote temps') -----
> + 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!
> 
> Item was added:
> + ParseNode subclass: #MessageNode
> +    instanceVariableNames: 'receiver selector precedence special arguments sizes equalNode caseErrorNode originalReceiver originalSelector originalArguments'
> +    classVariableNames: 'MacroEmitters MacroPrinters MacroSelectors MacroSizers MacroTransformers 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.!
> 
> Item was added:
> + ----- Method: MessageNode class>>initialize (in category 'class initialization') -----
> + initialize
> +    "MessageNode initialize"
> +    MacroSelectors := 
> +        #(    ifTrue: ifFalse: ifTrue:ifFalse: ifFalse:ifTrue:
> +            and: or:
> +            whileFalse: whileTrue: whileFalse whileTrue
> +            to:do: to:by:do:
> +            caseOf: caseOf:otherwise:
> +            ifNil: ifNotNil:  ifNil:ifNotNil: ifNotNil:ifNil:
> +            repeat ).
> +    MacroTransformers := 
> +        #(    transformIfTrue: transformIfFalse: transformIfTrueIfFalse: transformIfFalseIfTrue:
> +            transformAnd: transformOr:
> +            transformWhile: transformWhile: transformWhile: transformWhile:
> +            transformToDo: transformToDo:
> +            transformCase: transformCase:
> +            transformIfNil: transformIfNil:  transformIfNilIfNotNil: transformIfNotNilIfNil:
> +            transformRepeat: ).
> +    MacroEmitters := 
> +        #(    emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> +            emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> +            emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> +            emitCodeForWhile:encoder:value: emitCodeForWhile:encoder:value:
> +            emitCodeForWhile:encoder:value: emitCodeForWhile:encoder:value:
> +            emitCodeForToDo:encoder:value: emitCodeForToDo:encoder:value:
> +            emitCodeForCase:encoder:value: emitCodeForCase:encoder:value:
> +            emitCodeForIfNil:encoder:value: emitCodeForIfNil:encoder:value:
> +            emitCodeForIf:encoder:value: emitCodeForIf:encoder:value:
> +            emitCodeForRepeat:encoder:value:).
> +    MacroSizers := 
> +        #(    sizeCodeForIf:value: sizeCodeForIf:value: sizeCodeForIf:value: sizeCodeForIf:value:
> +            sizeCodeForIf:value: sizeCodeForIf:value:
> +            sizeCodeForWhile:value: sizeCodeForWhile:value: sizeCodeForWhile:value: sizeCodeForWhile:value:
> +            sizeCodeForToDo:value: sizeCodeForToDo:value:
> +            sizeCodeForCase:value: sizeCodeForCase:value:
> +            sizeCodeForIfNil:value: sizeCodeForIfNil:value: sizeCodeForIf:value: sizeCodeForIf:value:
> +            sizeCodeForRepeat:value:).
> +    MacroPrinters := 
> +        #(    printIfOn:indent: printIfOn:indent: printIfOn:indent: printIfOn:indent:
> +            printIfOn:indent: printIfOn:indent:
> +            printWhileOn:indent: printWhileOn:indent: printWhileOn:indent: printWhileOn:indent:
> +            printToDoOn:indent: printToDoOn:indent:
> +            printCaseOn:indent: printCaseOn:indent:
> +            printIfNil:indent: printIfNil:indent: printIfNilNotNil:indent: printIfNilNotNil:indent:
> +            printRepeatOn:indent:)!
> 
> Item was added:
> + ----- Method: MessageNode class>>isMacroEmitter: (in category 'browsing support') -----
> + isMacroEmitter: aLiteral
> +    "Let our macro methods be found when browsing senders"
> +    ^aLiteral isSymbol
> +         and: [MacroEmitters includes: aLiteral]!
> 
> Item was added:
> + ----- Method: MessageNode class>>isMacroPrinter: (in category 'browsing support') -----
> + isMacroPrinter: aLiteral
> +    "Let our macro methods be found when browsing senders"
> +    ^aLiteral isSymbol
> +         and: [MacroPrinters includes: aLiteral]
> + !
> 
> Item was added:
> + ----- Method: MessageNode class>>isMacroSizer: (in category 'browsing support') -----
> + isMacroSizer: aLiteral
> +    "Let our macro methods be found when browsing senders"
> +    ^aLiteral isSymbol
> +         and: [MacroSizers includes: aLiteral]
> + !
> 
> Item was added:
> + ----- Method: MessageNode class>>isMacroTransformer: (in category 'browsing support') -----
> + isMacroTransformer: aLiteral
> +    "Let our macro methods be found when browsing senders"
> +    ^aLiteral isSymbol
> +         and: [MacroTransformers includes: aLiteral]!
> 
> Item was added:
> + ----- Method: MessageNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitMessageNode: self!
> 
> Item was added:
> + ----- Method: MessageNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + 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 sorted: ParseNode tempSortBlock) do:
> +                [:each| each analyseClosure: rootNode].
> +             (writtenToTemps collect: [:each| each definingScope]) do:
> +                [:blockNode|
> +                blockNode ifHasRemoteTempNodeEnsureInitializationStatementExists: rootNode]]]!
> 
> Item was added:
> + ----- Method: MessageNode>>arguments (in category 'equation translation') -----
> + arguments
> +    ^arguments!
> 
> Item was added:
> + ----- Method: MessageNode>>arguments: (in category 'equation translation') -----
> + arguments: list
> +    arguments := list!
> 
> Item was added:
> + ----- Method: MessageNode>>argumentsInEvaluationOrder (in category 'visiting') -----
> + argumentsInEvaluationOrder
> +    "Answer the receiver's 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 weird 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>asMorphicCaseOn:indent: (in category 'printing') -----
> + 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
> + !
> 
> Item was added:
> + ----- Method: MessageNode>>canCascade (in category 'testing') -----
> + canCascade
> + 
> +    ^receiver ~~ NodeSuper!
> 
> Item was added:
> + ----- Method: MessageNode>>cascadeReceiver (in category 'cascading') -----
> + cascadeReceiver
> +    "Nil out rcvr (to indicate cascade) and return what it had been."
> + 
> +    | rcvr |
> +    rcvr := receiver.
> +    receiver := nil.
> +    ^rcvr!
> 
> Item was added:
> + ----- Method: MessageNode>>checkBlock:as:from:maxArgs: (in category 'private') -----
> + checkBlock: node as: nodeName from: encoder maxArgs: maxArgs
> +    "Answer true if node is a BlockNode with at most maxArgs arguments.
> +    This check is required in order to inline some special messages.
> +    Notify some undue usage of these special messages."
> + 
> +    node isBlockNode ifFalse: [ ^false ].
> +    node numberOfArguments <= maxArgs ifTrue: [ ^true ].
> +    ^encoder notify: '<- ', nodeName , ' of ' , (MacroSelectors at: special) , ' has too many arguments'!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForCase:encoder:value: (in category 'code generation') -----
> + 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 dropReceiver |
> +        dropReceiver := last and: [arguments size >= 2].
> +        thenSize := sizeStream next.
> +        elseSize := sizeStream next.
> +        dropReceiver ifFalse: [encoder genDup. stack push: 1].
> +        keyNode emitCodeForEvaluatedValue: stack encoder: encoder.
> +        keyNode pc: encoder nextPC.
> +        equalNode emitCode: stack args: 1 encoder: encoder.
> +        self emitCodeForBranchOn: false dist: thenSize pop: stack encoder: encoder.
> +        dropReceiver ifFalse: [encoder genPop. stack pop: 1].
> +        valueNode emitCodeForEvaluatedValue: stack encoder: encoder.
> +        dropReceiver 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:
> +            ["the receiver of caseOf: has been previously dup, just send"
> +            caseErrorNode emitCode: stack args: 0 encoder: encoder]!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForEffect:encoder: (in category 'code generation') -----
> + 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."
> +    <hasLiteralTest: #isMacroEmitter:>
> +    special > 0
> +        ifTrue: 
> +            [pc := 0.
> +            self perform: (MacroEmitters at: special) with: stack with: encoder with: false]
> +        ifFalse: 
> +            [super emitCodeForEffect: stack encoder: encoder]!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForIf:encoder:value: (in category 'code generation') -----
> + emitCodeForIf: stack encoder: encoder value: forValue
> +    | thenExpr thenSize elseExpr elseSize |
> +    thenSize := sizes at: 1.
> +    elseSize := sizes at: 2.
> +    thenExpr := arguments at: 1.
> +    elseExpr := arguments at: 2.
> +    receiver emitCodeForValue: stack encoder: encoder.
> +    pc := encoder nextPC.
> +    elseSize * thenSize > 0
> +        ifTrue:  "Code for two-armed"
> +            [self emitCodeForBranchOn: false dist: thenSize pop: stack encoder: encoder.
> +            thenExpr emitCodeForEvaluatedValue: stack encoder: encoder.
> +            stack pop: 1.  "then and else alternate; they don't accumulate"
> +            thenExpr returns ifFalse: "Elide jump over else after a return"
> +                [self emitCodeForJump: elseSize encoder: encoder].
> +            elseExpr emitCodeForEvaluatedValue: stack encoder: encoder.
> +            forValue ifFalse: "Two-armed IFs forEffect share a single pop - except if both return"
> +                [(arguments allSatisfy: #returns) ifFalse: [encoder genPop].
> +                stack pop: 1]]
> +        ifFalse:  "One arm is empty here (this can only ever be for effect)"
> +            [thenSize > 0
> +                ifTrue:
> +                    [self emitCodeForBranchOn: false dist: thenSize pop: stack encoder: encoder.
> +                    thenExpr emitCodeForEvaluatedEffect: stack encoder: encoder]
> +                ifFalse:
> +                    [self emitCodeForBranchOn: true dist: elseSize pop: stack encoder: encoder.
> +                    elseExpr emitCodeForEvaluatedEffect: stack encoder: encoder]]!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForIfNil:encoder:value: (in category 'code generation') -----
> + 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.
> +    pc := encoder nextPC.
> +    self 
> +        emitCodeForBranchOn: (selector key == ifNotNilSelector)
> +        dist: theSize 
> +        pop: stack 
> +        encoder: encoder.
> +    forValue 
> +        ifTrue: 
> +            [encoder genPop. stack pop: 1.
> +            theNode emitCodeForEvaluatedValue: stack encoder: encoder]    
> +        ifFalse: [theNode emitCodeForEvaluatedEffect: stack encoder: encoder]!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForRepeat:encoder:value: (in category 'code generation') -----
> + emitCodeForRepeat: stack encoder: encoder value: forValue 
> +    " L1: ... Jmp(L1)"
> +    | loopSize |
> +    loopSize := sizes at: 1.
> +    receiver emitCodeForEvaluatedEffect: stack encoder: encoder.
> +    self emitCodeForJump: 0 - loopSize encoder: encoder.
> +    forValue ifTrue: [encoder genPushSpecialLiteral: nil. stack push: 1]!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForToDo:encoder:value: (in category 'code generation') -----
> + 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.
> +        
> +    "This will return the receiver of to:do: which is the initial value of the loop"
> +    forValue
> +        ifTrue: [initStmt emitCodeForValue: stack encoder: encoder]
> +        ifFalse: [initStmt emitCodeForEffect: stack encoder: encoder].
> +    limitInit ifNotNil:
> +        [limitInit emitCodeForEffect: stack encoder: encoder].
> +    test emitCodeForValue: stack encoder: encoder.
> +    pc := encoder nextPC.
> +    self emitCodeForBranchOn: false dist: blockSize pop: stack encoder: encoder.
> +    block emitCodeForEvaluatedEffect: stack encoder: encoder.
> +    incStmt emitCodeForEffect: stack encoder: encoder.
> +    self emitCodeForJump: 0 - loopSize encoder: encoder!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + 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."
> +    <hasLiteralTest: #isMacroEmitter:>
> +    special > 0
> +        ifTrue: 
> +            [pc := 0.
> +            self perform: (MacroEmitters at: special) with: stack with: encoder with: true]
> +        ifFalse: 
> +            [receiver ~~ nil ifTrue: [receiver emitCodeForValue: stack encoder: encoder].
> +            arguments do: [:argument | argument emitCodeForValue: stack encoder: encoder].
> +            pc := encoder nextPC. "debug pc is first byte of the send, i.e. the next byte".
> +            selector
> +                emitCode: stack
> +                args: arguments size
> +                encoder: encoder
> +                super: receiver == NodeSuper]!
> 
> Item was added:
> + ----- Method: MessageNode>>emitCodeForWhile:encoder:value: (in category 'code generation') -----
> + 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.
> +    pc := encoder nextPC.
> +    self emitCodeForBranchOn: (selector key == #whileFalse:)  "Bfp for whileTrue"
> +                    dist: stmtSize pop: stack encoder: encoder.   "Btp for whileFalse"
> +    stmt emitCodeForEvaluatedEffect: stack encoder: encoder.
> +    self emitCodeForJump: 0 - loopSize encoder: encoder.
> +    forValue ifTrue: [encoder genPushSpecialLiteral: nil. stack push: 1]!
> 
> Item was added:
> + ----- Method: MessageNode>>ensureCanCascade: (in category 'cascading') -----
> + ensureCanCascade: encoder
> +    special > 0 ifTrue:
> +        [special := 0.
> +        receiver := originalReceiver.
> +        selector := encoder encodeSelector: originalSelector.
> +        arguments := originalArguments.
> +        receiver isBlockNode ifTrue: [receiver deoptimize].
> +        arguments do:
> +            [:each|
> +            (each isBlockNode or: [each isBraceNode]) ifTrue:
> +                [each deoptimize]]]!
> 
> Item was added:
> + ----- Method: MessageNode>>eval (in category 'equation translation') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageNode>>ifNilReceiver (in category 'private') -----
> + ifNilReceiver
> + 
> +    ^receiver!
> 
> Item was added:
> + ----- Method: MessageNode>>ifNilTemporary (in category 'private') -----
> + ifNilTemporary
> + 
> +    ^ self ifNilReceiver ifNilTemporary!
> 
> Item was added:
> + ----- Method: MessageNode>>isComplex (in category 'testing') -----
> + isComplex
> +    
> +    ^(special between: 1 and: 10) or: [arguments size > 2 or: [receiver isComplex]]!
> 
> Item was added:
> + ----- Method: MessageNode>>isMessage (in category 'testing') -----
> + isMessage
> +    ^true!
> 
> Item was added:
> + ----- Method: MessageNode>>isMessage:receiver:arguments: (in category '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])]]!
> 
> Item was added:
> + ----- Method: MessageNode>>isMessageNode (in category 'testing') -----
> + isMessageNode
> +    ^true!
> 
> Item was added:
> + ----- Method: MessageNode>>isNilIf (in category 'testing') -----
> + isNilIf
> + 
> +    ^(special between: 3 and: 4)
> +       and: [(arguments first returns or: [arguments first isJust: NodeNil])
> +       and: [(arguments last returns or: [arguments last isJust: NodeNil])]]!
> 
> Item was added:
> + ----- Method: MessageNode>>isOptimized (in category 'testing') -----
> + isOptimized
> +    ^special > 0!
> 
> Item was added:
> + ----- Method: MessageNode>>isOptimizedLoop (in category 'testing') -----
> + isOptimizedLoop
> +    ^special > 0
> +       and: [#(transformWhile: transformToDo: transformRepeat:) includes: (MacroTransformers at: special)]!
> 
> Item was added:
> + ----- Method: MessageNode>>isOptimizedWhileLoop (in category 'testing') -----
> + isOptimizedWhileLoop
> +    ^special > 0
> +       and: [#(transformWhile: transformRepeat:) includes: (MacroTransformers at: special)]!
> 
> Item was added:
> + ----- Method: MessageNode>>isReturningIf (in category 'testing') -----
> + 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]]!
> 
> Item was added:
> + ----- Method: MessageNode>>macroPrinter (in category 'printing') -----
> + macroPrinter
> + 
> +    special > 0 ifTrue: [^MacroPrinters at: special].
> +    ^nil
> + !
> 
> Item was added:
> + ----- Method: MessageNode>>noteSpecialSelector: (in category 'macro transformations') -----
> + noteSpecialSelector: selectorSymbol
> +    "special > 0 denotes specially treated (potentially inlined) messages. "
> + 
> +    special := MacroSelectors indexOf: selectorSymbol.
> + !
> 
> Item was added:
> + ----- Method: MessageNode>>precedence (in category 'printing') -----
> + precedence
> + 
> +    ^precedence!
> 
> Item was added:
> + ----- Method: MessageNode>>printCaseOn:indent: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>printIfNil:indent: (in category 'printing') -----
> + printIfNil: aStream indent: level
> + 
> +    self printReceiver: receiver on: aStream indent: level.
> + 
> +    ^self printKeywords: selector key
> +        arguments: (Array with: arguments first)
> +        on: aStream indent: level!
> 
> Item was added:
> + ----- Method: MessageNode>>printIfNilNotNil:indent: (in category 'printing') -----
> + printIfNilNotNil: aStream indent: level
> + 
> +    (arguments first isJust: NodeNil) ifTrue:
> +        [self printReceiver: receiver ifNilReceiver ifNilValue on: aStream indent: level.
> +        ^ self
> +            printKeywords: #ifNotNil:
> +            arguments: { arguments second }
> +            on: aStream indent: level].
> +            
> +    (arguments second isJust: NodeNil) ifTrue:
> +        [self printReceiver: receiver ifNilReceiver on: aStream indent: level.
> +        ^ self
> +            printKeywords: #ifNil:
> +            arguments: { arguments first }
> +            on: aStream indent: level].
> +    
> +    self printReceiver: receiver ifNilReceiver ifNilValue on: aStream indent: level.
> +    ^ self
> +        printKeywords: #ifNil:ifNotNil:
> +        arguments: arguments
> +        on: aStream indent: level!
> 
> Item was added:
> + ----- Method: MessageNode>>printIfOn:indent: (in category 'printing') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageNode>>printKeywords:arguments:on:indent: (in category 'printing') -----
> + printKeywords: key arguments: args on: aStream indent: level
> +    | keywords indent arg kwd doCrTab |
> +    args size = 0 ifTrue:
> +        [aStream space; nextPutAll: key.
> +         ^self].
> +    keywords := key asString 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])]!
> 
> Item was added:
> + ----- Method: MessageNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level
> +    "may not need this check anymore - may be fixed by the #receiver: change"
> +    <hasLiteralTest: #isMacroPrinter:>
> +    
> +    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]!
> 
> Item was added:
> + ----- Method: MessageNode>>printOn:indent:precedence: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>printParenReceiver:on:indent: (in category 'printing') -----
> + printParenReceiver: rcvr on: aStream indent: level
> +                    
> +    rcvr isBlockNode ifTrue:
> +        [^rcvr printOn: aStream indent: level].
> +    aStream nextPut: $(.
> +    rcvr printOn: aStream indent: level.
> +    aStream nextPut: $)
> + !
> 
> Item was added:
> + ----- Method: MessageNode>>printReceiver:on:indent: (in category 'printing') -----
> + printReceiver: rcvr on: aStream indent: level
> +                    
> +    rcvr ifNil: [^ self].
> + 
> +    "Force parens around keyword receiver of kwd message"
> +    rcvr printOn: aStream indent: level precedence: precedence!
> 
> Item was added:
> + ----- Method: MessageNode>>printRepeatOn:indent: (in category 'printing') -----
> + printRepeatOn: aStream indent: level
> + 
> +    self printReceiver: receiver on: aStream indent: level.
> + 
> +    ^self printKeywords: selector key
> +        arguments: (Array new)
> +        on: aStream indent: level!
> 
> Item was added:
> + ----- Method: MessageNode>>printToDoOn:indent: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>printWhileOn:indent: (in category 'printing') -----
> + printWhileOn: aStream indent: level
> +    self printReceiver: receiver on: aStream indent: level.
> +    self
> +        printKeywords: originalSelector
> +        arguments: originalArguments
> +        on: aStream indent: level!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisCaseOn:indent: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisIfNil:indent: (in category 'printing') -----
> + printWithClosureAnalysisIfNil: aStream indent: level
> + 
> +    self printWithClosureAnalysisReceiver: receiver on: aStream indent: level.
> + 
> +    ^self printWithClosureAnalysisKeywords: selector key
> +        arguments: (Array with: arguments first)
> +        on: aStream indent: level!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisIfNilNotNil:indent: (in category 'printing') -----
> + printWithClosureAnalysisIfNilNotNil: aStream indent: level
> + 
> +    (arguments first isJust: NodeNil) ifTrue:
> +        [self printWithClosureAnalysisReceiver: receiver ifNilReceiver ifNilValue on: aStream indent: level.
> +        ^ self
> +            printWithClosureAnalysisKeywords: #ifNotNil:
> +            arguments: { arguments second }
> +            on: aStream indent: level].
> +            
> +    (arguments second isJust: NodeNil) ifTrue:
> +        [self printWithClosureAnalysisReceiver: receiver ifNilReceiver on: aStream indent: level.
> +        ^ self
> +            printWithClosureAnalysisKeywords: #ifNil:
> +            arguments: { arguments first }
> +            on: aStream indent: level].
> +            
> +    self printWithClosureAnalysisReceiver: receiver ifNilReceiver ifNilValue on: aStream indent: level.
> +    ^ self
> +        printWithClosureAnalysisKeywords: #ifNil:ifNotNil:
> +        arguments: arguments
> +        on: aStream indent: level!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisIfOn:indent: (in category 'printing') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisKeywords:arguments:on:indent: (in category 'printing') -----
> + 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])]!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level
> +    "may not need this check anymore - may be fixed by the #receiver: change"
> +    <hasLiteralTest: #isMacroPrinter:>
> + 
> +    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!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisOn:indent:precedence: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisParenReceiver:on:indent: (in category 'printing') -----
> + printWithClosureAnalysisParenReceiver: rcvr on: aStream indent: level
> +                    
> +    rcvr isBlockNode ifTrue:
> +        [^rcvr printWithClosureAnalysisOn: aStream indent: level].
> +    aStream nextPut: $(.
> +    rcvr printWithClosureAnalysisOn: aStream indent: level.
> +    aStream nextPut: $)!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisReceiver:on:indent: (in category 'printing') -----
> + printWithClosureAnalysisReceiver: rcvr on: aStream indent: level
> +                    
> +    rcvr ifNil: [^self].
> + 
> +    "Force parens around keyword receiver of kwd message"
> +    rcvr printWithClosureAnalysisOn: aStream indent: level precedence: precedence!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisToDoOn:indent: (in category 'printing') -----
> + 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>printWithClosureAnalysisWhileOn:indent: (in category 'printing') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageNode>>pvtCheckForPvtSelector: (in category 'private') -----
> + 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']].!
> 
> Item was added:
> + ----- Method: MessageNode>>receiver (in category 'equation translation') -----
> + receiver
> +    ^receiver!
> 
> Item was added:
> + ----- Method: MessageNode>>receiver: (in category 'equation translation') -----
> + receiver: val
> +    "14 feb 2001 - removed return arrow"
> + 
> +    receiver := val!
> 
> Item was added:
> + ----- Method: MessageNode>>receiver:arguments:precedence: (in category 'private') -----
> + receiver: rcvr arguments: args precedence: p
> + 
> +    receiver := rcvr.
> +    originalReceiver := rcvr.
> +    arguments := args.
> +    originalArguments := arguments copy.
> +    sizes := Array new: arguments size.
> +    precedence := p!
> 
> Item was added:
> + ----- Method: MessageNode>>receiver:selector:arguments:precedence: (in category 'initialize-release') -----
> + receiver: rcvr selector: selNode arguments: args precedence: p 
> +    "Decompile."
> + 
> +    self receiver: rcvr
> +        arguments: args
> +        precedence: p.
> +    originalSelector := selNode key.
> +    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?"!
> 
> Item was added:
> + ----- Method: MessageNode>>receiver:selector:arguments:precedence:from: (in category 'initialize-release') -----
> + receiver: rcvr selector: aSelector arguments: args precedence: p from: encoder 
> +    "Compile."
> + 
> +    self receiver: rcvr
> +        arguments: args
> +        precedence: p.
> +    originalSelector := aSelector.
> +    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!
> 
> Item was added:
> + ----- Method: MessageNode>>receiver:selector:arguments:precedence:from:sourceRange: (in category 'initialize-release') -----
> + 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!
> 
> Item was added:
> + ----- Method: MessageNode>>selector (in category 'equation translation') -----
> + selector
> +    ^selector!
> 
> Item was added:
> + ----- Method: MessageNode>>selector: (in category 'initialize-release') -----
> + selector: sel
> +    selector := sel!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForCase:value: (in category 'code generation') -----
> + sizeCodeForCase: encoder value: forValue
> + 
> +    | braceNode sizeIndex elseSize allReturn |
> +    forValue not ifTrue:
> +        [^super sizeCodeForEffect: encoder].
> +    equalNode := encoder encodeSelector: #=.
> +    braceNode := arguments first.
> +    sizes := Array new: 2 * braceNode numElements.
> +    sizeIndex := sizes size.
> +    elseSize := arguments size = 2
> +        ifTrue:
> +            [arguments last sizeCodeForEvaluatedValue: encoder] "otherwise: [...]"
> +        ifFalse:
> +            [caseErrorNode := encoder encodeSelector: #caseError.
> +             "Assume that the receiver of caseOf: has been dup"
> +            (caseErrorNode sizeCode: encoder args: 0 super: false)]. "self caseError"
> +    "There must be at least one branch around the otherwise/caseError
> +      so the decompiler can identify the end of the otherwise/caseError."
> +    allReturn := true. "assume every case ends with a return"
> +    braceNode casesForwardDo:
> +        [:keyNode :valueNode :last |
> +        valueNode returns ifFalse: [allReturn := false]].
> +    braceNode casesReverseDo:
> +        [:keyNode :valueNode :last |
> +        | thenSize dropReceiver |
> +        dropReceiver := last and: [arguments size >= 2].
> +        sizes at: sizeIndex put: elseSize.
> +        thenSize := valueNode sizeCodeForEvaluatedValue: encoder.
> +        dropReceiver 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.
> +        dropReceiver 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!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForEffect: (in category 'code generation') -----
> + sizeCodeForEffect: encoder
> +    <hasLiteralTest: #isMacroSizer:>
> + 
> +    special > 0 
> +        ifTrue:
> +            [encoder noteOptimizedSelector: originalSelector.
> +            ^self perform: (MacroSizers at: special) with: encoder with: false].
> +    ^super sizeCodeForEffect: encoder!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForIf:value: (in category 'code generation') -----
> + sizeCodeForIf: encoder value: forValue
> +    | thenExpr elseExpr branchSize thenSize elseSize popSize requireTwoArms |
> +    thenExpr := arguments at: 1.
> +    elseExpr := arguments at: 2.
> +    popSize := 0.
> +    requireTwoArms := forValue or: [  "Code all forValue as two-armed"
> +        arguments noneSatisfy: [:expr | expr isJust: NodeNil]].
> +    requireTwoArms
> +        ifTrue:
> +            [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.
> +            "Two-armed IFs forEffect share a single pop - except if both branches return"
> +            forValue ifFalse: [(arguments allSatisfy: #returns) ifFalse: [popSize := encoder sizePop]]]
> +        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 + popSize!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForIfNil:value: (in category 'code generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForRepeat:value: (in category 'code generation') -----
> + sizeCodeForRepeat: encoder value: forValue 
> +    "L1: ... Jmp(L1) nil (nil for value only);"
> +    | loopSize |
> +    "We assume long backward branches are always maximal size branches."
> +    loopSize := (receiver sizeCodeForEvaluatedEffect: encoder) + (encoder sizeJumpLong: -1).
> +    sizes := Array with: loopSize.
> +    ^loopSize + (forValue ifTrue: [encoder sizePushSpecialLiteral: nil] ifFalse: [0])!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForToDo:value: (in category 'code generation') -----
> + 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 := forValue
> +        ifTrue: [initStmt sizeCodeForValue: encoder.]
> +        ifFalse: [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!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    <hasLiteralTest: #isMacroSizer:>
> +    | total |
> +    special > 0 ifTrue: 
> +        [encoder noteOptimizedSelector: originalSelector.
> +        ^self perform: (MacroSizers at: special) with: encoder with: true].
> +    receiver == NodeSuper ifTrue:
> +        [selector := selector forSuperSend "only necessary for special selectors"].
> +    total := selector sizeCode: encoder args: arguments size super: receiver == NodeSuper.
> +    receiver ifNotNil:
> +        [total := total + (receiver sizeCodeForValue: encoder)].
> +    sizes := arguments collect: 
> +                    [:arg | | argSize | 
> +                    argSize := arg sizeCodeForValue: encoder.
> +                    total := total + argSize.
> +                    argSize].
> +    ^total!
> 
> Item was added:
> + ----- Method: MessageNode>>sizeCodeForWhile:value: (in category 'code generation') -----
> + 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.
> +    "We assume long backward branches are always maximal size branches."
> +    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])!
> 
> Item was added:
> + ----- Method: MessageNode>>test (in category 'printing') -----
> + test
> + 
> +    3 > 4 ifTrue: [4+5 between: 6 and: 7]
> +            ifFalse: [4 between: 6+5 and: 7-2]!
> 
> Item was added:
> + ----- Method: MessageNode>>toDoFromWhileWithCounts:init:limit: (in category 'decompiling') -----
> + toDoFromWhileWithCounts: blockBodyTempCounts init: incrInit limit: limitInitOrNil
> +    "If the receiver, a whileTrue: loop, represents a to:[by:]do: loop
> +     then answer the replacement to:[by:]do:, otherwise answer nil."
> +    | variable increment limit toDoBlock body test |
> +    self assert: (selector key == #whileTrue:
> +                and: [incrInit isAssignmentNode]).
> +    (limitInitOrNil notNil "limit should not be referenced within the loop"
> +      and: [(blockBodyTempCounts at: limitInitOrNil variable ifAbsent: [0]) ~= 1]) ifTrue:
> +        [^nil].
> +    body := arguments last statements.
> +    (variable := incrInit variable) isTemp ifFalse:
> +        [^nil].
> +    (increment := body last toDoIncrement: variable) ifNil:
> +        [^nil].
> +    receiver statements size ~= 1 ifTrue:
> +        [^nil].
> +    test := receiver statements first.
> +    "Note: test should really be checked that <= or >= comparison
> +    jibes with the sign of the (constant) increment"
> +    (test isMessageNode
> +     and: [(limit := test toDoLimit: variable) notNil]) ifFalse:
> +        [^nil].
> +    "The block must not overwrite the limit"
> +    (limit isVariableNode and: [body anySatisfy: [:e | e isAssignmentNode and: [e variable = limit]]]) ifTrue:
> +        [^nil]. 
> +    toDoBlock := BlockNode statements: body allButLast returns: false.
> +    toDoBlock arguments: {variable}.
> +    ^MessageNode new
> +        receiver: incrInit value
> +        selector: (SelectorNode new key: #to:by:do: code: #macro)
> +        arguments: (Array with: limit with: increment with: toDoBlock)
> +        precedence: precedence!
> 
> Item was added:
> + ----- Method: MessageNode>>toDoFromWhileWithInit:withLimit: (in category 'decompiling') -----
> + toDoFromWhileWithInit: incrInit withLimit: limitInitOrNil
> +    "If the receiver, a whileTrue: loop, represents a to:[by:]do: loop
> +     then answer the replacement to:[by:]do:, otherwise answer nil."
> +    | variable increment limit toDoBlock body test |
> +    self assert: (selector key == #whileTrue:
> +                and: [incrInit isAssignmentNode]).
> +    body := arguments last statements.
> +    (variable := incrInit variable) isTemp ifFalse:
> +        [^nil].
> +    (increment := body last toDoIncrement: variable) ifNil:
> +        [^nil].
> +    receiver statements size ~= 1 ifTrue:
> +        [^nil].
> +    test := receiver statements first.
> +    "Note: test should really be checked that <= or >= comparison
> +    jibes with the sign of the (constant) increment"
> +    (test isMessageNode
> +     and: [(limit := test toDoLimit: variable) notNil]) ifFalse:
> +        [^nil].
> +    "The block must not overwrite the limit"
> +    (limit isVariableNode and: [body anySatisfy: [:e | e isAssignmentNode and: [e variable = limit]]]) ifTrue:
> +        [^nil]. 
> +    toDoBlock := BlockNode statements: body allButLast returns: false.
> +    toDoBlock arguments: {variable}.
> +    ^MessageNode new
> +        receiver: incrInit value
> +        selector: (SelectorNode new key: #to:by:do: code: #macro)
> +        arguments: (Array with: limit with: increment with: toDoBlock)
> +        precedence: precedence!
> 
> Item was added:
> + ----- Method: MessageNode>>toDoIncrement: (in category 'testing') -----
> + toDoIncrement: variable
> +    ^(receiver = variable
> +       and: [selector key = #+
> +       and: [arguments first isConstantNumber]]) ifTrue:
> +        [arguments first]!
> 
> Item was added:
> + ----- Method: MessageNode>>toDoLimit: (in category 'testing') -----
> + toDoLimit: variable
> +    ^(receiver = variable
> +       and: [selector key = #<= or: [selector key = #>=]]) ifTrue:
> +        [arguments first]!
> 
> Item was added:
> + ----- Method: MessageNode>>transform: (in category 'macro transformations') -----
> + transform: encoder
> +    <hasLiteralTest: #isMacroTransformer:>
> + 
> +    special = 0 ifTrue: [^false].
> +    (self perform: (MacroTransformers at: special) with: encoder)
> +        ifTrue: 
> +            [^true]
> +        ifFalse: 
> +            [special := 0. ^false]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformAnd: (in category 'macro transformations') -----
> + transformAnd: encoder
> +    (self transformBoolean: encoder)
> +        ifTrue: 
> +            [arguments := 
> +                Array 
> +                    with: ((arguments at: 1) noteOptimizedIn: self)
> +                    with: ((BlockNode withJust: NodeFalse) noteOptimizedIn: self).
> +            ^true]
> +        ifFalse: 
> +            [^false]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformBoolean: (in category 'macro transformations') -----
> + transformBoolean: encoder
> +    ^self
> +        checkBlock: (arguments at: 1)
> +        as: 'argument'
> +        from: encoder
> +        maxArgs: 0!
> 
> Item was added:
> + ----- Method: MessageNode>>transformCase: (in category 'macro transformations') -----
> + transformCase: encoder
> + 
> +    | caseNode |
> +    caseNode := arguments first.
> +    (caseNode isMemberOf: BraceNode) ifFalse: [^false].
> +    (caseNode blockAssociationCheck: encoder) ifFalse: [^false].
> +    (arguments size = 1
> +     or: [self checkBlock: arguments last as: 'otherwise arg' from: encoder maxArgs: 1]) ifFalse:
> +        [^false].
> +     caseNode elements do:
> +        [:messageNode |
> +        messageNode receiver noteOptimizedIn: self.
> +        messageNode arguments first noteOptimizedIn: self].
> +     arguments size = 2 ifTrue:
> +        [| otherwiseBlock |
> +        otherwiseBlock := arguments last noteOptimizedIn: self.
> +        otherwiseBlock numberOfArguments = 1 ifTrue:
> +            [receiver := AssignmentNode new
> +                variable: otherwiseBlock firstArgument
> +                value: receiver.
> +            encoder noteSourceRange: (encoder sourceRangeFor: self) forNode: receiver]].
> +     ^true!
> 
> Item was added:
> + ----- Method: MessageNode>>transformIfFalse: (in category 'macro transformations') -----
> + transformIfFalse: encoder
> +    (self transformBoolean: encoder)
> +        ifTrue: 
> +            [arguments := 
> +                Array 
> +                    with: ((BlockNode withJust: NodeNil) noteOptimizedIn: self)
> +                    with: ((arguments at: 1) noteOptimizedIn: self).
> +            ^true]
> +        ifFalse:
> +            [^false]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformIfFalseIfTrue: (in category 'macro transformations') -----
> + transformIfFalseIfTrue: encoder
> +    ^(self checkBlock: (arguments at: 1) as: 'False arg' from: encoder maxArgs: 0)
> +       and: [(self checkBlock: (arguments at: 2) as: 'True arg' from: encoder maxArgs: 0)
> +       and: [selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
> +            arguments swap: 1 with: 2.
> +            arguments do: [:arg| arg noteOptimizedIn: self].
> +            true]]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformIfNil: (in category 'macro transformations') -----
> + 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) noteOptimizedIn: self)
> +                        with: (arguments first noteOptimizedIn: self).
> +        (self transform: encoder) ifFalse:
> +            [self error: 'compiler logic error'].
> +        ^true].
> +    (self checkBlock: arguments first as: 'ifNil arg' from: encoder maxArgs: 0) ifFalse:
> +        [^false].
> +    arguments first noteOptimizedIn: self.
> +    ^true!
> 
> Item was added:
> + ----- Method: MessageNode>>transformIfNilIfNotNil: (in category 'macro transformations') -----
> + 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 maxArgs: 0)
> +      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.
> +        encoder noteSourceRange: (encoder sourceRangeFor: self) forNode: receiver].
> + 
> +    selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
> +    receiver := MessageNode new
> +                    receiver: receiver
> +                    selector: #==
> +                    arguments: (Array with: NodeNil)
> +                    precedence: 2
> +                    from: encoder.
> +    encoder noteSourceRange: (encoder sourceRangeFor: self) forNode: receiver.
> +    arguments do: [:arg| arg noteOptimizedIn: self].
> +    ^true!
> 
> Item was added:
> + ----- Method: MessageNode>>transformIfNotNilIfNil: (in category 'macro transformations') -----
> + 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 maxArgs: 0]) ifFalse:
> +        [^false].
> + 
> +    ifNotNilArg numberOfArguments = 1 ifTrue:
> +        [receiver := AssignmentNode new
> +                        variable: ifNotNilArg firstArgument
> +                        value: receiver.
> +        encoder noteSourceRange: (encoder sourceRangeFor: self) forNode: receiver].
> + 
> +    selector := SelectorNode new key: #ifTrue:ifFalse: code: #macro.
> +    receiver := MessageNode new
> +                    receiver: receiver
> +                    selector: #==
> +                    arguments: (Array with: NodeNil)
> +                    precedence: 2
> +                    from: encoder.
> +    encoder noteSourceRange: (encoder sourceRangeFor: self) forNode: receiver.
> +    arguments swap: 1 with: 2.
> +    arguments do: [:arg| arg noteOptimizedIn: self].
> +    ^true!
> 
> Item was added:
> + ----- Method: MessageNode>>transformIfTrue: (in category 'macro transformations') -----
> + transformIfTrue: encoder
> +    (self transformBoolean: encoder)
> +        ifTrue: 
> +            [arguments := 
> +                Array 
> +                    with: ((arguments at: 1) noteOptimizedIn: self)
> +                    with: ((BlockNode withJust: NodeNil) noteOptimizedIn: self).
> +            ^true]
> +        ifFalse: 
> +            [^false]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformIfTrueIfFalse: (in category 'macro transformations') -----
> + transformIfTrueIfFalse: encoder
> +    ^(self checkBlock: (arguments at: 1) as: 'True arg' from: encoder maxArgs: 0)
> +       and: [(self checkBlock: (arguments at: 2) as: 'False arg' from: encoder maxArgs: 0)
> +       and: [arguments do: [:arg| arg noteOptimizedIn: self].
> +            true]]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformOr: (in category 'macro transformations') -----
> + transformOr: encoder
> +    (self transformBoolean: encoder)
> +        ifTrue: 
> +            [arguments := 
> +                Array 
> +                    with: ((BlockNode withJust: NodeTrue) noteOptimizedIn: self)
> +                    with: ((arguments at: 1) noteOptimizedIn: self).
> +            ^true]
> +        ifFalse: 
> +            [^false]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformRepeat: (in category 'macro transformations') -----
> + transformRepeat: encoder
> +    "answer true if this #repeat message can be optimized"
> +    
> +    ^(self checkBlock: receiver as: 'receiver' from: encoder maxArgs: 0)
> +       and: [receiver noteOptimizedIn: self.
> +            true]!
> 
> Item was added:
> + ----- Method: MessageNode>>transformToDo: (in category 'macro transformations') -----
> + 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 |
> +    block := arguments last.
> +    "First check for valid arguments"
> +    (block notNil
> +     and: [block isBlockNode
> +     and: [block numberOfArguments = 1
> +     and: [block 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].
> +    (limit := arguments at: 1) isVariableReference ifTrue:
> +        [| shouldScanForAssignment |
> +         shouldScanForAssignment := limit isArg not
> +                                        or: [limit isBlockArg and: [Scanner allowBlockArgumentAssignment]].
> +         shouldScanForAssignment ifTrue:
> +             [block nodesDo:
> +                [:node|
> +                (node isAssignmentNode and: [node variable = limit]) ifTrue:
> +                    [^false]]]].
> +    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].
> +    blockRange := encoder rawSourceRanges at: block ifAbsent: [1 to: 0].
> +    blockVar := block firstArgument.
> +    initStmt := AssignmentNode new variable: blockVar value: receiver.
> +    (limit isVariableReference or: [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: {limit}
> +                precedence: precedence
> +                from: encoder
> +                sourceRange: (myRange first to: blockRange first).
> +    incStmt := AssignmentNode new
> +                variable: blockVar
> +                value: (MessageNode new
> +                            receiver: blockVar selector: #+
> +                            arguments: {increment}
> +                            precedence: precedence
> +                            from: encoder
> +                            sourceRange: (myRange last to: (myRange last max: blockRange last)))
> +                from: encoder
> +                sourceRange: (myRange last to: (myRange last max: blockRange last)).
> +    arguments := {limit. increment. block. initStmt. test. incStmt. limitInit}.
> +    block noteOptimizedIn: self.
> +    ^true!
> 
> Item was added:
> + ----- Method: MessageNode>>transformWhile: (in category 'macro transformations') -----
> + transformWhile: encoder
> +    (self checkBlock: receiver as: 'receiver' from: encoder maxArgs: 0) 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) noteOptimizedIn: self).
> +         receiver noteOptimizedIn: self.
> +         ^true].
> +    ^(self transformBoolean: encoder)
> +       and: [receiver noteOptimizedIn: self.
> +            arguments first noteOptimizedIn: self.
> +            true]!
> 
> Item was added:
> + ParseNode subclass: #MethodNode
> +    instanceVariableNames: 'selectorOrFalse precedence arguments block primitive encoder temporaries properties sourceText locationCounter localsPool'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !MethodNode commentStamp: 'eem 8/15/2010 10:49' prior: 0!
> + I am the root of the parse tree..
> + 
> + Instance Variables
> +    arguments:            <SequenceableCollection>
> +    block:                <BlockNode>
> +    encoder:            <BytecodeEncoder>
> +    localsPool:            <IdentitySet>
> +    locationCounter:    <Integer>
> +    precedence:        <Integer>
> +    primitive:            <Integer>
> +    properties:            <AdditionalMethodState|nil>
> +    selectorOrFalse:    <Object>
> +    sourceText:        <String|Text>
> +    temporaries:        <SequenceableCollection>
> + 
> + arguments
> +    - the collection of parsed or decompiled method arguments
> + 
> + block
> +    - the BlockNode holding the method's statements
> + 
> + encoder
> +    - the object that comprises the copiler's scope table, literal pool and back-end bytecode generator
> + 
> + localsPool
> +    - a set used to determine the set of copied values for each block in the method
> + 
> + locationCounter
> +    - an integer used to mark block scopes for the purposes of the closure transformation.  See BlockNode>>#analyseArguments:temporaries:rootNode:
> + 
> + precedence
> +    - the precedence of the method's selector (see Symbol>>precedence)
> + 
> + primitive
> +    - if non-zero this is the integer code of the method's primitive
> + 
> + properties
> +    - the object used to accumulate method properties (a.k.a. pragmas)
> + 
> + selectorOrFalse
> +    - the method's selector or false if this is a doit
> + 
> + sourceText
> +    - the source test from which the method was compiled
> + 
> + temporaries
> +    - the collection of parsed or decompiled method temporaries
> + !
> 
> Item was added:
> + ----- Method: MethodNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitMethodNode: self!
> 
> Item was added:
> + ----- Method: MethodNode>>addLocalsToPool: (in category 'closure analysis') -----
> + addLocalsToPool: locals "<Set of: TempVariableNode>"
> +    localsPool isNil ifTrue:
> +        [localsPool := IdentitySet new].
> +    localsPool addAll: locals!
> 
> Item was added:
> + ----- Method: MethodNode>>arguments (in category 'accessing') -----
> + arguments
> +    "For transformations etc, not used in compilation"
> +    ^arguments!
> 
> Item was added:
> + ----- Method: MethodNode>>arguments: (in category 'accessing') -----
> + arguments: aSequence
> +    "For transformations etc, not used in compilation"
> +    arguments := aSequence!
> 
> Item was added:
> + ----- Method: MethodNode>>asColorizedSmalltalk80Text (in category 'converting') -----
> + asColorizedSmalltalk80Text
> +    "Answer a colorized Smalltalk-80-syntax string description of the parse tree whose root is the receiver."
> + 
> +    | printText |
> +    printText := self printString asText.
> +    ^(TextStyler for: #Smalltalk)
> +        ifNotNil: [:stylerClass| stylerClass new styledTextFor: printText]
> +        ifNil: [printText]!
> 
> Item was added:
> + ----- Method: MethodNode>>block (in category 'initialize-release') -----
> + block
> +    ^ block!
> 
> Item was added:
> + ----- Method: MethodNode>>blockExtentsToTempsMap (in category 'debugger support') -----
> + 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 newParser
> +                        encoderClass: encoder class;
> +                        parse: (sourceText ifNil: [self decompileString])
> +                        class: self methodClass.
> +        "As a side effect generate: creates data needed for the map."
> +        methNode generate.
> +        methNode encoder blockExtentsToTempsMap]!
> 
> Item was added:
> + ----- Method: MethodNode>>body (in category 'accessing') -----
> + body
> +    ^block!
> 
> Item was added:
> + ----- Method: MethodNode>>decompileString (in category 'converting') -----
> + decompileString 
> +    "Answer a string description of the parse tree whose root is the receiver."
> + 
> +    ^self fullPrintString
> + !
> 
> Item was added:
> + ----- Method: MethodNode>>decompileText (in category 'converting') -----
> + decompileText 
> +    "Answer a string description of the parse tree whose root is the receiver."
> + 
> +    ^self asColorizedSmalltalk80Text!
> 
> Item was added:
> + ----- Method: MethodNode>>encoder (in category 'code generation') -----
> + encoder
> +    ^ encoder!
> 
> Item was added:
> + ----- Method: MethodNode>>ensureClosureAnalysisDone (in category 'closure analysis') -----
> + ensureClosureAnalysisDone
> +    block blockExtent ifNil:
> +        [temporaries := block analyseArguments: arguments temporaries: temporaries rootNode: self]!
> 
> Item was added:
> + ----- Method: MethodNode>>ensureNotQuick (in category 'converting') -----
> + ensureNotQuick
> +    "If the receiver is quick (can be generated as a Quick method, ^self,^inst var or ^ special constant)
> +     make it not so.  This is used to create break-pointable versions of quick methods.   Answer if the
> +     receiver was quick."
> +    ^block ensureNotQuick: encoder!
> 
> Item was added:
> + ----- Method: MethodNode>>generate (in category 'code generation') -----
> + 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: CompiledMethodTrailer empty using: CompiledMethod!
> 
> Item was added:
> + ----- Method: MethodNode>>generate: (in category 'code generation') -----
> + generate: trailer 
> +    "The receiver is the root of a parse tree. Answer a CompiledMethod.
> +     The argument, trailer, is arbitrary but is typically either the reference
> +     to the source code that is stored with every CompiledMethod, or an
> +     encoding of the method's temporary names."
> + 
> +    ^self generate: trailer using: CompiledMethod!
> 
> Item was added:
> + ----- Method: MethodNode>>generate:ifQuick: (in category 'code generation') -----
> + generate: trailer ifQuick: methodBlock
> +    ^self generate: trailer using: CompiledMethod ifQuick: methodBlock!
> 
> Item was added:
> + ----- Method: MethodNode>>generate:using: (in category 'code generation') -----
> + generate: trailer using: aCompiledMethodClass
> +    "The receiver is the root of a parse tree. Answer an instance of aCompiledMethodClass.
> +     The argument, trailer, is arbitrary but is typically either the reference to the source code
> +     that is stored with every CompiledMethod, or an encoding of the method's temporary names."
> + 
> +    | method |
> +    self generate: trailer
> +        using: aCompiledMethodClass
> +        ifQuick:
> +            [:m |
> +              m    literalAt: 2 put: encoder associationForClass;
> +                properties: properties.
> +            ^m].
> +    method := encoder generateMethodOfClass: aCompiledMethodClass trailer: trailer from: self.
> +    method properties: properties.
> +    ^method!
> 
> Item was added:
> + ----- Method: MethodNode>>generate:using:ifQuick: (in category 'code generation') -----
> + generate: trailer using: aCompiledMethodClass 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: (aCompiledMethodClass toReturnSelfTrailerBytes: trailer)].
> +    (v between: LdTrue and: LdMinus1 + 3) ifTrue:
> +        [^methodBlock value: (aCompiledMethodClass toReturnConstant: v - LdSelf trailerBytes: trailer)].
> +    v < ((CodeBases at: LdInstType) + (CodeLimits at: LdInstType)) ifTrue:
> +        [^methodBlock value: (aCompiledMethodClass toReturnField: v trailerBytes: trailer)].
> +    v // 256 = 1 ifTrue:
> +        [^methodBlock value: (aCompiledMethodClass toReturnField: v \\ 256 trailerBytes: trailer)]!
> 
> Item was added:
> + ----- Method: MethodNode>>generateWithTempNames (in category 'code generation') -----
> + generateWithTempNames
> +    "Answer a CompiledMethod with temps names encoded in its trailer."
> +    | methodSansTempNames |
> +    "The encoder computes the schematic temp names during generation, so 
> +     generate a method without temp names first.  If the method is quick there are
> +     no temps and hence no temp names."
> +    methodSansTempNames := self
> +                                    generate: CompiledMethodTrailer empty
> +                                    using: CompiledMethod.
> +    ^methodSansTempNames
> +        copyWithTrailerBytes:
> +            ((CompiledMethodTrailer new tempNames:
> +                (methodSansTempNames isQuick
> +                    ifTrue: ['']
> +                    ifFalse: [encoder schematicTempNamesString])))!
> 
> Item was added:
> + ----- Method: MethodNode>>hasGeneratedMethod (in category 'debugger support') -----
> + hasGeneratedMethod
> +    ^encoder hasGeneratedMethod!
> 
> Item was added:
> + ----- Method: MethodNode>>locationCounter (in category 'closure analysis') -----
> + locationCounter
> +    ^locationCounter!
> 
> Item was added:
> + ----- Method: MethodNode>>methodClass (in category 'printing') -----
> + methodClass
> + 
> +    ^ encoder classEncoding!
> 
> Item was added:
> + ----- Method: MethodNode>>noteBlockEntry: (in category 'closure analysis') -----
> + noteBlockEntry: aBlock
> +    "Evaluate aBlock with the numbering for the block entry."
> +    locationCounter isNil ifTrue:
> +        [locationCounter := -1].
> +    aBlock value: locationCounter + 1.
> +    locationCounter := locationCounter + 2!
> 
> Item was added:
> + ----- Method: MethodNode>>noteBlockExit: (in category 'closure analysis') -----
> + noteBlockExit: aBlock
> +    "Evaluate aBlock with the numbering for the block exit."
> +    aBlock value: locationCounter + 1.
> +    locationCounter := locationCounter + 2!
> 
> Item was added:
> + ----- Method: MethodNode>>parserClass (in category 'code generation') -----
> + parserClass
> +    "Which parser produces this class of parse node"
> + 
> +    ^ Parser!
> 
> Item was added:
> + ----- Method: MethodNode>>preen (in category 'converting') -----
> + preen
> +    "Preen for pretty-printing and/or decompilation.
> +     i.e. post-process to cover up for inadequacies in both algorithms.
> + 
> +     Currently two cases:
> + 
> +        preenLocalIfNotNilArg: blockNode
> +        hiding the assignment to the arg of an inlined block arg to ifNotNil:,
> +            (var := expr) ifNil: [...] ifNotNil: [...]    =>    expr ifNil: [...] ifNotNil: [:var| ...].
> + 
> +        preenTempsConflictingWithBlockNode: temps
> +        hiding the declaration of a temp that is redeclared in some block"
> + 
> +    self preenableNodes keysAndValuesDo:
> +        [:nodeOrArray :selector |
> +         self perform: selector with: nodeOrArray]!
> 
> Item was added:
> + ----- Method: MethodNode>>preenIfNotNilNode: (in category 'converting-private') -----
> + preenIfNotNilNode: messageNode
> +    "Transform a (var := expr) ifNil: [...] ifNotNil: [...] where var is only used in the ifNotNil: block
> +     and convert it to expr ifNil: [...] ifNotNil: [:var| ...].  Deal both with the pretty-print case where
> +     the block already declares the variable and the decompile case where it does not."
> + 
> +    | variable |
> +    self assert: (messageNode isMessageNode
> +                and: [messageNode macroPrinter == #printIfNilNotNil:indent:
> +                and: [messageNode receiver receiver isAssignmentNode]]).
> +    variable := messageNode receiver receiver variable.
> +    self assert: (variable isTemp and: [variable isRemote not]).
> +    messageNode arguments last arguments isEmpty
> +        ifTrue: [messageNode arguments last arguments: { variable }]
> +        ifFalse:
> +            [self assert: messageNode arguments last arguments asArray = { variable }.
> +             variable := nil].
> +    messageNode receiver receiver: messageNode receiver receiver value.
> +    variable ifNil: [^self].
> +    self nodesDo:
> +        [:node|
> +        ((node == self or: [node isBlockNode])
> +         and: [node temporaries includes: variable]) ifTrue:
> +            [node temporaries: (node temporaries copyWithout: variable)]]!
> 
> Item was added:
> + ----- Method: MethodNode>>preenNilNodeFollowingNilIfNode: (in category 'converting-private') -----
> + preenNilNodeFollowingNilIfNode: aNilIfMessageNode
> +    self nodesDo:
> +        [:node| | statements indices |
> +         (node isBlockNode
> +          and: [(statements := node statements) includes: aNilIfMessageNode]) ifTrue:
> +            [indices := (2 to: statements size) reject:
> +                            [:i|
> +                            (statements at: i) == NodeNil
> +                            and: [(statements at: i - 1) isNilIf]].
> +             node statements: (({1}, indices) collect: [:i| statements at: i])]]!
> 
> Item was added:
> + ----- Method: MethodNode>>preenTempsConflictingWithBlockNode: (in category 'converting-private') -----
> + preenTempsConflictingWithBlockNode: temps
> +    "Push temps that conflict with other blocks down into their narrowest enclosing block scope."
> +    temps do:
> +        [:tempVar|
> +        (self accept: (NarrowerVariableScopeFinder new ofVariable: tempVar)) ifNotNil:
> +            [:enclosingScope |
> +             self assert: enclosingScope isBlockNode.
> +             self nodesDo:
> +                [:node|
> +                 ((node == self or: [node isBlockNode])
> +                  and: [node temporaries includes: tempVar]) ifTrue:
> +                    [node temporaries: (node temporaries copyWithout: tempVar)]].
> +             enclosingScope temporaries: enclosingScope temporaries, { tempVar }]]!
> 
> Item was added:
> + ----- Method: MethodNode>>preenableNodes (in category 'converting-private') -----
> + preenableNodes
> +    "Answer a Dictionary from node or sequence of nodes to preen method selector for nodes
> +     in the tree that require post-processing after either a format or a decompile.  Such issues
> +     are the variable for an ifNotNil: which is local to the ifNotNil: block but, due to the inlining
> +     of ifNotNil: appears to be declared at the outer level, and, similarly, a temporary variable
> +     that conflicts with one of the same name in a block when, were the variable declared
> +     local to some inlined block it would no longer conflict.  The resulting dictionary is used to
> +     perform the value with the key (node or array) as argument to preen the tree."
> + 
> +    | preenableNodes priorBlocks priorVariables |
> +    preenableNodes := Dictionary new.
> +    priorBlocks := OrderedCollection new.
> +    priorVariables := Set new.
> +    self nodesWithPrecedingStatementsDo:
> +        [:node :precedingStatementOrNil| | variable temps |
> +        (node isMessageNode
> +        and: [node macroPrinter == #printIfNilNotNil:indent:
> +        and: [node receiver isMessageNode
> +        and: [node receiver selector key == #==
> +        and: [node receiver receiver isAssignmentNode
> +        and: [(variable := node receiver receiver variable) isTemp
> +        and: [variable isRemote not
> +        and: [variable isOnlySubnodeOf: node in: self]]]]]]]) ifTrue:
> +            [preenableNodes at: node put: #preenIfNotNilNode:.
> +             priorVariables add: variable].
> +        node isBlockNode ifTrue:
> +            [temps := OrderedCollection new.
> +             node temporaries do:
> +                [:temp|
> +                 priorBlocks do:
> +                    [:aBlock|
> +                     aBlock temporaries do:
> +                        [:priorTemp|
> +                         (priorVariables includes: priorTemp) ifFalse:
> +                            [priorTemp key = temp key ifTrue:
> +                                [temps addLast: priorTemp]]]]].
> +             temps isEmpty ifFalse:
> +                [preenableNodes at: temps put: #preenTempsConflictingWithBlockNode:].
> +             priorBlocks addLast: node].
> +        (node == NodeNil
> +         and: [precedingStatementOrNil notNil
> +         and: [precedingStatementOrNil isMessageNode
> +         and: [precedingStatementOrNil isNilIf]]]) ifTrue:
> +            [preenableNodes at: precedingStatementOrNil put: #preenNilNodeFollowingNilIfNode:]].
> +    ^preenableNodes!
> 
> Item was added:
> + ----- Method: MethodNode>>primitive (in category 'accessing') -----
> + primitive
> +    ^primitive!
> 
> Item was added:
> + ----- Method: MethodNode>>primitiveErrorVariableName (in category 'accessing') -----
> + 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"!
> 
> Item was added:
> + ----- Method: MethodNode>>printOn: (in category 'printing') -----
> + 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!
> 
> Item was added:
> + ----- Method: MethodNode>>printPragmasOn: (in category 'printing') -----
> + 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; nextPut: $<; print: pragma message; nextPut: $>]]!
> 
> Item was added:
> + ----- Method: MethodNode>>printPrimitiveOn: (in category 'printing') -----
> + 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 classNamed: #StackInterpreter) ifNil: [Smalltalk classNamed: #Interpreter]) ifNotNil:
> +        [:interpreterClass|
> +         aStream nextPutAll: ' "', (interpreterClass primitiveTable at: primitive + 1), '" ']!
> 
> Item was added:
> + ----- Method: MethodNode>>printPropertiesOn: (in category 'printing') -----
> + 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: $>]!
> 
> Item was added:
> + ----- Method: MethodNode>>printWithClosureAnalysisOn: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream
> +    self ensureClosureAnalysisDone.
> +    precedence = 1
> +        ifTrue: 
> +            [(self selector includesSubstring: '()/')
> +                ifTrue: [aStream nextPutAll: (self selector copyUpTo: $)).
> +                        arguments
> +                            do: [:arg| aStream nextPutAll: arg key]
> +                            separatedBy: [aStream nextPutAll: ', '].
> +                        aStream nextPut: $)]
> +                ifFalse: [aStream nextPutAll: self selector]]  "no node for method selector"
> +        ifFalse: 
> +            [self selector keywords with: arguments do: 
> +                [:kwd :arg | 
> +                aStream nextPutAll: kwd; space.
> +                arg printDefinitionForClosureAnalysisOn: aStream.
> +                aStream space]].
> +    comment == nil ifFalse: 
> +            [aStream crtab: 1.
> +             self printCommentOn: aStream indent: 1].
> +    temporaries size > 0 ifTrue: 
> +            [aStream crtab: 1; nextPut: $|.
> +            temporaries do: [:temp | 
> +                aStream space.
> +                temp printDefinitionForClosureAnalysisOn: aStream].
> +            aStream space; nextPut: $|].
> +    primitive > 0 ifTrue:
> +        [(primitive between: 255 and: 519) ifFalse:  "Dont decompile quick prims  e.g, ^ self or ^instVar"
> +            [aStream crtab: 1.
> +             self printPrimitiveOn: aStream]].
> +    self printPropertiesOn: aStream.
> +    self printPragmasOn: aStream.
> +    aStream crtab: 1.
> +    block printWithClosureAnalysisStatementsOn: aStream indent: 0!
> 
> Item was added:
> + ----- Method: MethodNode>>properties (in category 'code generation') -----
> + properties
> +    ^properties!
> 
> Item was added:
> + ----- Method: MethodNode>>rawSourceRanges (in category 'source mapping') -----
> + rawSourceRanges
> + 
> +    ^self rawSourceRangesAndMethodDo: [:rawSourceRanges :method| rawSourceRanges]!
> 
> Item was added:
> + ----- Method: MethodNode>>rawSourceRangesAndMethodDo: (in category 'source mapping') -----
> + rawSourceRangesAndMethodDo: aBinaryBlock
> +    "Evaluate aBinaryBlock with the rawSourceRanges and method generated from the receiver."
> + 
> +    | methNode method |
> +    methNode := encoder classEncoding newParser
> +                    encoderClass: encoder class;
> +                    parse: (sourceText "If no source, use decompile string as source to map from"
> +                            ifNil: [self decompileString]
> +                            ifNotNil: [sourceText])
> +                    class: self methodClass.
> +    method := methNode generate.  "set bytecodes to map to"
> +    ^aBinaryBlock
> +        value: methNode encoder rawSourceRanges
> +        value: method!
> 
> Item was added:
> + ----- Method: MethodNode>>referencedValuesWithinBlockExtent: (in category 'closure analysis') -----
> + referencedValuesWithinBlockExtent: anInterval 
> +    ^(localsPool select:
> +        [:temp|
> +         temp isReferencedWithinBlockExtent: anInterval]) collect:
> +            [:temp|
> +            temp isRemote ifTrue: [temp remoteNode] ifFalse: [temp]]!
> 
> Item was added:
> + ----- Method: MethodNode>>removeAndRenameLastTempIfErrorCode (in category 'primitive error codes') -----
> + removeAndRenameLastTempIfErrorCode
> +    self primitiveErrorVariableName ifNotNil:
> +        [:primitiveErrorVariableName|
> +         temporaries last
> +            name: primitiveErrorVariableName
> +            key: primitiveErrorVariableName
> +            code: temporaries last code.
> +         temporaries removeLast].!
> 
> Item was added:
> + ----- Method: MethodNode>>removeProperty: (in category 'accessing') -----
> + removeProperty: aSymbol
> +    properties := properties copyWithout: (Association
> +                                            key: aSymbol
> +                                            value: (properties propertyValueAt: aSymbol))!
> 
> Item was added:
> + ----- Method: MethodNode>>schematicTempNamesString (in category 'debugger support') -----
> + 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 blockExtentsToLocals map, except if the method is quick
> +          in which case it has no temps."
> +        self generate isQuick ifTrue:
> +            [^'']].
> +    ^encoder schematicTempNamesString!
> 
> Item was added:
> + ----- Method: MethodNode>>selector (in category 'code generation') -----
> + selector 
> +    "Answer the message selector for the method represented by the receiver."
> + 
> +    (selectorOrFalse isSymbol)
> +        ifTrue: [^selectorOrFalse].
> +    ^selectorOrFalse key.
> + !
> 
> Item was added:
> + ----- Method: MethodNode>>selector: (in category 'initialize-release') -----
> + selector: symbol
> + 
> +    selectorOrFalse := symbol!
> 
> Item was added:
> + ----- Method: MethodNode>>selector:arguments:precedence:temporaries:block:encoder:primitive: (in category 'initialize-release') -----
> + 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.!
> 
> Item was added:
> + ----- Method: MethodNode>>selector:arguments:precedence:temporaries:block:encoder:primitive:properties: (in category 'initialize-release') -----
> + 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.!
> 
> Item was added:
> + ----- Method: MethodNode>>selectorNode (in category 'code generation') -----
> + selectorNode
> +    "Answer a SelectorNode for the message selector of the method represented by the receiver."
> + 
> +    ^(selectorOrFalse isKindOf: SelectorNode)
> +        ifTrue: [selectorOrFalse]
> +        ifFalse: [SelectorNode new key: selectorOrFalse]!
> 
> Item was added:
> + ----- Method: MethodNode>>sourceText (in category 'printing') -----
> + sourceText
> + 
> +    ^ sourceText ifNil: [self printString]!
> 
> Item was added:
> + ----- Method: MethodNode>>sourceText: (in category 'initialize-release') -----
> + sourceText: stringOrText
> + 
> +    sourceText := stringOrText!
> 
> Item was added:
> + ----- Method: MethodNode>>tempNames (in category 'printing') -----
> + tempNames
> +    ^ encoder tempNames!
> 
> Item was added:
> + ----- Method: MethodNode>>temporaries (in category 'accessing') -----
> + temporaries
> +    "For transformations etc, not used in compilation"
> +    ^temporaries!
> 
> Item was added:
> + ----- Method: MethodNode>>temporaries: (in category 'accessing') -----
> + temporaries: aSequence
> +    "For transformations etc, not used in compilation"
> +    temporaries := aSequence!
> 
> Item was added:
> + ParseNode subclass: #MethodTempsNode
> +    instanceVariableNames: 'temporaries'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> 
> Item was added:
> + VariableScopeFinder subclass: #NarrowerVariableScopeFinder
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !NarrowerVariableScopeFinder commentStamp: 'eem 4/3/2017 11:59' prior: 0!
> + A NarrowerVariableScopeFinder is used to find a smaller scope for an already declared variable.!
> 
> Item was added:
> + ----- Method: NarrowerVariableScopeFinder>>visitTempVariableNode: (in category 'visiting') -----
> + visitTempVariableNode: aVariableNode
> +    ^theVariable = aVariableNode ifTrue: [theVariable]!
> 
> Item was added:
> + ----- Method: NarrowerVariableScopeFinder>>visitUndeclaredVariableNode: (in category 'visiting') -----
> + visitUndeclaredVariableNode: aVariableNode
> +    ^nil!
> 
> Item was added:
> + ParseNode subclass: #NewArrayNode
> +    instanceVariableNames: 'numElements'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !NewArrayNode commentStamp: '<historical>' prior: 0!
> + I represent a node for the genPushNewArray: opcode.!
> 
> Item was added:
> + ----- Method: NewArrayNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitNewArrayNode: self!
> 
> Item was added:
> + ----- Method: NewArrayNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> +    "This is a no-op except in TempVariableNode"
> +    ^self!
> 
> Item was added:
> + ----- Method: NewArrayNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    encoder genPushNewArray: numElements.
> +    stack push: 1!
> 
> Item was added:
> + ----- Method: NewArrayNode>>numElements (in category 'accessing') -----
> + numElements
> +    ^numElements!
> 
> Item was added:
> + ----- Method: NewArrayNode>>numElements: (in category 'accessing') -----
> + numElements: n
> +    numElements := n!
> 
> Item was added:
> + ----- Method: NewArrayNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    ^encoder sizePushNewArray: numElements!
> 
> Item was added:
> + ParseNodeVisitor subclass: #OptimizedBlockLocalTempReadBeforeWrittenVisitor
> +    instanceVariableNames: 'inOptimizedBlock readBeforeWritten written'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !OptimizedBlockLocalTempReadBeforeWrittenVisitor commentStamp: '<historical>' prior: 0!
> + Answer the set of temporary variables that are read before they are written in the visited parse tree.  Used by the compiler to detect those block-local temporaries of blocks in optimized loops that require nilling to prevent a value from a previous iteration persisting into a subsequent one.!
> 
> Item was added:
> + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>initialize (in category 'initialize-release') -----
> + initialize
> +    inOptimizedBlock := false!
> 
> Item was added:
> + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>readBeforeWritten (in category 'accessing') -----
> + readBeforeWritten
> +    ^readBeforeWritten ifNil: [IdentitySet new]!
> 
> Item was added:
> + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitAssignmentNode: (in category 'visiting') -----
> + visitAssignmentNode: anAssignmentNode
> +    anAssignmentNode value accept: self.
> +    anAssignmentNode variable isTemp
> +        ifTrue:
> +            [written ifNil: [written := IdentitySet new].
> +             written add: anAssignmentNode variable]
> +        ifFalse:
> +            [anAssignmentNode variable accept: self]!
> 
> Item was added:
> + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitBlockNode: (in category 'visiting') -----
> + visitBlockNode: aBlockNode
> +    | savedWritten |
> +    "If we're in the optimized block in one side of an optimized ifTrue:ifFalse: et al
> +     leave it to the enclosing visitMessageNode: activation to handle merging written."
> +    inOptimizedBlock ifTrue:
> +        [^super visitBlockNode: aBlockNode].
> +    "If we're not then don't update written because without evaluating the guard(s)
> +     we can't tell if the block is evaluated or not, and we must avoid false positives."
> +    savedWritten := written copy.
> +    super visitBlockNode: aBlockNode.
> +    written := savedWritten!
> 
> Item was added:
> + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitMessageNode: (in category 'visiting') -----
> + visitMessageNode: aMessageNode
> +    | savedWritten writtenPostFirstArm |
> +    (aMessageNode isOptimized
> +     and: [#(ifTrue:ifFalse: ifFalse:ifTrue: ifNil:ifNotNil: ifNotNil:ifNil:) includes: aMessageNode selector key]) ifFalse:
> +        [^super visitMessageNode: aMessageNode].
> +    aMessageNode receiver accept: self.
> +    aMessageNode selector accept: self.
> +    savedWritten := written copy.
> +    aMessageNode argumentsInEvaluationOrder
> +        do: [:argument|
> +            argument isBlockNode
> +                ifTrue: [| savedIOB |
> +                    savedIOB := inOptimizedBlock.
> +                    inOptimizedBlock := true.
> +                    [argument accept: self]
> +                        ensure: [inOptimizedBlock := savedIOB]]
> +                ifFalse: [argument accept: self]]
> +        separatedBy:
> +            [writtenPostFirstArm := written.
> +             written := savedWritten].
> +    (written notNil
> +     and: [writtenPostFirstArm notNil]) ifTrue:
> +        [written := written intersection: writtenPostFirstArm]!
> 
> Item was added:
> + ----- Method: OptimizedBlockLocalTempReadBeforeWrittenVisitor>>visitTempVariableNode: (in category 'visiting') -----
> + visitTempVariableNode: aTempVariableNode
> +    (aTempVariableNode isArg
> +     or: [written notNil
> +        and: [written includes: aTempVariableNode]]) ifTrue:
> +        [^self].
> +    readBeforeWritten ifNil:
> +        [readBeforeWritten := IdentitySet new].
> +    readBeforeWritten add: aTempVariableNode!
> 
> Item was added:
> + Notification subclass: #OutOfScopeNotification
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> 
> Item was added:
> + ----- Method: OutOfScopeNotification>>defaultAction (in category 'priv handling') -----
> + defaultAction
> + 
> +    ^false!
> 
> Item was added:
> + Object subclass: #ParseNode
> +    instanceVariableNames: 'comment pc'
> +    classVariableNames: 'CodeBases CodeLimits LdFalse LdInstType LdLitIndType LdLitType LdMinus1 LdNil LdSelf LdSuper LdTempType LdThisContext LdTrue LoadLong NodeFalse NodeNil NodeSelf NodeSuper NodeThisContext NodeTrue Send SendPlus SendType StdLiterals StdSelectors StdVariables'
> +    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.!
> 
> Item was added:
> + ----- Method: ParseNode class>>initialize (in category 'class initialization') -----
> + initialize
> +    "ParseNode initialize. VariableNode initialize"
> +    LdInstType := 1.
> +    LdTempType := 2.
> +    LdLitType := 3.
> +    LdLitIndType := 4.
> +    SendType := 5.
> +    "Back in the day the following constants corresponded to bytecodes.
> +     Now they're just unique values that need to be eliminated when and if
> +     things like code:type: are cleaned up."
> +    CodeBases := #(0 16 32 64 208 ).
> +    CodeLimits := #(16 16 32 32 16 ).
> +    LdSelf := 112.
> +    LdTrue := 113.
> +    LdFalse := 114.
> +    LdNil := 115.
> +    LdMinus1 := 116.
> +    LoadLong := 128.
> +    LdSuper := 133.
> +    LdThisContext := 137.
> +    SendPlus := 176.
> +    Send := 208
> +    
> +    "((ParseNode class >> #initialize) literals select: [:l| l isVariableBinding and: [(ParseNode classPool includesAssociation: l) and: [(self systemNavigation allCallsOn: l localTo: ParseNode) size = 1]]]) sort: [:a :b| a key <= b key]"
> + 
> +    "ParseNode classPool associations select: [:a| (self systemNavigation allCallsOn: a localTo: ParseNode) isEmpty]"!
> 
> Item was added:
> + ----- Method: ParseNode class>>pushNilCode (in category 'accessing') -----
> + pushNilCode
> + 
> +    ^LdNil!
> 
> Item was added:
> + ----- Method: ParseNode class>>tempSortBlock (in category 'accessing') -----
> + 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"!
> 
> Item was added:
> + ----- Method: ParseNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    "Accept a visitor by double-dispatching to a type-specific method on the visitor, e.g. visitBlockNode:.
> +     All such implementations under ParseNode should answer the result of the dispatch, e.g.
> +        ^aVisitor visitBlockNode: self"
> +    ^self subclassResponsibility!
> 
> Item was added:
> + ----- Method: ParseNode>>asReturnNode (in category 'converting') -----
> + asReturnNode
> + 
> +    ^ReturnNode new expr: self!
> 
> Item was added:
> + ----- Method: ParseNode>>assignmentCheck:at: (in category '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!
> 
> Item was added:
> + ----- Method: ParseNode>>canCascade (in category 'testing') -----
> + canCascade
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>comment (in category 'comment') -----
> + comment
> + 
> +    ^comment!
> 
> Item was added:
> + ----- Method: ParseNode>>comment: (in category 'comment') -----
> + comment: newComment
> + 
> +    comment := newComment!
> 
> Item was added:
> + ----- Method: ParseNode>>emitCodeForBlockValue:encoder: (in category 'code generation') -----
> + emitCodeForBlockValue: stack encoder: encoder
> +    "Generate code for evaluating the last statement in a block"
> +    ^self emitCodeForValue: stack encoder: encoder!
> 
> Item was added:
> + ----- Method: ParseNode>>emitCodeForBranchOn:dist:pop:encoder: (in category 'code generation') -----
> + 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]!
> 
> Item was added:
> + ----- Method: ParseNode>>emitCodeForEffect:encoder: (in category 'code generation') -----
> + emitCodeForEffect: stack encoder: encoder
> + 
> +    self emitCodeForValue: stack encoder: encoder.
> +    encoder genPop.
> +    stack pop: 1!
> 
> Item was added:
> + ----- Method: ParseNode>>emitCodeForJump:encoder: (in category 'code generation') -----
> + emitCodeForJump: dist encoder: encoder
> + 
> +    dist = 0 ifFalse: [encoder genJump: dist]!
> 
> Item was added:
> + ----- Method: ParseNode>>emitCodeForReturn:encoder: (in category 'code generation') -----
> + emitCodeForReturn: stack encoder: encoder
> + 
> +    self emitCodeForValue: stack encoder: encoder.
> +    encoder genReturnTop!
> 
> Item was added:
> + ----- Method: ParseNode>>encodeSelector: (in category 'encoding') -----
> + encodeSelector: selector
> + 
> +    ^nil!
> 
> Item was added:
> + ----- Method: ParseNode>>ensureCanCascade: (in category 'testing') -----
> + ensureCanCascade: encoder!
> 
> Item was added:
> + ----- Method: ParseNode>>ifNilReceiver (in category 'private') -----
> + ifNilReceiver
> +    "assuming this object is the receiver of an ifNil:, what object is being asked about?"
> +    ^self!
> 
> Item was added:
> + ----- Method: ParseNode>>ifNilTemporary (in category 'private') -----
> + ifNilTemporary
> + 
> +    ^ nil!
> 
> Item was added:
> + ----- Method: ParseNode>>ifNilValue (in category 'private') -----
> + ifNilValue
> + 
> +    ^self!
> 
> Item was added:
> + ----- Method: ParseNode>>isArg (in category 'testing') -----
> + isArg
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isAssignmentNode (in category 'testing') -----
> + isAssignmentNode
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isBlockNode (in category 'testing') -----
> + isBlockNode
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isBraceNode (in category 'testing') -----
> + isBraceNode
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isComplex (in category 'testing') -----
> + isComplex
> +    "Used for pretty printing to determine whether to start a new line"
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isConstantNumber (in category 'testing') -----
> + isConstantNumber  "Overridden in LiteralNode"
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isDoIt (in category 'testing') -----
> + isDoIt
> +    "polymorphic with RBNodes; called by debugger"
> + 
> +    ^ false!
> 
> Item was added:
> + ----- Method: ParseNode>>isFutureNode (in category 'testing') -----
> + isFutureNode
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isJust: (in category 'testing') -----
> + isJust: node
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isLiteralNode (in category 'testing') -----
> + isLiteralNode
> + 
> +    ^ false!
> 
> Item was added:
> + ----- Method: ParseNode>>isMessage (in category 'testing') -----
> + isMessage
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isMessage:receiver:arguments: (in category 'testing') -----
> + isMessage: selSymbol receiver: rcvrPred arguments: argsPred
> +    "See comment in MessageNode."
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isMessageNode (in category 'testing') -----
> + isMessageNode
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isOnlySubnodeOf:in: (in category 'testing') -----
> + isOnlySubnodeOf: aSubtree "<ParseNode>" in: aParseTree "<ParseNode>"
> +    "Answer if the receiver only occurs within aSubtree of aParseTree, not in the rest of aParseTree.
> +     Assumes that aSubtree is in fact a subnode of aParseTree."
> +    | isSubnode |
> +    isSubnode := false.
> +    aSubtree accept: (ParseNodeEnumerator
> +                            ofBlock: [:node| node == self ifTrue: [isSubnode := true]]).
> +    isSubnode ifFalse:
> +        [^false].
> +    aParseTree accept: (ParseNodeEnumerator
> +                            ofBlock: [:node| node == self ifTrue: [^false]]
> +                            select: [:node| node ~= aSubtree]).
> +    ^true!
> 
> Item was added:
> + ----- Method: ParseNode>>isReturnSelf (in category 'testing') -----
> + isReturnSelf
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isReturningIf (in category 'testing') -----
> + isReturningIf
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isSelfPseudoVariable (in category 'testing') -----
> + isSelfPseudoVariable    
> +    "Overridden in VariableNode."
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isSpecialConstant (in category 'testing') -----
> + isSpecialConstant
> +    ^ false!
> 
> Item was added:
> + ----- Method: ParseNode>>isTemp (in category 'testing') -----
> + isTemp
> +    ^ false!
> 
> Item was added:
> + ----- Method: ParseNode>>isUndefTemp (in category 'testing') -----
> + isUndefTemp
> +    ^ false!
> 
> Item was added:
> + ----- Method: ParseNode>>isUnusedTemp (in category 'testing') -----
> + isUnusedTemp
> +    ^ false!
> 
> Item was added:
> + ----- Method: ParseNode>>isVariableNode (in category 'testing') -----
> + isVariableNode
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>isVariableReference (in category 'testing') -----
> + isVariableReference
> + 
> +    ^false!
> 
> Item was added:
> + ----- Method: ParseNode>>nextWordFrom:setCharacter: (in category 'private') -----
> + 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!
> 
> Item was added:
> + ----- Method: ParseNode>>nodePrintOn:indent: (in category 'printing') -----
> + 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
> + !
> 
> Item was added:
> + ----- Method: ParseNode>>nodesDo: (in category 'visiting') -----
> + nodesDo: aBlock
> +    self accept: (ParseNodeEnumerator ofBlock: aBlock)!
> 
> Item was added:
> + ----- Method: ParseNode>>nodesWithPrecedingStatementsDo: (in category 'visiting') -----
> + nodesWithPrecedingStatementsDo: aBinaryBlock
> +    self accept: (ParseNodeWithPrecedingStatementEnumerator ofBlock: aBinaryBlock)!
> 
> Item was added:
> + ----- Method: ParseNode>>nowHasDef (in category 'testing') -----
> + nowHasDef  "Ignored in all but VariableNode"!
> 
> Item was added:
> + ----- Method: ParseNode>>nowHasRef (in category 'testing') -----
> + nowHasRef  "Ignored in all but VariableNode"!
> 
> Item was added:
> + ----- Method: ParseNode>>pc (in category 'code generation') -----
> + pc
> +    "Used by encoder source mapping."
> + 
> +    ^pc ifNil: [ 0 ]
> + !
> 
> Item was added:
> + ----- Method: ParseNode>>pc: (in category 'code generation') -----
> + pc: anInteger
> +    "Used by encoder source mapping."
> + 
> +    pc := anInteger!
> 
> Item was added:
> + ----- Method: ParseNode>>printCommentOn:indent: (in category 'printing') -----
> + 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: $"]!
> 
> Item was added:
> + ----- Method: ParseNode>>printOn: (in category 'printing') -----
> + printOn: aStream 
> +    "Refer to the comment in Object|printOn:."
> + 
> +    aStream nextPut: ${.
> +    self printOn: aStream indent: 0.
> +    aStream nextPut: $}.!
> 
> Item was added:
> + ----- Method: ParseNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: anInteger 
> +    "If control gets here, avoid recursion loop."
> + 
> +    super printOn: aStream!
> 
> Item was added:
> + ----- Method: ParseNode>>printOn:indent:precedence: (in category 'printing') -----
> + printOn: aStream indent: level precedence: p
> + 
> +    self printOn: aStream indent: level!
> 
> Item was added:
> + ----- Method: ParseNode>>printSingleComment:on:indent: (in category 'private') -----
> + printSingleComment: aString on: aStream indent: indent 
> +    "Print the comment string, assuming it has been indented indent tabs.
> +    Break the string at word breaks, given the widths in the default
> +    font, at 450 points."
> + 
> +    | readStream word position lineBreak font wordWidth tabWidth spaceWidth lastChar |
> +    readStream := ReadStream on: aString.
> +    font := TextStyle default defaultFont.
> +    tabWidth := TextStyle default tabWidth.
> +    spaceWidth := font widthOf: Character space.
> +    position := indent * tabWidth.
> +    lineBreak := 450.
> +    [readStream atEnd]
> +        whileFalse: 
> +            [word := self nextWordFrom: readStream setCharacter: [:lc | lastChar := lc].
> +            wordWidth := word inject: 0 into: [:width :char | width + (font widthOf: char)].
> +            position := position + wordWidth.
> +            position > lineBreak
> +                ifTrue: 
> +                    [aStream skip: -1; crtab: indent.
> +                    position := indent * tabWidth + wordWidth + spaceWidth.
> +                    lastChar = Character cr
> +                        ifTrue: [[readStream peekFor: Character tab] whileTrue].
> +                    word isEmpty ifFalse: [aStream nextPutAll: word; space]]
> +                ifFalse: 
> +                    [aStream nextPutAll: word.
> +                    readStream atEnd
> +                        ifFalse: 
> +                            [position := position + spaceWidth.
> +                            aStream space].
> +                    lastChar = Character cr
> +                        ifTrue: 
> +                            [aStream skip: -1; crtab: indent.
> +                            position := indent * tabWidth.
> +                            [readStream peekFor: Character tab] whileTrue]]]!
> 
> Item was added:
> + ----- Method: ParseNode>>printWithClosureAnalysis (in category 'printing') -----
> + printWithClosureAnalysis
> + 
> +    ^String streamContents: [:str| self printWithClosureAnalysisOn: str]!
> 
> Item was added:
> + ----- Method: ParseNode>>printWithClosureAnalysisOn: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream
> +    "Refer to the comment in Object|printOn:."
> + 
> +    aStream nextPut: ${.
> +    self printWithClosureAnalysisOn: aStream indent: 0.
> +    aStream nextPut: $}.!
> 
> Item was added:
> + ----- Method: ParseNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: anInteger 
> +    "If control gets here, avoid recursion loop."
> + 
> +    super printWithClosureAnalysisOn: aStream!
> 
> Item was added:
> + ----- Method: ParseNode>>printWithClosureAnalysisOn:indent:precedence: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level precedence: p
> + 
> +    self printWithClosureAnalysisOn: aStream indent: level!
> 
> Item was added:
> + ----- Method: ParseNode>>shortPrintOn: (in category 'printing') -----
> + shortPrintOn: aStream 
> +    self printOn: aStream indent: 0!
> 
> Item was added:
> + ----- Method: ParseNode>>sizeCode:forBranchOn:dist: (in category 'code generation') -----
> + sizeCode: encoder forBranchOn: condition dist: dist
> +    dist = 0 ifTrue: [^encoder sizePop].
> +    ^condition
> +        ifTrue: [encoder sizeBranchPopTrue: dist]
> +        ifFalse: [encoder sizeBranchPopFalse: dist]!
> 
> Item was added:
> + ----- Method: ParseNode>>sizeCode:forJump: (in category 'code generation') -----
> + sizeCode: encoder forJump: dist
> + 
> +    ^dist = 0 ifTrue: [0] ifFalse: [encoder sizeJump: dist]!
> 
> Item was added:
> + ----- Method: ParseNode>>sizeCodeForBlockValue: (in category 'code generation') -----
> + sizeCodeForBlockValue: encoder
> +    "Answer the size for evaluating the last statement in a block"
> +    ^self sizeCodeForValue: encoder!
> 
> Item was added:
> + ----- Method: ParseNode>>sizeCodeForEffect: (in category 'code generation') -----
> + sizeCodeForEffect: encoder
> + 
> +    ^(self sizeCodeForValue: encoder) + encoder sizePop!
> 
> Item was added:
> + ----- Method: ParseNode>>sizeCodeForReturn: (in category 'code generation') -----
> + sizeCodeForReturn: encoder
> + 
> +    ^(self sizeCodeForValue: encoder) + encoder sizeReturnTop!
> 
> Item was added:
> + ----- Method: ParseNode>>toDoIncrement: (in category 'testing') -----
> + toDoIncrement: ignored
> +    "Only meant for Messages or Assignments - else return nil"
> +    ^ nil!
> 
> Item was added:
> + ParseNodeVisitor subclass: #ParseNodeEnumerator
> +    instanceVariableNames: 'theBlock theSelectBlock'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !ParseNodeEnumerator commentStamp: 'eem 3/19/2019 11:58' prior: 0!
> + ParseNodeEnumerator implements ParseNode>>nodesDo:.  It can be used to enumerate an entire tree via
> +    aParseNode accept: (ParseNodeEnumerator ofBlock: aBlock)
> + or selectively, excluding the node and subnodes for which selectBlock answers false, via
> +    aParseNode accept: (ParseNodeEnumerator
> +                            ofBlock: aBlock
> +                            select: selectBlock)
> + Instance Variables
> +    theBlock:            <BlockClosure>
> +    theSelectBlock:        <BlockClosure | nil>
> + 
> + theBlock
> +    - the block that is evaluated with the parse nodes the receiver visits.
> + 
> + theSelectBlock
> +    - an optional block used to select blocks to visit and descend into.
> + 
> + Here's a doIt that generates and compiles the visiting methods:
> + 
> + self superclass selectors do:
> +    [:s|
> +    self compile: (String streamContents:
> +        [:str| | arg |
> +        arg := 'a', (s allButFirst: 5) allButLast.
> +        str nextPutAll: s, ' ', arg; crtab;
> +            nextPutAll: '(theSelectBlock isNil or: [theSelectBlock value: '; nextPutAll: arg; nextPutAll: ']) ifFalse:'; crtab;
> +            tab: 2; nextPutAll: '[^nil].'; crtab;
> +            nextPutAll: 'theBlock value: '; nextPutAll: arg; nextPut: $.; crtab;
> +            nextPutAll: '^super '; nextPutAll: s, ' ', arg])]!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator class>>ofBlock: (in category 'instance creation') -----
> + ofBlock: aBlock
> +    ^self new ofBlock: aBlock!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator class>>ofBlock:select: (in category 'instance creation') -----
> + ofBlock: aBlock select: selectBlock
> +    ^self new ofBlock: aBlock select: selectBlock!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>ofBlock: (in category 'initialize-release') -----
> + ofBlock: aBlock
> +    theBlock := aBlock!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>ofBlock:select: (in category 'initialize-release') -----
> + ofBlock: aBlock select: aSelectBlock
> +    theBlock := aBlock.
> +    theSelectBlock := aSelectBlock!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitAssignmentNode: (in category 'visiting') -----
> + visitAssignmentNode: anAssignmentNode
> +    (theSelectBlock isNil or: [theSelectBlock value: anAssignmentNode]) ifFalse:
> +        [^nil].
> +    theBlock value: anAssignmentNode.
> +    ^super visitAssignmentNode: anAssignmentNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitBlockNode: (in category 'visiting') -----
> + visitBlockNode: aBlockNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aBlockNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aBlockNode.
> +    ^super visitBlockNode: aBlockNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitBraceNode: (in category 'visiting') -----
> + visitBraceNode: aBraceNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aBraceNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aBraceNode.
> +    ^super visitBraceNode: aBraceNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitCascadeNode: (in category 'visiting') -----
> + visitCascadeNode: aCascadeNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aCascadeNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aCascadeNode.
> +    ^super visitCascadeNode: aCascadeNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitCommentNode: (in category 'visiting') -----
> + visitCommentNode: aCommentNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aCommentNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aCommentNode.
> +    ^super visitCommentNode: aCommentNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitFieldNode: (in category 'visiting') -----
> + visitFieldNode: aFieldNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aFieldNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aFieldNode.
> +    ^super visitFieldNode: aFieldNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitFutureNode: (in category 'visiting') -----
> + visitFutureNode: aFutureNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aFutureNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aFutureNode.
> +    ^super visitFutureNode: aFutureNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitInstanceVariableNode: (in category 'visiting') -----
> + visitInstanceVariableNode: anInstanceVariableNode
> +    (theSelectBlock isNil or: [theSelectBlock value: anInstanceVariableNode]) ifFalse:
> +        [^nil].
> +    theBlock value: anInstanceVariableNode.
> +    ^super visitInstanceVariableNode: anInstanceVariableNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitLiteralNode: (in category 'visiting') -----
> + visitLiteralNode: aLiteralNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aLiteralNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aLiteralNode.
> +    ^super visitLiteralNode: aLiteralNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitLiteralVariableNode: (in category 'visiting') -----
> + visitLiteralVariableNode: aLiteralVariableNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aLiteralVariableNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aLiteralVariableNode.
> +    ^super visitLiteralVariableNode: aLiteralVariableNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitMessageNode: (in category 'visiting') -----
> + visitMessageNode: aMessageNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aMessageNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aMessageNode.
> +    ^super visitMessageNode: aMessageNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitMessageNodeInCascade: (in category 'visiting') -----
> + visitMessageNodeInCascade: aMessageNodeInCascade
> +    (theSelectBlock isNil or: [theSelectBlock value: aMessageNodeInCascade]) ifFalse:
> +        [^nil].
> +    theBlock value: aMessageNodeInCascade.
> +    ^super visitMessageNodeInCascade: aMessageNodeInCascade!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitMethodNode: (in category 'visiting') -----
> + visitMethodNode: aMethodNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aMethodNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aMethodNode.
> +    ^super visitMethodNode: aMethodNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitNewArrayNode: (in category 'visiting') -----
> + visitNewArrayNode: aNewArrayNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aNewArrayNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aNewArrayNode.
> +    ^super visitNewArrayNode: aNewArrayNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitRemoteTempVectorNode: (in category 'visiting') -----
> + visitRemoteTempVectorNode: aRemoteTempVectorNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aRemoteTempVectorNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aRemoteTempVectorNode.
> +    ^super visitRemoteTempVectorNode: aRemoteTempVectorNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitReturnNode: (in category 'visiting') -----
> + visitReturnNode: aReturnNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aReturnNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aReturnNode.
> +    ^super visitReturnNode: aReturnNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitSelectorNode: (in category 'visiting') -----
> + visitSelectorNode: aSelectorNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aSelectorNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aSelectorNode.
> +    ^super visitSelectorNode: aSelectorNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitTempVariableNode: (in category 'visiting') -----
> + visitTempVariableNode: aTempVariableNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aTempVariableNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aTempVariableNode.
> +    ^super visitTempVariableNode: aTempVariableNode!
> 
> Item was added:
> + ----- Method: ParseNodeEnumerator>>visitVariableNode: (in category 'visiting') -----
> + visitVariableNode: aVariableNode
> +    (theSelectBlock isNil or: [theSelectBlock value: aVariableNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aVariableNode.
> +    ^super visitVariableNode: aVariableNode!
> 
> Item was added:
> + 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']]]!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitAssignmentNode: (in category 'visiting') -----
> + 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!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitBlockNode: (in category 'visiting') -----
> + visitBlockNode: aBlockNode
> +    aBlockNode statements do:
> +        [:statement| statement accept: self]!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitBraceNode: (in category 'visiting') -----
> + visitBraceNode: aBraceNode
> +    aBraceNode elements do:
> +        [:element| element accept: self]!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitCascadeNode: (in category 'visiting') -----
> + visitCascadeNode: aCascadeNode
> +    aCascadeNode receiver accept: self.
> +    aCascadeNode messages do:
> +        [:message| self visitMessageNodeInCascade: message]!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitCommentNode: (in category 'visiting') -----
> + visitCommentNode: aCommentNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitFieldNode: (in category 'visiting') -----
> + visitFieldNode: aFieldNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitFutureNode: (in category 'visiting') -----
> + visitFutureNode: aFutureNode
> +    aFutureNode receiver accept: self.
> +    (aFutureNode originalSelector isKindOf: SelectorNode) ifTrue:
> +        [aFutureNode originalSelector accept: self]!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitInstanceVariableNode: (in category 'visiting') -----
> + visitInstanceVariableNode: anInstanceVariableNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitLiteralNode: (in category 'visiting') -----
> + visitLiteralNode: aLiteralNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitLiteralVariableNode: (in category 'visiting') -----
> + visitLiteralVariableNode: aLiteralVariableNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitMessageNode: (in category 'visiting') -----
> + 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]!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitMessageNodeInCascade: (in category 'visiting') -----
> + visitMessageNodeInCascade: aMessageNode
> +    "receiver is nil for cascades"
> +    aMessageNode selector accept: self.
> +    aMessageNode argumentsInEvaluationOrder do:
> +        [:argument| argument accept: self]!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitMethodNode: (in category 'visiting') -----
> + visitMethodNode: aMethodNode
> +    aMethodNode block accept: self!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitNewArrayNode: (in category 'visiting') -----
> + visitNewArrayNode: aNewArrayNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitRemoteTempVectorNode: (in category 'visiting') -----
> + visitRemoteTempVectorNode: aRemoteTempVectorNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitReturnNode: (in category 'visiting') -----
> + visitReturnNode: aReturnNode
> +    aReturnNode expr accept: self!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitSelectorNode: (in category 'visiting') -----
> + visitSelectorNode: aSelectorNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitTempVariableNode: (in category 'visiting') -----
> + visitTempVariableNode: aTempVariableNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitUndeclaredVariableNode: (in category 'visiting') -----
> + visitUndeclaredVariableNode: aVariableNode!
> 
> Item was added:
> + ----- Method: ParseNodeVisitor>>visitVariableNode: (in category 'visiting') -----
> + visitVariableNode: aVariableNode!
> 
> Item was added:
> + ParseNodeEnumerator subclass: #ParseNodeWithPrecedingStatementEnumerator
> +    instanceVariableNames: 'precedingStatement'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !ParseNodeWithPrecedingStatementEnumerator commentStamp: 'eem 3/19/2019 11:55' prior: 0!
> + A ParseNodeWithPrecedingStatementEnumerator is a ParseNodeEnumerator that accepts a binary block in ofBlock:, and hence enumerates statement nodes with their preceding statement, or nil if they are the first.
> + 
> + Instance Variables
> +    precedingStatement:        <ParseNode | nil>
> + 
> + precedingStatement
> +    - the preceding statement node, if any
> + !
> 
> Item was added:
> + ----- Method: ParseNodeWithPrecedingStatementEnumerator>>ofBlock: (in category 'initialize-release') -----
> + ofBlock: aBlock
> +    "N.B. This enumerator visits a node before any of the node's children.
> +     Hence, when enumerating statements in a block, we can ensure that
> +     the second argument to the block, the preceding statement, is non-nil
> +     only for top-level statements in the block by nilling out precedingStatement
> +     once the block is evaluated. Perhaps stronger would be to capture its value
> +     in a temporary and nil it before evaluating, but this is good enough."
> +    theBlock := [:node|
> +                aBlock value: node value: precedingStatement.
> +                precedingStatement := nil]!
> 
> Item was added:
> + ----- Method: ParseNodeWithPrecedingStatementEnumerator>>ofBlock:select: (in category 'initialize-release') -----
> + ofBlock: aBlock select: aSelectBlock
> +    self ofBlock: aBlock.
> +    theSelectBlock := aSelectBlock!
> 
> Item was added:
> + ----- Method: ParseNodeWithPrecedingStatementEnumerator>>visitBlockNode: (in category 'visiting') -----
> + visitBlockNode: aBlockNode
> +    | savedPrecedingStatement |
> +    (theSelectBlock isNil or: [theSelectBlock value: aBlockNode]) ifFalse:
> +        [^nil].
> +    theBlock value: aBlockNode.
> +    savedPrecedingStatement := precedingStatement.
> +    precedingStatement := nil.
> +    [aBlockNode statements do:
> +        [:statement|
> +         statement accept: self.
> +         precedingStatement := statement]] ensure:
> +        [precedingStatement := savedPrecedingStatement]!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: ParseStack>>init (in category 'initialize-release') -----
> + init
> + 
> +    length := position := 0!
> 
> Item was added:
> + ----- Method: ParseStack>>pop: (in category 'accessing') -----
> + pop: n
> + 
> +    (position := position - n) < 0 
> +        ifTrue: [self error: 'Parse stack underflow']!
> 
> Item was added:
> + ----- Method: ParseStack>>position (in category 'results') -----
> + position
> + 
> +    ^position!
> 
> Item was added:
> + ----- Method: ParseStack>>position: (in category 'accessing') -----
> + position: n 
> +    (position := n) > length
> +        ifTrue: [length := position]!
> 
> Item was added:
> + ----- Method: ParseStack>>printOn: (in category 'printing') -----
> + printOn: aStream
> +    
> +    super printOn: aStream.
> +    aStream nextPutAll: ' at '; print: position; nextPutAll: ' of '; print: length!
> 
> Item was added:
> + ----- Method: ParseStack>>push: (in category 'accessing') -----
> + push: n
> + 
> +    (position := position + n) > length 
> +        ifTrue: [length := position]!
> 
> Item was added:
> + ----- Method: ParseStack>>size (in category 'accessing') -----
> + size
> + 
> +    ^length!
> 
> Item was added:
> + Scanner subclass: #Parser
> +    instanceVariableNames: 'here hereType hereMark hereEnd prevMark prevEnd encoder parseNode failBlock requestorOffset tempsMark doitFlag properties queriedUnusedTemporaries cue'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !Parser commentStamp: 'cwp 12/26/2012 23:34' prior: 0!
> + I parse Smalltalk syntax and create a MethodNode that is the root of the parse tree. I look one token ahead.!
> 
> Item was added:
> + ----- Method: Parser class>>primitivePragmaSelectors (in category 'accessing') -----
> + 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:)!
> 
> Item was added:
> + ----- Method: Parser>>addComment (in category 'private') -----
> + addComment
> + 
> +    parseNode ~~ nil
> +        ifTrue: 
> +            [parseNode comment: currentComment.
> +            currentComment := nil]!
> 
> Item was added:
> + ----- Method: Parser>>addPragma: (in category 'pragmas') -----
> + addPragma: aPragma
> +    properties := self properties copyWith: aPragma!
> 
> Item was added:
> + ----- Method: Parser>>addWarning: (in category 'error handling') -----
> + addWarning: aString
> +    "ignored by the default compiler."!
> 
> Item was added:
> + ----- Method: Parser>>advance (in category 'scanning') -----
> + advance
> +    | this |
> +    prevMark := hereMark.
> +    prevEnd := hereEnd.
> +    this := here.
> +    here := token.
> +    hereType := tokenType.
> +    hereMark := mark.
> +    hereEnd := source position - (aheadChar == DoItCharacter
> +        ifTrue: [hereChar == DoItCharacter
> +            ifTrue: [0]
> +            ifFalse: [1]]
> +        ifFalse: [2]).
> +    self scanToken.
> +    "Transcript show: 'here: ', here printString, ' mark: ', hereMark printString, ' end: ', hereEnd printString; cr."
> +    ^this!
> 
> Item was added:
> + ----- Method: Parser>>allocateLiteral: (in category 'primitives') -----
> + allocateLiteral: lit
> +    encoder litIndex: lit!
> 
> Item was added:
> + ----- Method: Parser>>allowUnderscoreAssignments (in category 'private') -----
> + allowUnderscoreAssignments
> +    "Query class + preference"
> +    ^ (encoder ifNotNil: [:e | 
> +        e == self 
> +            ifTrue: [nil]
> +            ifFalse: [e classEncoding allowUnderscoreAssignments]])
> +        ifNil: [super allowUnderscoreAssignments]!
> 
> Item was added:
> + ----- Method: Parser>>ambiguousSelector:inRange: (in category 'error correction') -----
> + ambiguousSelector: aString inRange: anInterval
> +    | correctedSelector intervalWithOffset |
> +    
> +    self interactive ifFalse: [
> +        "In non interactive mode, compile with backward comapatibility: $- is part of literal argument"
> +        Transcript cr; store: encoder classEncoding; nextPutAll:#'>>';store: encoder selector; show: ' would send ' , token , '-'.
> +        ^super ambiguousSelector: aString inRange: anInterval].
> +    
> +    "handle the text selection"
> +    intervalWithOffset := anInterval first + requestorOffset to: anInterval last + requestorOffset.
> +    self selectFrom: intervalWithOffset first to: intervalWithOffset last
> +        during:
> +            ["Build the menu with alternatives"
> +            correctedSelector := AmbiguousSelector 
> +                    signalName: aString
> +                    inRange: intervalWithOffset.
> +            correctedSelector ifNil: [^self fail]].
> +    
> +    "Execute the selected action"
> +    self substituteWord: correctedSelector wordInterval: intervalWithOffset offset: 0.
> +    token := (correctedSelector readStream upTo: Character space) asSymbol!
> 
> Item was added:
> + ----- Method: Parser>>argumentName (in category 'expression types') -----
> + argumentName
> + 
> +    hereType == #word
> +        ifFalse: [^self expected: 'Argument name'].
> +    ^self advance!
> 
> Item was added:
> + ----- Method: Parser>>assignment: (in category 'expression types') -----
> + 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!
> 
> Item was added:
> + ----- Method: Parser>>bindArg: (in category 'temps') -----
> + bindArg: name
> + 
> +    ^ self bindTemp: name!
> 
> Item was added:
> + ----- Method: Parser>>bindTemp: (in category 'temps') -----
> + bindTemp: name
> + 
> +    ^name!
> 
> Item was added:
> + ----- Method: Parser>>bindTemp:in: (in category 'temps') -----
> + bindTemp: name in: methodSelector
> + 
> +    ^name!
> 
> Item was added:
> + ----- Method: Parser>>blockExpression (in category 'expression types') -----
> + 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]!
> 
> Item was added:
> + ----- Method: Parser>>braceExpression (in category 'expression types') -----
> + 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 or right brace'].
> +            (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!
> 
> Item was added:
> + ----- Method: Parser>>canDeclareClassVariable (in category 'error correction') -----
> + canDeclareClassVariable
> +    ^encoder classEncoding ~~ UndefinedObject!
> 
> Item was added:
> + ----- Method: Parser>>canDeclareInstanceVariable (in category 'error correction') -----
> + canDeclareInstanceVariable
> +    ^encoder classEncoding ~~ UndefinedObject!
> 
> Item was added:
> + ----- Method: Parser>>cascade (in category 'expression types') -----
> + cascade
> +    " {; message} => CascadeNode."
> + 
> +    | rcvr msgs |
> +    parseNode canCascade ifFalse:
> +        [^self expected: 'Cascading not'].
> +    parseNode ensureCanCascade: encoder.
> +    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 ensureCanCascade: encoder.
> +                parseNode cascadeReceiver.
> +            msgs addLast: parseNode].
> +    parseNode := CascadeNode new receiver: rcvr messages: msgs!
> 
> Item was added:
> + ----- Method: Parser>>collectTemporaryDeclarationsFrom: (in category 'error correction') -----
> + collectTemporaryDeclarationsFrom: methodNode
> +    | tempsMarks str |
> +    tempsMarks := OrderedCollection new.
> +    str := cue requestor text asString.
> +    methodNode accept: (ParseNodeEnumerator
> +        ofBlock: [ :aNode | 
> +            | mark |
> +            (aNode class canUnderstand: #tempsMark) 
> +                ifTrue: 
> +                    [mark := aNode tempsMark.
> +                    (mark notNil and: [ mark between: 1 and: str size ] and: [ (str at: mark) = $| ])
> +                        ifTrue: [ tempsMarks addLast: aNode ]]]).
> +    (tempsMark notNil and: [ tempsMark between: 1 and: str size ] and: [ (str at: tempsMark) = $| ])
> +                        ifTrue: [ tempsMarks addLast: self ].
> +    ^ tempsMarks sorted: [ :a :b | a tempsMark > b tempsMark ]!
> 
> Item was added:
> + ----- Method: Parser>>correctSelector:wordIntervals:exprInterval:ifAbort: (in category 'error correction') -----
> + 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 |
> +    "If we can't ask the user, assume that the keyword will be defined later"
> +    self interactive ifFalse: [^ proposedKeyword asSymbol].
> +    
> +    self selectFrom: spots first first to: spots last last during: [
> +        correctSelector := UnknownSelector name: proposedKeyword.
> +        correctSelector ifNil: [^ abortAction value]].
> +    
> +    self substituteSelector: correctSelector keywords wordIntervals: spots.
> +    ^ (proposedKeyword last ~~ $:
> +       and: [correctSelector last == $:])
> +        ifTrue: [abortAction value]
> +        ifFalse: [correctSelector]!
> 
> Item was added:
> + ----- Method: Parser>>correctVariable:interval: (in category 'error correction') -----
> + 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."
> + 
> +    | binding action |
> +    "Check if this is an i-var, that has been corrected already (ugly)"
> +    (encoder classEncoding instVarNames includes: proposedVariable) ifTrue: 
> +        [^InstanceVariableNode new 
> +            name: proposedVariable
> +            index: (encoder classEncoding allInstVarNames indexOf: proposedVariable)].
> + 
> +    "First check to see if the requestor knows anything about the variable"
> +    (binding := cue requestor ifNotNil: [:object | object bindingOf: proposedVariable])
> +        ifNotNil: [^encoder global: binding name: proposedVariable].
> + 
> +    "If we can't ask the user for correction, make it undeclared"
> +    self interactive ifFalse: [^encoder undeclared: proposedVariable].
> + 
> +    self selectFrom: spot first to: spot last
> +        during:
> +            ["Build the menu with alternatives"
> +            action := UndeclaredVariable 
> +                        signalFor: self
> +                        name: proposedVariable
> +                        inRange: spot.
> +            action ifNil: [^self fail]].
> + 
> +    "Execute the selected action"
> +    ^action value!
> 
> Item was added:
> + ----- Method: Parser>>declareClassVar: (in category 'error correction') -----
> + declareClassVar: name
> +    | sym class |
> +    sym := name asSymbol.
> +    class := encoder classEncoding.
> +    class := class theNonMetaClass.        "not the metaclass"
> +    class addClassVarName: name.
> +    Smalltalk logChange: class definition.
> +    ^ encoder global: (class classPool associationAt: sym)
> +            name: sym!
> 
> Item was added:
> + ----- Method: Parser>>declareGlobal: (in category 'error correction') -----
> + declareGlobal: name
> +    | sym |
> +    sym := name asSymbol.
> +    ^encoder
> +        global: (encoder environment
> +                    at: sym put: nil;
> +                    associationAt: sym)
> +        name: sym!
> 
> Item was added:
> + ----- Method: Parser>>declareInstVar: (in category 'error correction') -----
> + 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.
> +    Smalltalk logChange: encoder classEncoding definition.
> +    ^InstanceVariableNode new name: name index: encoder classEncoding instSize
> +        !
> 
> Item was added:
> + ----- Method: Parser>>declareTemp:at: (in category 'error correction') -----
> + declareTemp: name at: levelTag
> +    "Defer declaring the temp until the parse has completed.  This allows
> +     the parser to declare the temp in the minimum enclosing block instead
> +     of always at method level.  See Parser>>declareUndeclaredTemps:"
> +    ^(encoder bindUndeclaredTemp: name)
> +        tag: levelTag;
> +        yourself!
> 
> Item was added:
> + ----- Method: Parser>>declareTempAndPaste: (in category 'error correction') -----
> + declareTempAndPaste: name
> +    "Defer declaring the temp until the parse has completed.  This allows
> +     the parser to declare the temp in the minimum enclosing block instead
> +     of always at method level.  See Parser>>declareUndeclaredTemps:"
> +    ^encoder bindUndeclaredTemp: name!
> 
> Item was added:
> + ----- Method: Parser>>declareUndeclaredTemps: (in category 'error correction') -----
> + declareUndeclaredTemps: methodNode
> +    "Declare any undeclared temps, declaring them at the smallest enclosing scope."
> + 
> +    | undeclared blocksToVars |
> +    (undeclared := encoder undeclaredTemps) isEmpty ifTrue:
> +        [^self].
> +    blocksToVars := IdentityDictionary new.
> +    undeclared do:
> +        [:var|
> +        (blocksToVars
> +            at: (var tag == #method
> +                    ifTrue: [methodNode block]
> +                    ifFalse: [methodNode accept: (VariableScopeFinder new ofVariable: var)])
> +            ifAbsentPut: [SortedCollection new]) add: var name].
> +    (blocksToVars removeKey: methodNode block ifAbsent: []) ifNotNil:
> +        [:rootVars|
> +        rootVars do: [:varName| self pasteTempAtMethodLevel: varName]].
> +    (blocksToVars keys sorted: [:a :b| a tempsMark < b tempsMark]) do:
> +        [:block| | decl |
> +        decl := (blocksToVars at: block) reduce: [:a :b| a, ' ', b].
> +        block temporaries isEmpty
> +            ifTrue:
> +                [self substituteWord: ' | ', decl, ' |'
> +                    wordInterval: (block tempsMark + 1 to: block tempsMark)
> +                    offset: requestorOffset]
> +            ifFalse:
> +                [self substituteWord: decl, ' '
> +                    wordInterval: (block tempsMark to: block tempsMark - 1)
> +                    offset: requestorOffset]].
> +    ReparseAfterSourceEditing signal!
> 
> Item was added:
> + ----- Method: Parser>>defineClass: (in category 'error correction') -----
> + 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 := Project uiManager request: 'Enter class category : ' initialAnswer: self encoder classEncoding theNonMetaClass category.
> +    cat
> +        ifEmpty: [cat := 'Unknown'].
> +    def := 'Object subclass: #' , sym , '
> +        instanceVariableNames: '''' 
> +        classVariableNames: ''''
> +        poolDictionaries: ''''
> +        category: ''' , cat , ''''.
> +    d2 := Project uiManager request: 'Edit class definition : ' initialAnswer: def.
> +    d2
> +        ifEmpty: [d2 := def].
> +    Compiler evaluate: d2.
> +    ^ encoder
> +        global: (cue environment bindingOf: sym)
> +        name: sym!
> 
> Item was added:
> + ----- Method: Parser>>encoder (in category 'private') -----
> + encoder
> +    ^encoder ifNil:
> +        [encoder := CompiledMethod preferredBytecodeSetEncoderClass new]!
> 
> Item was added:
> + ----- Method: Parser>>encoderClass: (in category 'public access') -----
> + encoderClass: anEncoderClass
> +    encoder ifNotNil: [
> +        self error: 'encoder already set'].
> +    encoder := anEncoderClass new!
> 
> Item was added:
> + ----- Method: Parser>>encoderFromCue: (in category 'private') -----
> + encoderFromCue: aCompilationCue
> +    ^encoder ifNil:
> +        [encoder := (aCompilationCue encoderClass ifNil: [CompiledMethod preferredBytecodeSetEncoderClass]) new]!
> 
> Item was added:
> + ----- Method: Parser>>endOfLastToken (in category 'scanning') -----
> + endOfLastToken
> + 
> +    ^ prevEnd ifNil: [mark]!
> 
> Item was added:
> + ----- Method: Parser>>expected: (in category 'error handling') -----
> + expected: aString 
> +    "Notify a problem at token 'here'."
> + 
> +    ^ self notify: aString , ' expected' at: hereMark + requestorOffset!
> 
> Item was added:
> + ----- Method: Parser>>expression (in category 'expression types') -----
> + expression
> +    (hereType == #word
> +     and: [tokenType == #leftArrow]) ifTrue:
> +        [^self assignment: self variable].
> +    self primaryExpression ifFalse:
> +        [^false].
> +    ((self messagePart: 3 repeat: true)
> +     and: [hereType == #semicolon]) ifTrue:
> +        [self cascade].
> +    ^true!
> 
> Item was added:
> + ----- Method: Parser>>fail (in category 'error handling') -----
> + fail
> + 
> +    | exitBlock |
> +    (encoder == nil or: [encoder == self])
> +        ifFalse: [encoder release. encoder := nil]. "break cycle"
> +    exitBlock := failBlock.
> +    failBlock := nil.
> +    ^exitBlock value!
> 
> Item was added:
> + ----- Method: Parser>>init:cue:failBlock: (in category 'private') -----
> + init: sourceStream cue: aCue failBlock: aBlock
> + 
> +    self setCue: aCue.
> +    failBlock := aBlock.
> +    requestorOffset := 0.
> +    super scan: sourceStream.
> +    prevMark := hereMark := mark.
> +    self advance
> + !
> 
> Item was added:
> + ----- Method: Parser>>initPattern:return: (in category 'private') -----
> + initPattern: aString return: aBlock
> + 
> +    | result |
> +    self
> +        init: (ReadStream on: aString asString)
> +        cue: (CompilationCue source: aString)
> +        failBlock: [^nil].
> +    encoder := self.
> +    result := aBlock value: (self pattern: false inContext: nil).
> +    encoder := failBlock := nil.  "break cycles"
> +    ^result!
> 
> Item was added:
> + ----- Method: Parser>>interactive (in category 'error handling') -----
> + interactive
> +    "The compilation is interactive if there is a requestor and that requestor does either not care or explicitly allow interactive error correction."
> + 
> +    ^ cue requestor notNil
> +        and: [(cue requestor respondsTo: #wantsInteractiveErrorCorrection) not
> +            or: [cue requestor perform: #wantsInteractiveErrorCorrection]]!
> 
> Item was added:
> + ----- Method: Parser>>match: (in category 'scanning') -----
> + match: type 
> +    "Answer with true if next tokens type matches."
> + 
> +    hereType == type
> +        ifTrue: 
> +            [self advance.
> +            ^true].
> +    ^false!
> 
> Item was added:
> + ----- Method: Parser>>matchReturn (in category 'scanning') -----
> + matchReturn
> + 
> +    ^ self match: #upArrow!
> 
> Item was added:
> + ----- Method: Parser>>matchToken: (in category 'scanning') -----
> + matchToken: thing 
> +    "Matches the token, not its type."
> + 
> +    here = thing ifTrue: [self advance. ^true].
> +    ^false!
> 
> Item was added:
> + ----- Method: Parser>>messagePart:repeat: (in category 'expression types') -----
> + 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].
> +            selector := (Symbol lookup: selector contents)
> +                ifNil: [ self correctSelector: selector contents
> +                            wordIntervals: words
> +                            exprInterval: (start to: self endOfLastToken)
> +                            ifAbort: [ ^ self fail ] ].
> +            precedence := 3]
> +        ifFalse: [
> +            (level >= 2 and: [hereType == #verticalBar]) ifTrue: [self transformAVerticalBarIntoABinarySelector].
> +            (hereType == #binary 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).
> +                            selector := (Symbol lookup: selector)
> +                                ifNil: [ 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!
> 
> Item was added:
> + ----- Method: Parser>>method:context: (in category 'expression types') -----
> + method: doit context: ctxt 
> +    " pattern [ | temporaries ] block => MethodNode."
> + 
> +    | sap blk prim temps messageComment methodNode |
> +    sap := self pattern: doit inContext: ctxt.
> +    "sap={selector, arguments, precedence}"
> +    self properties selector: (sap at: 1).
> +    encoder selector: (sap at: 1).
> +    (sap at: 2) do: [:argNode | argNode beMethodArg].
> +    doit ifFalse: [self pragmaSequence].
> +    temps := self temporaries.
> +    messageComment := currentComment.
> +    currentComment := nil.
> +    doit ifFalse: [self pragmaSequence].
> +    prim := self pragmaPrimitives.
> +    self statements: #() innerBlock: false blockNode: BlockNode new.
> +    blk := parseNode.
> +    doit ifTrue: [blk returnLast]
> +        ifFalse: [blk returnSelfIfNoOther: encoder].
> +    hereType == #doIt ifFalse: [^self expected: 'Nothing more'].
> +    methodNode := self newMethodNode comment: messageComment.
> +    methodNode
> +        selector: (sap at: 1)
> +        arguments: (sap at: 2)
> +        precedence: (sap at: 3)
> +        temporaries: temps
> +        block: blk
> +        encoder: encoder
> +        primitive: prim
> +        properties: properties.
> +    self interactive ifTrue:
> +        [self declareUndeclaredTemps: methodNode.
> +         self removeUnusedTemps: methodNode].
> +    ^methodNode!
> 
> Item was added:
> + ----- Method: Parser>>newMethodNode (in category 'expression types') -----
> + newMethodNode
> +    ^self encoder methodNodeClass new!
> 
> Item was added:
> + ----- Method: Parser>>notify: (in category 'error handling') -----
> + notify: aString 
> +    "Notify problem at token before 'here'."
> + 
> +    ^self notify: aString at: prevMark + requestorOffset!
> 
> Item was added:
> + ----- Method: Parser>>notify:at: (in category 'error handling') -----
> + notify: string at: location 
> +    | messageText |
> +    messageText := '"' , string , ' ->"'.
> +    cue requestor isNil
> +        ifTrue: [
> +            | notification |
> +            (encoder == self or: [encoder isNil])
> +                ifTrue: [^ self fail "failure setting up syntax error"].
> +            (notification := SyntaxErrorNotification
> +                cue: (cue copy
> +                    source: (source contents asText
> +                        copyReplaceFrom: location
> +                        to: location - 1
> +                        with: messageText);
> +                    yourself)
> +                doitFlag: doitFlag
> +                errorMessage: string
> +                location: location) signal.
> +            notification tryNewSourceIfAvailable]
> +        ifFalse: [cue requestor
> +            notify: messageText
> +            at: location
> +            in: source].
> +    ^ self fail!
> 
> Item was added:
> + ----- Method: Parser>>offEnd: (in category 'error handling') -----
> + 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]
> + !
> 
> Item was added:
> + ----- Method: Parser>>parse:class: (in category 'public access') -----
> + parse: sourceStreamOrString class: behavior
> + 
> +    ^ self parse: sourceStreamOrString readStream class: behavior
> +        noPattern: false notifying: nil ifFail: [^nil]!
> 
> Item was added:
> + ----- Method: Parser>>parse:class:noPattern:notifying:ifFail: (in category 'public access') -----
> + parse: sourceStream class: class noPattern: noPattern notifying: req ifFail: aBlock 
> +    | c |
> +    c := CompilationCue
> +            source: sourceStream
> +            class: class
> +            requestor: req.
> +    ^ self 
> +        parseCue: c 
> +        noPattern: noPattern 
> +        ifFail: aBlock!
> 
> Item was added:
> + ----- Method: Parser>>parseArgsAndTemps: (in category 'public access') -----
> + parseArgsAndTemps: aString 
> +         "Parse the argument, aString, answer nil if an error occurs. Otherwise,
> +         answer an Array 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
> +                 return: [:pattern | (pattern at: 2) , (self temporariesIn: (pattern at: 1))]!
> 
> Item was added:
> + ----- Method: Parser>>parseCue:noPattern:ifFail: (in category 'public access') -----
> + parseCue: aCue noPattern: noPattern ifFail: aBlock 
> +    "Answer a MethodNode for the argument, sourceStream, that is the root
> +     of a parse tree. Parsing is done with respect to the CompilationCue to 
> +     resolve variables, etc. Errors in parsing are reported to the cue's requestor; 
> +     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 subSelection |
> +    myStream := aCue sourceStream.
> +    [repeatNeeded := false.
> +     p := myStream position.
> +     s := myStream upToEnd.
> +     myStream position: p.
> + 
> +     doitFlag := noPattern.
> +     [(self encoderFromCue: aCue) init: aCue notifying: self.
> +     self init: myStream cue: aCue failBlock: [^aBlock value].
> + 
> +     subSelection := self interactive and: [cue requestor selectionInterval = (p + 1 to: p + s size)].
> + 
> +     failBlock:= aBlock.
> +     methNode := self method: noPattern context: cue context] 
> +        on: ReparseAfterSourceEditing 
> +        do:    [ :ex |
> +            repeatNeeded := true.
> +            properties := nil. "Avoid accumulating pragmas and primitives Number"
> +            myStream := ex newSource 
> +                ifNil: [subSelection
> +                            ifTrue:
> +                                [ReadStream
> +                                    on: cue requestor text string
> +                                    from: cue requestor selectionInterval first
> +                                    to: cue requestor selectionInterval last]
> +                            ifFalse:
> +                                [ReadStream on: cue requestor text string]]
> +                ifNotNil: [:src | myStream := src readStream]].
> +     repeatNeeded] whileTrue:
> +        [encoder := self encoder class new].
> +    methNode sourceText: s.
> +    ^methNode!
> 
> Item was added:
> + ----- Method: Parser>>parseMethodComment:setPattern: (in category '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
> +        return: aBlock.
> +    currentComment==nil
> +        ifTrue:    [^OrderedCollection new]
> +        ifFalse:    [^currentComment]!
> 
> Item was added:
> + ----- Method: Parser>>parseParameterNames: (in category 'public access') -----
> + parseParameterNames: aString 
> +    "Answer the parameter names 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
> +        return: [:pattern | pattern at: 2]!
> 
> Item was added:
> + ----- Method: Parser>>parseSelector: (in category 'public access') -----
> + 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 allowUnderscoreSelectors ifFalse: [self initScannerForTokenization].
> +    ^self
> +        initPattern: aString
> +        return: [:pattern | pattern at: 1]!
> 
> Item was added:
> + ----- Method: Parser>>pasteTempAtMethodLevel: (in category 'error correction') -----
> + pasteTempAtMethodLevel: name
> +    | insertion delta theTextString characterBeforeMark |
> + 
> +    theTextString := cue 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!
> 
> Item was added:
> + ----- Method: Parser>>pattern:inContext: (in category 'expression types') -----
> + 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}].
> +    ^self expected: 'Message pattern'!
> 
> Item was added:
> + ----- Method: Parser>>possibleVariablesFor: (in category 'error correction') -----
> + possibleVariablesFor: proposedVariable 
> +    ^encoder possibleVariablesFor: proposedVariable!
> 
> Item was added:
> + ----- Method: Parser>>pragmaLiteral: (in category 'pragmas') -----
> + 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 or: [ hereType == #character ] ] ])
> +        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: [ ^ (Scanner new scanTokens: self advance) first ].
> +    "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'!
> 
> Item was added:
> + ----- Method: Parser>>pragmaPrimitives (in category 'pragmas') -----
> + 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!
> 
> Item was added:
> + ----- Method: Parser>>pragmaSequence (in category 'pragmas') -----
> + pragmaSequence
> +    "Parse a sequence of method pragmas."
> +    
> +    [    (hereType == #binary and: [self matchToken: #<])
> +            ifFalse: [ ^ self ].
> +        self pragmaStatement.
> +        (hereType == #binary and: [self matchToken: #>])
> +            ifFalse: [ ^ self expected: '>' ] ] repeat!
> 
> Item was added:
> + ----- Method: Parser>>pragmaStatement (in category 'pragmas') -----
> + pragmaStatement
> +    "Parse a pragma statement. The leading '<' has already been consumed. The 'here' token is the first one in the pragma. Use that token to dispatch to a custom pragma-parsing method if one can be found with a selector that matches it.
> +    
> +    Note that custom pragma parsers need to fulfill two requirements:
> +        - method selector must match the current token as simple getter,
> +                e.g., <apicall: ...> matches #apicall or <primitive: ...> matches #primitive
> +        - method must have pragma <pragmaParser> to be called."
> +    
> +    "0) Early exit"
> +    (hereType = #keyword or: [ hereType = #word or: [ hereType = #binary ] ])
> +        ifFalse: [  ^ self expected: 'pragma declaration' ].
> + 
> +    "1) Do not consider one-word pragmas such as <primitive> and <foobar>. Only keyword pragmas."
> +    here last == $: ifTrue: [
> +        "2) Avoid interning new symbols for made-up pragmas such as #my for <my: 1 pragma: 2>."
> +        (Symbol lookup: here allButLast) ifNotNil: [:parserSelector |
> +            Parser methodDict at: parserSelector ifPresent: [:parserMethod |
> +                "3) Only call methods that claim to be a custom pragma parser via <pragmaParser>."
> +                (parserMethod hasPragma: #pragmaParser)
> +                    ifTrue: [^ self executeMethod: parserMethod]]]].
> + 
> +    "X) No custom pragma parser found. Use the default one."
> +    ^ self pragmaStatementKeywords!
> 
> Item was added:
> + ----- Method: Parser>>pragmaStatementKeywords (in category 'pragmas') -----
> + pragmaStatementKeywords
> +    "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 |
> +    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' ].
> +    keyword := (Symbol lookup: selector) 
> +        ifNil: [ 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!
> 
> Item was added:
> + ----- Method: Parser>>primaryExpression (in category '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 or: [hereType == #character]]])
> +        ifTrue: 
> +            [parseNode := encoder encodeLiteral: self advance.
> +            ^true].
> +    (here == #- and: [tokenType == #number and: [1 + hereEnd = mark]])
> +        ifTrue: 
> +            [self advance.
> +            parseNode := encoder encodeLiteral: self advance negated.
> +            ^true].
> +    ^false!
> 
> Item was added:
> + ----- Method: Parser>>primitive (in category 'primitives') -----
> + primitive
> +    "Pragmas that encode primitive calls are parsed as normal keyword pragmas. This hook exists so that packages do not break primitive-pragma parsing by accident. Instead, this method needs to be replaced intentionally.
> +    
> +    Note that primitive pragmas are special because they will be called back from the parser into the parser. See #pragmaPrimitives.
> +    
> +    Examples:
> +        <primitive: 42>
> +        <primitive: 'primitiveDirectoryCreate' module: 'FilePlugin'>
> +        <primitive: 'primitiveRegisterExternalFill' module: 'B2DPlugin' error: errorCode>"
> + 
> +    <pragmaParser>
> +    ^ self pragmaStatementKeywords!
> 
> Item was added:
> + ----- Method: Parser>>primitive: (in category 'primitives') -----
> + primitive: anIntegerOrString
> +    "Create indexed primitive."
> +    
> +    ^self primitive: anIntegerOrString error: nil!
> 
> Item was added:
> + ----- Method: Parser>>primitive:error: (in category 'primitives') -----
> + 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']]!
> 
> Item was added:
> + ----- Method: Parser>>primitive:error:module: (in category 'primitives') -----
> + primitive: aNameString error: errorCodeVariableOrNil module: aModuleStringOrNil
> +    "Create named primitive with optional error code."
> +    
> +    ^self primitive: aNameString module: aModuleStringOrNil error: errorCodeVariableOrNil!
> 
> Item was added:
> + ----- Method: Parser>>primitive:module: (in category 'primitives') -----
> + primitive: aNameString module: aModuleStringOrNil
> +    "Create named primitive."
> +    
> +    ^self primitive: aNameString module: aModuleStringOrNil error: nil!
> 
> Item was added:
> + ----- Method: Parser>>primitive:module:error: (in category 'primitives') -----
> + primitive: aNameString module: aModuleStringOrNil error: errorCodeVariableOrNil
> +    "Create named primitive with optional error code."
> +    | firstLiteral |
> +    (aNameString isString and: [ aModuleStringOrNil isNil or: [ aModuleStringOrNil isString ] ])
> +        ifFalse: [ ^ self expected: 'Named primitive' ].
> +    firstLiteral := {    aModuleStringOrNil ifNotNil: [aModuleStringOrNil asSymbol].
> +                    aNameString asSymbol.
> +                    0.
> +                    0 }.
> +    (encoder litIndex: firstLiteral) ~= 0 ifTrue:
> +        [self error: 'parser failed to allocate [primitive binding array as first literal'].
> +    firstLiteral beWritableObject. "Undo the read-only setting in litIndex:"
> +    errorCodeVariableOrNil ifNotNil:
> +        [encoder floatTemp: (encoder bindTemp: errorCodeVariableOrNil) nowHasDef].
> +    ^117!
> 
> Item was added:
> + ----- Method: Parser>>properties (in category 'pragmas') -----
> + properties
> +    ^ properties ifNil: [ properties := AdditionalMethodState new ]!
> 
> Item was added:
> + ----- Method: Parser>>queriedUnusedTemporaries (in category 'accessing') -----
> + queriedUnusedTemporaries
> + 
> +    queriedUnusedTemporaries ifNil: 
> +        [queriedUnusedTemporaries := Dictionary new].
> +    ^queriedUnusedTemporaries!
> 
> Item was added:
> + ----- Method: Parser>>queryUndefined (in category 'error correction') -----
> + queryUndefined
> +    | varStart varName | 
> +    varName := parseNode key.
> +    varStart := self endOfLastToken + requestorOffset - varName size + 1.
> +    self selectFrom: varStart to: varStart + varName size - 1 during: [
> +        (UndefinedVariable name: varName) ifFalse: [^ self fail]].!
> 
> Item was added:
> + ----- Method: Parser>>removeEmptyTempDeclarationsFrom: (in category 'error correction') -----
> + removeEmptyTempDeclarationsFrom: methodNode
> + 
> +    | sourceCode madeChanges tempsMarkHolder |
> +    sourceCode := cue requestor text asString.
> +    tempsMarkHolder := self collectTemporaryDeclarationsFrom: methodNode.
> +    madeChanges := false.
> +    tempsMarkHolder do: [ :currentBlock | | tempsMarkChar0 tempsMarkChar1 tempsMarkChar2 end start |
> +        tempsMarkChar0 := (sourceCode at: currentBlock tempsMark).
> +        tempsMarkChar1 := (sourceCode at: currentBlock tempsMark - 1).
> +        tempsMarkChar2 := (sourceCode at: currentBlock tempsMark - 2 ifAbsent: []).
> +        (tempsMarkChar0 == $| and: [ tempsMarkChar1 == $| ])
> +            ifTrue: 
> +                [ end := currentBlock tempsMark. 
> +                start := end - 1].
> +        (tempsMarkChar0 == $| and: [ tempsMarkChar1 == $  and: [ tempsMarkChar2 == $| ] ])
> +            ifTrue: 
> +                [ end := currentBlock tempsMark. 
> +                start := end - 2].
> +        
> +        (start notNil and: [ end notNil ]) ifTrue: [
> +            | lineStart lineEnd |
> +            lineStart := 1 + (sourceCode 
> +                lastIndexOf: Character cr 
> +                startingAt: start - 1).
> +            lineEnd := sourceCode 
> +                indexOf: Character cr
> +                startingAt: end + 1
> +                ifAbsent: [ sourceCode size ].
> +            ((sourceCode indexOfAnyOf: CharacterSet nonSeparators startingAt: lineStart) >= start 
> +                and: [ (sourceCode indexOfAnyOf: CharacterSet nonSeparators startingAt: end + 1) > lineEnd ]) ifTrue: [
> +                    start := lineStart.
> +                    end := lineEnd ].
> +            cue requestor correctFrom: start to: end with: ''.
> +            madeChanges := true.
> +            currentBlock tempsMark: nil ] ].
> +    madeChanges ifTrue: [ReparseAfterSourceEditing signal]!
> 
> Item was added:
> + ----- Method: Parser>>removeUnusedTemporaryNamed:from:lookingAt:movingTempMarksOf: (in category 'error correction') -----
> + removeUnusedTemporaryNamed: temp from: str lookingAt: currentBlock movingTempMarksOf: someBlocks
> + 
> +    | start end |
> +    end := currentBlock tempsMark - 1.
> +    ["Beginning at right temp marker..."
> +    start := end - temp size + 1.
> +    end < temp size or: [ (str at: start) = $| ]
> +        or: [ temp = (str copyFrom: start to: end) 
> +            and: [ ((str at: start - 1) = $| | (str at: start - 1) isSeparator) 
> +                & ((str at: end + 1) = $| | (str at: end + 1) isSeparator) ] ]]
> +        whileFalse: [ 
> +            "Search left for the unused temp"
> +            end := cue requestor nextTokenFrom: end direction: -1 ].
> +    (end < temp size or: [ (str at: start) = $| ])
> +        ifFalse: 
> +            [(str at: start - 1) = $ 
> +                ifTrue: [ start := start - 1 ].
> +            cue requestor correctFrom: start to: end with: ''.
> +            someBlocks do: [ :aBlock | aBlock tempsMark: aBlock tempsMark - (end - start + 1)].
> +            ^true ].
> +    ^false!
> 
> Item was added:
> + ----- Method: Parser>>removeUnusedTemps: (in category 'error correction') -----
> + removeUnusedTemps: methodNode
> +    "Scan for unused temp names, and prompt the user about the prospect of removing each one found"
> + 
> +    | madeChanges tempsMarkHolder unusedTempNames tempMarkHoldersToChange |
> +    madeChanges := false.
> +    tempMarkHoldersToChange := OrderedCollection new.
> +    tempsMarkHolder := self collectTemporaryDeclarationsFrom: methodNode.
> +    unusedTempNames := encoder unusedTempNames select: 
> +        [ :temp | (encoder lookupVariable: temp ifAbsent: [ ]) isUndefTemp 
> +            and: [ self queriedUnusedTemporaries at: temp ifAbsentPut: [
> +                (UnusedVariable name: temp) ifNil: [ ^ self fail ]] ]].
> +    tempsMarkHolder do: [ :currentBlock | 
> +        tempMarkHoldersToChange add: currentBlock.
> +        unusedTempNames do: 
> +            [ :temp |
> +            (self 
> +                removeUnusedTemporaryNamed: temp 
> +                from: cue requestor text asString 
> +                lookingAt: currentBlock
> +                movingTempMarksOf: tempMarkHoldersToChange) ifTrue: [ madeChanges := true ]]].
> +    madeChanges
> +        ifTrue: [ self removeEmptyTempDeclarationsFrom: methodNode.
> +            ReparseAfterSourceEditing signal ]!
> 
> Item was added:
> + ----- Method: Parser>>selectFrom:to:during: (in category 'error correction') -----
> + selectFrom: start to: stop during: aBlock
> +    "Temporarily focus user attention on a zone of error thru text section.
> +    Then restore original user selection.
> +    Note: the original selection is restored invisibly (not displayed).
> +    This will avoid flickering when chaining multiple corrections."
> +    
> +    | userSelection |
> +    userSelection := cue requestor selectionInterval.
> +    cue requestor selectFrom: start to: stop.
> +    aBlock value.
> +    cue requestor selectIntervalInvisibly: userSelection!
> 
> Item was added:
> + ----- Method: Parser>>setCue: (in category 'private') -----
> + setCue: aCue
> +    cue := aCue!
> 
> Item was added:
> + ----- Method: Parser>>startOfNextToken (in category 'scanning') -----
> + startOfNextToken
> +    "Return starting position in source of next token."
> + 
> +    hereType == #doIt ifTrue: [^source position + 1].
> +    ^hereMark!
> 
> Item was added:
> + ----- Method: Parser>>statements:innerBlock: (in category 'expression types') -----
> + statements: argNodes innerBlock: inner
> + 
> +    ^self statements: argNodes innerBlock: inner blockNode: BlockNode new!
> 
> Item was added:
> + ----- Method: Parser>>statements:innerBlock:blockNode: (in category 'expression types') -----
> + statements: argNodes innerBlock: inner blockNode: theBlockNode
> + 
> +    | stmts returns start |
> +    "give initial comment to block, since others trail statements"
> +    theBlockNode comment: currentComment.
> +    currentComment := nil.
> +    stmts := OrderedCollection new.
> +    returns := false.
> +    hereType ~~ #rightBracket ifTrue:
> +        [[theBlockNode startOfLastStatement: (start := self startOfNextToken).
> +          (returns := self matchReturn)
> +            ifTrue: 
> +                [self expression ifFalse:
> +                    [^self expected: 'Expression to return'].
> +                 self addComment.
> +                 stmts addLast: (parseNode isReturningIf
> +                                ifTrue: [parseNode]
> +                                ifFalse: [ReturnNode new
> +                                            expr: parseNode
> +                                            encoder: encoder
> +                                            sourceRange: (start to: self endOfLastToken)])]
> +            ifFalse: 
> +                [self expression
> +                    ifTrue: 
> +                        [self addComment.
> +                        "if both branches return, following code is unreachable, let's avoid this.
> +                        But only if interactive, we don't want to prevent loading of legacy code"
> +                        self interactive ifTrue: [returns := parseNode isReturningIf].
> +                         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!
> 
> Item was added:
> + ----- Method: Parser>>substituteSelector:wordIntervals: (in category 'error correction') -----
> + substituteSelector: selectorParts wordIntervals: spots
> +    "Substitute the correctSelector into the (presumed interactive) receiver."
> +    | offset |
> +    offset := 0.
> +    selectorParts with: spots do:
> +        [ :word :interval |
> +        offset := self substituteWord: word wordInterval: interval offset: offset ]
> + !
> 
> Item was added:
> + ----- Method: Parser>>substituteVariable:atInterval: (in category 'error correction') -----
> + substituteVariable: each atInterval: anInterval 
> +    self 
> +        substituteWord: each
> +        wordInterval: anInterval
> +        offset: 0.
> +    ^encoder encodeVariable: each!
> 
> Item was added:
> + ----- Method: Parser>>substituteWord:wordInterval:offset: (in category 'error correction') -----
> + substituteWord: correctWord wordInterval: spot offset: o
> +    "Substitute the correctSelector into the (presumed interactive) receiver.
> +     Update requestorOffset based on the delta size and answer the updated offset."
> + 
> +    cue requestor correctFrom: spot first + o to: spot last + o with: correctWord.
> +    requestorOffset := requestorOffset + correctWord size - spot size.
> +    ^o + correctWord size - spot size!
> 
> Item was added:
> + ----- Method: Parser>>temporaries (in category 'expression types') -----
> + temporaries
> +    " [ '|' (variable)* '|' ]"
> +    | vars theActualText |
> +    (self match: #verticalBar) ifFalse: 
> +        ["no temps"
> +        doitFlag ifTrue:
> +            [tempsMark := self interactive
> +                                ifTrue: [cue requestor selectionInterval first]
> +                                ifFalse: [1].
> +            ^ #()].
> +        tempsMark := hereMark    "formerly --> prevMark + prevToken".
> +        tempsMark > 0 ifTrue:
> +            [theActualText := source contents.
> +            [tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]]
> +                whileTrue: [tempsMark := tempsMark + 1]].
> +            ^ #()].
> +    vars := OrderedCollection new.
> +    [hereType == #word]
> +        whileTrue: [vars addLast: (encoder bindTemp: self advance)].
> +    (self match: #verticalBar) ifTrue: 
> +        [tempsMark := prevMark.
> +        ^ vars].
> +    ^ self expected: 'Vertical bar'
> + !
> 
> Item was added:
> + ----- Method: Parser>>temporariesIn: (in category 'expression types') -----
> + temporariesIn: methodSelector
> +    " [ '|' (variable)* '|' ]"
> +    | vars theActualText |
> +    (self match: #verticalBar) ifFalse: 
> +        ["no temps"
> +        doitFlag ifTrue:
> +            [tempsMark := self interactive
> +                                ifTrue: [cue requestor selectionInterval first]
> +                                ifFalse: [1].
> +            ^ #()].
> +        tempsMark := hereMark    "formerly --> prevMark + prevToken".
> +        tempsMark > 0 ifTrue:
> +            [theActualText := source contents.
> +            [tempsMark < theActualText size and: [(theActualText at: tempsMark) isSeparator]]
> +                whileTrue: [tempsMark := tempsMark + 1]].
> +            ^ #()].
> +    vars := OrderedCollection new.
> +    [hereType == #word]
> +        whileTrue: [vars addLast: (encoder bindTemp: self advance in: methodSelector)].
> +    (self match: #verticalBar) ifTrue: 
> +        [tempsMark := prevMark.
> +        ^ vars].
> +    ^ self expected: 'Vertical bar'!
> 
> Item was added:
> + ----- Method: Parser>>temporaryBlockVariablesFor: (in category 'expression types') -----
> + temporaryBlockVariablesFor: aBlockNode
> +    "Scan and answer temporary block variables."
> + 
> +    | variables |
> +    (self match: #verticalBar) ifFalse:
> +        "There are't any temporary variables."
> +        [aBlockNode tempsMark: prevMark + requestorOffset.
> +         ^#()].
> + 
> +    variables := OrderedCollection new.
> +    [hereType == #word] whileTrue:
> +        [variables addLast: (encoder bindBlockTemp: self advance within: aBlockNode)].
> +    (self match: #verticalBar) ifFalse:
> +        [^self expected: 'Vertical bar'].
> +    aBlockNode tempsMark: prevMark + requestorOffset.
> +    ^variables!
> 
> Item was added:
> + ----- Method: Parser>>tempsMark (in category 'accessing') -----
> + tempsMark
> +    ^ tempsMark!
> 
> Item was added:
> + ----- Method: Parser>>tempsMark: (in category 'accessing') -----
> + tempsMark: aNumber
> + tempsMark := aNumber!
> 
> Item was added:
> + ----- Method: Parser>>transformAVerticalBarIntoABinarySelector (in category 'scanning') -----
> + transformAVerticalBarIntoABinarySelector
> +    "Transform a vertical bar into a binary selector.
> +    Eventually aggregate a serie of immediately following vertical bars and a binary selector.
> +    Note that this aggregation cannot occur at scan time, because a pair of vertical bars can be encountered in two valid constructs:
> +    - either as an empty temporaries specification,
> +    - or as a local temporaries specification in a block of arity > 0"
> +    here := '|'.
> +    hereType := #binary.
> +    [tokenType == #verticalBar and: [hereMark + here size = mark]]
> +        whileTrue: [
> +            here := here , '|'.
> +            hereEnd := hereEnd + 1.
> +            self scanToken].
> +    (tokenType == #binary and: [hereMark + here size = mark])
> +        ifTrue: [
> +            here := here asString , token.
> +            hereType := #binary.
> +            hereEnd := hereEnd + token size.
> +            self scanToken].!
> 
> Item was added:
> + ----- Method: Parser>>variable (in category 'expression types') -----
> + 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)]!
> 
> Item was added:
> + Notification subclass: #ParserNotification
> +    instanceVariableNames: 'name'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> 
> Item was added:
> + ----- Method: ParserNotification class>>name: (in category 'instance creation') -----
> + name: aString
> +    ^ (self new setName: aString) signal!
> 
> Item was added:
> + ----- Method: ParserNotification>>openMenuIn: (in category 'handling') -----
> + openMenuIn: aBlock
> +    self subclassResponsibility!
> 
> Item was added:
> + ----- Method: ParserNotification>>setName: (in category 'initialization') -----
> + setName: aString
> +    name := aString!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitRemoteTempVectorNode: self!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>addRemoteTemp:encoder: (in category 'closure analysis') -----
> + addRemoteTemp: aTempVariableNode encoder: encoder
> +    remoteTemps ifNil:
> +        [remoteTemps := OrderedCollection new].
> +    remoteTemps addLast: aTempVariableNode.
> +    aTempVariableNode referenceScopesAndIndicesDo:
> +        [:scopeBlock "<BlockNode>" :location "<Integer>"|
> +         self addReadWithin: scopeBlock at: location]!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>emitCodeForStoreInto:stack:encoder: (in category 'code generation') -----
> + emitCodeForStoreInto: aTempVariableNode stack: stack encoder: encoder
> +    encoder
> +        genStoreRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> +        inVectorAt: index!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>emitCodeForStorePopInto:stack:encoder: (in category 'code generation') -----
> + emitCodeForStorePopInto: aTempVariableNode stack: stack encoder: encoder
> +    encoder
> +        genStorePopRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> +        inVectorAt: index.
> +    stack pop: 1!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>emitCodeForValueOf:stack:encoder: (in category 'code generation') -----
> + emitCodeForValueOf: aTempVariableNode stack: stack encoder: encoder
> +    encoder
> +        genPushRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> +        inVectorAt: index.
> +    stack push: 1!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>isIndirectTempVector (in category 'closure analysis') -----
> + isIndirectTempVector
> +    ^true!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>nodeToInitialize: (in category 'code generation') -----
> + nodeToInitialize: encoder
> +    ^AssignmentNode new
> +        variable: self
> +        value: (NewArrayNode new numElements: remoteTemps size)!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>printDefinitionForClosureAnalysisOn: (in category 'printing') -----
> + printDefinitionForClosureAnalysisOn: aStream 
> +    | refs |
> +    aStream
> +        nextPut: ${;
> +        nextPutAll: key.
> +    definingScope ifNotNil: [definingScope blockExtent ifNotNil: [:be| aStream nextPutAll: ' d@'; print: be first]].
> +    readingScopes ifNotNil: [
> +        refs := Set new.
> +        readingScopes do: [:elems| refs addAll: elems].
> +        refs sorted do: [:read| aStream nextPutAll: ' r@'; print: read]].
> +    remoteTemps
> +        do: [:rt| rt printDefinitionForClosureAnalysisOn: aStream]
> +        separatedBy: [aStream nextPut: $,; space].
> +    aStream nextPut: $}!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>referenceScopesAndIndicesDo: (in category 'closure analysis') -----
> + referenceScopesAndIndicesDo: aBinaryBlock
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>remoteTemps (in category 'accessing') -----
> + remoteTemps
> +    ^remoteTemps!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>remoteTemps: (in category 'decompiler') -----
> + remoteTemps: anArray
> +    remoteTemps := anArray.
> +    anArray do: [:tempNode| tempNode remoteNode: self]!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>scope (in category 'code generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>sizeCodeForStoreInto:encoder: (in category 'code generation') -----
> + sizeCodeForStoreInto: aTempVariableNode encoder: encoder
> +    ^encoder
> +        sizeStoreRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> +        inVectorAt: index!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>sizeCodeForStorePopInto:encoder: (in category 'code generation') -----
> + sizeCodeForStorePopInto: aTempVariableNode encoder: encoder
> +    ^encoder
> +        sizeStorePopRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> +        inVectorAt: index!
> 
> Item was added:
> + ----- Method: RemoteTempVectorNode>>sizeCodeForValueOf:encoder: (in category 'code generation') -----
> + sizeCodeForValueOf: aTempVariableNode encoder: encoder
> +    ^encoder
> +        sizePushRemoteTemp: (remoteTemps indexOf: aTempVariableNode) - 1
> +        inVectorAt: index!
> 
> Item was added:
> + Notification subclass: #ReparseAfterSourceEditing
> +    instanceVariableNames: 'newSource'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !ReparseAfterSourceEditing commentStamp: 'nice 9/18/2013 22:05' prior: 0!
> + A ReparseAfterSourceEditing is a Notification used to restart the syntax parsing phase of a compilation after a source code edition.
> + 
> + Instance Variables
> +    newSource:        <UndefinedObject | String | Text | Stream>
> + 
> + newSource
> +    - this is the new source code to be used for restarting compilation if non interactive
> + 
> + In case of interactive compilation, newSource variable is nil because source code edition is performed directly in the source code editor, and the new source code will be picked directly there by the compiler.
> + 
> + In case of non interactive compilation, source code edition typically occurs in a SyntaxError window popping up. But the compiler has no direct access to this object, so newSource has to be passed by our intermediate.
> + !
> 
> Item was added:
> + ----- Method: ReparseAfterSourceEditing class>>withNewSource: (in category 'instance creation') -----
> + withNewSource: aStringOrStream
> +    ^(self new withNewSource: aStringOrStream) signal!
> 
> Item was added:
> + ----- Method: ReparseAfterSourceEditing>>newSource (in category 'accessing') -----
> + newSource
> +    ^newSource!
> 
> Item was added:
> + ----- Method: ReparseAfterSourceEditing>>withNewSource: (in category 'initialize-release') -----
> + withNewSource: aStringOrStream
> +    newSource := aStringOrStream!
> 
> Item was added:
> + ParseNode subclass: #ReturnNode
> +    instanceVariableNames: 'expr'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !ReturnNode commentStamp: '<historical>' prior: 0!
> + I represent an expression of the form ^expr.!
> 
> Item was added:
> + ----- Method: ReturnNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitReturnNode: self!
> 
> Item was added:
> + ----- Method: ReturnNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + 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!
> 
> Item was added:
> + ----- Method: ReturnNode>>asReturnNode (in category 'converting') -----
> + asReturnNode!
> 
> Item was added:
> + ----- Method: ReturnNode>>code (in category 'code generation') -----
> + code
> + 
> +    ^expr code!
> 
> Item was added:
> + ----- Method: ReturnNode>>emitCodeForReturn:encoder: (in category 'code generation') -----
> + emitCodeForReturn: stack encoder: encoder
> + 
> +    expr emitCodeForReturn: stack encoder: encoder.
> +    pc := encoder pc!
> 
> Item was added:
> + ----- Method: ReturnNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> + 
> +    expr emitCodeForReturn: stack encoder: encoder.
> +    pc := encoder pc!
> 
> Item was added:
> + ----- Method: ReturnNode>>expr (in category 'printing') -----
> + expr
> + 
> +    ^ expr.
> + !
> 
> Item was added:
> + ----- Method: ReturnNode>>expr: (in category 'initialize-release') -----
> + expr: e
> + 
> +    expr := e!
> 
> Item was added:
> + ----- Method: ReturnNode>>expr:encoder:sourceRange: (in category 'initialize-release') -----
> + expr: e encoder: encoder sourceRange: range
> + 
> +    expr := e.
> +    encoder noteSourceRange: range forNode: self!
> 
> Item was added:
> + ----- Method: ReturnNode>>isReturnSelf (in category 'testing') -----
> + isReturnSelf
> + 
> +    ^expr == NodeSelf!
> 
> Item was added:
> + ----- Method: ReturnNode>>isSpecialConstant (in category 'testing') -----
> + isSpecialConstant
> + 
> +    ^expr isSpecialConstant!
> 
> Item was added:
> + ----- Method: ReturnNode>>isVariableReference (in category 'testing') -----
> + isVariableReference
> + 
> +    ^expr isVariableReference!
> 
> Item was added:
> + ----- Method: ReturnNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level
> + 
> +    aStream nextPutAll: '^ '. "make this a preference??"
> +    expr printOn: aStream indent: level.
> +    expr printCommentOn: aStream indent: level!
> 
> Item was added:
> + ----- Method: ReturnNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level
> + 
> +    aStream nextPutAll: '^ '. "make this a preference??"
> +    expr printWithClosureAnalysisOn: aStream indent: level.
> +    expr printCommentOn: aStream indent: level!
> 
> Item was added:
> + ----- Method: ReturnNode>>sizeCodeForReturn: (in category 'code generation') -----
> + sizeCodeForReturn: encoder
> + 
> +    ^expr sizeCodeForReturn: encoder!
> 
> Item was added:
> + ----- Method: ReturnNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> + 
> +    ^expr sizeCodeForReturn: encoder!
> 
> Item was added:
> + Object subclass: #Scanner
> +    instanceVariableNames: 'source mark hereChar aheadChar token tokenType currentComment buffer typeTable'
> +    classVariableNames: 'AllowBlockArgumentAssignment AllowUnderscoreAssignments AllowUnderscoreSelectors AllowUnicharSymbol DoItCharacter TypeTable'
> +    poolDictionaries: ''
> +    category: 'Compiler-Kernel'!
> + 
> + !Scanner commentStamp: 'ul 4/3/2011 02:04' 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.
> + 
> + Instance Variables
> +    aheadChar:        <Character>
> +    buffer:        <WriteStream>
> +    currentComment:        <OrderedCollection>
> +    hereChar:        <Character>
> +    mark:        <Integer>
> +    source:        <ReadStream>
> +    token:        <Symbol|String|NumberCharacter|Boolean|nil>
> +    tokenType:        <Symbol>
> +    typeTable:        <Array>
> + 
> + aheadChar
> +    - the next character in the input stream
> + 
> + buffer
> +    - a reusable WriteStream on a String which is used for building strings. Shouldn't be used from multiple methods without resetting.
> + 
> + currentComment
> +    - an OrderedCollection of strings which contain all comments between the current token and the previous token or the beginning of the source.
> + 
> + hereChar
> +    - the current character
> + 
> + mark
> +    - the position of the current token in the source stream
> + 
> + source
> +    - the input stream of characters
> + 
> + token
> +    - the current token
> + 
> + tokenType
> +    - the type of the current token. The possible token types are: #binary, #character, #colon, #doIt, #keyword, #leftArrow, #leftBrace, #leftBracket, #leftParenthesis, #literal, #period, #rightBrace, #rightBracket, #rightParenthesis, #semicolon, #string, #upArrow, #verticalBar, #word, #xBinary, #xColon, #xDelimiter, #xDigit, #xDollar, #xDoubleQuote, #xLetter, #xLitQuote, #xSingleQuote, #xUnderscore
> + 
> + typeTable
> +    - an array that maps each an evaluable tokenType to each character with asciiValue between 0 and 255!
> 
> Item was added:
> + ----- Method: Scanner class>>allowBlockArgumentAssignment (in category 'preferences') -----
> + allowBlockArgumentAssignment
> +    "Accessor for the system-wide preference"
> +    
> +    <preference: 'Allow block argument assignment.'
> +        category: 'Compiler'
> +        description: 'If enabled, the compiler will allow assignment into block arguments.
> + This provides backward compatibility with the pre-closure compiler.'
> +        type: #Boolean>
> +    ^AllowBlockArgumentAssignment ifNil: [ false ]!
> 
> Item was added:
> + ----- Method: Scanner class>>allowBlockArgumentAssignment: (in category 'preferences') -----
> + allowBlockArgumentAssignment: aBoolean
> +    "Accessor for the system-wide preference"
> +    
> +    AllowBlockArgumentAssignment := aBoolean!
> 
> Item was added:
> + ----- Method: Scanner class>>allowUnderscoreAsAssignment (in category 'preferences') -----
> + allowUnderscoreAsAssignment
> +    "Accessor for the system-wide preference"
> +    <preference: 'Allow underscore assignments'
> +        category: 'Compiler'
> +        description: 'When true, underscore can be used as assignment operator'
> +        type: #Boolean>
> +    ^AllowUnderscoreAssignments ifNil:[true]!
> 
> Item was added:
> + ----- Method: Scanner class>>allowUnderscoreAsAssignment: (in category 'preferences') -----
> + allowUnderscoreAsAssignment: aBool
> +    "Accessor for the system-wide preference"
> +    AllowUnderscoreAssignments := aBool!
> 
> Item was added:
> + ----- Method: Scanner class>>initialize (in category 'initialization') -----
> + initialize
> +    
> +    self initializeTypeTable.
> +    "The unicode ending with FFFE or FFFF are non characters and can be used by applications if they wish.
> +    We use last legal unicode 16r10FFFF to encode the end of source stream"
> +    DoItCharacter := Character value: 16r10FFFF!
> 
> Item was added:
> + ----- Method: Scanner class>>initializeTypeTable (in category 'initialization') -----
> + initializeTypeTable
> +    "self initializeTypeTable"
> + 
> +    | newTable |
> +    newTable := Array new: 256 withAll: #xBinary. "default"
> +    newTable atAll: #(9 10 12 13 32 16ra0) put: #xDelimiter. "tab lf ff cr space nbsp"
> +    newTable atAll: ($0 asciiValue to: $9 asciiValue) put: #xDigit.
> + 
> +    1 to: 255
> +        do: [:index |
> +            (Character value: index) isLetter
> +                ifTrue: [newTable at: index put: #xLetter]].
> + 
> +    newTable at: $" asciiValue put: #xDoubleQuote.
> +    newTable at: $# asciiValue put: #xLitQuote.
> +    newTable at: $$ asciiValue put: #xDollar.
> +    newTable at: $' asciiValue put: #xSingleQuote.
> +    newTable at: $: asciiValue put: #xColon.
> +    newTable at: $( asciiValue put: #leftParenthesis.
> +    newTable at: $) asciiValue put: #rightParenthesis.
> +    newTable at: $. asciiValue put: #period.
> +    newTable at: $; asciiValue put: #semicolon.
> +    newTable at: $[ asciiValue put: #leftBracket.
> +    newTable at: $] asciiValue put: #rightBracket.
> +    newTable at: ${ asciiValue put: #leftBrace.
> +    newTable at: $} asciiValue put: #rightBrace.
> +    newTable at: $^ asciiValue put: #upArrow.
> +    newTable at: $_ asciiValue put: #xUnderscore.
> +    newTable at: $| asciiValue put: #verticalBar.
> +    TypeTable := newTable "bon voyage!!"!
> 
> Item was added:
> + ----- Method: Scanner class>>inviolateInstanceVariableNames (in category 'testing') -----
> + inviolateInstanceVariableNames
> +    "Answer a list of instance variable names not to be used.  (Place holder for real list)"
> +    ^ #('thisContext' 'self')!
> 
> Item was added:
> + ----- Method: Scanner class>>isLegalInstVarName: (in category 'testing') -----
> + isLegalInstVarName: aString
> +    "Answer whether aString is a legal instance variable name."
> + 
> +    ^ ((self isLiteralSymbol: aString) and: [(aString includes: $:) not]) and:
> +        [(self inviolateInstanceVariableNames includes:  aString) not]!
> 
> Item was added:
> + ----- Method: Scanner class>>isLiteralSymbol: (in category 'testing') -----
> + 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:
> +        [^(2 to: i) allSatisfy: [:j |
> +            ascii := (aSymbol at: j) asciiValue.
> +            (TypeTable at: ascii ifAbsent: []) == #xBinary]].
> +    type == #verticalBar ifTrue: [^i = 1].
> +    ^false!
> 
> Item was added:
> + ----- Method: Scanner class>>isMessageSelector: (in category 'testing') -----
> + isMessageSelector: aSymbol
> +    "Answer if the argument is a valid message selector.
> +     This is optimized for fast filtering."
> +    | first last sz type |
> +    (sz := aSymbol size) = 0 ifTrue: [^false].
> +    first := aSymbol at: 1.
> +    last := aSymbol at: sz.
> +    type := TypeTable at: first asciiValue.
> + 
> +    type == #xLetter ifTrue:
> +        ["Alas some people (myself included) do create selectors with an initial capital.
> +          But this is unusual, and it is even rarer for these to be unary selectors, so I think
> +          it is better to exclude class names than include the few exceptions."
> +         (first isUppercase and: [last ~~ $:]) ifTrue:
> +            [^false].
> +         "Could be unary or keyword, may include underscores if AllowUnderscoreSelectors.
> +          It is possible to be more agressive here, filtering out two successive colons, but I'm lazy"
> +         ^aSymbol allSatisfy: (AllowUnderscoreSelectors
> +                                ifTrue:
> +                                    [last == $:
> +                                        ifTrue: [[:c| c == $: or: [c == $_ or: [c isAlphaNumeric]]]]
> +                                        ifFalse: [[:c| c ~~ $: and: [c == $_ or: [c isAlphaNumeric]]]]]
> +                                ifFalse:
> +                                    [last == $:
> +                                        ifTrue: [[:c| c == $: or: [c isAlphaNumeric]]]
> +                                        ifFalse: [[:c| c ~~ $: and: [c isAlphaNumeric]]]])].
> + 
> +    type == #xBinary ifTrue:
> +        [^aSymbol allSatisfy: [:c| c == $| or: [(TypeTable at: c asciiValue) == #xBinary]]].
> + 
> +    ^type == #xUnderscore
> +     and: [AllowUnderscoreSelectors
> +     and: [self isMessageSelector: aSymbol allButFirst]]
> + 
> +    "| implemented |
> +    implemented := Set new.
> +    self systemNavigation allSelect: [:m| implemented add: m selector. false].
> +    ^Symbol allSubInstances select: [:s| (implemented includes: s) not and: [self isMessageSelector: s]]"
> + 
> +    "| implemented |
> +    implemented := Set new.
> +    self systemNavigation allSelect: [:m| implemented add: m selector. false].
> +    ^implemented reject: [:s| self isMessageSelector: s]"!
> 
> Item was added:
> + ----- Method: Scanner class>>prefAllowUnderscoreAssignments (in category 'preferences') -----
> + prefAllowUnderscoreAssignments
> +    "Accessor for the system-wide preference"
> +    
> +    self deprecated: 'Use #allowUnderscoreAsAssignment'.
> +    ^self allowUnderscoreAsAssignment!
> 
> Item was added:
> + ----- Method: Scanner class>>prefAllowUnderscoreAssignments: (in category 'preferences') -----
> + prefAllowUnderscoreAssignments: aBool
> +    "Accessor for the system-wide preference"
> +    
> +    self deprecated: 'Use #allowUnderscoreAsAssignment:'.
> +    self allowUnderscoreAsAssignment: aBool!
> 
> Item was added:
> + ----- Method: Scanner class>>prefAllowUnderscoreSelectors (in category 'preferences') -----
> + prefAllowUnderscoreSelectors
> +    "Accessor for the system-wide preference"
> +    <preference: 'Allow underscore selectors'
> +        category: 'Compiler'
> +        description: 'When true, underscore can be used in selectors and varibable names'
> +        type: #Boolean>
> +    ^AllowUnderscoreSelectors ifNil:[false]!
> 
> Item was added:
> + ----- Method: Scanner class>>prefAllowUnderscoreSelectors: (in category 'preferences') -----
> + prefAllowUnderscoreSelectors: aBool
> +    "Accessor for the system-wide preference"
> +    AllowUnderscoreSelectors := aBool.
> +    
> +    "Reinitialize String's tokenish character map"
> +    String initialize!
> 
> Item was added:
> + ----- Method: Scanner class>>prefAllowUnicharSymbol (in category 'preferences') -----
> + prefAllowUnicharSymbol
> +    "Accessor for the system-wide preference"
> +    <preference: 'Allow symbols with unique character like #.'
> +        category: 'Compiler'
> +        description: 'When true, the historical syntax #., #,, or # is allowed.'
> +        type: #Boolean>
> +    ^AllowUnicharSymbol ifNil: [false]!
> 
> Item was added:
> + ----- Method: Scanner class>>prefAllowUnicharSymbol: (in category 'preferences') -----
> + prefAllowUnicharSymbol: aBoolean
> +    "Accessor for the system-wide preference"
> +    AllowUnicharSymbol := aBoolean!
> 
> Item was added:
> + ----- Method: Scanner class>>wellFormedInstanceVariableNameFrom: (in category 'testing') -----
> + 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'"!
> 
> Item was added:
> + ----- Method: Scanner>>advance (in category 'expression types') -----
> + advance
> + 
> +    | prevToken |
> +    prevToken := token.
> +    self scanToken.
> +    ^prevToken!
> 
> Item was added:
> + ----- Method: Scanner>>allowUnderscoreAssignments (in category 'private') -----
> + allowUnderscoreAssignments
> +    "Query preference"
> +    ^self class allowUnderscoreAsAssignment!
> 
> Item was added:
> + ----- Method: Scanner>>allowUnderscoreSelectors (in category 'private') -----
> + allowUnderscoreSelectors
> +    "Query preference"
> +    ^self class prefAllowUnderscoreSelectors!
> 
> Item was added:
> + ----- Method: Scanner>>ambiguousSelector:inRange: (in category 'error handling') -----
> + ambiguousSelector: aString inRange: anInterval
> +    "Compile with backward compatibility: $- is part of literal argument.."
> +    
> +    token := token asSymbol.
> +    ^self!
> 
> Item was added:
> + ----- Method: Scanner>>initScannerForTokenization (in category 'initialize-release') -----
> + 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.
> +    typeTable at: (typeTable identityIndexOf: #xLitQuote) put: #xLitQuoteForTokenization!
> 
> Item was added:
> + ----- Method: Scanner>>initialize (in category 'initialize-release') -----
> + initialize
> + 
> +    super initialize.
> +    buffer := WriteStream on: (String new: 40).
> +    typeTable := TypeTable!
> 
> Item was added:
> + ----- Method: Scanner>>notify: (in category 'error handling') -----
> + notify: string 
> +    "Refer to the comment in Object|notify:." 
> +    self error: string!
> 
> Item was added:
> + ----- Method: Scanner>>notify:at: (in category 'error handling') -----
> + notify: string at: posiiton
> +    "Parser compatible message"
> +     
> +    ^self notify: string !
> 
> Item was added:
> + ----- Method: Scanner>>offEnd: (in category 'error handling') -----
> + offEnd: aString 
> +    "Parser overrides this"
> + 
> +    ^self notify: aString!
> 
> Item was added:
> + ----- Method: Scanner>>scan: (in category 'initialize-release') -----
> + scan: inputStream 
> +    "Bind the input stream, fill the character buffers and first token buffer."
> + 
> +    source := inputStream.
> +    self step.
> +    self step.
> +    self scanToken!
> 
> Item was added:
> + ----- Method: Scanner>>scanAllTokenPositionsInto: (in category 'expression types') -----
> + scanAllTokenPositionsInto: aBlock
> +    "Evaluate aBlock with the start and end positions of all separate non-white-space tokens, including comments."
> + 
> +    | lastMark |
> +    lastMark := 1.
> +    [currentComment ifNotNil:
> +        [currentComment do:
> +            [:cmnt| | idx |
> +             idx := source originalContents findLastOccurrenceOfString: cmnt startingAt: lastMark.
> +             (idx > 0 and: [idx < mark]) ifTrue:
> +                [aBlock value: idx - 1 value: (lastMark := idx + cmnt size)]].
> +         currentComment := nil].
> +    mark ifNotNil:
> +        [(token == #- 
> +          and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue:
> +            [| savedMark |
> +             savedMark := mark.
> +             self scanToken.
> +             token := token negated.
> +             mark := savedMark].
> +        "Compensate for the fact that the parser uses two character lookahead.  Normally we must
> +          remove the extra two characters.  But this mustn't happen for the last token at the end of stream."
> +         aBlock
> +            value: mark
> +            value: source position - (aheadChar == DoItCharacter
> +                ifTrue: [hereChar == DoItCharacter
> +                    ifTrue: [0]
> +                    ifFalse: [1]]
> +                ifFalse: [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 ] repeat!
> 
> Item was added:
> + ----- Method: Scanner>>scanFieldNames: (in category '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' )"!
> 
> Item was added:
> + ----- Method: Scanner>>scanLitByteVec (in category 'expression types') -----
> + 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!
> 
> Item was added:
> + ----- Method: Scanner>>scanLitVec (in category 'expression types') -----
> + 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 isCharacter and: [tokenType ~~ #character])
> +                            ifTrue: [token := token asSymbol]
> +                            ifFalse: [(token == #- 
> +                                  and: [(self typeTableAt: hereChar) == #xDigit]) ifTrue: 
> +                                    [self scanToken.
> +                                     token := token negated]]]].
> +        s nextPut: token.
> +        self scanToken].
> +    token := s contents!
> 
> Item was added:
> + ----- Method: Scanner>>scanLitWord (in category 'expression types') -----
> + scanLitWord
> +    "Accumulate keywords and asSymbol the result."
> + 
> +    token := (String streamContents: [ :stream |
> +        stream nextPutAll: token.
> +        [ (self typeTableAt: hereChar) == #xLetter ] whileTrue: [
> +            self xLetter.
> +            stream nextPutAll: token ] ]) asSymbol!
> 
> Item was added:
> + ----- Method: Scanner>>scanMessageParts: (in category 'public access') -----
> + 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 = #| and: [ 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!
> 
> Item was added:
> + ----- Method: Scanner>>scanStringStruct (in category '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!
> 
> Item was added:
> + ----- Method: Scanner>>scanStringStruct: (in category '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)'"!
> 
> Item was added:
> + ----- Method: Scanner>>scanToken (in category 'expression types') -----
> + scanToken
> + 
> +    [(tokenType := self typeTableAt: hereChar) == #xDelimiter]
> +        whileTrue: [self step].  "Skip delimiters fast, there almost always is one."
> +    mark := aheadChar == DoItCharacter
> +        ifTrue: [hereChar == DoItCharacter
> +            ifTrue: [source position + 1]
> +            ifFalse: [source position]]
> +        ifFalse: [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 "else just unique the first char"].
> +    ^token!
> 
> Item was added:
> + ----- Method: Scanner>>scanTokenPositionsIn:into: (in category 'public access') -----
> + 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]'"!
> 
> Item was added:
> + ----- Method: Scanner>>scanTokens: (in category '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'' .'"!
> 
> Item was added:
> + ----- Method: Scanner>>step (in category 'expression types') -----
> + step
> + 
> +    | c |
> +    c := hereChar.
> +    hereChar := aheadChar.
> +    source atEnd
> +        ifTrue: [aheadChar := DoItCharacter]
> +        ifFalse: [aheadChar := source next].
> +    ^c!
> 
> Item was added:
> + ----- Method: Scanner>>typeTableAt: (in category 'multi-character scans') -----
> + typeTableAt: aCharacter
> +    ^typeTable
> +        at: aCharacter charCode
> +        ifAbsent:
> +            [aCharacter == DoItCharacter
> +                ifTrue: [#doIt]
> +                ifFalse: [#xLetter]]!
> 
> Item was added:
> + ----- Method: Scanner>>typedScan:do: (in category 'public access') -----
> + typedScan: textOrString do: aBinaryBlock
> +    "Evaluate aBinaryBlock with the token and its type for the first token in input,
> +     mapping literals to type #literal and anything else to type #word."
> +    | theTokensType atNumber theToken |
> +    self initScannerForTokenization.
> +    self scan: (ReadStream on: textOrString asString).
> +    atNumber := hereChar notNil and: [hereChar isDigit].
> +    theTokensType := tokenType.
> +    theToken := self advance.
> +    (theToken == #- and: [atNumber and: [token isNumber]]) ifTrue:
> +        [theToken := self advance negated].
> +    theToken isNumber ifTrue: [theTokensType := #number].
> +    ^aBinaryBlock
> +        value: theToken
> +        value: ((#(number string literal character) includes: theTokensType)
> +                ifTrue: [#literal]
> +                ifFalse: [#word])!
> 
> Item was added:
> + ----- Method: Scanner>>typedScanTokens: (in category 'public access') -----
> + 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:)"!
> 
> Item was added:
> + ----- Method: Scanner>>xBinary (in category 'multi-character scans') -----
> + xBinary
> + 
> +    | startOfToken |
> +    tokenType := #binary.
> +    startOfToken := mark.
> +    token := String with: self step.
> +    [(self typeTableAt: hereChar) == #xBinary or: [(self typeTableAt: hereChar) == #verticalBar]] whileTrue:
> +        [(hereChar == $- and: [(self typeTableAt: aheadChar) == #xDigit])
> +            ifTrue: [^self ambiguousSelector: (token , '-')
> +                    inRange: (startOfToken to: source position - 1).].
> +        token := token, (String with: self step)].
> +    token := token asSymbol!
> 
> Item was added:
> + ----- Method: Scanner>>xColon (in category 'multi-character scans') -----
> + 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!
> 
> Item was added:
> + ----- Method: Scanner>>xDelimiter (in category 'multi-character scans') -----
> + xDelimiter
> +    "Ignore blanks, etc."
> + 
> +    self scanToken!
> 
> Item was added:
> + ----- Method: Scanner>>xDigit (in category 'multi-character scans') -----
> + xDigit
> +    "Form a number."
> + 
> +    tokenType := #number.
> +    aheadChar == DoItCharacter
> +        ifTrue: [source skip: -1 "Read off the end last time"]
> +        ifFalse: [source skip: -2].
> +    token := (SqNumberParser on: source)
> +        failBlock: [:errorString :position | self notify: errorString at:position];
> +        nextNumber.
> +    self step; step!
> 
> Item was added:
> + ----- Method: Scanner>>xDollar (in category 'multi-character scans') -----
> + xDollar
> +    "Form a Character literal."
> + 
> +    aheadChar == DoItCharacter
> +        ifTrue:
> +            [mark := mark + 1. "Let the notification lie behind the dollar"
> +            ^self offEnd: 'A Character was expected'].
> +    self step. "pass over $"
> +    token := self step.
> +    tokenType := #character!
> 
> Item was added:
> + ----- Method: Scanner>>xDoubleQuote (in category 'multi-character scans') -----
> + xDoubleQuote
> +     "Collect a comment."
> + 
> +    buffer reset.
> +    self step.
> +    [ hereChar == $" ] whileFalse: [
> +        hereChar == DoItCharacter ifTrue: [
> +            ^self offEnd: 'Unmatched comment quote' ].
> +        buffer nextPut: self step ].
> +    self step.
> +    (currentComment ifNil: [ 
> +        currentComment := OrderedCollection new ])
> +            add: buffer contents.
> +    self scanToken!
> 
> Item was added:
> + ----- Method: Scanner>>xIllegal (in category 'multi-character scans') -----
> + xIllegal
> +    "An illegal character was encountered"
> +    self notify: 'Illegal character (char code ' , hereChar charCode , ' ' , hereChar charCode storeStringHex , ')' at: mark!
> 
> Item was added:
> + ----- Method: Scanner>>xLetter (in category 'multi-character scans') -----
> + xLetter
> +    "Form a word or keyword."
> + 
> +    | type |
> +    buffer reset.
> +    [(type := self typeTableAt: hereChar) == #xLetter
> +        or: [type == #xDigit
> +        or: [type == #xUnderscore and:[self allowUnderscoreSelectors]]]] whileTrue:
> +            [buffer nextPut: self step].
> +    tokenType := (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: 
> +                        [#word].
> +    token := buffer contents!
> 
> Item was added:
> + ----- Method: Scanner>>xLitQuote (in category 'multi-character scans') -----
> + 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: [(tokenType == #word or: [tokenType == #keyword or: [tokenType == #colon]])
> +                        ifTrue: [self scanLitWord]
> +                        ifFalse: [(tokenType == #string or: [ tokenType == #verticalBar ])
> +                            ifTrue: [token := token asSymbol]
> +                            ifFalse: [tokenType == #binary 
> +                                ifFalse: [(token isCharacter and: [tokenType ~~ #character and: [self class prefAllowUnicharSymbol]])
> +                                    ifTrue: [token := token asSymbol]
> +                                    ifFalse: [self notify: 'Invalid literal character' at: start + 1]]]]]].
> +    mark := start.
> +    tokenType := #literal
> + 
> +    "#(Pen)
> +    #Pen
> +    #'Pen'
> +    "!
> 
> Item was added:
> + ----- Method: Scanner>>xLitQuoteForTokenization (in category 'multi-character scans') -----
> + xLitQuoteForTokenization
> +    "Parse underscores as per the regular parser when following a # symbol, so that e.g. #_WIN32 is correctly tokenized."
> +    | index |
> +    index :=  typeTable identityIndexOf: #xUnderscoreForTokenization ifAbsent: [^self xLitQuote].
> +    typeTable at: index put: #xUnderscore.
> +    [self xLitQuote] ensure:
> +        [typeTable at: index put: #xUnderscoreForTokenization]!
> 
> Item was added:
> + ----- Method: Scanner>>xSingleQuote (in category 'multi-character scans') -----
> + xSingleQuote
> +    "String."
> + 
> +    self step.
> +    buffer reset.
> +    [hereChar == $' 
> +        and: [aheadChar == $' 
> +                ifTrue: [self step. false]
> +                ifFalse: [true]]]
> +        whileFalse: 
> +            [hereChar == DoItCharacter
> +                ifTrue: [^self offEnd: 'Unmatched string quote'].
> +            buffer nextPut: self step].
> +    self step.
> +    token := buffer contents.
> +    tokenType := #string!
> 
> Item was added:
> + ----- Method: Scanner>>xUnderscore (in category 'multi-character scans') -----
> + xUnderscore
> +    self allowUnderscoreAssignments ifTrue:
> +        "Figure out if x _foo (no space between _ and foo) should be a selector or assignment."
> +        [(self allowUnderscoreSelectors
> +          and: [#(xLetter xDigit xUnderscore xColon) includes: (self typeTableAt: aheadChar)])
> +            ifFalse:
> +                [self step.
> +                 tokenType := #leftArrow.
> +                 ^token := #'_']].
> +    self allowUnderscoreSelectors ifTrue:
> +        [^self xLetter].
> +    ^self xIllegal!
> 
> Item was added:
> + ----- Method: Scanner>>xUnderscoreForTokenization (in category 'multi-character scans') -----
> + xUnderscoreForTokenization
> +    "Parse underscores as assignments so as to be able to correctly tokenize ancient source code."
> +    self step.
> +    tokenType := #leftArrow.
> +    ^token := #'_'!
> 
> Item was added:
> + LeafNode subclass: #SelectorNode
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !SelectorNode commentStamp: '<historical>' prior: 0!
> + I am a parse tree leaf representing a selector.!
> 
> Item was added:
> + ----- Method: SelectorNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitSelectorNode: self!
> 
> Item was added:
> + ----- Method: SelectorNode>>emitCode:args:encoder: (in category 'code generation') -----
> + emitCode: stack args: nArgs encoder: encoder
> + 
> +    self emitCode: stack
> +        args: nArgs
> +        encoder: encoder
> +        super: false!
> 
> Item was added:
> + ----- Method: SelectorNode>>emitCode:args:encoder:super: (in category 'code generation') -----
> + emitCode: stack args: nArgs encoder: encoder super: supered
> +    code < Send ifTrue:
> +        [self internalEncodingError].
> +    stack pop: nArgs.
> +    supered
> +        ifTrue:
> +            [(encoder supportsFullBlocks
> +              and: [encoder generatingFullBlock])
> +                ifTrue:
> +                    [encoder genPushLiteral: (encoder sharableLitIndex: encoder classEncoding).
> +                     encoder genSendDirectedSuper: index numArgs: nArgs]
> +                ifFalse: [encoder genSendSuper: index numArgs: nArgs]]
> +        ifFalse:
> +            [encoder genSend: index numArgs: nArgs]!
> 
> Item was added:
> + ----- Method: SelectorNode>>emitCodeForEffect:encoder: (in category 'code generation') -----
> + emitCodeForEffect: stack encoder: encoder
> + 
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: SelectorNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> + 
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: SelectorNode>>emitForEffect:on: (in category 'inappropriate') -----
> + emitForEffect: stack on: strm
> + 
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: SelectorNode>>emitForValue:on: (in category 'inappropriate') -----
> + emitForValue: stack on: strm
> + 
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: SelectorNode>>forSuperSend (in category 'code generation') -----
> + forSuperSend
> +    "Answer the receiver or a derivative, suitable for use in a super send.
> +     This is overridden by SpecialSelectorNode to return a SelectorNode clone."
> +    ^self!
> 
> Item was added:
> + ----- Method: SelectorNode>>internalEncodingError (in category 'private') -----
> + internalEncodingError
> +    self error: 'with the split between SelectorNode and SpecialSelectorNode code should never be < Send for normal sends.'!
> 
> Item was added:
> + ----- Method: SelectorNode>>isForFFICall (in category 'testing') -----
> + isForFFICall
> +    ^key asString includesSubstring: '()/'!
> 
> Item was added:
> + ----- Method: SelectorNode>>isPvtSelector (in category 'testing') -----
> + isPvtSelector
> +    "Answer if this selector node is a private message selector."
> + 
> +    ^key isPvtSelector!
> 
> Item was added:
> + ----- Method: SelectorNode>>key: (in category 'printing') -----
> + key: aSelector
> +    "This is for printing of FFI selectors."
> +    key := aSelector!
> 
> Item was added:
> + ----- Method: SelectorNode>>key:code:index: (in category 'initialize-release') -----
> + key: object code: byte index: idx
> + 
> +    key := object.
> +    code := byte.
> +    index := idx!
> 
> Item was added:
> + ----- Method: SelectorNode>>name:key:index:type: (in category 'initialize-release') -----
> + name: literal key: object index: i type: type
> +    "For compatibility with Encoder>>name:key:class:type:set:"
> +    ^self key: object index: i type: type!
> 
> Item was added:
> + ----- Method: SelectorNode>>printAsFFICallWithArguments:on:indent: (in category 'printing') -----
> + printAsFFICallWithArguments: aSequence on: aStream indent: level
> +    aStream nextPutAll: (key copyUpTo: $)).
> +    aSequence
> +        do: [:arg| arg printOn: aStream indent: level]
> +        separatedBy: [aStream nextPutAll: ', '].
> +    aStream nextPut: $)!
> 
> Item was added:
> + ----- Method: SelectorNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level 
> +    aStream nextPutAll: (key == nil
> +                            ifTrue: ['<key==nil>']
> +                            ifFalse: [key])!
> 
> Item was added:
> + ----- Method: SelectorNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level 
> +    aStream nextPutAll: (key == nil
> +                            ifTrue: ['<key==nil>']
> +                            ifFalse: [key])!
> 
> Item was added:
> + ----- Method: SelectorNode>>reserve: (in category 'code generation') -----
> + reserve: encoder 
> +    "If this is a yet unused literal of type -code, reserve it."
> + 
> +    index ifNil:
> +        [index := encoder sharableLitIndex: key.
> +         code := Send]!
> 
> Item was added:
> + ----- Method: SelectorNode>>resetForBlockGeneration (in category 'code generation') -----
> + resetForBlockGeneration
> +    "Reset the receiver to an unassigned state such that its index
> +     in the encoder's literalStream is as yet to be determined."
> +    code := SendType negated.
> +    index := nil!
> 
> Item was added:
> + ----- Method: SelectorNode>>sizeCode:args:super: (in category 'code generation') -----
> + sizeCode: encoder args: nArgs super: supered
> +    self reserve: encoder.
> +    code < Send ifTrue:
> +        [self internalEncodingError].
> +    supered ifFalse:
> +        [^encoder sizeSend: index numArgs: nArgs].
> +    (encoder supportsFullBlocks
> +     and: [encoder generatingFullBlock]) ifTrue:
> +        [^(encoder sizePushLiteral: (encoder sharableLitIndex: encoder classEncoding))
> +         + (encoder sizeSendDirectedSuper: index numArgs: nArgs)].
> +    ^encoder sizeSendSuper: index numArgs: nArgs!
> 
> Item was added:
> + ----- Method: SelectorNode>>sizeCodeForEffect: (in category 'code generation') -----
> + sizeCodeForEffect: encoder
> + 
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: SelectorNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> + 
> +    self shouldNotImplement!
> 
> Item was added:
> + Notification subclass: #ShadowedVariableNotification
> +    instanceVariableNames: 'name selector class'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !ShadowedVariableNotification commentStamp: 'ct 2/7/2022 22:18' prior: 0!
> + I tell interested exception handlers or the Transcript about an attempt to compile a method with a shadowed variable, i.e., a temporary variable that has the same name as an existing instance variable in the subject class. The use and usage of shadowed variables are generally disputed: They can lead to confusion when a temporary variable declaration is missed, but they can also be utilized to make an instance variable unaccessible in a local scope.!
> 
> Item was added:
> + ----- Method: ShadowedVariableNotification>>defaultAction (in category 'handling') -----
> + defaultAction
> + 
> +    Transcript showln: ('{1} ({2} is shadowed)' translated format:
> +        {self methodClass name , '>>' , self selector.
> +        self variableName}).!
> 
> Item was added:
> + ----- Method: ShadowedVariableNotification>>methodClass (in category 'accessing') -----
> + methodClass
> + 
> +    ^ class!
> 
> Item was added:
> + ----- Method: ShadowedVariableNotification>>name:selector:class: (in category 'initialize-release') -----
> + name: aString selector: aSymbolOrNil class: aBehavior
> + 
> +    name := aString.
> +    selector := aSymbolOrNil.
> +    class := aBehavior.!
> 
> Item was added:
> + ----- Method: ShadowedVariableNotification>>selector (in category 'accessing') -----
> + selector
> + 
> +    ^ selector!
> 
> Item was added:
> + ----- Method: ShadowedVariableNotification>>variableName (in category 'accessing') -----
> + variableName
> + 
> +    ^ name!
> 
> Item was added:
> + LiteralNode subclass: #SpecialLiteralNode
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> 
> Item was added:
> + ----- Method: SpecialLiteralNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    stack push: 1.
> +    encoder genPushSpecialLiteral: key!
> 
> Item was added:
> + ----- Method: SpecialLiteralNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    ^encoder sizePushSpecialLiteral: key!
> 
> Item was added:
> + SelectorNode subclass: #SpecialSelectorNode
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> + 
> + !SpecialSelectorNode commentStamp: 'eem 8/5/2014 20:18' prior: 0!
> + A SpecialSelectorNode is a subclass of SelectorNode that handles the special selectors, a high static and/or dynamic frequency set of selectors that are assigned their own bytecodes.  Special selectors both save space in the literal frame and allow an interpreter to implement these sends directly for certain classes of receiver and argument, for example the SmallIntegers, a technique known as static receiver prediction.!
> 
> Item was added:
> + ----- Method: SpecialSelectorNode>>emitCode:args:encoder:super: (in category 'code generation') -----
> + emitCode: stack args: nArgs encoder: encoder super: supered
> +    "Generate a special selector send.
> +     A super send of a special selector must be handled like a normal send.
> +     This is handled in MessageNode>>sizeCodeForValue: by mapping any
> +     SpecialSelectorNodes used in super sends into normal SelectorNodes."
> +    supered ifTrue: [self invalidSuperSendError].
> +    stack pop: nArgs.
> +    encoder genSendSpecial: code numArgs: nArgs!
> 
> Item was added:
> + ----- Method: SpecialSelectorNode>>forSuperSend (in category 'code generation') -----
> + forSuperSend
> +    "Answer the receiver or a derivative, suitable for use in a super send."
> + 
> +    "Excuse the code negation nonsense.  It is a vestige of a very concise but now
> +     obsolete back-end bytecode encoding scheme. We're working on removing it."
> +    ^SelectorNode new
> +        key: key
> +        code: SendType negated
> +        index: index!
> 
> Item was added:
> + ----- Method: SpecialSelectorNode>>invalidSuperSendError (in category 'private') -----
> + invalidSuperSendError
> +    self error: 'special selectors can only be used for ordinary sends'!
> 
> Item was added:
> + ----- Method: SpecialSelectorNode>>resetForBlockGeneration (in category 'code generation') -----
> + resetForBlockGeneration
> +    "Reset the receiver to an unassigned state such that its index
> +     in the encoder's literalStream is as yet to be determined."
> +    index := nil!
> 
> Item was added:
> + ----- Method: SpecialSelectorNode>>sizeCode:args:super: (in category 'code generation') -----
> + sizeCode: encoder args: nArgs super: supered
> +    "Size a special selector send.
> +     A super send of a special selector must be handled like a normal send.
> +     This is handled in MessageNode>>sizeCodeForValue: by mapping any
> +     SpecialSelectorNodes used in super sends into normal SelectorNodes."
> +    supered ifTrue: [self invalidSuperSendError].
> +    ^encoder sizeSendSpecial: code numArgs: nArgs!
> 
> Item was added:
> + Error subclass: #SyntaxErrorNotification
> +    instanceVariableNames: 'cue doitFlag errorMessage location newSource'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> + 
> + !SyntaxErrorNotification commentStamp: 'ct 10/24/2020 00:01' prior: 0!
> + A SyntaxErrorNotification is an Exception occuring when compiling a Smalltalk source code with incorrect syntax.
> + Note that in interactive mode, this exception is not raised because the Compiler will interact directly with source code editor.
> + The defaultAction is to raise a SyntaxError pop up window so as to enable interactive handling even in non interactive mode.
> + 
> + Instance Variables
> +    cue:        <CompilationCue>
> +    doitFlag:        <Boolean>
> +    errorMessage:        <String>
> +    location:        <Integer>
> +    newSource:        <String | Text | Stream | nil>
> + 
> + cue
> +    - the cue for compilation, including receiver class, optional context, and original source code
> + 
> + doitFlag
> +    - true if this is a doIt (code to evaluate), false if this is a method (code of a method to be compiled)
> + 
> + errorMessage
> +    - contains information about the syntax error
> + 
> + location
> +    - position in the source code where the syntax error occured
> + 
> + newSource
> +    - eventually hold a source code replacement typically passed by the SyntaxError window!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification class>>cue:doitFlag:errorMessage:location: (in category 'instance creation') -----
> + cue: aCue doitFlag: doitFlag errorMessage: errorString location: location
> + 
> +    ^ self new
> +        setCue: aCue
> +        doitFlag: doitFlag
> +        errorMessage: errorString
> +        location: location!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification class>>inClass:withCode:doitFlag:errorMessage:location: (in category 'instance creation') -----
> + inClass: aClass withCode: codeString doitFlag: doitFlag errorMessage: errorString location: location
> + 
> +    self deprecated: 'ct: Use #cue:doitFlag:errorMessage:location:'.
> +    ^ self
> +        cue: (CompilationCue source: codeString class: aClass requestor: nil)
> +        doitFlag: doitFlag
> +        errorMessage: errorString
> +        location: location!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>context (in category 'accessing') -----
> + context
> + 
> +    ^ cue context!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>doitFlag (in category 'accessing') -----
> + doitFlag
> +    ^doitFlag!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>environment (in category 'accessing') -----
> + environment
> + 
> +    ^ cue environment!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>errorClass (in category 'accessing') -----
> + errorClass
> + 
> +    ^ cue getClass!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>errorCode (in category 'accessing') -----
> + errorCode
> + 
> +    ^ cue source!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>errorMessage (in category 'accessing') -----
> + errorMessage
> +    ^errorMessage!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>isResumable (in category 'accessing') -----
> + isResumable
> + 
> +    ^ true!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>location (in category 'accessing') -----
> + location
> +    ^location!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>messageText (in category 'accessing') -----
> + messageText
> +    ^ super messageText
> +        ifEmpty: [messageText := self errorCode]!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>newSource (in category 'accessing') -----
> + newSource
> +    ^newSource!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>reparse:notifying:ifFail: (in category 'accessing') -----
> + reparse: aString notifying: aController ifFail: failBlock
> +    "Try to parse if aString has correct syntax, but do not evaluate/install any code.
> +    In case of incorrect syntax, execute failBlock and let a Compiler interact with the requestor.
> +    In case of correct syntax, set newSource."
> + 
> +    (doitFlag ifTrue: [nil class] ifFalse: [self errorClass]) newCompiler
> +        compileCue: (cue copy
> +            source: aString;
> +            requestor: aController;
> +            yourself)
> +        noPattern: doitFlag
> +        ifFail: failBlock.
> +    newSource := aString.!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>retryWithNewSource: (in category 'handling') -----
> + retryWithNewSource: source
> +    "Retry the compilation with new source code.
> +    Assume
> +    - that the signallerContext will tryNewSourceIfAvailable
> +    - the presence of a handler of ReparseAfterSourceEditing on the sender stack"
> +    
> +    newSource := source.
> +    ^ self resume!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>setCue:doitFlag:errorMessage:location: (in category 'initialize-release') -----
> + setCue: aCue doitFlag: aBoolean errorMessage: errorString location: anInteger
> + 
> +    cue := aCue.
> +    doitFlag := aBoolean.
> +    errorMessage := errorString.
> +    location := anInteger!
> 
> Item was added:
> + ----- Method: SyntaxErrorNotification>>tryNewSourceIfAvailable (in category 'accessing') -----
> + tryNewSourceIfAvailable
> +    newSource ifNotNil: [ReparseAfterSourceEditing withNewSource: newSource]!
> 
> Item was added:
> + 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!
> 
> Item was added:
> + ----- Method: TempVariableNode>>absorbHoistedTemp: (in category 'closure analysis') -----
> + absorbHoistedTemp: aTempVar
> +    "Collapse aTempVar into the receiver, being sure to update any closure analysis."
> +    aTempVar copyScopeAccessTo: self.
> +    aTempVar becomeForward: self!
> 
> Item was added:
> + ----- Method: TempVariableNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitTempVariableNode: self!
> 
> Item was added:
> + ----- Method: TempVariableNode>>addReadWithin:at: (in category 'closure analysis') -----
> + 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]!
> 
> Item was added:
> + ----- Method: TempVariableNode>>addWriteWithin:at: (in category 'closure analysis') -----
> + 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]!
> 
> Item was added:
> + ----- Method: TempVariableNode>>analyseClosure: (in category 'closure analysis') -----
> + 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!
> 
> Item was added:
> + ----- Method: TempVariableNode>>analyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + analyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> +    self addReadWithin: scopeBlock at: rootNode locationCounter!
> 
> Item was added:
> + ----- Method: TempVariableNode>>assignmentCheck:at: (in category 'testing') -----
> + assignmentCheck: encoder at: location
> +    ^((self isBlockArg and: [Scanner allowBlockArgumentAssignment not])
> +        or: [self isMethodArg])
> +            ifTrue: [location]
> +            ifFalse: [-1]!
> 
> Item was added:
> + ----- Method: TempVariableNode>>beBlockArg (in category 'testing') -----
> + beBlockArg
> +    argType := #block!
> 
> Item was added:
> + ----- Method: TempVariableNode>>beMethodArg (in category 'testing') -----
> + beMethodArg
> +    argType := #method!
> 
> Item was added:
> + ----- Method: TempVariableNode>>beingAssignedToAnalyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + 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]]!
> 
> Item was added:
> + ----- Method: TempVariableNode>>copyScopeAccessTo: (in category 'closure analysis') -----
> + copyScopeAccessTo: aTempVar
> +    "For absorbHoistedTemp:, copy the receiver's reads and writes into the record in aTempVar."
> +    readingScopes ifNotNil:
> +        [readingScopes keysAndValuesDo:
> +            [:scopeBlock :reads|
> +             reads do:
> +                [:location|
> +                 aTempVar addReadWithin: scopeBlock "<BlockNode>" at: location]]].
> +    writingScopes ifNotNil:
> +        [writingScopes keysAndValuesDo:
> +            [:scopeBlock :writes|
> +             writes do:
> +                [:location|
> +                 aTempVar addWriteWithin: scopeBlock "<BlockNode>" at: location]]]!
> 
> Item was added:
> + ----- Method: TempVariableNode>>definingScope (in category 'closure analysis') -----
> + definingScope
> +    ^definingScope!
> 
> Item was added:
> + ----- Method: TempVariableNode>>definingScope: (in category 'closure analysis') -----
> + definingScope: scopeBlock "<BlockNode>"
> +    definingScope = scopeBlock ifTrue: [^ self]. "No need to bail"
> +    definingScope ifNotNil:
> +        [self error: 'temp has more than one defining scope.  This is probably a parser error'].
> +    definingScope := scopeBlock!
> 
> Item was added:
> + ----- Method: TempVariableNode>>emitCodeForStore:encoder: (in category 'code generation') -----
> + emitCodeForStore: stack encoder: encoder
> +    remoteNode ~~ nil ifTrue:
> +        [^remoteNode emitCodeForStoreInto: self stack: stack encoder: encoder].
> +    encoder genStoreTemp: index!
> 
> Item was added:
> + ----- Method: TempVariableNode>>emitCodeForStorePop:encoder: (in category 'code generation') -----
> + emitCodeForStorePop: stack encoder: encoder
> +    remoteNode ~~ nil ifTrue:
> +        [^remoteNode emitCodeForStorePopInto: self stack: stack encoder: encoder].
> +    encoder genStorePopTemp: index.
> +    stack pop: 1!
> 
> Item was added:
> + ----- Method: TempVariableNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + emitCodeForValue: stack encoder: encoder
> +    remoteNode ~~ nil ifTrue:
> +        [^remoteNode emitCodeForValueOf: self stack: stack encoder: encoder].
> +    encoder genPushTemp: index.
> +    stack push: 1!
> 
> Item was added:
> + ----- Method: TempVariableNode>>index: (in category 'closure analysis') -----
> + index: anInteger
> +    "For renumbering temps in the closure compiler."
> +    index := anInteger.
> +    code := self code: index type: LdTempType!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isArg (in category 'testing') -----
> + isArg
> +    ^argType notNil!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isBlockArg (in category 'testing') -----
> + isBlockArg
> +    ^#block == argType!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isDeclaredAtMethodLevel (in category 'testing') -----
> + isDeclaredAtMethodLevel
> +    "For the explainer."
> +    ^scope = 0!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isDefinedWithinBlockExtent: (in category 'closure analysis') -----
> + isDefinedWithinBlockExtent: anInterval
> +    ^anInterval rangeIncludes: definingScope actualScope blockExtent first!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isIndirectTempVector (in category 'closure analysis') -----
> + isIndirectTempVector
> +    ^false!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isMethodArg (in category 'testing') -----
> + isMethodArg
> +    ^#method == argType!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isReferencedWithinBlockExtent: (in category 'closure analysis') -----
> + 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!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isRemote (in category 'testing') -----
> + isRemote
> +    ^remoteNode notNil!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isTemp (in category 'testing') -----
> + isTemp
> +    ^ true!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isUndefTemp (in category 'testing') -----
> + isUndefTemp
> +    ^ hasDefs not!
> 
> Item was added:
> + ----- Method: TempVariableNode>>isUnusedTemp (in category 'testing') -----
> + isUnusedTemp
> +    ^ hasRefs not!
> 
> Item was added:
> + ----- Method: TempVariableNode>>name:index:type:scope: (in category 'initialize-release') -----
> + 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!
> 
> Item was added:
> + ----- Method: TempVariableNode>>nowHasDef (in category 'initialize-release') -----
> + nowHasDef
> +    hasDefs := true!
> 
> Item was added:
> + ----- Method: TempVariableNode>>nowHasRef (in category 'initialize-release') -----
> + nowHasRef
> +    hasRefs := true!
> 
> Item was added:
> + ----- Method: TempVariableNode>>printDefinitionForClosureAnalysisOn: (in category 'printing') -----
> + 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 sorted do: [:read| aStream nextPutAll: ' r@'; print: read]].
> +    writingScopes notNil ifTrue:
> +        [refs := Set new.
> +        writingScopes do: [:elems| refs addAll: elems].
> +        refs sorted do: [:write| aStream nextPutAll: ' w@'; print: write]].
> +    aStream nextPut: $}!
> 
> Item was added:
> + ----- Method: TempVariableNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level 
> + 
> +    aStream nextPutAll: name!
> 
> Item was added:
> + ----- Method: TempVariableNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level 
> + 
> +    aStream nextPutAll: name.
> +    readingScopes notNil ifTrue:
> +        [(readingScopes inject: Set new into: [:them :reads| them addAll: reads. them]) sorted do:
> +            [:location|
> +            aStream space; nextPut: $r; nextPut: $@; print: location]].
> +    writingScopes notNil ifTrue:
> +        [(writingScopes inject: Set new into: [:them :writes| them addAll: writes. them]) sorted do:
> +            [:location|
> +            aStream space; nextPut: $w; nextPut: $@; print: location]]!
> 
> Item was added:
> + ----- Method: TempVariableNode>>referenceScopesAndIndicesDo: (in category 'closure analysis') -----
> + 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]]]!
> 
> Item was added:
> + ----- Method: TempVariableNode>>remoteNode (in category 'testing') -----
> + remoteNode
> +    ^remoteNode!
> 
> Item was added:
> + ----- Method: TempVariableNode>>remoteNode: (in category 'decompiler') -----
> + remoteNode: aRemoteTempVectorNode
> +    remoteNode := aRemoteTempVectorNode!
> 
> Item was added:
> + ----- Method: TempVariableNode>>resetFromCopy: (in category 'code generation') -----
> + resetFromCopy: aFieldNode
> +    "Reset the state of the recever to match that of the argument.
> +     This is used to reset nodes that may have been repurposed
> +     while generatig the compiled method for a full block.
> +     Temps are managed via the reindexingLocalsDo:encoder: route,
> +     not via reindexingLiteralsDo:."
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: TempVariableNode>>scope (in category 'testing') -----
> + 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!
> 
> Item was added:
> + ----- Method: TempVariableNode>>scope: (in category '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!
> 
> Item was added:
> + ----- Method: TempVariableNode>>sizeCodeForStore: (in category 'code generation') -----
> + sizeCodeForStore: encoder
> +    remoteNode ~~ nil ifTrue:
> +        [^remoteNode sizeCodeForStoreInto: self encoder: encoder].
> +    self reserve: encoder.
> +    ^encoder sizeStoreTemp: index!
> 
> Item was added:
> + ----- Method: TempVariableNode>>sizeCodeForStorePop: (in category 'code generation') -----
> + sizeCodeForStorePop: encoder
> +    remoteNode ~~ nil ifTrue:
> +        [^remoteNode sizeCodeForStorePopInto: self encoder: encoder].
> +    self reserve: encoder.
> +    ^encoder sizeStorePopTemp: index!
> 
> Item was added:
> + ----- Method: TempVariableNode>>sizeCodeForValue: (in category 'code generation') -----
> + sizeCodeForValue: encoder
> +    remoteNode ~~ nil ifTrue:
> +        [^remoteNode sizeCodeForValueOf: self encoder: encoder].
> +    self reserve: encoder.
> +    ^encoder sizePushTemp: index!
> 
> Item was added:
> + ParserNotification subclass: #UndeclaredVariable
> +    instanceVariableNames: 'parser interval'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> 
> Item was added:
> + ----- Method: UndeclaredVariable class>>signalFor:name:inRange: (in category 'instance creation') -----
> + signalFor: aParser name: aString inRange: anInterval 
> +    ^ (self new setParser: aParser name: aString range: anInterval) signal!
> 
> Item was added:
> + ----- Method: UndeclaredVariable>>openMenuIn: (in category 'handling') -----
> + openMenuIn: aBlock 
> +    | alternatives labels actions lines caption choice |
> +    alternatives := parser possibleVariablesFor: name.
> +    labels := OrderedCollection new.
> +    actions := OrderedCollection new.
> +    lines := OrderedCollection new.
> +    name first isLowercase 
> +        ifTrue: 
> +            [labels add: 'declare method temp' translated.
> +            actions add: [parser declareTemp: name at: #method].
> +            labels add: 'declare block-local temp' translated.
> +            actions add: [parser declareTemp: name at: #block].
> +            parser canDeclareInstanceVariable 
> +                ifTrue: 
> +                    [labels add: 'declare instance' translated.
> +                    actions add: [parser declareInstVar: name]]]
> +        ifFalse: 
> +            [labels add: 'define new class' translated.
> +            actions add: [parser defineClass: name].
> +            labels add: 'declare global' translated.
> +            actions add: [parser declareGlobal: name].
> +            parser canDeclareClassVariable
> +                ifTrue: 
> +                    [labels add: 'declare class variable' translated.
> +                    actions add: [parser declareClassVar: name]]].
> +    lines add: labels size.
> +    alternatives do: 
> +        [:each | 
> +        labels add: each.
> +        actions add: [parser substituteVariable: each atInterval: interval]].
> +    lines add: labels size.
> +    labels add: 'cancel' translated.
> +    caption := 'Unknown variable: {1}!! please correct, or cancel:' translated format: {name}.
> +    choice := aBlock value: labels value: lines value: caption.
> +    self resume: (actions at: choice ifAbsent: [nil])!
> 
> Item was added:
> + ----- Method: UndeclaredVariable>>setParser:name:range: (in category 'initialize-release') -----
> + setParser: aParser name: aString range: anInterval 
> +    parser := aParser.
> +    name := aString.
> +    interval := anInterval!
> 
> Item was added:
> + VariableNode subclass: #UndeclaredVariableNode
> +    instanceVariableNames: 'tag'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-ParseNodes'!
> 
> Item was added:
> + ----- Method: UndeclaredVariableNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitUndeclaredVariableNode: self!
> 
> Item was added:
> + ----- Method: UndeclaredVariableNode>>isUndeclared (in category 'testing') -----
> + isUndeclared
> +    ^true!
> 
> Item was added:
> + ----- Method: UndeclaredVariableNode>>tag (in category 'accessing') -----
> + tag
> +    "Tag can be whatever one wants it to be; used by Parser to tag
> +      undeclared temps with the user's desired declaration level."
> + 
> +    ^tag!
> 
> Item was added:
> + ----- Method: UndeclaredVariableNode>>tag: (in category 'accessing') -----
> + tag: anObject
> +    "Tag can be whatever one wants it to be; used by Parser to tag
> +      undeclared temps with the user's desired declaration level."
> + 
> +    tag := anObject!
> 
> Item was added:
> + Notification subclass: #UndeclaredVariableNotification
> +    instanceVariableNames: 'name selector class'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> 
> Item was added:
> + ----- Method: UndeclaredVariableNotification>>defaultAction (in category 'exceptionDescription') -----
> + 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!
> 
> Item was added:
> + ----- Method: UndeclaredVariableNotification>>defaultResumeValue (in category 'initialize-release') -----
> + defaultResumeValue
> +    "Answer the value that by default should be returned if the exception is resumed"
> +    ^true!
> 
> Item was added:
> + ----- Method: UndeclaredVariableNotification>>name:selector:class: (in category 'initialize-release') -----
> + name: aString selector: aSymbolOrNil class: aBehavior
> +    name := aString.
> +    selector := aSymbolOrNil.
> +    class := aBehavior!
> 
> Item was added:
> + ParserNotification subclass: #UndefinedVariable
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> 
> Item was added:
> + ----- Method: UndefinedVariable>>openMenuIn: (in category 'handling') -----
> + openMenuIn: aBlock
> + 
> +    self resume: (Project uiManager
> +        confirm: ('{1} appears to be undefined at this point.\Proceed anyway?' translated withCRs asText
> +            format: {name asText allBold})
> +        orCancel: [false]
> +        title: 'Undefined Variable' translated).!
> 
> Item was added:
> + ParserNotification subclass: #UnknownSelector
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> 
> Item was added:
> + ----- Method: UnknownSelector>>openMenuIn: (in category 'handling') -----
> + openMenuIn: aBlock
> +    | alternatives labels lines caption choice |
> +    alternatives := Symbol possibleSelectorsFor: name.
> +    labels := Array streamContents:
> +                [:s | s nextPut: name; nextPutAll: alternatives].
> +    lines := {1. alternatives size + 1}.
> +    caption := 'Unknown selector, please\confirm, correct, or cancel' translated withCRs.
> +    
> +    choice := aBlock value: labels value: lines value: caption.
> +    
> +    choice = 0 ifTrue: [^ self resume: nil].
> +    choice = 1 ifTrue: [^ self resume: name asSymbol].
> +    self resume: (alternatives at: choice - 1)!
> 
> Item was added:
> + ParserNotification subclass: #UnusedVariable
> +    instanceVariableNames: ''
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Exceptions'!
> 
> Item was added:
> + ----- Method: UnusedVariable>>openMenuIn: (in category 'handling') -----
> + openMenuIn: aBlock
> +    
> +    self resume: (Project uiManager
> +        confirm: ('{1} appears to be unused in this method.\Remove it from the code?' translated withCRs asText
> +            format: {name asText allBold})
> +        orCancel: [nil]
> +        title: 'Unused Variable' translated).!
> 
> Item was added:
> + 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.!
> 
> Item was added:
> + ----- Method: VariableNode class>>initialize (in category 'class initialization') -----
> + initialize    "VariableNode 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: SpecialSelectorNode
> +        mapping: ((1 to: Smalltalk specialSelectorSize) collect: 
> +                            [:i | Smalltalk specialSelectorAt: i])
> +        to: (1 to: Smalltalk specialSelectorSize) asArray.
> +    StdLiterals := PluggableDictionary new equalBlock: #literalEqual:. "This is at least as fast as a block and eliminates a recompileAll dependency. eem 10/8/2019"
> +    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'!
> 
> Item was added:
> + ----- Method: VariableNode>>accept: (in category 'visiting') -----
> + accept: aVisitor
> +    ^aVisitor visitVariableNode: self!
> 
> Item was added:
> + ----- Method: VariableNode>>asStorableNode: (in category 'initialize-release') -----
> + asStorableNode: encoder
> +    ^ self!
> 
> Item was added:
> + ----- Method: VariableNode>>assignmentCheck:at: (in category 'testing') -----
> + assignmentCheck: encoder at: location
> +    ^(encoder cantStoreInto: name) ifTrue: [location] ifFalse: [-1]!
> 
> Item was added:
> + ----- Method: VariableNode>>beingAssignedToAnalyseTempsWithin:rootNode:assignmentPools: (in category 'closure analysis') -----
> + beingAssignedToAnalyseTempsWithin: scopeBlock "<BlockNode>" rootNode: rootNode "<MethodNode>" assignmentPools: assignmentPools "<Dictionary>"
> +    "No-op overridden by TempVariableNode"!
> 
> Item was added:
> + ----- Method: VariableNode>>emitCodeForReturn:encoder: (in category 'code generation') -----
> + 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!
> 
> Item was added:
> + ----- Method: VariableNode>>emitCodeForStore:encoder: (in category 'code generation') -----
> + emitCodeForStore: stack encoder: encoder
> + 
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: VariableNode>>emitCodeForStorePop:encoder: (in category 'code generation') -----
> + emitCodeForStorePop: stack encoder: encoder
> +    self type ~= 1 ifTrue:
> +        [self halt].
> +    encoder genStorePopInstVar: index.
> +    stack pop: 1!
> 
> Item was added:
> + ----- Method: VariableNode>>emitCodeForValue:encoder: (in category 'code generation') -----
> + 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 error: 'internal compiler error; should not happen'!
> 
> Item was added:
> + ----- Method: VariableNode>>fieldOffset (in category 'code generation') -----
> + fieldOffset
> +    "Return temp or instVar offset for this variable"
> +    ^index ifNil: [code < 256
> +                    ifTrue: [code \\ 16]
> +                    ifFalse: [code \\ 256]]!
> 
> Item was added:
> + ----- Method: VariableNode>>index (in category 'testing') -----
> + index
> +    "If index is nil, this code attempts to reconstruct the index from its encoding in code."
> +    index ifNotNil:
> +        [^index].
> +    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!
> 
> Item was added:
> + ----- Method: VariableNode>>isSelfPseudoVariable (in category 'testing') -----
> + isSelfPseudoVariable
> +    "Answer if this ParseNode represents the 'self' pseudo-variable."
> + 
> +    ^ key = 'self' or: [name = '{{self}}']!
> 
> Item was added:
> + ----- Method: VariableNode>>isUndeclared (in category 'testing') -----
> + isUndeclared
> +    ^false!
> 
> Item was added:
> + ----- Method: VariableNode>>isVariableNode (in category 'testing') -----
> + isVariableNode
> +    ^true!
> 
> Item was added:
> + ----- Method: VariableNode>>isVariableReference (in category 'testing') -----
> + isVariableReference
> + 
> +    ^true!
> 
> Item was added:
> + ----- Method: VariableNode>>name (in category 'accessing') -----
> + name
> +    ^ name!
> 
> Item was added:
> + ----- Method: VariableNode>>name: (in category 'initialize-release') -----
> + name: string
> +    "Change name"
> + 
> +    name := string!
> 
> Item was added:
> + ----- Method: VariableNode>>name:index:type: (in category 'initialize-release') -----
> + name: varName index: i type: type
> +    "Only used for initting instVar refs"
> +    ^self name: varName key: varName index: i type: type!
> 
> Item was added:
> + ----- Method: VariableNode>>name:key:code: (in category 'initialize-release') -----
> + name: string key: object code: byte
> +    "Only used for initting std variables, nil, true, false, self, etc."
> +    name := string.
> +    key := object.
> +    code := byte!
> 
> Item was added:
> + ----- Method: VariableNode>>name:key:index:type: (in category 'initialize-release') -----
> + 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)!
> 
> Item was added:
> + ----- Method: VariableNode>>printOn:indent: (in category 'printing') -----
> + printOn: aStream indent: level 
> + 
> +    aStream nextPutAll: name!
> 
> Item was added:
> + ----- Method: VariableNode>>printWithClosureAnalysisOn:indent: (in category 'printing') -----
> + printWithClosureAnalysisOn: aStream indent: level 
> + 
> +    aStream nextPutAll: name!
> 
> Item was added:
> + ----- Method: VariableNode>>resetFromCopy: (in category 'code generation') -----
> + resetFromCopy: aVariableNode
> +    "Reset the state of the recever to match that of the argument.
> +     This is used to reset nodes that may have been repurposed
> +     while generatig the compiled method for a full block."
> + 
> +    self assert: name == aVariableNode name.
> +    super resetFromCopy: aVariableNode!
> 
> Item was added:
> + ----- Method: VariableNode>>sizeCodeForReturn: (in category 'code generation') -----
> + sizeCodeForReturn: encoder
> +    encoder
> +        if: code
> +        isSpecialLiteralForReturn:
> +            [:specialLiteral|
> +             ^encoder sizeReturnSpecialLiteral: specialLiteral].
> +    (self code = LdSelf or: [self code = LdSuper]) ifTrue:
> +        [^encoder sizeReturnReceiver].
> +    ^super sizeCodeForReturn: encoder!
> 
> Item was added:
> + ----- Method: VariableNode>>sizeCodeForStore: (in category 'code generation') -----
> + sizeCodeForStore: encoder
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: VariableNode>>sizeCodeForStorePop: (in category 'code generation') -----
> + sizeCodeForStorePop: encoder
> +    self shouldNotImplement!
> 
> Item was added:
> + ----- Method: VariableNode>>sizeCodeForValue: (in category 'code generation') -----
> + 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 error: 'internal compiler error; should not happen'!
> 
> Item was added:
> + ----- Method: VariableNode>>type (in category 'testing') -----
> + 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]!
> 
> Item was added:
> + ParseNodeVisitor subclass: #VariableScopeFinder
> +    instanceVariableNames: 'theVariable'
> +    classVariableNames: ''
> +    poolDictionaries: ''
> +    category: 'Compiler-Support'!
> + 
> + !VariableScopeFinder commentStamp: 'eem 8/14/2010 19:45' prior: 0!
> + A VariableScopeFinder is used to find the minimum enclosing scope of a variable in a method.  This is used when auto-declaring temporaries to find the smallest enclosing block in which to declare the temp.
> + 
> + Instance Variables
> +    theVariable:        <VariableNode>
> + 
> + theVariable
> +    - the varable whose scope is to be determined
> + !
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>enclosingNodeFor:of: (in category 'private') -----
> + enclosingNodeFor: enumerator of: rootNode
> +    "Answer the minimum enclosing root node for aVariabe or nil if none.
> +     If the variable is accessed in more than one subnode then the rootNode is the
> +     enclosing node, otherwise it is which ever single subnode node that includes it, if any.
> +     enumerator applies its argument to all relevant subnodes of rootNode."
> +    | enclosingNodeOrNil |
> +    enclosingNodeOrNil := nil.
> +    enumerator value:
> +        [:subnode|
> +        (subnode accept: self) ifNotNil:
> +            [:enclosingNode|
> +            enclosingNodeOrNil := enclosingNodeOrNil
> +                                        ifNil: [enclosingNode]
> +                                        ifNotNil: [rootNode]]].
> +    ^enclosingNodeOrNil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>ofVariable: (in category 'initialize-release') -----
> + ofVariable: aVariableNode
> +    theVariable := aVariableNode!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitAssignmentNode: (in category 'visiting') -----
> + visitAssignmentNode: anAssignmentNode
> +    "Answer the minimum enclosing node for aVariabe or nil if none.
> +     If the variable is accessed in more than one subexpression then anAssignmentNode
> +     is the enclosing node, otherwise it is which ever single node that includes it, if any."
> +    ^self
> +        enclosingNodeFor: [:aBlock|
> +                            aBlock
> +                                value: anAssignmentNode value;
> +                                value: anAssignmentNode variable]
> +        of: anAssignmentNode!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitBlockNode: (in category 'visiting') -----
> + visitBlockNode: aBlockNode
> +    "Answer the minimum enclosing node for aVariabe or nil if none.
> +     If the variable is accessed in more than one statement then aBlockNode is the
> +     enclosing node, otherwise it is which ever single block node that includes it, if any."
> +    ^(self enclosingNodeFor: [:aBlock| aBlockNode statements do: aBlock] of: aBlockNode) ifNotNil:
> +        [:aNode|
> +        aNode isBlockNode ifTrue: [aNode] ifFalse: [aBlockNode]]!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitBraceNode: (in category 'visiting') -----
> + visitBraceNode: aBraceNode
> +    "Answer the minimum enclosing node for aVariabe or nil if none.
> +     If the variable is accessed in more than one subexpression then aBraceNode
> +     is the enclosing node, otherwise it is which ever single node that includes it, if any."
> +    ^self
> +        enclosingNodeFor: [:aBlock| aBraceNode elements do: aBlock]
> +        of: aBraceNode!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitCascadeNode: (in category 'visiting') -----
> + visitCascadeNode: aCascadeNode
> +    "Answer the minimum enclosing node for aVariabe or nil if none.
> +     If the variable is accessed in more than one subexpression then aMessageNode is the
> +     enclosing node, otherwise it is which ever single node that includes it, if any."
> +    ^self
> +        enclosingNodeFor: [:aBlock|
> +                            aBlock value: aCascadeNode receiver.
> +                            aCascadeNode messages do:
> +                                [:msg| msg argumentsInEvaluationOrder do: aBlock]]
> +        of: aCascadeNode!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitCommentNode: (in category 'visiting') -----
> + visitCommentNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitFieldNode: (in category 'visiting') -----
> + visitFieldNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitFutureNode: (in category 'visiting') -----
> + visitFutureNode: aFutureNode
> +    ^aFutureNode receiver accept: self!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitInstanceVariableNode: (in category 'visiting') -----
> + visitInstanceVariableNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitLiteralNode: (in category 'visiting') -----
> + visitLiteralNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitLiteralVariableNode: (in category 'visiting') -----
> + visitLiteralVariableNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitMessageNode: (in category 'visiting') -----
> + visitMessageNode: aMessageNode
> +    "Answer the minimum enclosing node for aVariabe or nil if none.
> +     If the variable is accessed in more than one subexpression then aMessageNode is the
> +     enclosing node, otherwise it is which ever single node that includes it, if any."
> +    ^self
> +        enclosingNodeFor: [:aBlock|
> +                            aBlock value: aMessageNode receiver.
> +                            aMessageNode argumentsInEvaluationOrder do: aBlock]
> +        of: aMessageNode!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitMethodNode: (in category 'visiting') -----
> + visitMethodNode: aMethodNode
> +    ^aMethodNode block accept: self!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitNewArrayNode: (in category 'visiting') -----
> + visitNewArrayNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitRemoteTempVectorNode: (in category 'visiting') -----
> + visitRemoteTempVectorNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitReturnNode: (in category 'visiting') -----
> + visitReturnNode: aReturnNode
> +    ^aReturnNode expr accept: self!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitSelectorNode: (in category 'visiting') -----
> + visitSelectorNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitTempVariableNode: (in category 'visiting') -----
> + visitTempVariableNode: aNode
> +    ^nil!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitUndeclaredVariableNode: (in category 'visiting') -----
> + visitUndeclaredVariableNode: aVariableNode
> +    ^theVariable name = aVariableNode name ifTrue: [theVariable]!
> 
> Item was added:
> + ----- Method: VariableScopeFinder>>visitVariableNode: (in category 'visiting') -----
> + visitVariableNode: aVariableNode
> +    ^nil!
> 
> Item was added:
> + (PackageInfo named: 'Compiler') postscript: '"below, add code to be run after the loading of this package"
> + 
> + "Recompile senders of caseOf:"
> + self systemNavigation allSelectorsAndMethodsDo: [ :behavior :selector :method |
> +    (method hasLiteral: #caseOf:)
> +        ifTrue: [behavior recompile: selector]].
> + 
> + "Treat non-breaking space (16ra0) as delimiter in parser/scanner (Compiler-ct.473)."
> + Scanner initialize.'!
> 
> 
> 


More information about the Squeak-dev mailing list