DIRECTORY
Alloc: TYPE USING [Notifier],
ComData: TYPE USING [interface, mainCtx, textIndex, typeCARDINAL],
PrincOps: TYPE USING [GFTIndex, globalbase, localbase],
Log: TYPE USING [Error, ErrorSei, ErrorTree, Warning],
P4: 
TYPE 
USING [
Repr, none, signed, unsigned, both, other, OpWordCount, Prop, mark, ownGfi,
currentLevel,
AdjustBias, BitsForType, CheckFields, ConstantInterval, EmptyInterval,
ForceType, Interval, LayoutArgs, LayoutFields, MakeEPLink,
RewriteAssign, Rhs, StructuredLiteral, TreeLiteral, TreeLiteralValue,
VPop, VProp, VRep],
 
Symbols: 
TYPE 
USING [
Base, ExtensionType, Type, ISEIndex, CSEIndex, RecordSEIndex,
CTXIndex, CBTIndex, BitAddress, BitCount, TypeClass, WordCount,
WordLength, nullType, ISENull, CSENull, RecordSENull, CBTNull,
codeANY, codeCHAR, codeINT, lG, lZ, RootBti,
typeANY, typeTYPE, seType, ctxType, bodyType],
 
SymbolOps: 
TYPE 
USING [
ArgRecord, BitsPerElement, Cardinality, ConstantId, CtxEntries, EnterExtension,
FindExtension, FirstCtxSe, LinkMode, NextSe, NormalType, RCType,
SearchContext, TypeLink, UnderType, WordsForType],
 
Tree: TYPE USING [Base, Index, Link, Map, NodeName, Scan, Null, treeType],
TreeOps: 
TYPE 
USING [
CopyTree, FreeNode, FreeTree, GetNode, IdentityMap, ListHead, ListLength,
NthSon, OpName, PopTree, PushList, PushNode, PushTree,
ScanList, SetAttr, SetInfo, UpdateList];
 
 
Pass4D: 
PROGRAM
IMPORTS
Log, P4, SymbolOps, TreeOps,
dataPtr: ComData
 
