MispCedar.Mesa
Spreitzer, July 30, 1985 2:05:25 pm PDT
DIRECTORY AMBridge, AMModel, AMModelBridge, AMTypes, Atom, BackStop, BBUrpEval, Commander, EvalQuote, Interpreter, InterpreterOps, IO, List, Misp, ProcessProps, Rope, RTTypesPrivate, StatementInterpreter, SymTab;
MispCedar: CEDAR PROGRAM
IMPORTS AMBridge, AMModel, AMModelBridge, AMTypes, Atom, BackStop, BBUrpEval, EvalQuote, Interpreter, InterpreterOps, IO, List, Misp, ProcessProps, Rope, StatementInterpreter, SymTab
={
LORA: TYPE = LIST OF REF ANY;
ROPE: TYPE = Rope.ROPE;
TV: TYPE = AMTypes.TV;
ReallyTV: TYPE = REF RTTypesPrivate.TypedVariableRec;
Accessing Cedar from Misp:
EvalCedarExpr: PROC [args: LORA, environment: Misp.Environment, data: REF ANYNIL, stack: Misp.Stack] RETURNS [cooked: REF ANY] --Misp.EvalProc-- = {
cedarExpression: ROPENARROW[args.first];
symTab: SymTab.Ref ← Symtabize[environment];
result: TV;
errorRope: ROPE;
noResult: BOOL;
[result, errorRope, noResult] ← Interpreter.Evaluate[
rope: cedarExpression,
symTab: symTab,
abort: Misp.EnvStop[environment]
];
IF errorRope.Length[] # 0 THEN ERROR Misp.Error[environment, stack, errorRope];
cooked ← IF NOT noResult THEN CedarToMisp[result] ELSE NIL;
};
EvalCedarStmt: PROC [args: LORA, environment: Misp.Environment, data: REF ANYNIL, stack: Misp.Stack] RETURNS [cooked: REF ANY] --Misp.EvalProc-- = {
cedarStatement: ROPENARROW[args.first];
symTab: SymTab.Ref ← Symtabize[environment];
errorRope: ROPE;
cooked ← NIL;
errorRope ← StatementInterpreter.InterpretStatement[
blockAsRope: cedarStatement,
symTab: symTab,
abort: Misp.EnvStop[environment]
!Yield => {
cooked ← CedarToMisp[value];
CONTINUE
}
];
IF errorRope.Length[] # 0 THEN ERROR Misp.Error[environment, stack, errorRope];
};
Yield: ERROR [value: TV] = CODE;
EvalYield: PROC [head: InterpreterOps.EvalHead, tree: InterpreterOps.Tree, target: AMTypes.Type ← AMTypes.nullType, data: REFNIL] RETURNS [return: TV] --EvalQuote.EvalQuoteProc-- = {
argTree: InterpreterOps.Tree ← InterpreterOps.GetArg[tree, 1];
argTV: TV ← InterpreterOps.Eval[tree: argTree, head: head, target: target];
BackStop.SuspendBackStop[];
ERROR Yield[argTV];
};
Symtabize: PROC [env: Misp.Environment] RETURNS [symTab: SymTab.Ref] = {
size: NAT ← 0;
FOR e: Misp.Environment ← env, e.parent WHILE e # NIL DO
size ← size + e.class.Size[e];
ENDLOOP;
size ← size*2 + 1;
symTab ← SymTab.Create[size];
FOR e: Misp.Environment ← env, e.parent WHILE e # NIL DO
Per: PROC [key: ATOM, binding: REF ANY] = {
name: ROPE ← Atom.GetPName[key];
[] ← symTab.Insert[name, MispToCedar[binding]];
};
e.class.Enumerate[e, Per];
ENDLOOP;
};
DefineCedar: PROC [environment: Misp.Environment] = {
environment.Defun[$cedarExpr, EvalCedarExpr];
environment.Defun[$cedarStmt, EvalCedarStmt];
};
Accessing Misp from Cedar:
EvalMisp: PROC [head: InterpreterOps.EvalHead, tree: InterpreterOps.Tree, target: AMTypes.Type ← AMTypes.nullType, data: REFNIL] RETURNS [return: TV] --EvalQuote.EvalQuoteProc-- = {
argTree: InterpreterOps.Tree ← InterpreterOps.GetArg[tree, 1];
argTV: TV ← InterpreterOps.Eval[tree: argTree, head: head];
argRef, raw, cooked: REF ANY;
env: Misp.Environment ← Environmentize[head];
TRUSTED {argRef ← CedarToMisp[argTV]};
WITH argRef SELECT FROM
rope: ROPE => raw ← GetStreamRefAny[IO.RIS[rope]];
text: REF TEXT => raw ← GetStreamRefAny[IO.TIS[text]];
ENDCASE => raw ← argRef;
BackStop.SuspendBackStop[];
cooked ← Misp.Eval[raw: raw, environment: env, stack: NIL !
Misp.Error => {
BackStop.ResumeBackStop[];
BBUrpEval.UrpFatal[head, tree, IO.PutFR["Misp: %g, stack = %g", IO.rope[msg], IO.rope[Misp.PrintValRope[stack]]]];
ERROR;
};
UNWIND => BackStop.ResumeBackStop[]
];
BackStop.ResumeBackStop[];
return ← MispToCedar[cooked];
};
GetStreamRefAny: PROC [s: IO.STREAM] RETURNS [ra: REF ANY] = {
ra ← s.GetRefAny[];
[] ← s.SkipWhitespace[];
IF NOT s.EndOf[] THEN ERROR;
s.Close[];
};
Environmentize: PROC [head: InterpreterOps.EvalHead] RETURNS [env: Misp.Environment] = {
cc: AMModel.Class;
DoRecord: PROC [tv: TV, name: ROPE] =
{IF tv # NIL THEN env ← Misp.NewEnvironment[name: name, parent: env, class: recordClass, initData: tv]};
in, out: IO.STREAMNIL;
WITH List.Assoc[$CommanderHandle, ProcessProps.GetPropList[]] SELECT FROM
cmd: Commander.Handle => {in ← cmd.in; out ← cmd.out};
ENDCASE;
env ← Misp.NewEnvironment[name: "Standard Misp stuff for a Cedar evaluation", in: in, out: out, sizeGuess: 200, stop: head.abortClosure];
Misp.DefinePrimitives[env];
TRUSTED {cc ← AMModel.ContextClass[head.context]};
SELECT cc FROM
world => NULL --don't define the Cedar world for Misp ... it can't use it--;
model => ERROR --don't know how to break down a CONFIG--;
statement => ERROR --don't know how to break down a statement--;
interface => TRUSTED {
DoRecord[
AMModelBridge.IRFromContext[head.context],
AMModel.ContextName[head.context]];
};
prog => TRUSTED {
DoRecord[
AMTypes.Globals[AMModelBridge.FrameFromContext[head.context]],
AMModel.ContextName[head.context]];
};
proc => TRUSTED {
context: TV ← AMModelBridge.FrameFromContext[head.context];
Work: UNSAFE PROC [tv: TV] = {
IF tv # NIL THEN {
Work[AMTypes.EnclosingBody[tv]];
DoRecord[
AMTypes.Locals[tv],
AMTypes.TVToName[AMTypes.Procedure[tv]]
];
}
ELSE DoRecord[
AMTypes.Globals[AMTypes.GlobalParent[context]],
AMModel.ContextName[AMModel.ParentContext[context]]
];
};
Work[context];
};
ENDCASE => ERROR;
env ← Misp.NewEnvironment[name: "Cedar specials", parent: env, class: symtabClass, initData: head.specials];
};
recordClass: Misp.EnvironmentClass ← NEW [Misp.EnvironmentClassRep ← [
Init: InitRecord,
GetBinding: GetRecordBinding,
SetBinding: SetRecordBinding,
Enumerate: EnumerateRecord,
Size: RecordSize]];
InitRecord: PROC [env: Misp.Environment, sizeGuess: NAT, initData: REF ANY] = {
env.rep ← initData;
};
GetRecordBinding: PROC [env: Misp.Environment, key: ATOM] RETURNS [found: BOOL, binding: REF ANY] = {
name: ROPE ← Atom.GetPName[key];
record: TVNARROW[env.rep];
type: AMTypes.Type ← AMTypes.TVType[record];
index: CARDINAL;
valTV: TV;
found ← TRUE;
index ← AMTypes.NameToIndex[type, name !AMTypes.Error => {IF reason = badName THEN {found ← FALSE; CONTINUE}};];
IF NOT found THEN RETURN;
valTV ← AMTypes.IndexToTV[record, index];
binding ← CedarToMisp[valTV];
};
SetRecordBinding: PROC [env: Misp.Environment, key: ATOM, binding: REF ANY, overwriteOld: BOOL] = {
name: ROPE ← Atom.GetPName[key];
record: TVNARROW[env.rep];
type: AMTypes.Type ← AMTypes.TVType[record];
index: CARDINAL;
varTV, valTV: TV;
found: BOOLTRUE;
index ← AMTypes.NameToIndex[type, name !AMTypes.Error => {IF reason = badName THEN {found ← FALSE; CONTINUE}};];
IF NOT found THEN ERROR Misp.Error[env, NIL, "Can't add fields to a Cedar frame"];
varTV ← AMTypes.IndexToTV[record, index];
SELECT AMTypes.TVStatus[varTV] FROM
mutable => NULL;
readOnly, const => ERROR Misp.Error[env, NIL, Rope.Cat["Can't update ", name]];
ENDCASE => ERROR;
valTV ← MispToCedar[binding];
AMTypes.Assign[varTV, valTV];
};
EnumerateRecord: PROC [env: Misp.Environment, consume: PROC [key: ATOM, binding: REF ANY]] = {
record: TVNARROW[env.rep];
type: AMTypes.Type ← AMTypes.TVType[record];
n: NAT ← AMTypes.NComponents[type];
FOR i: NAT IN [1 .. n] DO
name: ROPE ← AMTypes.IndexToName[type, i];
key: ATOM ← Atom.MakeAtom[name];
valTV: TV ← AMTypes.IndexToTV[record, i];
valRef: REF ANY ← CedarToMisp[valTV];
consume[key, valRef];
ENDLOOP;
n ← n;
};
RecordSize: PROC [env: Misp.Environment] RETURNS [NAT] = {
record: TVNARROW[env.rep];
type: AMTypes.Type ← AMTypes.TVType[record];
n: NAT ← AMTypes.NComponents[type];
RETURN [n];
};
symtabClass: Misp.EnvironmentClass ← NEW [Misp.EnvironmentClassRep ← [
Init: InitSymtab,
GetBinding: GetSymtabBinding,
SetBinding: SetSymtabBinding,
Enumerate: EnumerateSymtab,
Size: SymtabSize]];
InitSymtab: PROC [env: Misp.Environment, sizeGuess: NAT, initData: REF ANY] = {
env.rep ← initData;
};
GetSymtabBinding: PROC [env: Misp.Environment, key: ATOM] RETURNS [found: BOOL, binding: REF ANY] = {
name: ROPE ← Atom.GetPName[key];
symtab: SymTab.Ref ← NARROW[env.rep];
tv: TV;
[found, tv] ← symtab.Fetch[name];
IF NOT (found AND ISTYPE[tv, ReallyTV]) THEN RETURN [FALSE, NIL];
binding ← CedarToMisp[tv];
};
SetSymtabBinding: PROC [env: Misp.Environment, key: ATOM, binding: REF ANY, overwriteOld: BOOL] = {
name: ROPE ← Atom.GetPName[key];
symtab: SymTab.Ref ← NARROW[env.rep];
tv: TV;
tv ← MispToCedar[binding];
[] ← (IF overwriteOld THEN SymTab.Store ELSE SymTab.Insert)[symtab, name, tv];
};
EnumerateSymtab: PROC [env: Misp.Environment, consume: PROC [key: ATOM, binding: REF ANY]] = {
symtab: SymTab.Ref ← NARROW[env.rep];
PerPair: PROC [key: ROPE, val: REF ANY] RETURNS [quit: BOOL] --SymTab.EachPairAction-- = {
atom: ATOM ← Atom.MakeAtom[key];
WITH val SELECT FROM
tv: ReallyTV => {
binding: REF ANY ← CedarToMisp[tv];
consume[atom, binding];
};
ENDCASE;
quit ← FALSE;
};
[] ← symtab.Pairs[PerPair];
symtab ← symtab};
SymtabSize: PROC [env: Misp.Environment] RETURNS [NAT] = {
symtab: SymTab.Ref ← NARROW[env.rep];
RETURN [symtab.GetSize[]];
};
A different way to Environmentize:
Environmentize: PROC [head: InterpreterOps.EvalHead] RETURNS [env: Misp.Environment] = {
top: Misp.Environment ← Misp.NewEnvironment[name: "Standard Misp stuff for a Cedar evaluation", sizeGuess: 200, stop: head.abortClosure];
fromCedar: Misp.Environment ← Misp.NewEnvironment[name: "stuff from Cedar", parent: top, class: fromCedarClass, initData: head];
Misp.DefinePrimitives[top];
};
fromCedarClass: Misp.EnvironmentClass ← NEW [Misp.EnvironmentClassRep ← [
Init: InitFromCedar,
GetBinding: GetCedarBinding,
SetBinding: SetCedarBinding,
Enumerate: EnumerateCedar,
Size: CedarSize]];
InitFromCedar: PROC [env: Misp.Environment, sizeGuess: NAT, initData: REF ANY] = {
env.rep ← initData;
};
GetCedarBinding: PROC [env: Misp.Environment, key: ATOM] RETURNS [found: BOOL, binding: REF ANY] = {
name: ROPE ← Atom.GetPName[key];
head: InterpreterOps.EvalHead ← NARROW[env.rep];
valTV: TV;
errorRope: ROPE;
noResult: BOOL;
[valTV, errorRope, noResult] ← Interpreter.Evaluate[
rope: name,
context: head.context,
symTab: head.specials,
abort: head.abortClosure];
IF found ← NOT (errorRope.Length[] # 0 OR noResult) THEN binding ← CedarToMisp[valTV];
};
SetCedarBinding: PROC [env: Misp.Environment, key: ATOM, binding: REF ANY, overwriteOld: BOOL] = {
name: ROPE ← Atom.GetPName[key];
head: InterpreterOps.EvalHead ← NARROW[env.rep];
varTV, valTV: TV;
errorRope: ROPE;
noResult: BOOL;
[varTV, errorRope, noResult] ← Interpreter.Evaluate[
rope: name,
context: head.context,
symTab: head.specials,
abort: head.abortClosure];
IF errorRope.Length[] # 0 THEN Misp.Error[env, NIL, errorRope];
IF noResult THEN Misp.Error[env, NIL, name.Cat[" has no value"]];
valTV ← MispToCedar[binding];
AMTypes.Assign[varTV, valTV];
};
EnumerateCedar: PROC [env: Misp.Environment, consume: PROC [key: ATOM, binding: REF ANY]] = {
head: InterpreterOps.EvalHead ← NARROW[env.rep];
cc: AMModel.Class;
FromRecord: PROC [record: TV] = {
type: AMTypes.Type ← AMTypes.TVType[record];
n: NAT ← AMTypes.NComponents[type];
FOR i: NAT IN [1 .. n] DO
name: ROPE ← AMTypes.IndexToName[type, i];
key: ATOM ← Atom.MakeAtom[name];
valTV: TV ← AMTypes.IndexToTV[record, i];
valRef: REF ANY ← CedarToMisp[valTV];
consume[key, valRef];
ENDLOOP;
};
PerSpecial: PROC [name: ROPE, help: ROPE, tv: TV, data: REF] RETURNS [stop: BOOL] = {
WITH tv SELECT FROM
reallyTV: ReallyTV => {
key: ATOM ← Atom.MakeAtom[name];
valRef: REF ANY ← CedarToMisp[tv];
consume[key, valRef];
};
ENDCASE;
stop ← FALSE;
};
TRUSTED {cc ← AMModel.ContextClass[head.context]};
[] ← InterpreterOps.EnumerateSymbols[PerSpecial, NIL, head.specials];
SELECT cc FROM
world => NULL --don't define the Cedar world for Misp ... it can't use it--;
model => ERROR --don't know how to break down a CONFIG--;
statement => ERROR --don't know how to break down a statement--;
interface => FromRecord[AMModelBridge.IRFromContext[head.context]];
prog => FromRecord[AMTypes.Globals[AMModelBridge.FrameFromContext[head.context]]];
proc => {
context: TV ← AMModelBridge.FrameFromContext[head.context];
FOR tv: TV ← context, AMTypes.EnclosingBody[tv] WHILE tv # NIL DO
FromRecord[AMTypes.Locals[tv]];
ENDLOOP;
FromRecord[AMTypes.Globals[AMTypes.GlobalParent[context]]];
};
ENDCASE => ERROR;
};
CedarSize: PROC [env: Environment] RETURNS [NAT] = {
head: InterpreterOps.EvalHead ← NARROW[env.rep];
size: NAT ← 0;
Per: PROC [key: ATOM, binding: REF ANY] = {size ← size + 1};
env.class.Enumerate[env, Per];
RETURN [size];
};
Yet another way to Environmentize:
Environmentize: PROC [head: InterpreterOps.EvalHead] RETURNS [env: Misp.Environment] = {
size: NAT ← head.specials.GetSize[];
cc: AMModel.Class;
context: TVNIL;
contextType: AMTypes.Type;
FromRecord: PROC [record: TV] = {
type: AMTypes.Type ← AMTypes.TVType[record];
n: NAT ← AMTypes.NComponents[type];
FOR i: NAT IN [1 .. n] DO
name: ROPE ← AMTypes.IndexToName[type, i];
key: ATOM ← Atom.MakeAtom[name];
valTV: TV ← AMTypes.IndexToTV[record, i];
valRef: REF ANY ← CedarToMisp[valTV];
env.class.SetBinding[env, key, valRef, FALSE];
ENDLOOP;
};
PerSpecial: PROC [name: ROPE, help: ROPE, tv: TV, data: REF] RETURNS [stop: BOOL] = {
key: ATOM ← Atom.MakeAtom[name];
valRef: REF ANY ← CedarToMisp[tv];
env.class.SetBinding[env, key, valRef, FALSE];
stop ← FALSE;
};
TRUSTED {cc ← AMModel.ContextClass[head.context]};
SELECT cc FROM
world => NULL --don't define the Cedar world for Misp ... it can't use it--;
model => ERROR --don't know how to break down a CONFIG--;
statement => ERROR --don't know how to break down a statement--;
interface => TRUSTED {
context ← AMModelBridge.IRFromContext[head.context];
contextType ← AMTypes.TVType[context];
size ← size + AMTypes.NComponents[contextType];
};
prog => TRUSTED {
context ← AMTypes.Globals[ AMModelBridge.FrameFromContext[head.context]];
contextType ← AMTypes.TVType[context];
size ← size + AMTypes.NComponents[contextType];
};
proc => TRUSTED {
context ← AMModelBridge.FrameFromContext[head.context];
contextType ← AMTypes.TVType[context];
FOR tv: TV ← context, AMTypes.EnclosingBody[tv] WHILE tv # NIL DO
size ← size + AMTypes.NComponents[AMTypes.TVType[AMTypes.Locals[tv]]];
ENDLOOP;
size ← size + AMTypes.NComponents[AMTypes.TVType[AMTypes.Globals[context]]];
};
ENDCASE => ERROR;
size ← size*2 + 201;
env ← Misp.NewEnvironment[name: "Cedar values", sizeGuess: size, stop: head.abortClosure];
Misp.DefinePrimitives[env];
[] ← InterpreterOps.EnumerateSymbols[PerSpecial, NIL, head.specials];
SELECT cc FROM
world => NULL --don't define the Cedar world for Misp ... it can't use it--;
model => ERROR --don't know how to break down a CONFIG--;
statement => ERROR --don't know how to break down a statement--;
interface => FromRecord[context];
prog => FromRecord[context];
proc => {
FOR tv: TV ← context, AMTypes.EnclosingBody[tv] WHILE tv # NIL DO
FromRecord[AMTypes.Locals[tv]];
ENDLOOP;
FromRecord[AMTypes.Globals[context]];
};
ENDCASE => ERROR;
};
Utilities:
ROPEType: AMTypes.Type ← AMTypes.UnderType[CODE[ROPE]];
ATOMType: AMTypes.Type ← AMTypes.UnderType[CODE[ATOM]];
CedarToMisp: PROC [tv: TV] RETURNS [ref: REF ANY] = TRUSTED {
class: AMTypes.Class ← AMTypes.UnderClass[AMTypes.TVType[tv]];
SELECT class FROM
atom => ref ← AMBridge.TVToATOM[tv];
rope => ref ← AMTypes.TVToName[tv];
list, ref => ref ← AMBridge.SomeRefFromTV[
AMTypes.Referent[tv !
AMTypes.Error => IF reason = typeFault THEN {
SELECT TRUE FROM
SafeStorage.EquivalentTypes[type, ROPEType] => ref ← AMTypes.TVToName[tv];
SafeStorage.EquivalentTypes[type, ATOMType] => ref ← AMBridge.TVToATOM[tv];
ENDCASE => ref ← AMBridge.SomeRefFromTV[tv];
CONTINUE}
]
];
atom, rope, list, ref => ref ← AMBridge.TVToRef[tv];
nil => ref ← NIL;
ENDCASE => ref ← AMBridge.SomeRefFromTV[tv];
};
MispToCedar: PROC [ref: REF ANY] RETURNS [tv: TV] = TRUSTED {
tv ← AMBridge.TVForReferent[NEW [REF ANY ← ref], const];
};
Start: PROC = {
Misp.RegisterPrimitiveDefiner[DefineCedar];
EvalQuote.Register[name: "&yield", proc: EvalYield, symTab: NIL];
EvalQuote.Register[name: "&misp", proc: EvalMisp, symTab: NIL];
};
Start[];
}.