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