EXPORTS P4 = {
OPEN TreeOps, SymbolOps, Symbols;
tb: Tree.Base; -- tree base address (local copy)
seb: Symbols.Base; -- se table base address (local copy)
ctxb: Symbols.Base; -- context table base address (local copy)
bb: Symbols.Base; -- body table base address (local copy)
DeclNotify: 
PUBLIC Alloc.Notifier = {
called by allocator whenever table area is repacked
tb ← base[Tree.treeType];
seb ← base[seType];  ctxb ← base[ctxType];
bb ← base[bodyType]};
 
VarInit: PUBLIC SIGNAL RETURNS [BOOL] = CODE;
ownGfi: PrincOps.GFTIndex = P4.ownGfi;
ItemId: 
PROC [t: Tree.Link] 
RETURNS [ISEIndex] = {
RETURN [
WITH t 
SELECT 
FROM
symbol => index,
subtree => ItemId[tb[index].son[1]],
ENDCASE => ERROR]};
 
 
FirstId: 
PROC [node: Tree.Index] 
RETURNS [ISEIndex] = {
RETURN [ItemId[ListHead[tb[node].son[1]]]]};
 
DeclItem: 
PUBLIC 
PROC [item: Tree.Link] = {
node: Tree.Index = GetNode[item];
initFlag, eqFlag: BOOL;
ExpInit: 
PROC = 
INLINE {
OPEN tb[node];
type: CSEIndex = UnderType[TypeForDecl[node]];
class: TypeClass = seb[NormalType[type]].typeTag;
son[3] ← P4.Rhs[son[3], type, $init];
IF eqFlag 
THEN {
t: Tree.Link ← son[3];
prop: P4.Prop = P4.VProp[];
WHILE OpName[t] = cast DO t ← NthSon[t, 1] ENDLOOP;
IF P4.TreeLiteral[t] 
THEN {
DefineSEValue[ids:son[1], value:P4.TreeLiteralValue[t]]; GO TO defined};
 
IF prop.noFreeVar 
AND prop.noXfer 
AND class # $transfer 
THEN {
DefineSEValue[ids:son[1]];
AugmentSEValue[son[1], value, son[3]]; son[3] ← Tree.Null; GO TO defined};
 
IF class = $transfer 
THEN
WITH t 
SELECT 
FROM
symbol => {
sei: ISEIndex = index;
IF seb[sei].constant 
THEN {
DefineSEValue[ids:son[1], value:seb[sei].idValue, info:seb[sei].idInfo];
IF seb[sei].extended 
THEN
AugmentSEValue[son[1], form, FindExtension[sei].tree, TRUE];
 
GO TO defined}};
 
 
ENDCASE;
 
 
DefineSEVar[ids:son[1]];
EXITS
defined => son[3] ← FreeTree[son[3]]};
 
 
SELECT class 
FROM
$ref, $arraydesc, $relative =>
IF ListLength[son[1]] # 1 
AND son[3] # Tree.Null
AND ~P4.StructuredLiteral[son[3]] 
THEN
Log.Warning[pointerInit];
 
 
 
ENDCASE;
 
P4.VPop[]};
 
BodyInit: 
PROC = 
INLINE {
expNode: Tree.Index = GetNode[tb[node].son[3]];
bti: CBTIndex = tb[expNode].info;
IF eqFlag 
THEN {
IF tb[expNode].attr3 
THEN {  
-- inline
DefineSEValue[ids:tb[node].son[1], info:bti];
AugmentSEValue[tb[node].son[1], form,
IF dataPtr.interface THEN TrimTree[tb[node].son[3]] ELSE Tree.Null]}
 
 
ELSE DefineSEValue[
ids: tb[node].son[1],
value: P4.MakeEPLink[bb[bti].entryIndex, ownGfi], info: bti];
 
tb[node].son[3] ← Tree.Null}
 
ELSE {PushNode[body, 0]; SetInfo[bti]; tb[node].son[3] ← PopTree[]}};
 
saveIndex: CARDINAL = dataPtr.textIndex;
IF tb[node].attr3 = P4.mark THEN RETURN; -- already processed
tb[node].attr3 ← P4.mark;
dataPtr.textIndex ← tb[node].info;
initFlag ← (tb[node].son[3] # Tree.Null);
IF tb[node].name = typedecl 
THEN {
ENABLE VarInit => {RESUME [FALSE]};
TypeExp[tb[node].son[2]];  CheckDefaults[item]}
 
ELSE {
OPEN tb[node];
op: Tree.NodeName = OpName[son[3]];
IF son[2] # Tree.Null THEN TypeExp[son[2], op = body];
IF initFlag 
THEN {
eqFlag ← attr1;
SELECT op 
FROM
body, procinit => BodyInit[];
signalinit =>
IF eqFlag 
THEN {
expNode: Tree.Index = GetNode[son[3]];
DefineSEValue[son[1], P4.MakeEPLink[tb[expNode].info, ownGfi], RootBti]; 
son[3] ← FreeTree[son[3]]};
 
 
inline => {
expNode: Tree.Index = GetNode[son[3]];
tb[expNode].son[1] ← UpdateList[tb[expNode].son[1], InlineOp];
DefineSEValue[ids:son[1]];
AugmentSEValue[son[1], value, son[3]];  son[3] ← Tree.Null};
 
ENDCASE => ExpInit[]}};
 
 
 
MarkAndCheckSE[tb[node].son[1], initFlag];
dataPtr.textIndex ← saveIndex};
 
TypeForDecl: 
PROC [node: Tree.Index] 
RETURNS [Type] = {
RETURN [
IF tb[node].son[2] # Tree.Null
THEN TypeForTree[tb[node].son[2]]
ELSE seb[FirstId[node]].idType]};
 
 
ConstInit: 
PROC [t: Tree.Link] 
RETURNS [
BOOL] = {
RETURN [
IF OpName[t] # all
THEN P4.StructuredLiteral[t]
ELSE ConstInit[NthSon[t, 1]]]};
 
 
InlineByte: Tree.Map = {
v ← P4.Rhs[t, dataPtr.typeCARDINAL];  P4.VPop[];
IF ~P4.TreeLiteral[v] THEN Log.ErrorTree[nonConstant, v];
RETURN};
 
InlineOp: Tree.Map = {RETURN [UpdateList[t, InlineByte]]};
DefineSEVar: PROC [ids: Tree.Link] = {
UpdateSE: Tree.Scan = {
sei: ISEIndex = ItemId[t];
seb[sei].constant ← FALSE};
 
ScanList[ids, UpdateSE]};
 
DefineSEValue: PROC [ids: Tree.Link, value: UNSPECIFIED𡤀, info: CBTIndexTNull] = {
UpdateSE: Tree.Scan = {
sei: ISEIndex = ItemId[t];
seb[sei].constant ← TRUE;
seb[sei].idValue ← value;  seb[sei].idInfo ← info};
 
ScanList[ids, UpdateSE]};
 
AugmentSEValue: 
PROC [
ids: Tree.Link,
type: ExtensionType, extension: Tree.Link,
copy: BOOL←FALSE] = {
UpdateSE: Tree.Scan = {
sei: ISEIndex = ItemId[t];
EnterExtension[sei, type, IF copy THEN IdentityMap[extension] ELSE extension];
copy ← TRUE};
 
ScanList[ids, UpdateSE]};
 
MarkAndCheckSE: PROC [ids: Tree.Link, initialized: BOOL] = {
UpdateSE: Tree.Scan = {
sei: ISEIndex = ItemId[t];
seb[sei].mark4 ← TRUE;
IF dataPtr.interface THEN CheckDefinition[sei, initialized];
IF seb[sei].idType = typeTYPE 
AND ctxb[seb[sei].idCtx].level # lZ 
THEN
seb[sei].idValue ← sei - ISEIndex.FIRST};
 
 
ScanList[ids, UpdateSE]};
 
CheckDefinition: 
PROC [sei: ISEIndex, initialized: 
BOOL] = {
SELECT seb[sei].idCtx 
FROM
dataPtr.mainCtx =>
SELECT LinkMode[sei] 
FROM
val => IF ~initialized OR seb[sei].extended THEN RETURN;
ref => IF ~initialized THEN RETURN;
manifest, type => IF ConstantId[sei] THEN RETURN;
ENDCASE;
 
 
ENDCASE => RETURN;
 
Log.ErrorSei[nonDefinition, sei]};
 
CheckDefaults: PROC [t: Tree.Link] = {
TestDefaults: Tree.Scan = {
node: Tree.Index = GetNode[t];
saveIndex: CARDINAL = dataPtr.textIndex;
sei: ISEIndex = FirstId[node];
dataPtr.textIndex ← tb[node].info;
IF seb[sei].extended 
THEN {
type: CSEIndex =
UnderType[IF seb[sei].idType = typeTYPE THEN sei ELSE seb[sei].idType];
 
nType: CSEIndex = NormalType[type];
TestDefault: Tree.Map = {
IF OpName[t] = void THEN v ← t
ELSE {
v ← P4.AdjustBias[P4.Rhs[t, type, $init], -BiasForType[type]];
IF P4.TreeLiteral[v] 
AND (
WITH n: seb[nType] 
SELECT 
FROM
basic => n.code # codeINT OR P4.VRep[] = P4.signed,
ENDCASE => TRUE) THEN
v ← P4.ForceType[v, type];
 
 
IF ~(P4.VProp[].noFreeVar 
OR (
SIGNAL VarInit[])) 
THEN
Log.ErrorTree[nonConstant, v];
 
P4.VPop[]};
 
RETURN};
 
t: Tree.Link ← FindExtension[sei].tree;
v: Tree.Link ← UpdateList[IdentityMap[t], TestDefault];
IF t.tag # symbol 
AND P4.StructuredLiteral[v] 
THEN
UpdateDefaults[tb[node].son[1], v]
 
ELSE v ← FreeTree[v]};
 
dataPtr.textIndex ← saveIndex};
 
IF dataPtr.interface THEN ScanList[t, TestDefaults]};
 
UpdateDefaults: 
PROC [ids: Tree.Link, v: Tree.Link] = {
copy: BOOL ← FALSE;
UpdateDefault: Tree.Scan = {
sei: ISEIndex = ItemId[t];
old: Tree.Link ← FindExtension[sei].tree;
EnterExtension[sei, default, IF copy THEN IdentityMap[v] ELSE v];
copy ← TRUE;
[] ← FreeTree[old]};
 
ScanList[ids, UpdateDefault]};
 
TrimTree: Tree.Map = {
WITH t 
SELECT 
FROM
subtree => {
node: Tree.Index = index;
SELECT tb[node].name 
FROM
body => {
OPEN tb[node];
PushTree[TrimTree[son[1]]];
PushTrimDecls[son[2]];
PushTree[TrimTree[son[3]]];  PushTree[TrimTree[son[4]]];
PushNode[body, 4];  SetInfo[info];
SetAttr[1, attr1]; SetAttr[2, attr2]; SetAttr[3, attr3];
v ← PopTree[]};
 
block => {
OPEN tb[node];
PushTrimDecls[son[1]];  PushTree[TrimTree[son[2]]];
PushNode[block, 2];  SetInfo[info];
SetAttr[1, attr1]; SetAttr[2, attr2]; SetAttr[3, attr3];
v ← PopTree[]};
 
cdot => v ← TrimTree[tb[node].son[2]];
ENDCASE => v ← CopyTree[[@tb, t], TrimTree]};
 
 
ENDCASE => v ← t;
 
RETURN};
 
PushTrimDecls: 
PROC [t: Tree.Link] = {
IF OpName[t] = initlist 
THEN {
node: Tree.Index = GetNode[t];
PushTree[TrimTree[tb[node].son[1]]];  PushTrimDecls[tb[node].son[2]];
PushNode[initlist, 2];  SetInfo[tb[node].info]}
 
ELSE {
n: CARDINAL ← 0;
PushDecl: Tree.Scan = {
node: Tree.Index = GetNode[t];
SELECT tb[node].name 
FROM
typedecl => NULL;
decl =>
IF tb[node].son[3] # Tree.Null 
THEN {
OPEN  tb[node];
PushTree[TrimTree[son[1]]];  PushTree[Tree.Null];
PushTree[TrimTree[son[3]]];
PushNode[decl, 3];  SetInfo[info];
SetAttr[1, attr1]; SetAttr[2, attr2]; SetAttr[3, ~P4.mark];
n ← n+1};
 
 
ENDCASE => ERROR};
 
 
ScanList[t, PushDecl];  PushList[n]}};
 
 
DeclUpdate: 
PUBLIC 
PROC [item: Tree.Link] 
RETURNS [update: Tree.Link] = {
node: Tree.Index = GetNode[item];
IF tb[node].name = typedecl 
OR tb[node].son[3] = Tree.Null 
THEN
update ← Tree.Null
 
ELSE {
OPEN tb[node];
type: CSEIndex = UnderType[TypeForDecl[node]];
rewrite: 
BOOL = 
SELECT OpName[tb[node].son[3]] 
FROM
body, signalinit => FALSE,
ENDCASE => TRUE;
 
n: CARDINAL = ListLength[tb[node].son[1]];
ScanList[tb[node].son[1], PushTree];
PushTree[tb[node].son[3]];
FOR i: 
CARDINAL 
IN [1 .. n] 
DO
IF i = n THEN PushNode[assign, 2]
ELSE {PushNode[assignx, 2]; SetInfo[type]};
SetInitAttr[type, ConstInit[tb[node].son[3]]];
IF rewrite THEN PushTree[P4.RewriteAssign[GetNode[PopTree[]], type]];
ENDLOOP;
 
SetInfo[info];  update ← PopTree[];  tb[node].son[3] ← Tree.Null};
 
FreeNode[node];
RETURN};
 
SetInitAttr: 
PROC [type: CSEIndex, const: 
BOOL] = {
SetAttr[1, TRUE];
IF P4.currentLevel = lG 
AND ~const 
THEN
SELECT RCType[type] 
FROM
simple => {SetAttr[2, TRUE]; SetAttr[3, FALSE]};
composite => {SetAttr[2, TRUE]; SetAttr[3, TRUE]};
ENDCASE => SetAttr[2, FALSE]
 
 
ELSE SetAttr[2, FALSE]};
 
TypeExp: 
PUBLIC 
PROC [typeExp: Tree.Link, body, indirect: 
BOOL ← 
FALSE] = {
body => arg records subsumed by frame
WITH typeExp 
SELECT 
FROM
symbol =>
IF ~indirect 
THEN {
iSei: ISEIndex = index;
IF ~seb[iSei].mark4 THEN DeclItem[[subtree[index: seb[iSei].idValue]]]};
 
 
subtree => {
node: Tree.Index = index;
SELECT tb[node].name 
FROM
discrimTC => TypeExp[tb[node].son[1], FALSE, indirect];
cdot => TypeExp[tb[node].son[2], body, indirect];
implicitTC, linkTC => NULL;
frameTC => NULL;
ENDCASE => {
OPEN tb[node];
sei: CSEIndex = info;
IF ~seb[sei].mark4 
THEN
WITH type: seb[sei] 
SELECT 
FROM
enumerated =>
IF type.machineDep 
THEN
[nValues:type.nValues, sparse:type.sparse] ←
LayoutEnum[son[1], type.valueCtx];
 
 
 
record => {
ENABLE VarInit => {RESUME [FALSE]};
ScanList[son[1], DeclItem];
IF attr1 THEN ScanList[son[1], AssignPositions];
WITH type 
SELECT 
FROM
notLinked =>
IF attr1 THEN P4.CheckFields[LOOPHOLE[sei, RecordSEIndex], 0]
ELSE P4.LayoutFields[LOOPHOLE[sei, RecordSEIndex], 0];
 
ENDCASE;
 
ExtractFieldAttributes[LOOPHOLE[sei, RecordSEIndex]];
CheckDefaults[son[1]]};
 
ref => {
IF type.var AND FALSE THEN Log.Error[unimplemented];
TypeExp[son[1], FALSE, TRUE]};
 
array => {
maxArraySize: WordCount = BitCount.LAST/WordLength;
IF son[1] # Tree.Null THEN TypeExp[son[1]];
TypeExp[son[2], FALSE, indirect];
IF Cardinality[type.indexType] >
MaxCardinality[type.componentType, type.packed, maxArraySize] 
THEN
Log.Error[addressOverflow]};
 
 
 
arraydesc => TypeExp[son[1], FALSE, TRUE];
transfer => {
origin, newOrigin: CARDINAL;
rSei: RecordSEIndex;
origin ← 
SELECT type.mode 
FROM
program => PrincOps.globalbase,
signal, error => PrincOps.localbase+1,
proc => PrincOps.localbase,
ENDCASE => 0;
 
IF OpName[son[1]] # anyTC 
THEN {
ScanList[son[1], DeclItem];  CheckDefaults[son[1]]};
 
rSei ← ArgRecord[type.typeIn];
IF rSei # RecordSENull 
THEN {
seb[rSei].hints.comparable ← TRUE; -- for now
newOrigin ← P4.LayoutArgs[rSei, origin, body];
seb[rSei].length ← (newOrigin - origin)*WordLength;
seb[rSei].mark4 ← TRUE;
origin ← newOrigin};
 
IF OpName[son[2]] # anyTC 
THEN {
ScanList[son[2], DeclItem];  CheckDefaults[son[2]]};
 
rSei ← ArgRecord[type.typeOut];
IF rSei # RecordSENull 
THEN {
seb[rSei].hints.comparable ← TRUE; -- for now
seb[rSei].length ← (P4.LayoutArgs[rSei, origin, body]-origin)*WordLength;
seb[rSei].mark4 ← TRUE}};
 
 
definition => NULL;
union => {
DeclItem[son[1]];
IF attr1 AND type.controlled THEN AssignPositions[son[1]];
ProcessVariants[UnderType[seb[type.tagSei].idType], son[2]]};
 
sequence => {
DeclItem[son[1]];
IF attr1 AND type.controlled THEN AssignPositions[son[1]];
TypeExp[son[2], FALSE, indirect]};
 
relative => {TypeExp[son[1], FALSE, TRUE];  TypeExp[son[2], FALSE, TRUE]};
opaque =>
IF son[1] # Tree.Null 
THEN {
son[1] ← P4.Rhs[son[1], dataPtr.typeCARDINAL];  P4.VPop[];
IF P4.TreeLiteral[son[1]] 
THEN
type.length ← P4.TreeLiteralValue[son[1]]*WordLength};
 
 
 
zone => NULL;
subrange => {
subNode: Tree.Index;
tSei: CSEIndex = UnderType[type.rangeType];
TypeExp[son[1], FALSE, indirect];
subNode ← GetNode[son[2]];
IF P4.Interval[subNode, 0, P4.both] 
THEN
[type.origin, type.range] ← P4.ConstantInterval[subNode
! P4.EmptyInterval => {type.empty ← TRUE; RESUME}]
 
 
ELSE type.origin ← type.range ← 0;
type.filled ← TRUE;
SELECT P4.VRep[] 
FROM
P4.none => Log.ErrorTree[mixedRepresentation, son[2]];
P4.unsigned => IF type.origin < 0 THEN Log.Error[subrangeNesting];
ENDCASE;
 
P4.VPop[];
WITH cover: seb[tSei] 
SELECT 
FROM
subrange => 
-- incomplete test
IF  type.origin < cover.origin
OR (~type.empty 
AND type.range > cover.range) 
THEN
Log.Error[subrangeNesting];
 
 
 
ENDCASE => NULL;
 
son[2] ← FreeTree[son[2]]};
 
long => TypeExp[son[1], FALSE, indirect];
any => NULL;
ENDCASE => ERROR;
 
 
seb[sei].mark4 ← TRUE}};
 
 
 
ENDCASE => ERROR};
 
 
machine dependent representations
MaxCardinality: 
PUBLIC 
PROC [type: Type, packed: 
BOOL, maxSize: WordCount]
RETURNS [LONG CARDINAL] = {
maxBits: BitCount =
(IF maxSize > BitCount.LAST/WordLength THEN BitCount.LAST ELSE maxSize*WordLength);
 
eSize: BitCount = BitsPerElement[type, packed];
RETURN [maxBits/(IF eSize # 0 THEN eSize ELSE 1)]};
 
EvalUnsigned: 
PROC [t: Tree.Link, default: 
CARDINAL]
RETURNS [v: Tree.Link, n: CARDINAL] = {
v ← P4.Rhs[t, dataPtr.typeCARDINAL];  P4.VPop[];
IF P4.TreeLiteral[v] THEN n ← P4.TreeLiteralValue[v]
ELSE {Log.ErrorTree[nonConstant, v]; n ← default};
RETURN};
 
LayoutEnum: 
PROC [t: Tree.Link, ctx: CTXIndex]
RETURNS [sparse: BOOL, nValues: CARDINAL] = {
sei: ISEIndex;
started: BOOL;
last: CARDINAL;
AssignElement: Tree.Scan = {
val: CARDINAL;
WITH t 
SELECT 
FROM
subtree => {
node: Tree.Index = index;
[tb[node].son[2], val] ←
EvalUnsigned[tb[node].son[2], IF started THEN last+1 ELSE 0]};
 
 
ENDCASE => val ← IF started THEN last+1 ELSE 0;
 
IF ~started THEN {sparse ← (val#0); started ← TRUE}
ELSE {
IF val <= last THEN Log.ErrorSei[enumOrder, sei];
IF val # last+1 THEN sparse ← TRUE};
 
last ← seb[sei].idValue ← val;  sei ← NextSe[sei]};
 
started ← sparse ← FALSE; sei ← FirstCtxSe[ctx];
ScanList[t, AssignElement];
nValues ← IF ~started THEN 0 ELSE last+1;  RETURN};
 
AssignPositions: 
PROC [item: Tree.Link] = {
node: Tree.Index = GetNode[item];
saveIndex: CARDINAL = dataPtr.textIndex;
type: Type = TypeForTree[tb[node].son[2]];
nB, nW: CARDINAL;
AssignPosition: Tree.Scan = {
wd, bL, bR: CARDINAL;
dB: CARDINAL = IF nB=0 THEN 0 ELSE nB-1;
sei: ISEIndex = ItemId[t];
node: Tree.Index = GetNode[NthSon[t, 2]];
[tb[node].son[1], wd] ← EvalUnsigned[tb[node].son[1], 0];
IF tb[node].son[2] = Tree.Null 
THEN {
bL ← 0;  bR ← IF nB = 0 THEN 0 ELSE nW*WordLength - 1}
 
ELSE {
subNode: Tree.Index = GetNode[tb[node].son[2]];
[tb[subNode].son[1], bL] ← EvalUnsigned[tb[subNode].son[1], 0];
[tb[subNode].son[2], bR] ← EvalUnsigned[tb[subNode].son[2], dB]};
 
wd ← wd + bL/WordLength;
IF bR >= bL THEN bR ← bR - (bL/WordLength)*WordLength;
bL ← bL MOD WordLength;
IF (
SELECT 
TRUE 
FROM
(nB = 0) => bR < bL,
(nB >= WordLength) => bL # 0 OR bR # bL + dB,
ENDCASE => bR > WordLength OR bR < bL + dB) THEN {
Log.ErrorSei[fieldPosition, sei]; bR ← bL + dB};
 
seb[sei].idValue ← BitAddress[wd:wd, bd:bL];
seb[sei].idInfo ← IF nB=0 AND tb[node].son[2] = Tree.Null THEN 0 ELSE bR-bL + 1};
 
dataPtr.textIndex ← tb[node].info;
nB ← P4.BitsForType[type];  nW ← (nB+(WordLength-1))/WordLength;
ScanList[tb[node].son[1], AssignPosition];
dataPtr.textIndex ← saveIndex};
 
ExtractFieldAttributes: 
PROC [rType: RecordSEIndex] = {
compatibility version
type: CSEIndex;
comparable, privateFields: BOOL;
comparable ← TRUE;   privateFields ← FALSE;
FOR sei: ISEIndex ← FirstCtxSe[seb[rType].fieldCtx], NextSe[sei] 
UNTIL sei = ISENull 
DO
IF ~seb[sei].public THEN privateFields ← TRUE;
type ← UnderType[seb[sei].idType];
WITH t: seb[type] 
SELECT 
FROM
record =>
IF ~t.hints.comparable AND ~ComparableType[type] THEN comparable ← FALSE;
 
array => IF ~ComparableType[type] THEN comparable ← FALSE;
union => IF ~t.hints.equalLengths THEN comparable ← FALSE;
sequence => comparable ← FALSE;
ENDCASE;
 
ENDLOOP;
 
seb[rType].hints.comparable ← comparable;
seb[rType].hints.privateFields ← privateFields};
 
ProcessVariants: 
PROC [tagType: CSEIndex, list: Tree.Link] = {
lb, ub: CARDINAL;
MapTag: 
PROC [vSei: ISEIndex] 
RETURNS [
CARDINAL] = {
WITH t: seb[tagType] 
SELECT 
FROM
enumerated =>
IF t.machineDep 
THEN {
sei: ISEIndex = SearchContext[seb[vSei].hash, t.valueCtx];
IF sei # ISENull THEN RETURN [seb[sei].idValue]};
 
 
ENDCASE;
 
RETURN [seb[vSei].idValue]};
 
CheckTag: Tree.Scan = {
sei: ISEIndex = ItemId[t];
tag: CARDINAL = MapTag[sei];
IF tag NOT IN [lb .. ub) THEN Log.ErrorSei[boundsFault, sei];
seb[sei].idValue ← tag - lb};
 
ProcessVariant: Tree.Scan = {
saveIndex: CARDINAL = dataPtr.textIndex;
node: Tree.Index = GetNode[t];
dataPtr.textIndex ← tb[node].info;
ScanList[tb[node].son[1], CheckTag];
DeclItem[t];
dataPtr.textIndex ← saveIndex};
 
lb ← BiasForType[tagType];  ub ← lb + CARDINAL[Cardinality[tagType]];
ScanList[list, ProcessVariant]};
 
TypeForTree: 
PUBLIC 
PROC [t: Tree.Link] 
RETURNS [Type] = {
RETURN [
WITH t 
SELECT 
FROM
symbol => index,
subtree => tb[index].info,
ENDCASE => typeANY]};
 
 
CanonicalType: 
PUBLIC 
PROC [type: CSEIndex] 
RETURNS [CSEIndex] = {
RETURN [
WITH t: seb[type] 
SELECT 
FROM
subrange => CanonicalType[UnderType[t.rangeType]],
record =>
IF t.hints.unifield 
AND CtxEntries[t.fieldCtx] = 1
THEN CanonicalType[UnderType[seb[ctxb[t.fieldCtx].seList].idType]]
ELSE type,
 
 
ENDCASE => type]};
 
 
BiasForType: 
PUBLIC 
PROC [type: CSEIndex] 
RETURNS [
INTEGER] = {
RETURN [
IF type = CSENull
THEN 0
ELSE
WITH t: seb[type] 
SELECT 
FROM
subrange => t.origin,
record =>
IF t.hints.unifield 
AND CtxEntries[t.fieldCtx] = 1
THEN BiasForType[UnderType[seb[ctxb[t.fieldCtx].seList].idType]]
ELSE 0,
 
 
ENDCASE => 0]};
 
 
 
 
RepForType: 
PUBLIC 
PROC [type: CSEIndex] 
RETURNS [P4.Repr] = {
RETURN [
IF type = CSENull
THEN P4.none
ELSE
WITH t: seb[type] 
SELECT 
FROM
basic =>
SELECT t.code 
FROM
codeANY => P4.both + P4.other,
codeINT => P4.signed,
codeCHAR => P4.both,
ENDCASE => P4.other,
 
 
enumerated => P4.both,
ref => P4.unsigned,
record =>
IF t.hints.unifield 
AND CtxEntries[t.fieldCtx] = 1
THEN RepForType[UnderType[seb[ctxb[t.fieldCtx].seList].idType]]
ELSE P4.other,
 
 
relative => RepForType[UnderType[t.offsetType]],
subrange =>
IF t.origin >= 0
THEN (IF CARDINAL[t.origin] + t.range > 77777b THEN P4.unsigned ELSE P4.both)
ELSE (IF t.range <= 77777b THEN P4.signed ELSE P4.none),
 
 
long => RepForType[UnderType[t.rangeType]],
opaque => IF t.lengthKnown THEN P4.both + P4.other ELSE P4.none,
ENDCASE => P4.other]};
 
 
 
 
SparseRep: 
PUBLIC 
PROC [type: CSEIndex] 
RETURNS [
BOOL] = {
nType: CSEIndex = NormalType[type];
RETURN [
WITH seb[nType] 
SELECT 
FROM
enumerated => sparse,
ENDCASE => FALSE]};
 
 
WordsForType: 
PUBLIC 
PROC [type: CSEIndex] 
RETURNS [WordCount] = {
RETURN [
IF ~seb[type].mark4
THEN (P4.BitsForType[type]+(WordLength-1))/WordLength
ELSE SymbolOps.WordsForType[type]]};
 
 
ComparableType: 
PUBLIC 
PROC [type: CSEIndex] 
RETURNS [
BOOL] = {
compatibility version
RETURN [
WITH t: seb[type] 
SELECT 
FROM
record => t.hints.comparable OR t.argument, -- for now
array => ~SparseRep[UnderType[t.indexType]]
AND ComparableType[UnderType[t.componentType]]
AND WordsForType[type] <= P4.OpWordCount.LAST,
 
opaque => t.lengthKnown,
any => FALSE,
ENDCASE => TRUE]};
 
 
DefaultBasicOps: 
PUBLIC 
PROC [type: Type, size: BitCount] 
RETURNS [
BOOL] = {
uType: CSEIndex = UnderType[type];
next: Type;
FOR s: Type ← type, next 
DO
WITH se: seb[s] 
SELECT 
FROM
id => {
sei: ISEIndex = LOOPHOLE[s];
IF seb[sei].extended 
THEN {
IF OpName[FindExtension[sei].tree] # void THEN RETURN [FALSE] ELSE EXIT};
 
next ← seb[sei].idInfo};
 
cons =>
WITH t: se 
SELECT 
FROM
ref => IF t.counted THEN RETURN [FALSE] ELSE EXIT;
array => next ← t.componentType;
record => IF t.hints.default THEN RETURN [FALSE] ELSE EXIT;
transfer => IF t.mode = port THEN RETURN [FALSE] ELSE EXIT;
long => next ← t.rangeType;
zone => IF t.counted THEN RETURN [FALSE] ELSE EXIT;
ENDCASE => EXIT;
 
 
ENDCASE;
 
ENDLOOP;
 
RETURN [WordsForType[uType]*WordLength = size
AND ComparableType[uType] AND TypeLink[uType] = nullType]};
 
 
}.