Branch resolve-check, tree clean. Suite 214/214; fixpoint
OK (3,710,201 bytes); corpus 372 OK / 0 crash.
ISO 10514-2 refinement generics, instantiated by re-parsing the generic source with a substitution scope, driven by the session driver.
| Feature | Syntax | Notes |
|---|---|---|
| Type parameters | MODULE Box (T : TYPE) |
Box(INTEGER) |
| Value parameters | MODULE Buf (size : CARDINAL) |
Buf(10); template binds a placeholder |
| Procedure parameters | MODULE Sort (E : TYPE; Compare : PROCEDURE(a,b : E) : INTEGER) |
actual is Mod.Proc |
| Constraints | MODULE OrdBox (T : TYPE (ORDINAL)) |
ORDINAL, INTEGER, REAL, POINTER, SCALAR |
| Multiple parameters | MODULE Pair (T : TYPE; U : TYPE) |
both bound |
| Nested generics | MODULE WrapB = Wrap(IntBox.Box) |
an instance's exported type as an actual |
| Def + impl | DEFINITION/IMPLEMENTATION MODULE X = G(...) |
both required; template not emitted |
Constraints and actual-kind are checked at instantiation (233 on
mismatch). Suite: GenericProg, PairProg, BufProg, g_badbuf,
SortProg, OrdProg, g_realbox, GWrapProg.
SymTab.EnterTypeParamBound (types),
SetSymVal on a CONST (values), or SymTab.AliasProc +
Lower.AliasProc (procedures; ProcBaseByUid fixes mangling after
the instance scope is popped).Mod.Name) are classified as proc or type, which
is how both procedure parameters and nested generics reach a name
without an import.BoxA = OrdBox(INTEGER), BoxB = OrdBox(INTEGER) coexist
cleanly; verified). The only "same instance twice" case is a
refinement's DEFINITION and IMPLEMENTATION, which must instantiate
the generic's def and impl respectively.GENERIC CLASS — already achievable through generic
modules (verified, suite GCBoxProg): declare the class in the
generic module's TYPE block, implement it in the generic impl, and
instantiate the module: GENERIC DEFINITION MODULE GBox (T : TYPE);
TYPE
CLASS Box;
v : T;
PROCEDURE Put(x : T);
PROCEDURE Get() : T;
END Box;
END GBox.
* GBox's CLASS IMPLEMENTATION Box holds the method bodies;
DEFINITION/IMPLEMENTATION MODULE GCInt = GBox(INTEGER);
(* program: *) b : GCInt.Box; b.Put(42); ExitCode := b.Get()
So no standalone GENERIC CLASS syntax is required for the
capability. It also composes with the increment-3 features: suite
GStkProg instantiates a class whose array field is sized by a
value parameter and whose element is the type parameter:
GENERIC DEFINITION MODULE GStk (T : TYPE; cap : CARDINAL);
TYPE
CLASS Stk;
a : ARRAY [0..cap] OF T;
PROCEDURE Capacity() : INTEGER;
END Stk;
END GStk.
(* class impl: *) PROCEDURE Capacity() : INTEGER; BEGIN RETURN HIGH(a) END Capacity;
DEFINITION/IMPLEMENTATION MODULE GIntStk = GStk(INTEGER, 4); (* HIGH(a)=4 *)
Small print for the pattern: a class must be declared inside a
TYPE block (a bare CLASS item is not accepted in a DEFINITION
unit's item list); the CLASS IMPLEMENTATION block is a DeclSeq
item, so it needs a trailing ;; and a class impl's BEGIN
initialiser cannot assign a field (only module globals) — so
field state must be set by a method, as above.
cd .../m2compiler-V3/compiler
./M2 tests/g_ordbox.def tests/g_ordbox.mod tests/g_intbox.def \
tests/g_intbox.mod tests/g_wrap.def tests/g_wrap.mod \
tests/g_wrapb.def tests/g_wrapb.mod tests/g_wrapprog.mod # GWrapProg -> 42