|
|
@@ -85,6 +85,8 @@ VAR
|
|
|
tparent : ARRAY [0 .. MaxTypes - 1] OF TypeIndex;
|
|
|
tscope : ARRAY [0 .. MaxTypes - 1] OF ScopePtr;
|
|
|
tdone : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN;
|
|
|
+ tvtag : ARRAY [0 .. MaxTypes - 1] OF BOOLEAN; (* record has variants *)
|
|
|
+ ttag : ARRAY [0 .. MaxTypes - 1] OF FieldPtr; (* variant CASE selector *)
|
|
|
alo : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
|
|
|
ahi : ARRAY [0 .. MaxTypes - 1] OF INTEGER;
|
|
|
blo : ARRAY [0 .. 7] OF INTEGER;
|
|
|
@@ -510,6 +512,8 @@ PROCEDURE NewDesc (form: INTEGER; ref: TypeIndex): TypeIndex;
|
|
|
tform[nTypes] := form;
|
|
|
tref[nTypes] := ref;
|
|
|
tdone[nTypes] := FALSE;
|
|
|
+ tvtag[nTypes] := FALSE;
|
|
|
+ ttag[nTypes] := NIL;
|
|
|
INC(nTypes);
|
|
|
RETURN VAL(INTEGER, nTypes - 1)
|
|
|
END NewDesc;
|
|
|
@@ -591,6 +595,7 @@ PROCEDURE NewRecord (): TypeIndex;
|
|
|
RETURN NewDesc(FRecord, -1)
|
|
|
END NewRecord;
|
|
|
|
|
|
+
|
|
|
PROCEDURE NewSet (base: TypeIndex): TypeIndex;
|
|
|
BEGIN
|
|
|
RETURN NewDesc(FSet, base)
|
|
|
@@ -642,6 +647,72 @@ PROCEDURE Resolve (t: TypeIndex): TypeIndex;
|
|
|
RETURN t
|
|
|
END Resolve;
|
|
|
|
|
|
+PROCEDURE IsOrdinal (t: TypeIndex): BOOLEAN;
|
|
|
+(* An ordinal type: integer family, CHAR, UCHAR, BOOLEAN or an
|
|
|
+ enumeration (drives CASE/variant selectors). *)
|
|
|
+ VAR c: INTEGER;
|
|
|
+ BEGIN
|
|
|
+ IF Resolve(t) = InvalidType THEN RETURN FALSE END;
|
|
|
+ c := ClassOf(t);
|
|
|
+ RETURN (c = ClInt) OR (c = ClChar) OR (c = ClUChar)
|
|
|
+ OR (c = ClBool) OR (c = ClEnum)
|
|
|
+ END IsOrdinal;
|
|
|
+
|
|
|
+PROCEDURE ResetFields (rec: TypeIndex);
|
|
|
+(* Starts a fresh variant branch: drops any still-pending fields of
|
|
|
+ rec (their identifiers saw no ":" yet) and clears its layout so
|
|
|
+ the next branch overlays from the tag slot. Field names already
|
|
|
+ committed in an earlier branch stay in the record's scope. *)
|
|
|
+ VAR i: CARDINAL;
|
|
|
+ r: TypeIndex;
|
|
|
+ BEGIN
|
|
|
+ r := Resolve(rec);
|
|
|
+ i := 0;
|
|
|
+ WHILE i < nPendF DO
|
|
|
+ IF pendF[i]^.owner = r THEN
|
|
|
+ nPendF := nPendF - 1;
|
|
|
+ pendF[i] := pendF[nPendF]
|
|
|
+ ELSE
|
|
|
+ INC(i)
|
|
|
+ END
|
|
|
+ END;
|
|
|
+ IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
|
|
|
+ tdone[r] := FALSE
|
|
|
+ END
|
|
|
+ END ResetFields;
|
|
|
+
|
|
|
+PROCEDURE SetVariantTag (rec: TypeIndex; name: ARRAY OF CHAR);
|
|
|
+(* Records the variant CASE selector field of rec (by name); called
|
|
|
+ just after the tag's type is fixed, before the variant branches. *)
|
|
|
+ VAR r: TypeIndex;
|
|
|
+ BEGIN
|
|
|
+ r := Resolve(rec);
|
|
|
+ IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
|
|
|
+ ttag[r] := FindField(r, name)
|
|
|
+ END
|
|
|
+ END SetVariantTag;
|
|
|
+
|
|
|
+PROCEDURE MarkVariant (rec: TypeIndex);
|
|
|
+(* Records that this record has a variant part (its fields overlap
|
|
|
+ from the tag slot on, so whole-record comparison is 236). *)
|
|
|
+ VAR r: TypeIndex;
|
|
|
+ BEGIN
|
|
|
+ r := Resolve(rec);
|
|
|
+ IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
|
|
|
+ tvtag[r] := TRUE
|
|
|
+ END
|
|
|
+ END MarkVariant;
|
|
|
+
|
|
|
+PROCEDURE IsVariant (rec: TypeIndex): BOOLEAN;
|
|
|
+ VAR r: TypeIndex;
|
|
|
+ BEGIN
|
|
|
+ r := Resolve(rec);
|
|
|
+ IF (r >= 0) AND (r < VAL(INTEGER, nTypes)) THEN
|
|
|
+ RETURN tvtag[r]
|
|
|
+ END;
|
|
|
+ RETURN FALSE
|
|
|
+ END IsVariant;
|
|
|
+
|
|
|
PROCEDURE PushClassScope (t: TypeIndex);
|
|
|
VAR r: TypeIndex;
|
|
|
BEGIN
|
|
|
@@ -991,7 +1062,8 @@ PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
|
|
|
separately); records sum members. Depth guards cycles (not 223). *)
|
|
|
VAR r: TypeIndex;
|
|
|
f: FieldPtr;
|
|
|
- n: CARDINAL;
|
|
|
+ tagF: FieldPtr;
|
|
|
+ n, plain, high: CARDINAL;
|
|
|
BEGIN
|
|
|
IF depth > ResDepth THEN RETURN 0 END;
|
|
|
r := Resolve(t);
|
|
|
@@ -1005,6 +1077,45 @@ PROCEDURE TypeSizeD (t: TypeIndex; depth: CARDINAL): CARDINAL;
|
|
|
| FPtr, FOpenArr, FArray, FProc, FUStr : RETURN 8
|
|
|
| FRecord, FClass :
|
|
|
n := 0;
|
|
|
+ IF tvtag[r] AND (ttag[r] # NIL) THEN
|
|
|
+ (* variant record: plain fields (declared before the tag) pack
|
|
|
+ normally; the tag and every variant field overlay in one
|
|
|
+ slot, so the record is plainSize + max(tag, variants). *)
|
|
|
+ plain := 0; high := 0;
|
|
|
+ f := fields;
|
|
|
+ WHILE f # NIL DO
|
|
|
+ IF f^.owner = r THEN
|
|
|
+ IF f^.ord < ttag[r]^.ord THEN
|
|
|
+ (* a plain field, packed before the tag *)
|
|
|
+ IF ClassOf(f^.typ) = ClArray THEN
|
|
|
+ plain := plain + ArrObjSize(f^.typ)
|
|
|
+ ELSE
|
|
|
+ plain := plain + TypeSizeD(f^.typ, depth + 1)
|
|
|
+ END
|
|
|
+ ELSIF f = ttag[r] THEN
|
|
|
+ (* the tag itself: its own slot *)
|
|
|
+ IF ClassOf(f^.typ) = ClArray THEN
|
|
|
+ plain := plain + ArrObjSize(f^.typ)
|
|
|
+ ELSE
|
|
|
+ plain := plain + TypeSizeD(f^.typ, depth + 1)
|
|
|
+ END
|
|
|
+ ELSE
|
|
|
+ (* a variant field: overlay in the region after the tag *)
|
|
|
+ IF ClassOf(f^.typ) = ClArray THEN
|
|
|
+ IF ArrObjSize(f^.typ) > high THEN
|
|
|
+ high := ArrObjSize(f^.typ)
|
|
|
+ END
|
|
|
+ ELSE
|
|
|
+ IF TypeSizeD(f^.typ, depth + 1) > high THEN
|
|
|
+ high := TypeSizeD(f^.typ, depth + 1)
|
|
|
+ END
|
|
|
+ END
|
|
|
+ END
|
|
|
+ END;
|
|
|
+ f := f^.next
|
|
|
+ END;
|
|
|
+ RETURN plain + high
|
|
|
+ END;
|
|
|
f := fields;
|
|
|
WHILE f # NIL DO
|
|
|
IF f^.owner = r THEN
|
|
|
@@ -1051,29 +1162,92 @@ PROCEDURE ObjectSize (t: TypeIndex): CARDINAL;
|
|
|
PROCEDURE ComputeOffsets (r: TypeIndex);
|
|
|
(* Declaration-order offsets over the (prepend-built, hence reverse)
|
|
|
field chain, plus declaration ranks. Array fields count 8
|
|
|
- (pointer-sized in records, matching the locked layout). *)
|
|
|
+ (pointer-sized in records, matching the locked layout).
|
|
|
+ A record with a variant part lays every field from the first tag
|
|
|
+ slot on at that slot's offset (all variant fields overlap), and
|
|
|
+ the record's size is the largest such field. *)
|
|
|
VAR f: FieldPtr;
|
|
|
- total: INTEGER;
|
|
|
+ tagF: FieldPtr; (* the variant CASE selector field *)
|
|
|
+ total, high, tagSize, varOff: INTEGER;
|
|
|
cnt, ord: CARDINAL;
|
|
|
off: INTEGER;
|
|
|
BEGIN
|
|
|
- total := 0; cnt := 0;
|
|
|
+ IF NOT tvtag[r] THEN
|
|
|
+ (* plain record: declaration-ordered, tightly packed *)
|
|
|
+ total := 0; cnt := 0;
|
|
|
+ f := fields;
|
|
|
+ WHILE f # NIL DO
|
|
|
+ IF f^.owner = r THEN
|
|
|
+ total := total + VAL(INTEGER, FieldSize(f^.typ));
|
|
|
+ INC(cnt)
|
|
|
+ END;
|
|
|
+ f := f^.next
|
|
|
+ END;
|
|
|
+ off := total; ord := cnt;
|
|
|
+ f := fields;
|
|
|
+ WHILE f # NIL DO
|
|
|
+ IF f^.owner = r THEN
|
|
|
+ off := off - VAL(INTEGER, FieldSize(f^.typ));
|
|
|
+ DEC(ord);
|
|
|
+ f^.off := off;
|
|
|
+ f^.ord := ord
|
|
|
+ END;
|
|
|
+ f := f^.next
|
|
|
+ END;
|
|
|
+ tdone[r] := TRUE;
|
|
|
+ RETURN
|
|
|
+ END;
|
|
|
+ (* variant record. Fields declared before the CASE tag pack
|
|
|
+ normally; the tag starts the overlay region and every variant
|
|
|
+ field (declared after the tag) overlays at the tag's slot.
|
|
|
+ Ranks are reverse-declaration (0 = last declared), so the tag
|
|
|
+ has rank = number-of-fields-after-it, and plain fields have
|
|
|
+ larger ranks. *)
|
|
|
+ tagF := ttag[r];
|
|
|
+ IF tagF = NIL THEN
|
|
|
+ (* no tag recorded (malformed); fall back to plain layout *)
|
|
|
+ tvtag[r] := FALSE;
|
|
|
+ ComputeOffsets(r);
|
|
|
+ RETURN
|
|
|
+ END;
|
|
|
+ cnt := 0;
|
|
|
f := fields;
|
|
|
WHILE f # NIL DO
|
|
|
- IF f^.owner = r THEN
|
|
|
- total := total + VAL(INTEGER, FieldSize(f^.typ));
|
|
|
- INC(cnt)
|
|
|
+ IF f^.owner = r THEN INC(cnt) END;
|
|
|
+ f := f^.next
|
|
|
+ END;
|
|
|
+ ord := cnt;
|
|
|
+ f := fields;
|
|
|
+ WHILE f # NIL DO
|
|
|
+ IF f^.owner = r THEN DEC(ord); f^.ord := ord END;
|
|
|
+ f := f^.next
|
|
|
+ END;
|
|
|
+ (* plain fields: pack in declaration order up to the tag *)
|
|
|
+ total := 0;
|
|
|
+ f := fields;
|
|
|
+ WHILE f # NIL DO
|
|
|
+ IF (f^.owner = r) AND (f^.ord < tagF^.ord) THEN
|
|
|
+ total := total + VAL(INTEGER, FieldSize(f^.typ))
|
|
|
END;
|
|
|
f := f^.next
|
|
|
END;
|
|
|
- off := total; ord := cnt;
|
|
|
+ off := total;
|
|
|
f := fields;
|
|
|
WHILE f # NIL DO
|
|
|
- IF f^.owner = r THEN
|
|
|
+ IF (f^.owner = r) AND (f^.ord < tagF^.ord) THEN
|
|
|
off := off - VAL(INTEGER, FieldSize(f^.typ));
|
|
|
- DEC(ord);
|
|
|
- f^.off := off;
|
|
|
- f^.ord := ord
|
|
|
+ f^.off := off
|
|
|
+ END;
|
|
|
+ f := f^.next
|
|
|
+ END;
|
|
|
+ (* the tag occupies its own slot after the plain fields; every
|
|
|
+ variant field overlays in the region after the tag *)
|
|
|
+ tagF^.off := total;
|
|
|
+ varOff := total + VAL(INTEGER, FieldSize(tagF^.typ));
|
|
|
+ f := fields;
|
|
|
+ WHILE f # NIL DO
|
|
|
+ IF (f^.owner = r) AND (f^.ord > tagF^.ord) THEN
|
|
|
+ f^.off := varOff
|
|
|
END;
|
|
|
f := f^.next
|
|
|
END;
|