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. Standalone syntax would only matter if a class must be
instantiated without a whole generic module; the principled form
for that is a type refinement (TYPE IntStack = Stack(INTEGER);),
which mirrors MODULE X = G(args) at type level but needs the
class's CLASS IMPLEMENTATION block re-parsed/renamed per instance —
a design of its own. Recommendation: keep the generic-module pattern.
Minor asymmetry noted: a class is accepted as a top-level item in an
IMPLEMENTATION/program DeclSeq but not in a DEFINITION unit's item
list (only inside a TYPE block) — harmless, but a tidy-up
candidate.
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