[Oberon] Module aliases - what is the correct way to handle them

Andreas Pirklbauer andreas_pirklbauer at yahoo.com
Sun Feb 23 19:11:05 CET 2020

Hi Paul,

I’ve now fully bought into your proposal to make ORB.ThisModule a tick
less restrictive by no longer checking the two "cross-combinations"
(obj.orgname # name) and (obj.name # orgname) that I had originally
proposed for the first WHILE loop in ThisModule - as I have now verified
that this omission indeed merely (and safely) re-allows the following cases:

  MODULE B10; IMPORT X := M, M := M0; END B10.  (*reuse M as alias*)
  MODULE B11; IMPORT M := M0, M0 := M; END B11.  (*swap M and M0*)
  MODULE B12; IMPORT M0 := M, X := M0; END B12.  (*reuse M0 as canonical*)

However, am still a bit uncomfortable with *always* generating “invalid import error”
  ELSE (*module already present*)
    IF non THEN ORS.Mark("invalid import order") END
  END ;

I would therefore like to propose the following as a minimum change to your
proposed solution, which (a) not only fixes the current bug in ORB.Mod bug,
but (b) also outputs the “appropriate” error message in *all* possible cases:

  PROCEDURE ThisModule(name, orgname: ORS.Ident; non: BOOLEAN; key: LONGINT): Object;
    VAR mod: Module; obj, obj1: Object;
  BEGIN obj1 := topScope; obj := obj1.next;  (*search for module*)
    WHILE (obj # NIL) & (obj(Module).orgname # orgname) DO obj1 := obj; obj := obj1.next END;
    IF obj = NIL THEN  (*new module, search for alias*)
      obj := topScope.next;
      WHILE (obj # NIL) & (obj.name # name) DO obj := obj.next END ;
      IF obj = NIL THEN  (*insert new module*)
        NEW(mod); mod.class := Mod; mod.rdo := FALSE;
        mod.name := name; mod.orgname := orgname; mod.val := key;
        mod.lev := nofmod; INC(nofmod); mod.dsc := NIL; mod.next := NIL;
        IF non THEN mod.type := noType ELSE mod.type := nilType END ;       (*!*)
        obj1.next := mod; obj := mod
      ELSIF non THEN
        IF obj.type.form = NoTyp THEN ORS.Mark("mult def") ELSE ORS.Mark("invalid import order") END
      ELSE ORS.Mark("re-import impossible")  (*conflict with alias*)
    ELSIF non THEN (*module already present and explicit import*)
      IF obj.type.form = NoTyp THEN ORS.Mark("mult def") ELSE ORS.Mark("invalid import order") END
    END ;
    RETURN obj
  END ThisModule;

(= http://github.com/andreaspirklbauer/Oberon-test-module-aliases/blob/master/Sources/ORB06ImprovedErrMsg.Mod)

The set of possible cases, together with their error messages, is shown below in the appendix.

Apart from the different error messages, the only difference to your proposed solution is to assign
mod.type := noType, when an explicit import is inserted for the first time, and mod.type := nilType,
when a re-import is inserted for the first time. This tiny change allows one to easily identify (and
check for) each possible case individually, when the same module name is encountered again.

Thanks to the discussion with yourself, Luca, Jörg and several others, there now is
even a complete proof that this indeed works in *all* possible cases. It is about as
boring as it gets, but in case you can actually endure it (yawn), there it is.. 


The set of test cases itself is listed below, together with the compiler message, or at:


I also felt that re-allowing *single* aliases for the cases B10, B11 and B12, as described above,
while at the same time continuing to disallow *multiple* aliases to the same module, was a
sensible choice as it requires only minimal changes to the current FPGA Oberon implementation.

PS: Turns out that multiple aliases could also be easily be added (with ~20 additional lines, see
ORB10 in the above repository), but I felt this would be overkill. Who needs more than one alias?

What do you think ?


Appendix: Test cases, together with the “appropriate” error messages:


(*B0 is correct*)
MODULE B0; IMPORT M0, X := M1; END B0.  (*no error message*)

(*B1-B5 are definitely erroneous*)
MODULE B1; IMPORT M, M; END B1.  (*mult def*)
MODULE B2; IMPORT M, M := M0; END B2.  (*mult def*)
MODULE B3; IMPORT M := M0, M; END B3.  (*mult def*)
MODULE B4; IMPORT M := M0, M := M0; END B4.  (*mult def*)
MODULE B5; IMPORT X := M, X := M0; END B5.  (*mult def*)

(*B6-B9 depend on the implementation - some allow these cases, others don't*)
MODULE B6; IMPORT M, X := M; END B6.  (*mult def*)
MODULE B7; IMPORT X := M, M; END B7.  (*mult def*)
MODULE B8; IMPORT M, X := M, Y := M; END B8.  (*mult def*)
MODULE B9; IMPORT X := M, Y := M; END B9.  (*mult def*)

(*B10-B12 can safely allowed by not checking obj.orgname # name and obj.name # orgname*)
MODULE B10; IMPORT X := M, M := M0; END B10.   (*no error message*)
MODULE B11; IMPORT M := M0, M0 := M; END B11.  (*no error message*)
MODULE B12; IMPORT M0 := M, X := M0; END B12.  (*no error message*)

(*B13-B16 test re-imports*)
MODULE B13; IMPORT M0, M1; END B13.  (*no error message*)
MODULE B14; IMPORT M := M0, M1; END B14.  (*no error message*)
MODULE B15; IMPORT M0 := M, M1; END B15.  (*re-import impossible*)
MODULE B16; IMPORT M1, M0 := M; END B16.  (*invalid import order*)
MODULE B17; IMPORT M1, M0; END B17.  (*invalid import*)

More information about the Oberon mailing list