InterpreterOps.mesa
Lifted from BBEval.mesa by Russ Atkinson, December 7, 1982 11:40 am
Paul Rovner, July 26, 1983 2:23 pm
DIRECTORY
AMModel USING [Context],
AMTypes USING [TV],
Interpreter USING [AbortClosure],
IO USING [STREAM],
PPTree USING [Link],
Rope USING [ROPE],
SafeStorage USING [nullType, Type],
SymTab USING [Ref],
WorldVM USING [World];
InterpreterOps: CEDAR DEFINITIONS
= BEGIN OPEN AMTypes, Rope, SafeStorage;
Basic interpreter operations
Eval: PROC[tree: Tree, head: EvalHead, target: Type ← nullType] RETURNS [TV];
evaluates the given tree using the given eval head
the TV returned is the return record if multiple values are returned
the TV = AMTypes.GetEmptyTV[] if no args are returned
otherwise the appropriate single TV is returned
ParseExpr: PROC [expr: ROPE, errout: IO.STREAMNIL] RETURNS [Tree];
returns a tree for the given expression
error output (if any) will go to errout
TreeToName: PROC [t: Tree] RETURNS [name: ROPE];
returns NIL if the tree is not simple enuff to yield a name
GetArg: PROC [tree: Tree, which: NAT] RETURNS [son: InterpreterOps.Tree ← NIL];
tree must represent the tree for an application. GetArg returns NIL if there is no argument in the specified position. Args are numbered left to right, starting at 1.
Types: Tree, EvalHead
Tree: TYPE = PPTree.Link;
EvalHead: TYPE = REF EvalHeadRep;
EvalHeadRep: TYPE = RECORD
[context: AMModel.Context,
context # NIL.
AMModel.ContextClass[context]
= one of: world, prog(global frame), interface(ir), proc(local frame)
specials: SymTab.Ref,
abortClosure: AbortClosure,
helpFatalClosure: HelpFatalClosure,
helpWrongTypeClosure: HelpWrongTypeClosure,
helpIdClosure: HelpIdClosure,
helpSelectorClosure: HelpSelectorClosure,
helpDefaultClosure: HelpDefaultClosure
];
AbortClosure: TYPE = Interpreter.AbortClosure;
This is called by Eval or ParseExpr at intervals to ask whether to abort the task and return.
return TRUE to cause a call to helpFatal[data, head, tree, "aborted"]
return FALSE to proceed normally
Help closures
HelpFatalClosure: TYPE = RECORD[proc: HelpFatal, data: REFNIL];
HelpFatal: TYPE = PROC [data: REF, head: EvalHead, parent: Tree, msg: ROPE];
This is called when a non-recoverable error is found.
parent is the offending tree, msg describes what went wrong
HelpWrongTypeClosure: TYPE = RECORD[proc: HelpWrongType, data: REFNIL];
HelpWrongType: TYPE = PROC
[data: REF, head: EvalHead, parent: Tree, value: TV, target: Type, msg: ROPE]
RETURNS [correct: RopeOrTV];
This is called when the wrong type of TV is found
the client should return the correct TV (which must be OK for the target)
if a ROPE is returned, it replaces msg as the error message
if target = nullType, then the true target may not be known
(this occurs for msg = "not applicable", for example)
if target = CODE[PROC], then some procedure should be returned
HelpIdClosure: TYPE = RECORD[proc: HelpId, data: REFNIL];
HelpId: TYPE = PROC
[data: REF, head: EvalHead, parent: Tree, id: ROPE, context: Type, target: Type, msg: ROPE]
RETURNS [correct: RopeOrTV];
This is called when the given id is not valid for the context
if the client returns a rope, the lookup will begin again with the new rope
if the client returns a TV, the lookup will return with that TV
if the client returns a fail, that will be the new msg for HelpFatal
if context = nullType, then the context is probably dynamic
(this may occur for msg = "undefined", for example)
if target = nullType, then the true target is not known
HelpSelectorClosure: TYPE = RECORD[proc: HelpSelector, data: REFNIL];
HelpSelector: TYPE = PROC
[data: REF, head: EvalHead, parent: Tree, id: ROPE, context: TV, target: Type, msg: ROPE]
RETURNS [correct: RopeOrTV];
This is called when the given id is not valid for the context
(note that the context is a TV)
if the client returns a rope, the lookup will begin again with the new rope
if the client returns a TV, the lookup will return with that TV
if the client returns a fail, that will be the new msg for HelpFatal
if target = nullType, then the true target is not known
HelpDefaultClosure: TYPE = RECORD[proc: HelpDefault, data: REFNIL];
HelpDefault: TYPE = PROC
[data: REF, head: EvalHead, parent: Tree, type: Type, index: CARDINAL, msg: ROPE]
RETURNS [correct: RopeOrTV];
This is called when a default value is not present
if index = 0, then the default is missing for type
if index > 0, then the default is missing for that component of type
the client should return a TV to be used as the default value
the client may also return a new error message
RopeOrTV: TYPE = RECORD[
SELECT tag: * FROM
rope => [rope: ROPE],
tv => [tv: TV],
both => [rope: ROPE, tv: TV],
fail => [fail: ROPE],
ENDCASE
] ← [fail[NIL]];
EvalHead operations
NewEvalHead: PROC
[context: AMModel.Context,
context # NIL.
AMModel.ContextClass[context]
= one of: world, prog(global frame), interface(ir), proc(local frame)
specials: SymTab.Ref, -- non-NIL
abortClosure: AbortClosure ← [NIL, NIL],
helpFatalClosure: HelpFatalClosure ← [NIL, NIL],
helpWrongTypeClosure: HelpWrongTypeClosure ← [NIL, NIL],
helpIdClosure: HelpIdClosure ← [NIL, NIL],
helpSelectorClosure: HelpSelectorClosure ← [NIL, NIL],
helpDefaultClosure: HelpDefaultClosure ← [NIL, NIL]
]
RETURNS [EvalHead];
returns a new evaluator head
note that most of the help routines are optional
the client can supply special variables for lookup
WorldFromHead: PROC [head: EvalHead] RETURNS [WorldVM.World];
Dealing with the interpreter's symbol tables
EnumerateSymbols: PROC
[proc: Ruminant, data: REFNIL, symTab: SymTab.Ref ← NIL] RETURNS [stopped: BOOL];
Enumerates the symbols in the specified table (in no particular order). IF symTab = NIL then the global SymTab is used. Returns TRUE if the client stopped the enumeration, FALSE if not.
Ruminant: TYPE = PROC [name: ROPE, help: ROPE, tv: TV, data: REF] RETURNS [stop: BOOL];
RegisterTV: PROC [name: ROPE, tv: TV, help: ROPENIL, symTab: SymTab.Ref];
Registers the TV under the given name in the specified SymTab. The name must start with the & character. tv = NIL is OK.
END.