Copyright (C) 1994, Digital Equipment Corp. INTERFACEObValue ; IMPORT SynWr, SynLocation, Rd, Wr, ObTree, NetObj, Thread, AtomList; EXCEPTION Exception(ExceptionPacket); (* trappable *) Error(ErrorPacket); (* only trappable by try-else *) ServerError(TEXT); (* like Error, but has no location info; immediately converted to Error on the way back from a server *) TYPE ErrorPacket = BRANDED "ErrorPacket" OBJECT msg: TEXT; location: SynLocation.T; END; ExceptionPacket = BRANDED "ExceptionPacket" OBJECT msg: TEXT; location: SynLocation.T; exception: ValException; data: Val; END; Tbl <: REFANY; TYPE Vals = ARRAY OF Val; Env = BRANDED OBJECT name: ObTree.IdeName; rest: Env; END; LocalEnv = Env BRANDED OBJECT val: Val; END; GlobalEnv = REF Vals; Val = BRANDED "Val" OBJECT END; ValOk = Val BRANDED "ValOk" OBJECT END; ValBool = Val BRANDED "ValBool" OBJECT bool: BOOLEAN; END; ValChar = Val BRANDED "ValChar" OBJECT char: CHAR; END; ValText = Val BRANDED "ValText" OBJECT text: TEXT; (* Non-NIL ! *) END; ValInt = Val BRANDED "ValInt" OBJECT int: INTEGER; temp: BOOLEAN:=FALSE; END; ValReal = Val BRANDED "ValReal" OBJECT real: LONGREAL; temp: BOOLEAN:=FALSE; END; ValException = Val BRANDED "ValException" OBJECT name: TEXT; END; ValOption = Val BRANDED "ValOption" OBJECT tag: TEXT; val: Val; END; ValVar = Val BRANDED "ValVar" OBJECT remote: RemVar; END; ValArray = Val BRANDED "ValArray" OBJECT remote: RemArray; END; ValFun = Val BRANDED "ValFun" OBJECT fun: ObTree.TermFun; global: GlobalEnv; END; ValMeth = Val BRANDED "ValMeth" OBJECT meth: ObTree.TermMeth; global: GlobalEnv; END; ValAlias = Val BRANDED "ValAlias" OBJECT label: TEXT; labelIndexHint: INTEGER; obj: ValObj; END; ValAnything = (* to be subtyped *) Val BRANDED "ValAnything" OBJECT what: TEXT; (* Only used for printing. *) picklable: BOOLEAN; METHODS Is(other: ValAnything): BOOLEAN := IsSelfOther; (* Override with what you want the "is" primitive to do to determine equality of two ValAnything values. The default method returns self=other. *) Print(): TEXT := PrintWhat; (* Override with a routine to print this value. The default method returns the "what"field. *) Copy(tbl: Tbl; loc: SynLocation.T): ValAnything RAISES {Error, NetObj.Error} := CopyError; (* Override with a routine that makes a copy of this value (the default CopyError raises error, CopyId returns self). Use this pattern: IF tbl.Get(self, (*out*)newVal) THEN RETURN newVal END; newVal := NEW(ValAnything, what:=self.what, ... all private fields set to NIL ... ); EVAL tbl.Put(self, newVal); ... fill private fields, possibly calling: newVal.field:=ObValue.CopyVal(self.field, tbl, loc) ... RETURN newVal; *) END; ValObj = Val BRANDED "ValObj" OBJECT remote: RemObj; END; ObjFields = ARRAY OF RECORD label: TEXT; field: Val; (* ValMeth for method fields, ValAlias for alias fields, other Val for value fields *) END; ValEngine = Val BRANDED "ValEngine" OBJECT remote: RemEngine; END; ValFileSystem = ValAnything BRANDED "ValFileSystem" OBJECT remote: RemFileSystem; OVERRIDES Is := FileSystemIs; Copy := CopyId; END; ValProcessor = ValAnything BRANDED "ValProcessor" OBJECT OVERRIDES Copy := CopyId; END; RemVar = NetObj.T BRANDED "RemVar" OBJECT METHODS Get(): Val RAISES {NetObj.Error}; Set(val: Val) RAISES {NetObj.Error}; END; RemVarServer <: RemVar; RemArray = NetObj.T BRANDED "RemArray" OBJECT METHODS Size(): INTEGER RAISES {NetObj.Error}; Get(i: INTEGER): Val RAISES {ServerError, NetObj.Error}; Set(i: INTEGER; val: Val) RAISES {ServerError, NetObj.Error}; Sub(start,size: INTEGER): ValArray RAISES {ServerError, NetObj.Error}; (* Extract the subarray self[start for size]. *) Upd(start, size: INTEGER; READONLY other: REF Vals) RAISES {ServerError, NetObj.Error}; (* Update self[start for size] with other[0 for size]. *) Obtain(): REF Vals RAISES {NetObj.Error}; (* Return self.array if local, or a copy of it if remote. Modifying the result of Obtain may violate network transparency. *) END; RemArrayServer <: RemArray; RemObj = NetObj.T BRANDED "RemObj" OBJECT METHODS Who(VAR(*out*) protected, serialized: BOOLEAN): TEXT RAISES {NetObj.Error}; Select(label: TEXT; internal: BOOLEAN; VAR hint: INTEGER): Val RAISES {Error, Exception, ServerError, NetObj.Error}; Invoke(label: TEXT; argNo: INTEGER; READONLY args: Vals; internal: BOOLEAN; VAR hint: INTEGER): Val RAISES {Error, Exception, ServerError, NetObj.Error}; Update(label: TEXT; val: Val; internal: BOOLEAN; VAR hint: INTEGER) RAISES {ServerError, NetObj.Error}; Redirect(val: Val; internal: BOOLEAN) RAISES {ServerError, NetObj.Error}; Has(label: TEXT; VAR hint: INTEGER): BOOLEAN RAISES {NetObj.Error}; (* Whether a field called label exists. *) Obtain(internal: BOOLEAN): REF ObjFields RAISES {ServerError, NetObj.Error}; (* Return self.fields if local, or a copy of it if remote. Modifying the result of Obtain may violate network transparency. *) END; RemObjServer <: RemObjServerPublic; RemObjServerPublic = RemObj BRANDED "RemObjServerPublic" OBJECT who: TEXT; sync: Sync; END; (* RemObjServer, a subtype of RemObj, is the standard implementation of local objects. Another subtype of RemObj is automatically produced by the Network Objects stub generator, for remote surrogates. Further subtypes of RemObj can be defined and used as client-specific pseudo-objects. In the latter case, the result of Who is used for printing; copying, cloning, and pickling operate on the results of Who and Obtain. *) Sync = BRANDED "Sync" OBJECT mutex: Thread.Mutex; END; RemEngine = NetObj.T BRANDED "RemEngine" OBJECT METHODS Who(): TEXT RAISES {NetObj.Error}; Eval(proc: Val; mySelf: RemObj): Val RAISES {Error, Exception, ServerError, NetObj.Error}; END; RemEngineServer = RemEngine BRANDED "RemEngineServer" OBJECT who: TEXT; arg: Val; OVERRIDES Who := EngineWho; Eval := EngineEval; END; RemFileSystem = NetObj.T BRANDED "RemFileSystem" OBJECT METHODS OpenRead(fileName: TEXT): Rd.T RAISES {NetObj.Error, ServerError}; OpenWrite(fileName: TEXT): Wr.T RAISES {NetObj.Error, ServerError}; OpenAppend(fileName: TEXT): Wr.T RAISES {NetObj.Error, ServerError}; END; RemFileSystemServer <: RemFileSystem; ArgArray = ARRAY [1..8] OF Val; VAR valOk: Val; netException, threadAlerted: ValException; showNetObjMsgs: BOOLEAN; machineAddress: TEXT; localProcessor: ValProcessor; PROCEDURE Setup(); (* To be called before any other use of this module. *) PROCEDURE Is(v1,v2: Val; location: SynLocation.T): BOOLEAN; PROCEDURE NewText(text: TEXT): Val; (* Create an Obliq text containing a non-NIL m3 TEXT. *) PROCEDURE NewVar(val: Val): ValVar; (* Create a new variable. *) PROCEDURE NewArray(READONLY vals: Vals): ValArray; (* Create a new array. *) PROCEDURE NewArrayFromVals(vals: REF Vals): ValArray; (* Careful: the vals passed in are shared and may get modified later. *) PROCEDURE ArrayCat(vals1, vals2: REF Vals): Val RAISES {}; PROCEDURE NewObject(READONLY fields: ObjFields; who: TEXT:=""; protected: BOOLEAN:=FALSE; sync: Sync:=NIL): ValObj; (* Create a new object. *) PROCEDURE NewObjectFromFields(fields: REF ObjFields; who: TEXT; protected: BOOLEAN; sync: Sync): ValObj; (* Careful: the fields passed in are shared and may get modified later. *) PROCEDURE ObjClone1(remObj: RemObj; mySelf: RemObj): ValObj RAISES {ServerError, NetObj.Error}; (* mySelf is the object invoking cloning, if any, or NIL. Then cloning is self-inflicted if remObj=mySelf. *) PROCEDURE ObjClone(READONLY remObjs: ARRAY OF RemObj; mySelf: RemObj): ValObj RAISES {ServerError, NetObj.Error}; (* mySelf is the object invoking cloning, if any, or NIL. Then cloning is self-inflicted for any remObjs[i]=mySelf. *) PROCEDURE NewAlias(obj: ValObj; label: TEXT; location: SynLocation.T) : ValAlias RAISES {Error, Exception}; PROCEDURE EngineWho(self: RemEngineServer): TEXT RAISES {NetObj.Error}; PROCEDURE EngineEval(self: RemEngineServer; proc: Val; mySelf: RemObj): Val RAISES {Error, Exception, ServerError, NetObj.Error}; PROCEDURE NewFileSystem(readOnly: BOOLEAN): ValFileSystem; PROCEDURE FileSystemIs(self: ValFileSystem; other: ValAnything): BOOLEAN; PROCEDURE SameException(exc1, exc2: ValException): BOOLEAN; PROCEDURE RaiseError(msg: TEXT; location: SynLocation.T) RAISES {Error}; PROCEDURE RaiseException(exception: ValException; msg: TEXT; loc: SynLocation.T) RAISES {Exception}; PROCEDURE RaiseNetException(msg: TEXT; atoms: AtomList.T; loc: SynLocation.T) RAISES {Exception}; PROCEDURE ErrorMsg(swr: SynWr.T; packet: ErrorPacket); PROCEDURE ExceptionMsg(wr: SynWr.T; packet: ExceptionPacket); PROCEDURE BadOp(pkg, op: TEXT; location: SynLocation.T) RAISES {Error}; PROCEDURE BadArgType(argNo: INTEGER; expected, pkg, op: TEXT; location: SynLocation.T) RAISES {Error}; PROCEDURE BadArgVal(argNo: INTEGER; expected, pkg, op: TEXT; location: SynLocation.T) RAISES {Error}; PROCEDURE BadArgsNoMsg(desired, found: INTEGER; routineKind, routineName: TEXT): TEXT; PROCEDURE IsSelfOther(self, other: ValAnything): BOOLEAN; PROCEDURE PrintWhat(self: ValAnything): TEXT; PROCEDURE CopyError(self: ValAnything; tbl: Tbl; loc: SynLocation.T): ValAnything RAISES {Error}; PROCEDURE CopyId(self: ValAnything; tbl: Tbl; loc: SynLocation.T): ValAnything; PROCEDURE InhibitTransmission(tc: INTEGER; reason: TEXT); (* Inhibits the network transmission of any object whose type has typecode "tc"; an obliq exception will result. To be used on all M3 types that are embedded in obliq values but that have only "local" meaning, such as threads. The reason should be a string like "threads cannot be transmitted/duplicated". *) PROCEDURE NewTbl(): Tbl; (* A new empty table for CopyVal. *) PROCEDURE CopyVal(val: Val; tbl: Tbl; loc: SynLocation.T): Val RAISES {Error, NetObj.Error}; (* Make a complete local copy of val, preserving sharing and circularities. Substructures are fetched over the network, if necessary. Protected objects and non-transferrable values produce errors. *) PROCEDURE CopyValToLocal(val: Val; tbl: Tbl; loc: SynLocation.T) : Val RAISES {Error, NetObj.Error}; PROCEDURE CopyLocalToVal(val: Val; tbl: Tbl; loc: SynLocation.T) : Val RAISES {Error, NetObj.Error}; (* Internal use only. *) VAR sysCallFailure: ValException; TYPE SysCallClosure = OBJECT METHODS SysCall(READONLY args: Vals; loc: SynLocation.T:=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 FetchSysCall(name: TEXT; VAR(*out*) clos: SysCallClosure): BOOLEAN; (* To fetch a registered Modula-3 procedure by its given name. Returns FALSE if not found. *) END ObValue.