X will be required to have imported X.
MI_* for interfaces and MM_* for modules which have the
type UNTRACED REF RT0.ModuleInfo, but these symbols are
not accessible from Modula-3 code. Our solution is to create two new
builtin functions called THIS_MODULE(), which returns the
MM_ symbol for the module in which the function appears,
and INTERFACE_UNIT(X) which returns MI_X for
the named interface. Since THIS_MODULE() takes no
argument, it is impossible for one module to get the descriptor for a
second unless the second one explicitly provides it. Also the only
names which may be passed to INTERFACE_UNIT() are those
which are explicitly imported in the calling module.
Additionally, we want to ensure that arbitrary safe programs cannot
alter the contents of the interface or module descriptors, nor can
they forge descriptors. So we define two opaque types which are the
return types of THIS_MODULE() and
INTERFACE_UNIT(X).
INTERFACE RTCodeBuiltin;
TYPE
Module <: ADDRESS; (* return type of THIS_MODULE() *)
Interface <: ADDRESS; (* return type of INTERFACE_UNIT() *)
END RTCodeBuiltin.
The revelations of these types occur in RTCode.m3.
REVEAL RTCodeBuiltin.Module = UNTRACED BRANDED REF RT0.ModuleInfo; REVEAL RTCodeBuiltin.Interface = UNTRACED BRANDED REF RT0.ModuleInfo;We provide a second interface, called
RTCode, that is
imported by callers of THIS_MODULE() and
INTERFACE_UNIT(). This interface declares two procedures
that answer questions about modules.
ModuleExportsInterface determines if the module
m exports any of the procedures declared in the interface
i. ModuleImplementsProcedure determines if
the procedure referred to by p_ref is defined in the
module m.
INTERFACE RTCode;
IMPORT RTCodeBuiltin;
TYPE
Module = RTCodeBuiltin.Module;
Interface = RTCodeBuiltin.Interface;
(* returns true iff m exports a function declared in i *)
PROCEDURE ModuleExportsInterface(m: Module; i: Interface): BOOLEAN;
(* return true iff m defines procedure p *)
PROCEDURE ModuleImplementsProcedure(m: Module; p_ref: PROCANY): BOOLEAN;
INTERFACE_UNIT() with that interface name. Just
exporting an interface from a module is not enough to bring that
interface's name into the top level scope of a module. A second
related problem is that it is impossible to refer to the interface
exported by a generic module, because you cannot name that interface
at all. But you may use INTERFACE_UNIT() for other
interfaces inside a generic module.
The third problem is that the
RTCode.ModuleExportsInterface function deduces the export
relationship by looking for exported procedures. It is possible for a
module to contain an EXPORTS declaration but not export
any procedures, in which case this function will return
FALSE.
Domain and Dispatcher interfaces.
Domain.CreateFromInterface(i: RTCode.Interface): T (* safely create a domain *) Dispatcher.InstallAuthHandler(THIS_MODULE(), event, authHandler) (* assert authority over event. Dispatcher checks RTCode.ModuleImplementsProcedure(firstArg, secondArg) *)