<> <<>> <> <> <> <> <> DIRECTORY JaM USING [AGet, Any, Array, Command, ErrorType, ExecuteRope, Load, Op, Pop, PopBool, PopInt, Push, PushInt, ROPE, State, AtomToRope], Rope USING [ROPE, Concat], IO USING [PutRope], Process USING [Yield], JaMPrimitives USING []; JaMExecImpl: CEDAR PROGRAM IMPORTS JaM, IO, Process, Rope EXPORTS JaM, JaMPrimitives = BEGIN OPEN JaM; <> Error: PUBLIC ERROR[type: ErrorType, msg: Rope.ROPE _ NIL] = CODE; Exit: PUBLIC ERROR = CODE; Stop: PUBLIC ERROR = CODE; ExecuteCommand: PROC[self: State, command: Command] = INLINE { command.proc[self] }; ExecuteOp: PROC[self: State, op: Op] = INLINE { ExecuteAny[self, op.body] }; ExecuteAtom: PROC[self: State, atom: ATOM] = INLINE { Execute[self, Load[self, atom]] }; Execute: PUBLIC PROC[self: State, x: Any] = { DoIt: PROC = { IF self.aborted THEN {self.aborted _ FALSE; ERROR Stop}; WITH x SELECT FROM x: ATOM => ExecuteAtom[self, x]; x: Command => ExecuteCommand[self, x]; x: Op => ExecuteOp[self, x]; ENDCASE => Push[self, x]; }; DoIt [! Error => { rope: ROPE _ IF msg#NIL THEN msg ELSE SELECT type FROM AttachmentCycle => "attachment cycle", BoundsFault => "bounds fault", DictionaryUnderflow => "dictionary underflow", InvalidArgs => "invalid arguments", LoadFailed => "load failed", NotAttached => "not attached", NumericOverflow => "numeric overflow", OpenFailed => "open failed", StackOverflow => "stack overflow", StackUnderflow => "stack underflow", UndefinedKey => Rope.Concat["undefined key: ", AtomToRope[NARROW[x]]], Unimplemented => "unimplemented", WrongMark => "wrong mark", WrongType => "wrong type", ENDCASE => "unknown error"; self.out.PutRope[rope]; self.out.PutRope["\n"]; ERROR Stop; }]; Process.Yield[]; --to help abort infinite loops <> <> <> <> <<};>> }; ExecuteAny: PROC[self: State, x: Any] = { WITH x SELECT FROM x: ATOM => ExecuteAtom[self, x]; x: Command => ExecuteCommand[self, x]; x: Op => ExecuteOp[self, x]; x: Array => ExecuteArray[self, x]; x: ROPE => ExecuteRope[self, x]; ENDCASE => Push[self, x]; }; ExecuteArray: PROC[self: State, array: Array] = { FOR i: INT IN[0..array.length) DO Execute[self, AGet[array, i]]; ENDLOOP; }; GetAbort: PUBLIC PROC[self: State] RETURNS[BOOL] = { RETURN[self.aborted] }; SetAbort: PUBLIC PROC[self: State, b: BOOL] = { self.aborted _ b }; <<"Stop" clears the execution stack and returns to the caller>> <> ApplyStop: PUBLIC PROC[self: State] = { ERROR Stop; }; <<"Exec" executes the object on top of the operand stack.>> ApplyExec: PUBLIC PROC[self: State] = { Execute[self, Pop[self]]; }; <<"If" is the implementation of the testing instruction.>> <> <> <> ApplyIf: PUBLIC PROC[self: State] = { x: Any = Pop[self]; b: BOOL = PopBool[self]; IF b THEN Execute[self, x]; }; <<"IfElse" is the implementation of the two way conditional execution>> <> <> <> ApplyIfElse: PUBLIC PROC[self: State] = { xF: Any = Pop[self]; xT: Any = Pop[self]; b: BOOL = PopBool[self]; Execute[self, IF b THEN xT ELSE xF]; }; <<"Rept" is the "loop for count" instruction. Two operands are required:>> <> <> ApplyRept: PUBLIC PROC[self: State] = { x: Any = Pop[self]; n: INT = PopInt[self]; THROUGH [0..n) DO Execute[self, x ! Exit => EXIT] ENDLOOP; }; <<"For" is based on the Algol "for n _ i step j until k do" instruction.>> <> <> <> ApplyFor: PUBLIC PROC[self: State] = { x: Any = Pop[self]; k: INT = PopInt[self]; j: INT = PopInt[self]; i: INT = PopInt[self]; IF j>=0 THEN FOR n: INT _ i, n+j UNTIL n>k DO PushInt[self, n]; Execute[self, x ! Exit => EXIT]; ENDLOOP ELSE FOR n: INT _ i, n+j UNTIL n EXIT]; ENDLOOP; }; <<"Loop" is the "loop forever" instruction. One operand is required:>> <> ApplyLoop: PUBLIC PROC[self: State] = { x: Any = Pop[self]; DO Execute[self, x ! Exit => EXIT] ENDLOOP; }; <<"Exit" pops the execution stack until the innermost loop is terminated.>> ApplyExit: PUBLIC PROC[self: State] = { ERROR Exit; }; END.