Copyright (C) 1994, Digital Equipment Corp. INTERFACEProgram interface to Obliq run-time values and evaluation. Other important interfaces are ObTree and ObValue, but the present interface attempts to be fairly self-contained.Obliq ; IMPORT SynWr, SynLocation, ObTree, ObValue, ObScope, ObCheck, ObLib, Thread; FROM ObValue IMPORT Error, Exception;
====== Setup ======
PROCEDURE PackageSetup(); (* To be called at least once before any other use of the obliqrt package. *)====== Types ======
TYPE
Term = ObTree.Term;
Phrase = ObTree.Phrase;
Val = ObValue.Val;
Vals = ARRAY OF Val;
Fields = ObValue.ObjFields;
Location = SynLocation.T;
(* Error locations: if one is passed to your procedures, pass it along
to other procedures that take location parameters. Otherwise
use the NIL defaults for location (for pretty good error reporting)
or synthesize you own locations (for optimal error reporting). *)
Env =
BRANDED OBJECT
frameName: TEXT; (* the module name, to handle reloading *)
forName: TEXT; (* the qualified name for the operations. *)
libEnv: ObLib.Env;
scopeEnv: ObScope.Env;
checkEnv: ObCheck.Env;
valueEnv: ObValue.Env;
nextFrame: Env;
END;
(* An interpreter environment. Consider this opaque. *)
====== Environments ======
PROCEDURE EmptyEnv(): Env;
(* The empty evaluation environment, containing the currently registered
built-in modules. This is a legal environment. *)
PROCEDURE NewEnv(name: TEXT; val: Val; rest: Env; loc: Location:=NIL)
: Env RAISES {Error};
(* Extend an evaluation environment with a new association name-val.
This is a legal environment if "rest" is, and if "val" is
a legal value. *)
PROCEDURE Lookup(name: TEXT; env: Env): Val RAISES {Error};
(* Retrieve the value associated with name in env, or Error if not found. *)
====== Eval ======
PROCEDURE EvalTerm(term: Term; env: Env; loc: Location:=NIL)
: Val RAISES {Error, Exception};
(* Check and evaluate a term in an environment. "env" must be a legal
environment. Produces a legal value, or an exception.
A Term can be obtained via ObliqParser.i3. *)
PROCEDURE EvalPhrase(phrase: Phrase; VAR (*in-out*) env: Env;
loc: Location:=NIL): Val RAISES {Error, Exception};
(* Check and evaluate a term, definition, or command phrase in an
environment. "env" must be a legal environment. Produces an enriched
legal environment or an exception. (The result environment is enriched
with new bindings when phrase is a definition.) A Phrase can be obtained
via ObliqParser.i3.
N.B. This procedure does NOT evaluate load phrases and module phrases;
ObliqParser.EvalPhrase is a more general general procedure that
also does that. *)
====== Ground types ======
VAR (*READONLY*) ok: Val;
VAR (*READONLY*) true, false: Val;
PROCEDURE NewBool(bool: BOOLEAN): Val;
PROCEDURE ToBool(val: Val; loc: Location:=NIL): BOOLEAN RAISES{Error};
PROCEDURE Is(val1, val2: Val): BOOLEAN;
VAR (*READONLY*) zero, one: Val;
PROCEDURE NewInt(int: INTEGER): Val;
PROCEDURE ToInt(val: Val; loc: Location:=NIL): INTEGER RAISES{Error};
VAR (*READONLY*) zeroPointZero, onePointZero: Val;
PROCEDURE NewReal(real: LONGREAL): Val;
PROCEDURE ToReal(val: Val; loc: Location:=NIL): LONGREAL RAISES{Error};
VAR (*READONLY*) char: ARRAY [0..255] OF Val;
PROCEDURE NewChar(char: CHAR): Val;
PROCEDURE ToChar(val: Val; loc: Location:=NIL): CHAR RAISES{Error};
VAR (*READONLY*) emptyText: Val;
PROCEDURE NewText(text: TEXT): Val; (* Converts NIL to "" *)
PROCEDURE ToText(val: Val; loc: Location:=NIL): TEXT RAISES{Error};
====== Objects ======
PROCEDURE NewObject(READONLY fields: Fields): Val;
(* Allocates a legal object from a list of fields. This is a legal
value if the fields have unique names and contain legal values. *)
(* The fields parameter should contain non-method values only.
Constructing methods by hand requires knowledge beyond the scope
of this interface, and is highly obliq-implementation-dependent.
It is much better to call Eval with appropriate arguments, so that
objects-with-methods are produced. *)
PROCEDURE ObjectSelect(object: Val; label: TEXT; loc: Location:=NIL): Val
RAISES {Error, Exception};
(* Selects the contents of a field of an object. The value produced
(if any) is a legal value provided that "object" is both a legal value
and an object. *)
PROCEDURE ObjectInvoke(object: Val; label: TEXT; args: Vals;
loc: Location:=NIL): Val RAISES {Error, Exception};
(* Invokes a method of an object. The value produced (if any) is a
legal value provided that "object" is both a legal value and
an object, and args is an array of legal values. *)
PROCEDURE ObjectUpdate(object: Val; label: TEXT; val: Val;
loc: Location:=NIL) RAISES {Error, Exception};
(* Updates a field or method of an object. The value produced (if any) is a
legal value provided that "object" is both a legal value and
an object, and val is a legal value. *)
PROCEDURE ObjectClone1(object: Val; loc: Location:=NIL): Val
RAISES {Error, Exception};
(* Clone a single object. The value produced (if any) is a legal value
provided that "object" is both a legal value and an object. *)
PROCEDURE ObjectClone(READONLY objects: Vals; loc: Location:=NIL): Val
RAISES {Error, Exception};
(* Clone many objects into one. The value produced (if any) is a legal value
provided that "objects" are both legal values and objects. *)
PROCEDURE ObjectHas(object: Val; label: TEXT; loc: Location:=NIL):
BOOLEAN RAISES{Error, Exception};
(* Whether the object has a field called label. *)
====== Network Objects and Engines ======
PROCEDURE NetExport(name, server: TEXT; object: Val;
loc: SynLocation.T:=NIL) RAISES {Error, Exception};
(* Export an object to a name server under a name. object must be an object;
server must be the IP address of a machine running a network object
daemon. Otherwise an exception is raised. *)
PROCEDURE NetImport(name, server: TEXT;
loc: SynLocation.T:=NIL): Val RAISES {Exception};
(* Import a named object from a name server. server must be the IP address
of a machine running a network object, holding the named object.
The result is an object, or an exception is raised if the named
object cannot be obtained. *)
PROCEDURE NetExportEngine(name, server: TEXT; arg: Val;
loc: SynLocation.T:=NIL) RAISES {Error, Exception};
(* Export an engine to a name server under a name. arg is given as an
argument to engine clients; server must be the IP address of a machine
running a network object daemon. Otherwise an exception is raised. *)
PROCEDURE NetImportEngine(name, server: TEXT;
loc: SynLocation.T:=NIL): Val RAISES {Exception};
(* Import a named engine from a name server. server must be the IP address
of a machine running a network object, holding the named object.
The result is an engine that accepts procedures of one argument,
(use "Call" to invoke) or an exception is raised if the named engine
cannot be obtained. *)
PROCEDURE NetWho(object: Val; loc: SynLocation.T:=NIL): TEXT
RAISES {Error, Exception};
(* Return a description of the origin of an object.
The precise format is not determined at this moment. *)
====== Arrays ======
PROCEDURE NewArray(READONLY vals: Vals): Val;
(* Allocates an array value from an array of values. *)
PROCEDURE ArraySize(array: Val; loc: Location:=NIL): INTEGER RAISES {Error};
(* The size of an array value. *)
PROCEDURE ArrayGet(array: Val; i: INTEGER; loc: Location:=NIL)
: Val RAISES {Error};
(* The ith component of an array value. *)
PROCEDURE ArraySet(array: Val; i: INTEGER; val: Val;
loc: Location:=NIL) RAISES {Error};
(* Set the ith componet of an array value to val. *)
PROCEDURE ArraySub(array: Val; start,size: INTEGER; loc: Location:=NIL)
: Val RAISES {Error};
(* Extract a subarray an array value. *)
PROCEDURE ArrayUpd(array: Val; start, size: INTEGER; sub: Val;
loc: Location:=NIL) RAISES {Error};
(* Update array[start for size] with sub[0 for size]. *)
PROCEDURE ArrayCat(array1, array2: Val; loc: Location:=NIL)
: Val RAISES {Error};
(* A new array that is the concatenation of two others. *)
PROCEDURE ToArray(val: Val; VAR(*out*) array: Vals; loc: Location:=NIL)
RAISES {Error};
(* Put the elements of an array value into an array. The size of "array"
must much the array size of "val". *)
PROCEDURE NewIntArray(READONLY array: ARRAY OF INTEGER): Val;
PROCEDURE ToIntArray(val: Val; VAR(*out*) array: ARRAY OF INTEGER;
loc: Location:=NIL) RAISES {Error};
PROCEDURE NewRealArray(READONLY array: ARRAY OF LONGREAL): Val;
PROCEDURE ToRealArray(val: Val; VAR(*out*) array: ARRAY OF LONGREAL;
loc: Location:=NIL) RAISES {Error};
PROCEDURE NewTextArray(READONLY array: ARRAY OF TEXT): Val;
PROCEDURE ToTextArray(val: Val; VAR(*out*) array: ARRAY OF TEXT;
loc: Location:=NIL) RAISES {Error};
(* These utility array routines maps to and from arrays of ground
types. They use NewArray and ToArray with appopriate coercions
for the array elements. *)
====== Variables ======
PROCEDURE NewVar(val: Val): Val;
(* Create a new variable with given contents. *)
PROCEDURE VarGet(var: Val; loc: Location:=NIL): Val RAISES {Error};
(* The contents of a variable. *)
PROCEDURE VarSet(var: Val; val: Val; loc: Location:=NIL) RAISES {Error};
(* Set the contents of a variable to val. *)
====== Procedures ======
PROCEDURE Call(proc: Val; READONLY args: Vals; loc: Location:=NIL): Val
RAISES {Error, Exception};
(* Take a procedure value with N parameters (i.e. the result of evaluating
an Obliq program of the form "proc(x1..xn)...end"), and call it
(do the equivalent of "(proc(x1..xn)...end)(a1..an)"), returning
its result. N.B. the original procedure text may have global variables.
Moreover, proc may be an engine, with the single arg a procedure of
one argument.
*)
(* Constructing procedure values by hand requires knowledge beyond the scope
of this interface, and is highly obliq-implementation-dependent.
It is much better to call Eval with appropriate arguments, so that
procedure values are produced. *)
====== Threads Etc. ======
PROCEDURE NewMutex(): Val;
(* Create a new mutex. *)
PROCEDURE MutexGet(mutex: Val; loc: Location:=NIL): Thread.Mutex
RAISES {Error};
(* The Thread.Mutex of a mutex. *)
PROCEDURE NewCondition(): Val;
(* Create a new condition. *)
PROCEDURE ConditionGet(mutex: Val; loc: Location:=NIL): Thread.Condition
RAISES {Error};
(* The Thread.Condition of a condition. *)
PROCEDURE Fork(proc: Val; stackSize: INTEGER; loc: Location:=NIL): Val
RAISES {Error};
(* Fork a procedure of no arguments and return a thread value. *)
PROCEDURE Join(thread: Val; loc: Location:=NIL): Val
RAISES {Error, Exception};
(* Join a thread and return its result. *)
====== Calling Modula-3 from Obliq via sys_call ======
VAR
sysCallFailure: ObValue.ValException;
(* An exception to be raised by SysCall procedures. *)
TYPE
SysCallClosure = OBJECT
METHODS
SysCall(READONLY args: Vals; loc: Location:=NIL): Val
RAISES{Error, Exception};
(* To be overridden. It should return an obliq Val, or raise an error
by calling RaiseError, or raise an exception by calling
RaiseException. The raised exception should normally be
sysCallFailure. The loc parameter should be passed through whenever
appropriate, or appriate error locations should be synthesized.
Alternatively, errors and exceptions may be left uncought, so
that they propagate back to Obliq; however this may result
in poor error location reporting. *)
END;
PROCEDURE RegisterSysCall(name: TEXT; clos: SysCallClosure);
(* To register a Modula-3 procedure that can be called from Obliq,
under a given name. Re-registering for the same name overrides
the previous proc for that name. Use clos=NIL to unregister. *)
PROCEDURE RaiseSysCallFailure(self: SysCallClosure; READONLY args: Vals;
loc: Location:=NIL): Val RAISES{Error, Exception};
(* A SysCallProc that simply raises sysCallFailure. *)
====== Errors and Exceptions ======
PROCEDURE RaiseError(msg: TEXT; loc: Location:=NIL) RAISES {Error};
(* Raises an Obliq error. *)
PROCEDURE NewException(name: TEXT): ObValue.ValException;
(* Creates a new obliq exception; the name is used for exception
matching in try expressions. *)
PROCEDURE RaiseException(exception: ObValue.ValException; msg: TEXT;
loc: Location:=NIL) RAISES {Exception};
(* Raises an Obliq exception. *)
PROCEDURE ReportError(swr: SynWr.T; packet: ObValue.ErrorPacket);
PROCEDURE ReportException(swr: SynWr.T; packet: ObValue.ExceptionPacket);
(* Report error conditions and return normally.
Use to intercept Obliq errors and report them:
TRY
... code that raises ObValue.Error and ObValue.Exception ...
EXCEPT ObValue.Error(packet) => Obliq.ReportError(swr, packet);
| ObValue.Exception(packet) => Obliq.ReportException(swr, packet);
END; *)
END Obliq.