JaMExecImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Original version by John Warnock, January, 1978.
Bill Paxton, 29-Jan-82 15:45:10
Maureen Stone February 6, 1984 5:13:11 pm PST
Doug Wyatt, March 18, 1985 2:52:41 pm PST
Michael Plass, August 15, 1985 11:09:16 am PDT
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 [priorityBackground, priorityNormal, SetPriority, Yield],
JaMPrimitives USING [];
JaMExecImpl: CEDAR PROGRAM
IMPORTS JaM, IO, Process, Rope
EXPORTS JaM, JaMPrimitives
= BEGIN OPEN JaM;
Errors
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]] };
GetKeyName:
PROC[x: Any]
RETURNS [
ROPE] = {
WITH x
SELECT
FROM
x: ATOM => RETURN [AtomToRope[x]];
x: Command => RETURN [AtomToRope[x.name]];
ENDCASE => RETURN ["<???>"];
};
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: ", GetKeyName[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
IF self.stepping THEN {
self.stepping ← FALSE;
Push[self, x]; ExecuteName[self, $.step];
self.stepping ← TRUE;
};
};
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
of the outermost instance of Execute.
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.
Two operands are required: an Object and a Boolean. If the
Boolean is TRUE then the object is executed otherwise the
object is popped.
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
instruction. Three operands are required: Object1,Object2, and a Boolean.
If the Boolean is TRUE then Object2 is executed otherwise Object1 is
executed.
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:
an integer and an Object. The Object is executed for the number
of times indicated by the integer. (0 for Negative).
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.
Four operands are required: three IntegerTypes and an Object.
The Object is executed for each iteration, with the current loop index on
the operand stack.
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<k
DO
PushInt[self, n]; Execute[self, x ! Exit => EXIT];
ENDLOOP;
};
"Loop" is the "loop forever" instruction. One operand is required:
The Object is executed until an ".exit" command is executed.
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;
};
ApplyNicePriority:
PUBLIC PROC[self: JaM.State] = {
nice: BOOL = JaM.PopBool[self];
Process.SetPriority[IF nice THEN Process.priorityBackground ELSE Process.priorityNormal];
};
END.