'From Squeak5.3beta of 21 February 2020 [latest update: #19389] on 22 February 2020 at 6:33:22 pm'! !Object methodsFor: 'error handling' stamp: 'ct 2/22/2020 17:22'! caseError "Report an error from an in-line or explicit case statement." self error: ('Case not found ({1}), and no otherwise clause' format: {self printString})! ! !MessageNode methodsFor: 'code generation' stamp: 'ct 2/22/2020 18:28'! 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 :isLast | | thenSize elseSize dropReceiver | thenSize := sizeStream next. elseSize := sizeStream next. dropReceiver := isLast and: [arguments size >= 2]. 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]. (isLast and: [allReturn]) ifTrue: [ self emitCodeForJump: elseSize encoder: encoder]]. arguments at: 2 ifPresent: [:otherwiseBlock | otherwiseBlock emitCodeForEvaluatedValue: stack encoder: encoder] ifAbsent: [ "self caseError" caseErrorNode emitCode: stack args: 0 encoder: encoder].! ! !MessageNode methodsFor: 'code generation' stamp: 'ct 2/22/2020 18:28'! 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 at: 2 ifPresent: [:otherwiseBlock | otherwiseBlock sizeCodeForEvaluatedValue: encoder] ifAbsent: [ "self caseError" caseErrorNode := encoder encodeSelector: #caseError. (caseErrorNode sizeCode: encoder args: 0 super: false)]. "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 :isLast | valueNode returns ifFalse: [allReturn := false]]. braceNode casesReverseDo: [:keyNode :valueNode :isLast | | thenSize dropReceiver | dropReceiver := isLast 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)]. (isLast 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! !