-- JaMOps.mesa
-- Last changed by Wyatt, 24-Oct-81 15:18:05
-- Last changed by Paxton, 30-Jan-82  8:49:44

DIRECTORY
  JaMBasic USING [Object, Root, StringLength, Tag],
  JaMInternal USING [Cache, Frame, Locals, Node, Stack],
  StreamDefs USING [StreamHandle];

JaMOps: DEFINITIONS = {
OPEN JaMInternal, JaMBasic;

-- Types and Constants

StreamHandle: TYPE = StreamDefs.StreamHandle;
Text: TYPE = LONG STRING;

nullOb: Object = [X,null[]];

-- Signals and Errors

Error: ERROR[error: Object];
StackOverflow: ERROR[stack: Stack];
Bug: ERROR;
Assert: PROC[pred: BOOLEAN] = INLINE { IF NOT pred THEN ERROR Bug };

-- Commonly-used error names

rangechk,typechk,undefname,limitchk: name Object;

-- Stack operations

Top: PROC[stack: Stack] RETURNS[Object] = INLINE {
  node: Node ← stack.head; IF node=NIL THEN Underflow[stack];
  RETURN[node.ob] };

Pop: PROC[stack: Stack] RETURNS[Object] = INLINE {
  node: Node ← stack.head; IF node=NIL THEN Underflow[stack];
  stack.head ← node.next; node.next ← stack.free;
  stack.free ← node; RETURN[node.ob] };

Push: PROC[stack: Stack, ob: Object] = INLINE {
  node: Node ← stack.free; IF node=NIL THEN Overflow[stack];
  stack.free ← node.next; node.next ← stack.head;
  stack.head ← node; node.ob ← ob };

Underflow,Overflow: PROC[stack: Stack]; -- these never return

Empty: PROC[stack: Stack] RETURNS[BOOLEAN] = INLINE { RETURN[stack.head=NIL] };
Full: PROC[stack: Stack] RETURNS[BOOLEAN] = INLINE { RETURN[stack.free=NIL] };

GetMark: PROC[stack: Stack] RETURNS[Node] = INLINE { RETURN[stack.free] };
Restore: PROC[stack: Stack, mark: Node];

Copy: PROC[stack: Stack, n: CARDINAL];
Dup: PROC[stack: Stack] = INLINE { Copy[stack,1] };
Exch: PROC[stack: Stack];
Roll: PROC[stack: Stack, n,k: CARDINAL];
ClearStack: PROC[stack: Stack];
CountStack: PROC[stack: Stack, max: CARDINAL ← LAST[CARDINAL]] RETURNS[CARDINAL];
CountToMark: PROC[stack: Stack] RETURNS[CARDINAL];
ClearToMark: PROC[stack: Stack];
Index: PROC[stack: Stack, i: CARDINAL] RETURNS[Object];

StackForAll: PROC[stack: Stack, proc: PROC[Object] RETURNS[BOOLEAN],
  unwind: BOOLEAN ← FALSE] RETURNS[BOOLEAN];
ArrayFromStack: PROC[stack: Stack] RETURNS[array Object];

NewStack: PROC[CARDINAL] RETURNS[Stack];
FreeStack: PROC[Stack];

-- Type-specific stack operations

PushCardinal: PROC[stack: Stack, c: CARDINAL] = INLINE { Push[stack,[L,integer[c]]] };
PushInteger: PROC[stack: Stack, i: LONG INTEGER] = INLINE { Push[stack,[L,integer[i]]] };
PushReal: PROC[stack: Stack, r: REAL] = INLINE { Push[stack,[L,real[r]]] };
PushBoolean: PROC[stack: Stack, b: BOOLEAN] = INLINE { Push[stack,[L,boolean[b]]] };

PopCardinal: PROC[stack: Stack, limit: CARDINAL ← 0] RETURNS[CARDINAL];
PopInteger: PROC[stack: Stack] RETURNS[LONG INTEGER];
PopReal: PROC[stack: Stack] RETURNS[REAL];
PopBoolean: PROC[stack: Stack] RETURNS[BOOLEAN];
PopString: PROC[stack: Stack] RETURNS[string Object];
PopArray: PROC[stack: Stack] RETURNS[array Object];
PopDict: PROC[stack: Stack] RETURNS[dict Object];
PopCommand: PROC[stack: Stack] RETURNS[command Object];
PopStream: PROC[stack: Stack] RETURNS[stream Object];

TopInteger: PROC[stack: Stack] RETURNS[LONG INTEGER];
TopDict: PROC[stack: Stack] RETURNS[dict Object];

-- Array operations

Array: PROC[length: CARDINAL] RETURNS[array Object];
ACopy: PROC[array: array Object, expand: CARDINAL ← 0] RETURNS[array Object];
SubArray: PROC[array: array Object, beg,len: CARDINAL] RETURNS[array Object];
PutArray: PROC[from: array Object, beg: CARDINAL, into: array Object];
APut: PROC[array: array Object, i: CARDINAL, ob: Object];
AGet: PROC[array: array Object, i: CARDINAL] RETURNS[Object];
AStore: PROC[stack: Stack, array: array Object];
ALoad: PROC[stack: Stack, array: array Object];
AFind: PROC[array: array Object, ob: Object] RETURNS[BOOLEAN,CARDINAL];
AAtom: PROC[array: array Object]
  RETURNS[found: BOOLEAN, atom: Object, rem: array Object];
ABind: PROC[array: array Object, dict: dict Object];
ArrayForAll: PROC[array: array Object, proc: PROC[Object] RETURNS[BOOLEAN]]
  RETURNS[BOOLEAN];

-- Dictionary operations

Dict: PROC[maxlen: CARDINAL] RETURNS[dict Object];
DictLength: PROC[dict: dict Object] RETURNS[CARDINAL];
Where: PROC[frame: Frame, key: Object] RETURNS[BOOLEAN,dict Object];
Get: PROC[dict: dict Object, key: Object] RETURNS[Object];
TryToGet: PROC[dict: dict Object, key: Object] RETURNS[BOOLEAN,Object];
Put: PROC[dict: dict Object, key, value: Object];
Def: PROC[frame: Frame, key, value: Object];
Load: PROC[frame: Frame, key: Object] RETURNS[Object];
TryToLoad: PROC[frame: Frame, key: Object] RETURNS[BOOLEAN,Object];
Store: PROC[frame: Frame, key, value: Object];
Del: PROC[dict: dict Object, key: Object];
ClrDict: PROC[dict: dict Object];
AttachDict: PROC[dict, adict: dict Object];
DetachDict: PROC[dict, adict: dict Object];
DetachAll: PROC[dict: dict Object];
Begin: PROC[frame: Frame, dict: dict Object];
End: PROC[frame: Frame];

NewCache: PROC RETURNS[Cache];
FreeCache: PROC[Cache];

-- Locals

GetLocalsTop: PROC[frame: Frame] RETURNS[CARDINAL] = INLINE {
  RETURN[frame.locals.curlen] };
SetLocalsTop: PROC[frame: Frame, top: CARDINAL] = INLINE {
  frame.locals.curlen ← MIN[frame.locals.curlen,top] };

DefineLocal: PROC[frame: Frame, key,value: Object];
LoadLocal: PROC[frame: Frame, key: Object] RETURNS[Object];
TryToLoadLocal: PROC[frame: Frame, key: Object] RETURNS[BOOLEAN,Object];
StoreLocal: PROC[frame: Frame, key,value: Object];

NewLocals: PROC RETURNS[Locals];
FreeLocals: PROC[Locals];

-- Key comparison

KeyName: PROC[key: Object] RETURNS[Object] = INLINE {
  RETURN[WITH k:key SELECT FROM string => StringToName[k], ENDCASE => key] };

Equality: TYPE = {nil,F,T}; -- nil (if incompatible types), False, or True
Compare: PROC[a,b: Object] RETURNS[Equality];
Equal: PROC[a,b: Object] RETURNS[BOOLEAN] = INLINE {
  WITH a:a SELECT FROM name => WITH b:b SELECT FROM name => RETURN[a.id=b.id];
    ENDCASE; ENDCASE; RETURN[Compare[a,b]=T] };

-- Execution

Execute: PROC[Frame,Object];
Stop: PROC[Frame];
GetAbort: PROC[Frame] RETURNS[BOOLEAN];
SetAbort: PROC[Frame,BOOLEAN];
MarkLoop: PROC[frame: Frame];
UnmarkLoop: PROC[frame: Frame];

-- Names

NameToString: PROC[name Object] RETURNS[string Object];
StringToName: PROC[string Object,Text ← NIL] RETURNS[name Object];
CreateName: PROC[text: Text, tag: Tag ← X] RETURNS[name: name Object, known: BOOLEAN];
	-- boolean is true if name already existed, false if was just created
MakeName: PROC[text: Text, tag: Tag ← X] RETURNS[name Object] = INLINE {
	RETURN [CreateName[text,tag].name] };

-- Strings

String: PROC[length: StringLength] RETURNS[string Object];
SCopy: PROC[string: string Object, expand: CARDINAL ← 0] RETURNS[string Object];
SubString: PROC[s: string Object, beg,len: CARDINAL] RETURNS[string Object];
PutString: PROC[from: string Object, beg: CARDINAL, into: string Object];
StringCompare: PROC[a,b: string Object] RETURNS[INTEGER];
MakeString: PROC[Text,Tag ← L] RETURNS[string Object];
StringText: PROC[string Object, Text];
StringForAll: PROC[string Object, PROC[CHARACTER] RETURNS[BOOLEAN]];

-- Scanning

StreamToken: PROC[frame: Frame, stream: StreamHandle]
  RETURNS[found,error: BOOLEAN, token: Object];
StringToken: PROC[frame: Frame, ob: string Object]
  RETURNS[found,error: BOOLEAN, token: Object, rem: string Object];
LineComplete: PROC[text: Text] RETURNS[BOOLEAN];

-- Streams

MakeStream: PROC[StreamHandle, Tag ← L] RETURNS[stream Object];
GetStream: PROC[stream Object] RETURNS[StreamHandle];
KillStream: PROC[stream Object];

-- Registration and control

root: READONLY LONG POINTER TO Root;
defaultFrame: READONLY Frame;

RegisterExplicit: PROC[frame: Frame, text: Text, proc: PROC[Frame]];
RegisterImplicit: PROC[frame: Frame, text: Text, proc: PROC[]];
RegisterInternal: PROC[text: Text, proc: PROC[Frame]] RETURNS[command Object];

ForEachFrame: PROC[PROC[Frame]];
ForEachFrameExcept: PROC[Frame,PROC[Frame]];

NewFrame: PROC RETURNS[Frame];
FreeFrame: PROC[Frame];

DoCommand: PROC[frame: Frame, ob: command Object];

-- Installation

InstallReason: TYPE = {init,free,register};
InstallProc: TYPE = PROC[InstallReason,Frame];
Install: PROC[InstallProc];
ForEachInstalled: InstallProc;

StartJaM: PROC;

}.