#class(#pointer) Context(Apex) { #dcl sender ip sp ntmprs. #method sender { ^self.sender } #method isDead { ^self.ip < 0 } #method temporaryCount { ^self.ntmprs } (* --------------------------------- #method varargCount { method context, ^do calculation... for a block context, it must access homeContext first and call varargCount ^self.home varargCount... } #method varargAt: index { method context ^do calculation... block context... ^self.home varargAt: index } ---------------------------------- *) } #class(#pointer) MethodContext(Context) { #dcl method receiver home origin. #method pc { ^self.ip } #method pcplus1 { ^self.ip + 1 } #method goto: anInteger { self primitiveFailed. ## TODO: need to make this a hard failure? } #method pc: anInteger { self.ip := anInteger. } #method sp { ^self.sp. } #method sp: new_sp { self.sp := new_sp } #method pc: new_pc sp: new_sp { self.ip := new_pc. self.sp := new_sp. } #method method { ^self.method } #method varArgCount { ^self basicSize - self class specNumInstVars - self.ntmprs } } #class(#pointer) BlockContext(Context) { #dcl nargs source home origin. #method varArgCount { ^self.home varArgCount } #method fork { "crate a new process in the runnable state" ^self newProcess resume. } #method newProcess { "create a new process in the suspended state" self primitiveFailed. } #method newProcessWith: anArray { "create a new process in the suspended state passing the elements of anArray as block arguments" self primitiveFailed. } #method value { self primitiveFailed. } #method value: a { self primitiveFailed. } #method value: a value: b { self primitiveFailed. } #method value: a value: b value: c { self primitiveFailed. } #method value: a value: b value: c value: d { self primitiveFailed. } #method value: a value: b value: c value: d value: e { self primitiveFailed. } #method ifTrue: aBlock { ^(self value) ifTrue: aBlock. } #method ifFalse: aBlock { ^(self value) ifFalse: aBlock. } #method ifTrue: trueBlock ifFalse: falseBlock { ^(self value) ifTrue: trueBlock ifFalse: falseBlock } #method whileTrue: aBlock { ## -------------------------------------------------- ## Naive implementation ## -------------------------------------------------- ## (self value) ifFalse: [^nil]. ## aBlock value. ## self whileTrue: aBlock. ## -------------------------------------------------- ## -------------------------------------------------- ## Non-recursive implementation ## -------------------------------------------------- | pc sp | pc := thisContext pcplus1. (self value) ifFalse: [ ^nil ]. aBlock value. ## the pc: method leaves thisContext and pc in the stack after ## having changes the instruction poointer. ## as a result, the stack keeps growing. the goto method ## clears thisContext and pc off the stack unlike normal methods. ##thisContext pc: pc. thisContext goto: pc. ## -------------------------------------------------- } #method whileTrue { ## (self value) ifFalse: [^nil]. ## self whileTrue. ## -------------------------------------------------- ## Non-recursive implementation ## -------------------------------------------------- | pc | pc := thisContext pcplus1. (self value) ifFalse: [ ^nil ]. thisContext goto: pc. ## -------------------------------------------------- } #method whileFalse: aBlock { ## -------------------------------------------------- ## Naive implementation ## -------------------------------------------------- ## (self value) ifTrue: [^nil]. ## aBlock value. ## self whileFalse: aBlock. ## -------------------------------------------------- ## -------------------------------------------------- ## Non-recursive implementation ## -------------------------------------------------- ## The assignment to 'pc' uses the POP_INTO_TEMPVAR_1. ## It pops a value off the stack top, stores it to the second ## temporary variable(aBlock is the first temporary variable). ## It is a single byte instruction. 'pc' returned by ## 'thisContext pcplus1'' should point to the instruction after ## the POP_INTO_TEMPVAR_0 instruction. ## ## It would need the increment of 2 if the pair of ## STORE_INTO_TEMPVAR_1 and POP_STACKTOP were used. ## This implementation is subject to the instructions chosen ## by the compiler. ## | pc | pc := thisContext pcplus1. (self value) ifTrue: [ ^nil "^self" ]. aBlock value. thisContext goto: pc. ## -------------------------------------------------- } #method whileFalse { ## (self value) ifTrue: [^nil]. ## self whileFalse. ## -------------------------------------------------- ## Non-recursive implementation ## -------------------------------------------------- | pc | pc := thisContext pcplus1. (self value) ifTrue: [ ^nil "^self" ]. thisContext goto: pc. ## -------------------------------------------------- } #method pc { ^self.ip } #method pc: anInteger { self.ip := anInteger. } #method sp { ^self.sp } #method sp: anInteger { self.sp := anInteger. } #method restart { ip := self.source pc. } }