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.ROPENIL] = 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: ROPEIF 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.