InterpreterOps.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Paul Rovner, July 26, 1983 2:23 pm
Russ Atkinson (RRA) February 12, 1985 3:03:50 pm PST
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];
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.STREAM ←
NIL]
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
HelpFatal:
TYPE =
PROC [data:
REF, head: EvalHead, parent: Tree, msg:
ROPE];
HelpFatalClosure: TYPE = RECORD[proc: HelpFatal, data: REF ← NIL];
HelpFatal is called when a non-recoverable error is found. parent is the offending tree, msg describes what went wrong
HelpWrongType:
TYPE =
PROC [data:
REF, head: EvalHead, parent: Tree, value:
TV, target: Type, msg:
ROPE]
RETURNS [correct: RopeOrTV];
HelpWrongTypeClosure: TYPE = RECORD[proc: HelpWrongType, data: REF ← NIL];
HelpWrongType 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
HelpId:
TYPE =
PROC [data:
REF, head: EvalHead, parent: Tree, id:
ROPE, context: Type, target: Type, msg:
ROPE]
RETURNS [correct: RopeOrTV];
HelpIdClosure: TYPE = RECORD[proc: HelpId, data: REF ← NIL];
HelpId 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
HelpSelector:
TYPE =
PROC [data:
REF, head: EvalHead, parent: Tree, id:
ROPE, context:
TV, target: Type, msg:
ROPE]
RETURNS [correct: RopeOrTV];
HelpSelectorClosure: TYPE = RECORD[proc: HelpSelector, data: REF ← NIL];
HelpSelector 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
HelpDefault:
TYPE =
PROC [data:
REF, head: EvalHead, parent: Tree, type: Type, index:
CARDINAL, msg:
ROPE]
RETURNS [correct: RopeOrTV];
HelpDefaultClosure: TYPE = RECORD[proc: HelpDefault, data: REF ← NIL];
HelpDefault 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,
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];
context # NIL.
AMModel.ContextClass[context]
= one of: world, prog(global frame), interface(ir), proc(local frame)
NewEvalHead 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:
REF ←
NIL, 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];
... is the type of proc passed to EnumerateSymbols.
RegisterTV:
PROC [name:
ROPE, tv:
TV, help:
ROPE ←
NIL, 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.