-- file Pass3D.mesa -- last modified by Satterthwaite, May 6, 1983 9:17 am -- last modified by Donahue, 10-Dec-81 10:22:58 DIRECTORY A3: TYPE USING [ AssignableType, Default, DefaultInit, IndexType, NewableType, OrderedType, TargetType, TypeForTree, Voidable, VoidItem], Alloc: TYPE USING [Notifier], ComData: TYPE USING [ idANY, idCARDINAL, interface, mainCtx, moduleCtx, seAnon, textIndex, typeINT, typeStringBody], Inline: TYPE USING [BITOR], Log: TYPE USING [Error, ErrorHti, ErrorSei, ErrorTree], P3: TYPE USING [ Attr, NPUse, SequenceNP, fullAttr, voidAttr, mark, pathNP, phraseNP, CheckDisjoint, ClearRefStack, CopyTree, EnterComposite, Exp, FindSe, InterfaceCtx, MakeFrameRecord, PopCtx, PushCtx, RAttr, RecordLhs, RecordMention, Rhs, RPop, RPush, RType, SafetyAttr, SealRefStack, SearchCtxList, SelectVariantType, TopCtx, UnsealRefStack, VariantUnionType, VoidExp], Symbols: TYPE USING [ Base, SERecord, HTIndex, SEIndex, ISEIndex, CSEIndex, RecordSEIndex, RefSEIndex, CTXIndex, CBTIndex, SENull, ISENull, CTXNull, codeANY, codeINT, lG, lZ, typeANY, typeTYPE, seType, ctxType, mdType, bodyType], SymbolOps: TYPE USING [ ArgCtx, CopyXferType, EnterExtension, LinkMode, MakeNonCtxSe, NormalType, RCType, ReferentType, TypeForm, TypeLink, UnderType, XferMode], Tree: TYPE USING [Base, Index, Link, Map, Null, NullIndex, Scan, treeType], TreeOps: TYPE USING [ FreeTree, GetHash, GetNode, GetSe, IdentityMap, ListHead, ListLength, NthSon, OpName, ScanList, UpdateList]; Pass3D: PROGRAM IMPORTS A3, Inline, Log, P3, SymbolOps, TreeOps, dataPtr: ComData EXPORTS P3 = { OPEN TreeOps, SymbolOps, Symbols, A3, P3; 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) mdb: Symbols.Base; -- module 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]; mdb ← base[mdType]; bb ← base[bodyType]}; -- signals for type loop detection CheckTypeLoop: SIGNAL [loopNode: Tree.Index] RETURNS [BOOL] = CODE; LogTypeLoop: SIGNAL [loopNode: Tree.Index] = CODE; -- declaration processing ItemId: PUBLIC PROC [t: Tree.Link] RETURNS [ISEIndex] = { RETURN [WITH t SELECT FROM symbol => index, subtree => ItemId[tb[index].son[1]], ENDCASE => ERROR]}; FirstId: PUBLIC PROC [node: Tree.Index] RETURNS [ISEIndex] = { RETURN [ItemId[ListHead[tb[node].son[1]]]]}; DeclList: PUBLIC Tree.Scan = {ScanList[t, DeclA]; ScanList[t, DeclBInit]}; DeclA: Tree.Scan = { node: Tree.Index = GetNode[t]; type: SEIndex; saveIndex: CARDINAL = dataPtr.textIndex; IF tb[node].attr3 = P3.mark THEN RETURN; -- already processed tb[node].attr3 ← P3.mark; dataPtr.textIndex ← tb[node].info; tb[node].son[2] ← TypeLink[tb[node].son[2] ! CheckTypeLoop => {IF loopNode = node THEN RESUME [TRUE]}; LogTypeLoop => {IF loopNode = node THEN RESUME}]; type ← TypeForTree[tb[node].son[2]]; SELECT tb[node].name FROM typedecl => DefineTypeSe[tb[node].son[1], type]; decl => DefineSeType[tb[node].son[1], type, tb[node].attr1]; ENDCASE => ERROR; ClearRefStack[]; dataPtr.textIndex ← saveIndex}; DeclBField: Tree.Scan = {DeclBDefault[t, FALSE]}; DeclBVarField: Tree.Scan = {DeclBDefault[t, TRUE]}; DeclBDefault: PROC [t: Tree.Link, varOK: BOOL←FALSE] = { node: Tree.Index = GetNode[t]; saveIndex: CARDINAL = dataPtr.textIndex; IF tb[node].attr2 = P3.mark THEN RETURN; -- already processed tb[node].attr2 ← P3.mark; dataPtr.textIndex ← tb[node].info; TypeAttr[typeExp: tb[node].son[2], varOK: varOK]; SELECT tb[node].name FROM typedecl => NULL; decl => { type: SEIndex = TypeForTree[tb[node].son[2]]; IF ~NewableType[type] THEN Log.ErrorTree[typeLength, tb[node].son[2]]; IF tb[node].son[3] # Tree.Null THEN { ScanList[tb[node].son[1], RecordDeclInit]; tb[node].son[3] ← DefaultExp[t:tb[node].son[3], type:type, ids:tb[node].son[1]]}; DefineSeValue[tb[node].son[1], FALSE]}; ENDCASE => ERROR; ClearRefStack[]; dataPtr.textIndex ← saveIndex}; DeclBInit: Tree.Scan = { node: Tree.Index = GetNode[t]; saveIndex: CARDINAL = dataPtr.textIndex; IF tb[node].attr2 = P3.mark THEN RETURN; -- already processed tb[node].attr2 ← P3.mark; dataPtr.textIndex ← tb[node].info; [] ← CheckPositions[tb[node].son[1], FieldAttrs[]]; SELECT tb[node].name FROM typedecl => { TypeAttr[tb[node].son[2]]; IF tb[node].son[3] # Tree.Null THEN { tb[node].son[3] ← DefaultExp[ t:tb[node].son[3], type:TypeForTree[tb[node].son[2]], ids:tb[node].son[1]]; [] ← ProcessDefault[node]}}; decl => { type: SEIndex; constFlag, extFlag: BOOL; ctx: CTXIndex = TopCtx[]; TypeAttr[typeExp: tb[node].son[2], varOK: InterfaceContext[ctx]]; type ← TypeForTree[tb[node].son[2]]; IF ~NewableType[type] THEN Log.ErrorTree[typeLength, tb[node].son[2]]; IF tb[node].son[3] = Tree.Null THEN { IF ~InterfaceContext[ctx] AND ~tb[node].attr1 THEN { tb[node].son[3] ← DefaultInit[type]; pathNP ← SequenceNP[pathNP][phraseNP]; RPop[]}; constFlag ← FALSE} ELSE { [tb[node].son[3], extFlag] ← InitialExp[tb[node].son[3], type]; IF extFlag AND ~tb[node].attr1 THEN Log.ErrorTree[misusedInline, tb[node].son[3]]; pathNP ← SequenceNP[pathNP][phraseNP]; constFlag ← tb[node].attr1 AND RAttr[].const; RPop[]; IF tb[node].son[3] # Tree.Null THEN ScanList[tb[node].son[1], RecordDeclInit]}; SELECT TRUE FROM (tb[node].son[3] = Tree.Null) => IF ~InterfaceContext[ctx] AND ~Voidable[type] THEN Log.ErrorSei[missingInit, FirstId[node]]; GlobalContext[ctx] => SELECT RCType[UnderType[type]] FROM composite => EnterComposite[UnderType[type], tb[node].son[3], TRUE]; ENDCASE => NULL; ENDCASE => NULL; DefineSeValue[tb[node].son[1], constFlag]}; ENDCASE => ERROR; ClearRefStack[]; dataPtr.textIndex ← saveIndex}; RecordDeclInit: Tree.Scan = { sei: ISEIndex = ItemId[t]; RecordMention[sei]; RecordLhs[sei]}; DefaultExp: PROC [t: Tree.Link, type: SEIndex, ids: Tree.Link] RETURNS [v: Tree.Link] = { subType: CSEIndex = TargetType[UnderType[type]]; ExpInit: PROC [t: Tree.Link] RETURNS [val: Tree.Link] = { val ← Rhs[t, subType]; RPop[]; RETURN}; v ← UpdateList[t, ExpInit]; IF VoidItem[v] AND ~Voidable[type] THEN Log.ErrorSei[defaultForm, ItemId[ids]]; RETURN}; InitialExp: PUBLIC PROC [t: Tree.Link, type: SEIndex] RETURNS [v: Tree.Link, extended: BOOL] = { subType: CSEIndex = UnderType[type]; v ← t; extended ← FALSE; phraseNP ← none; SELECT OpName[t] FROM body => { -- defer processing of bodies (see Body) expNode: Tree.Index = GetNode[t]; bti: CBTIndex = tb[expNode].info; attr: Attr ← voidAttr; SELECT XferMode[type] FROM proc, program => NULL; ENDCASE => IF TypeForm[type] = definition THEN attr ← fullAttr ELSE Log.Error[bodyType]; bb[bti].ioType ← SELECT seb[type].seTag FROM cons => subType, ENDCASE => CopyXferType[subType, IdentityMap]; RPush[subType, attr]; extended ← tb[expNode].attr3; -- inline CheckBodyType[subType, expNode]}; inline => { expNode: Tree.Index = GetNode[t]; CodeBody: Tree.Map = {RETURN [UpdateList[t, NumericConst]]}; IF XferMode[type] # proc THEN Log.Error[inlineType]; IF tb[expNode].attr1 THEN Log.Error[attrClash]; tb[expNode].son[1] ← UpdateList[tb[expNode].son[1], CodeBody]; RPush[subType, fullAttr]; extended ← TRUE; CheckBodyType[subType, expNode]}; apply => { expNode: Tree.Index = GetNode[t]; IF tb[expNode].son[1] = Tree.Null AND ReferentType[subType] = dataPtr.typeStringBody AND ListLength[tb[expNode].son[2]] = 1 THEN tb[expNode].name ← stringinit; v ← Rhs[t, TargetType[subType]]}; signalinit => RPush[subType, voidAttr]; void => {v ← FreeTree[t]; RPush[subType, voidAttr]}; ENDCASE => v ← Rhs[t, TargetType[subType]]; RETURN}; RecordField: PROC [ctx: CTXIndex] RETURNS [BOOL] = INLINE { RETURN [ctx = CTXNull OR (ctxb[ctx].level = lZ AND ctx # dataPtr.moduleCtx)]}; GlobalContext: PROC [ctx: CTXIndex] RETURNS [BOOL] = INLINE { RETURN [~dataPtr.interface AND ctxb[ctx].level = lG]}; InterfaceContext: PROC [ctx: CTXIndex] RETURNS [BOOL] = INLINE { RETURN [dataPtr.interface AND ctx = dataPtr.mainCtx]}; InterfaceSe: PROC [sei: ISEIndex] RETURNS [BOOL] = INLINE { RETURN [InterfaceContext[seb[sei].idCtx]]}; CheckBodyType: PROC [type: CSEIndex, node: Tree.Index] = { WITH t: seb[type] SELECT FROM transfer => { IF TypeForm[t.typeIn] = any OR TypeForm[t.typeOut] = any THEN Log.Error[bodyType]; IF t.safe AND SafetyAttr[node] = none THEN Log.Error[unsafeBlock]}; ENDCASE}; DefineTypeSe: PROC [t: Tree.Link, info: SEIndex] = { first: BOOL ← TRUE; UpdateSe: Tree.Scan = { sei: ISEIndex = ItemId[t]; seb[sei].idType ← typeTYPE; seb[sei].idInfo ← info; seb[sei].immutable ← seb[sei].constant ← TRUE; IF first THEN {info ← sei; first ← FALSE}; seb[sei].mark3 ← TRUE}; ScanList[t, UpdateSe]}; DefineSeType: PROC [t: Tree.Link, type: SEIndex, fixed: BOOL] = { UpdateSe: Tree.Scan = { sei: ISEIndex = ItemId[t]; seb[sei].idType ← type; seb[sei].constant ← FALSE; IF InterfaceSe[sei] THEN seb[sei].immutable ← seb[sei].immutable OR fixed ELSE seb[sei].immutable ← fixed; seb[sei].mark3 ← TRUE}; ScanList[t, UpdateSe]}; DefineSeValue: PROC [t: Tree.Link, const: BOOL] = { UpdateSe: Tree.Scan = { sei: ISEIndex = ItemId[t]; seb[sei].constant ← const; IF InterfaceSe[sei] AND LinkMode[sei] = val THEN seb[sei].immutable ← TRUE}; ScanList[t, UpdateSe]}; ProcessDefault: PROC [node: Tree.Index] RETURNS [nonVoid: BOOL] = { copy: BOOL; v: Tree.Link = tb[node].son[3]; DefineDefault: Tree.Scan = { EnterExtension[ItemId[t], default, IF copy THEN CopyTree[v] ELSE v]; copy ← TRUE}; SELECT OpName[v] FROM stringinit => Log.ErrorSei[defaultForm, FirstId[node]]; lengthen => IF OpName[NthSon[v, 1]] = stringinit THEN Log.ErrorSei[defaultForm, FirstId[node]]; void => nonVoid ← FALSE; ENDCASE => nonVoid ← TRUE; copy ← FALSE; ScanList[tb[node].son[1], DefineDefault]; tb[node].son[3] ← Tree.Null}; -- forward reference resolution ResolveType: PUBLIC PROC [sei: ISEIndex] = { currentCtx: CTXIndex = TopCtx[]; IF seb[sei].idCtx # currentCtx THEN {PopCtx[]; ResolveType[sei]; PushCtx[currentCtx]} ELSE {SealRefStack[]; DeclA[[subtree[index: seb[sei].idValue]]]; UnsealRefStack[]}}; ResolveValue: PUBLIC PROC [sei: ISEIndex] = { currentCtx: CTXIndex = TopCtx[]; IF seb[sei].idCtx # currentCtx THEN {PopCtx[]; ResolveValue[sei]; PushCtx[currentCtx]} ELSE { SealRefStack[]; IF RecordField[currentCtx] THEN DeclBDefault[[subtree[index: seb[sei].idValue]]] ELSE DeclBInit[[subtree[index: seb[sei].idValue]]]; UnsealRefStack[]}}; -- type expressions CheckTypeId: PROC [sei: ISEIndex] RETURNS [BOOL] = { SELECT TRUE FROM (sei = ISENull) => RETURN [FALSE]; seb[sei].mark3 => RETURN [seb[sei].idType = typeTYPE]; ENDCASE => { node: Tree.Index = seb[sei].idValue; RETURN [node = Tree.NullIndex OR tb[node].name = typedecl]}}; TypeSymbol: PROC [sei: ISEIndex] RETURNS [val: Tree.Link] = { entryIndex: CARDINAL = dataPtr.textIndex; circular: BOOL ← FALSE; IF ~seb[sei].mark3 THEN { ENABLE LogTypeLoop => { saveIndex: CARDINAL = dataPtr.textIndex; dataPtr.textIndex ← entryIndex; Log.ErrorSei[circularType, sei]; circular ← TRUE; dataPtr.textIndex ← saveIndex}; declNode: Tree.Index = seb[sei].idValue; IF tb[declNode].attr3 # P3.mark THEN ResolveType[sei] ELSE IF SIGNAL CheckTypeLoop[declNode] THEN SIGNAL LogTypeLoop[declNode]}; IF CheckTypeId[sei] AND ~circular THEN val ← [symbol[index: sei]] ELSE { IF ~circular AND sei # dataPtr.seAnon THEN Log.ErrorSei[nonTypeId, sei]; val ← [symbol[index: dataPtr.idANY]]}; RETURN}; PushArgCtx: PROC [sei: CSEIndex] = { ctx: CTXIndex = ArgCtx[sei]; IF ctx # CTXNull THEN PushCtx[ctx]}; PopArgCtx: PROC [sei: CSEIndex] = { IF ArgCtx[sei] # CTXNull THEN PopCtx[]}; TypeExp: PUBLIC PROC [typeExp: Tree.Link] RETURNS [val: Tree.Link] = { val ← TypeLink[typeExp]; TypeAttr[val]; RETURN}; TypeAppl: PUBLIC PROC [typeExp: Tree.Link] RETURNS [val: Tree.Link] = { attr: Attr; IF OpName[typeExp] = apply THEN { node: Tree.Index = GetNode[typeExp]; rType: SEIndex; tb[node].son[1] ← TypeExp[tb[node].son[1]]; tb[node].info ← rType ← TypeForTree[tb[node].son[1]]; SELECT TRUE FROM (UnderType[rType] = dataPtr.typeStringBody), (TypeForm[VariantUnionType[rType]] = sequence) => { tb[node].son[2] ← Rhs[tb[node].son[2], dataPtr.typeINT]; attr ← RAttr[]; RPop[]}; (TypeForm[VariantUnionType[rType]] = union) => { TypeDiscrim[rType, node]; phraseNP ← none; attr ← fullAttr}; ENDCASE => { Log.ErrorTree[typeClash, tb[node].son[1]]; tb[node].son[2] ← Exp[tb[node].son[2], typeANY]; attr ← RAttr[]; RPop[]}; val ← typeExp} ELSE {val ← TypeExp[typeExp]; phraseNP ← none; attr ← fullAttr}; RPush[typeTYPE, attr]}; ClusterExp: PROC [t: Tree.Link] RETURNS [val: Tree.Link] = { WITH t SELECT FROM hash => { sei: ISEIndex = FindSe[index].symbol; IF ~CheckTypeId[sei] THEN -- prevent duplicate error messages val ← Exp[IF sei = dataPtr.seAnon THEN [symbol[sei]] ELSE t, typeANY] ELSE {val ← TypeSymbol[sei]; RPush[typeTYPE, fullAttr]}}; symbol => { sei: ISEIndex = index; IF ~CheckTypeId[sei] THEN val ← Exp[t, typeANY] ELSE {val ← TypeSymbol[sei]; RPush[typeTYPE, fullAttr]}}; ENDCASE => {val ← TypeLink[t]; RPush[typeTYPE, fullAttr]}; RETURN}; TypeDot: PROC [rType: SEIndex, node: Tree.Index] = TypeDiscrim; -- for now, should do other possible cluster items TypeDiscrim: PROC [rType: SEIndex, node: Tree.Index] = { t2: Tree.Link = tb[node].son[2]; WITH h: t2 SELECT FROM hash => { iSei: ISEIndex = SelectVariantType[rType, h.index]; IF iSei # ISENull THEN { tb[node].info ← iSei; tb[node].son[2] ← [symbol[index: iSei]]; tb[node].name ← discrimTC} ELSE { IF rType # typeANY THEN Log.ErrorTree[unknownVariant, t2]; tb[node].info ← dataPtr.idANY}}; ENDCASE => { Log.ErrorTree[unknownVariant, t2]; tb[node].son[2] ← VoidExp[t2]}}; FindLinkType: SIGNAL RETURNS [CSEIndex] = CODE; -- to find list link type TypeLink: PROC [typeExp: Tree.Link] RETURNS [val: Tree.Link] = { WITH typeExp SELECT FROM hash => { sei: ISEIndex = FindSe[index].symbol; IF sei # SENull THEN val ← TypeSymbol[sei] ELSE {Log.ErrorHti[nonTypeId, index]; val ← [symbol[dataPtr.idANY]]}}; symbol => val ← TypeSymbol[index]; subtree => { node: Tree.Index = index; iSei: ISEIndex; SELECT tb[node].name FROM discrimTC => { tb[node].son[1] ← TypeLink[tb[node].son[1]]; TypeDiscrim[TypeForTree[tb[node].son[1]], node]}; apply => { rType: SEIndex; tb[node].son[1] ← TypeLink[tb[node].son[1]]; tb[node].info ← rType ← TypeForTree[tb[node].son[1]]; IF TypeForm[VariantUnionType[rType]] = union THEN TypeDiscrim[rType, node] ELSE Log.ErrorTree[noApplication, tb[node].son[1]]}; dot => { hti: HTIndex = GetHash[tb[node].son[2]]; nDerefs: CARDINAL ← 0; found: BOOL; next: SEIndex; ctx: CTXIndex ← CTXNull; tb[node].son[1] ← ClusterExp[tb[node].son[1]]; FOR subType: CSEIndex ← RType[], UnderType[next] DO WITH t: seb[subType] SELECT FROM mode => GOTO type; definition, transfer => { ctx ← InterfaceCtx[subType, tb[node].son[1]]; GO TO cluster}; record => {ctx ← t.fieldCtx; GO TO cluster}; ref => {IF (nDerefs ← nDerefs+1) > 63 THEN GO TO cluster; next ← t.refType}; long => next ← t.rangeType; subrange => next ← t.rangeType; ENDCASE => GO TO cluster; REPEAT type => TypeDot[TypeForTree[tb[node].son[1]], node]; cluster => { [found, iSei] ← SearchCtxList[hti, ctx]; IF ~found THEN {iSei ← dataPtr.idANY; Log.ErrorHti[unknownField, hti]}; tb[node].name ← cdot; tb[node].info ← iSei; tb[node].son[2] ← TypeSymbol[iSei]}; ENDLOOP; RPop[]}; paintTC => { tb[node].son[1] ← TypeLink[tb[node].son[1]]; tb[node].son[2] ← TypeLink[tb[node].son[2]]; tb[node].info ← TypeForTree[tb[node].son[2]]}; linkTC => tb[node].info ← SIGNAL FindLinkType[]; implicitTC => NULL; frameTC => { tb[node].son[1] ← Exp[tb[node].son[1], typeANY]; RPop[]; tb[node].info ← MakeFrameRecord[tb[node].son[1]]}; ENDCASE => { OPEN tb[node]; type: CSEIndex = info; WITH t: seb[type] SELECT FROM enumerated => NULL; record => {PushCtx[t.fieldCtx]; ScanList[son[1], DeclA]; PopCtx[]}; ref => { son[1] ← TypeLink[son[1] ! CheckTypeLoop => {RESUME [FALSE]}]; t.refType ← TypeForTree[son[1]]}; array => { IF son[1] = Tree.Null THEN t.indexType ← dataPtr.idCARDINAL ELSE {son[1] ← TypeLink[son[1]]; t.indexType ← TypeForTree[son[1]]}; son[2] ← TypeLink[son[2]]; t.componentType ← TypeForTree[son[2]]}; arraydesc => { son[1] ← TypeLink[son[1] ! CheckTypeLoop => {RESUME [FALSE]}]; t.describedType ← TypeForTree[son[1]]}; transfer => { ENABLE CheckTypeLoop => {RESUME [FALSE]}; CheckDisjoint[ArgCtx[t.typeIn], ArgCtx[t.typeOut]]; PushArgCtx[t.typeIn]; IF OpName[son[1]] # anyTC THEN ScanList[son[1], DeclA]; PushArgCtx[t.typeOut]; IF OpName[son[2]] # anyTC THEN ScanList[son[2], DeclA]; PopArgCtx[t.typeOut]; PopArgCtx[t.typeIn]}; definition => t.defCtx ← dataPtr.mainCtx; union => {DeclA[son[1]]; ScanList[son[2], DeclA]}; sequence => { DeclA[son[1]]; son[2] ← TypeLink[son[2]]; t.componentType ← TypeForTree[son[2]]}; relative => { son[1] ← TypeLink[son[1] ! CheckTypeLoop => {RESUME [FALSE]}]; t.baseType ← TypeForTree[son[1]]; son[2] ← TypeLink[son[2]]; t.resultType ← t.offsetType ← TypeForTree[son[2]]}; opaque => IF t.id = SENull OR ~InterfaceSe[t.id] THEN Log.Error[misplacedType]; zone => NULL; subrange => { t.range ← LOOPHOLE[node]; -- to allow symbolic evaluation son[1] ← TypeLink[son[1]]; t.rangeType ← TypeForTree[son[1]]}; long => { son[1] ← TypeLink[son[1] ! FindLinkType => {RESUME [type]}]; t.rangeType ← TypeForTree[son[1]]}; any => NULL; ENDCASE => ERROR; seb[type].mark3 ← TRUE}; val ← typeExp}; ENDCASE => ERROR; RETURN}; TypeAttr: PROC [typeExp: Tree.Link, indirect, varOK: BOOL ← FALSE] = { WITH typeExp SELECT FROM symbol => IF ~indirect THEN { sei: ISEIndex = index; IF seb[sei].mark3 AND ~seb[sei].mark4 THEN { declNode: Tree.Index = seb[sei].idValue; IF tb[declNode].attr2 # P3.mark THEN ResolveValue[sei]}}; subtree => { node: Tree.Index = index; SELECT tb[node].name FROM discrimTC => TypeAttr[tb[node].son[1], indirect]; cdot => TypeAttr[tb[node].son[2], indirect]; paintTC => { TypeAttr[tb[node].son[1]]; TypeAttr[tb[node].son[2], indirect]; Log.Error[unimplemented]}; implicitTC, linkTC => NULL; frameTC => NULL; apply => tb[node].son[2] ← VoidExp[tb[node].son[2]]; dot => NULL; ENDCASE => { OPEN tb[node]; type: CSEIndex = info; subType: CSEIndex; WITH t: seb[type] SELECT FROM enumerated => IF AssignedEnumeration[son[1]] AND ~t.machineDep THEN Log.Error[machDep]; record => { saveNP: NPUse = pathNP; PushCtx[t.fieldCtx]; pathNP ← none; ScanList[son[1], DeclBField]; WITH s: t SELECT FROM linked => CheckDisjointPrefix[t.fieldCtx, s.linkType]; notLinked => { attrs: FieldAttrs = CollectAttrs[ son[1], FieldAttrs[positionValid: t.machineDep]]; UpdateHints[LOOPHOLE[type], attrs]; attr1 ← AssignedPositions[attrs]}; ENDCASE => ERROR; PopCtx[]; pathNP ← saveNP}; ref => { IF t.var AND ~varOK THEN Log.Error[var]; TypeAttr[son[1], TRUE]}; array => { IF son[1] # Tree.Null THEN TypeAttr[son[1]]; SELECT TRUE FROM ~IndexType[t.indexType] => { t.indexType ← typeANY; Log.Error[nonOrderedType]}; (TypeForm[t.indexType]=long) => Log.Error[subrangeNesting]; ENDCASE; TypeAttr[son[2], indirect]; IF ~NewableType[t.componentType] THEN Log.ErrorTree[typeLength, son[2]]}; arraydesc => { TypeAttr[son[1], TRUE]; IF TypeForm[t.describedType] # array THEN Log.Error[descriptor]}; transfer => { saveNP: NPUse = pathNP; IF t.mode = error THEN t.safe ← FALSE; PushArgCtx[t.typeIn]; ArgAttr[t.typeIn, son[1], t.mode = proc OR t.mode = signal]; PushArgCtx[t.typeOut]; ArgAttr[t.typeOut, son[2], FALSE]; PopArgCtx[t.typeOut]; PopArgCtx[t.typeIn]; pathNP ← saveNP}; definition => NULL; union => { tagType: CSEIndex; DeclBDefault[son[1]]; seb[t.tagSei].immutable ← TRUE; tagType ← TargetType[UnderType[seb[t.tagSei].idType]]; IF seb[tagType].typeTag # enumerated THEN { Log.ErrorSei[nonTagType, t.tagSei]; tagType ← typeANY}; VariantList[son[2], tagType]}; sequence => { DeclBDefault[son[1]]; seb[t.tagSei].immutable ← TRUE; SELECT TRUE FROM ~IndexType[seb[t.tagSei].idType] => Log.ErrorSei[nonTagType, t.tagSei]; (TypeForm[seb[t.tagSei].idType]=long) => Log.Error[unimplemented]; ENDCASE; TypeAttr[son[2], indirect]}; relative => { vType: CSEIndex; TypeAttr[son[1], TRUE]; IF seb[NormalType[UnderType[t.baseType]]].typeTag # ref THEN Log.Error[relative]; TypeAttr[son[2]]; vType ← UnderType[t.offsetType]; subType ← NormalType[vType]; SELECT seb[subType].typeTag FROM ref, arraydesc => NULL; ENDCASE => {Log.Error[relative]; subType ← typeANY}; IF seb[UnderType[t.baseType]].typeTag = long OR seb[vType].typeTag = long THEN subType ← MakeLongType[subType, vType]; t.resultType ← subType}; zone => NULL; opaque => IF son[1] # Tree.Null THEN { son[1] ← Rhs[son[1], dataPtr.typeINT]; IF ~RAttr[].const THEN Log.ErrorTree[nonConstant, son[1]]; RPop[]}; subrange => { target: CSEIndex; subNode: Tree.Index = GetNode[son[2]]; TypeAttr[son[1], indirect]; subType ← UnderType[t.rangeType]; SELECT TRUE FROM (TypeForm[subType] = ref) => target ← dataPtr.typeINT; OrderedType[subType] => { WITH s: seb[subType] SELECT FROM long => { t.rangeType ← s.rangeType; subType ← UnderType[s.rangeType]}; real => Log.Error[subrangeNesting]; ENDCASE; target ← TargetType[subType]}; ENDCASE => {Log.Error[nonOrderedType]; target ← typeANY}; tb[subNode].son[1] ← EndPoint[tb[subNode].son[1], target]; tb[subNode].son[2] ← EndPoint[tb[subNode].son[2], target]}; long => { TypeAttr[son[1], indirect, varOK]; subType ← UnderType[t.rangeType]; WITH s: seb[subType] SELECT FROM basic => SELECT s.code FROM codeINT, codeANY => NULL; ENDCASE => Log.Error[long]; ref, arraydesc => NULL; subrange => IF t.rangeType # dataPtr.idCARDINAL THEN Log.Error[long]; ENDCASE => Log.Error[long]}; any => NULL; ENDCASE => ERROR}}; ENDCASE => ERROR}; EndPoint: PROC [t: Tree.Link, target: CSEIndex] RETURNS [v: Tree.Link] = { v ← Rhs[t, target]; IF ~RAttr[].const THEN Log.ErrorTree[nonConstant, v]; RPop[]}; -- record attribute collection FieldAttrs: TYPE = RECORD [ positionValid: BOOL ← FALSE, noAssign: BOOL ← FALSE, refField, unVoidable, default: BOOL ← FALSE, positions: PACKED ARRAY {implicit, explicit} OF BOOL ← [FALSE, FALSE]]; MergeAttrs: PROC [attr1, attr2: FieldAttrs] RETURNS [FieldAttrs] = LOOPHOLE[Inline.BITOR]; UpdateHints: PROC [rSei: RecordSEIndex, attrs: FieldAttrs] = { seb[rSei].hints.assignable ← ~attrs.noAssign; seb[rSei].hints.refField ← attrs.refField; seb[rSei].hints.voidable ← ~attrs.unVoidable; seb[rSei].hints.default ← attrs.default}; AssignedPositions: PROC [attrs: FieldAttrs] RETURNS [assigned: BOOL] = { IF attrs.positionValid THEN { IF attrs.positions = [TRUE, TRUE] THEN Log.Error[mixedPositions]; assigned ← attrs.positions[explicit]} ELSE assigned ← FALSE; RETURN}; CollectAttrs: PROC [t: Tree.Link, attrs: FieldAttrs] RETURNS [FieldAttrs] = { ProcessField: Tree.Scan = { node: Tree.Index = GetNode[t]; type: SEIndex = TypeForTree[tb[node].son[2]]; subType: CSEIndex = UnderType[type]; attrs ← CheckPositions[tb[node].son[1], attrs]; IF (IF tb[node].son[3] = Tree.Null THEN Default[type] = nonVoid ELSE ProcessDefault[node]) THEN attrs.default ← TRUE; WITH t: seb[subType] SELECT FROM union => { subNode: Tree.Index = GetNode[tb[node].son[2]]; IF t.controlled THEN ProcessField[tb[subNode].son[1]]; attrs ← MergeVariantAttrs[tb[subNode].son[2], attrs]; t.hints.refField ← attrs.refField; t.hints.voidable ← ~attrs.unVoidable; t.hints.default ← attrs.default; tb[subNode].attr1 ← attrs.positions[explicit]}; sequence => { subNode: Tree.Index = GetNode[tb[node].son[2]]; IF t.controlled THEN ProcessField[tb[subNode].son[1]]; IF RCType[UnderType[t.componentType]] # none THEN { IF ~t.controlled THEN Log.Error[attrClash]; attrs.refField ← --attrs.unVoidable ←-- TRUE}; attrs.noAssign ← TRUE; tb[subNode].attr1 ← attrs.positions[explicit]}; ENDCASE => { IF ~attrs.refField AND RCType[subType] # none THEN attrs.refField ← attrs.unVoidable ← TRUE; IF ~attrs.unVoidable AND ~Voidable[type] THEN attrs.unVoidable ← TRUE; IF ~AssignableType[subType, FALSE] THEN attrs.noAssign ← TRUE}}; ScanList[t, ProcessField]; RETURN [attrs]}; ArgAttr: PROC [rSei: CSEIndex, t: Tree.Link, varOK: BOOL] = { IF rSei # SENull THEN WITH seb[rSei] SELECT FROM record => { ScanList[t, IF varOK THEN DeclBVarField ELSE DeclBField]; UpdateHints[LOOPHOLE[rSei], CollectAttrs[t, FieldAttrs[]]]}; ENDCASE}; -- machine dependent layout NumericConst: Tree.Map = {v ← Rhs[t, dataPtr.typeINT]; RPop[]; RETURN}; AssignedEnumeration: PROC [t: Tree.Link] RETURNS [assigned: BOOL] = { AssignElement: Tree.Scan = { WITH t SELECT FROM subtree => { node: Tree.Index = index; tb[node].son[2] ← NumericConst[tb[node].son[2]]; assigned ← TRUE}; ENDCASE => NULL; RETURN}; assigned ← FALSE; ScanList[t, AssignElement]; RETURN}; CheckPositions: PROC [t: Tree.Link, attrs: FieldAttrs] RETURNS [FieldAttrs] = { CheckPosition: Tree.Scan = { WITH t SELECT FROM subtree => { node: Tree.Index = GetNode[tb[index].son[2]]; IF ~attrs.positionValid THEN Log.ErrorSei[position, ItemId[tb[index].son[1]]]; tb[node].son[1] ← NumericConst[tb[node].son[1]]; IF tb[node].son[2] # Tree.Null THEN { subNode: Tree.Index = GetNode[tb[node].son[2]]; tb[subNode].son[1] ← NumericConst[tb[subNode].son[1]]; tb[subNode].son[2] ← NumericConst[tb[subNode].son[2]]}; attrs.positions[explicit] ← TRUE}; ENDCASE => attrs.positions[implicit] ← TRUE}; ScanList[t, CheckPosition]; RETURN [attrs]}; -- variants CheckDisjointPrefix: PROC [ctx: CTXIndex, link: SEIndex] = { FOR sei: SEIndex ← link, SymbolOps.TypeLink[sei] UNTIL sei = SENull DO type: CSEIndex = UnderType[sei]; WITH t: seb[type] SELECT FROM record => CheckDisjoint[ctx, t.fieldCtx]; ENDCASE; ENDLOOP}; VariantList: PROC [t: Tree.Link, tagType: CSEIndex] = { DefineTag: Tree.Scan = { sei: ISEIndex = GetSe[t]; seb[sei].idValue ← TagValue[seb[sei].hash, tagType]}; VariantItem: Tree.Scan = { node: Tree.Index = GetNode[t]; saveIndex: CARDINAL = dataPtr.textIndex; dataPtr.textIndex ← tb[node].info; ScanList[tb[node].son[1], DefineTag]; DeclBDefault[t]; dataPtr.textIndex ← saveIndex}; ScanList[t, VariantItem]}; TagValue: PROC [tag: HTIndex, tagType: CSEIndex] RETURNS [CARDINAL] = { matched: BOOL; sei: ISEIndex; WITH seb[tagType] SELECT FROM enumerated => { [matched, sei] ← SearchCtxList[tag, valueCtx]; IF matched THEN RETURN [seb[sei].idValue]}; ENDCASE; Log.ErrorHti[unknownTag, tag]; RETURN [0]}; MergeVariantAttrs: PROC [list: Tree.Link, prefixAttrs: FieldAttrs] RETURNS [mergedAttrs: FieldAttrs] = { ProcessVariant: Tree.Scan = { node: Tree.Index = GetNode[t]; ProcessLabel: Tree.Scan = { sei: ISEIndex = GetSe[t]; type: SEIndex = seb[sei].idInfo; WITH v: seb[type] SELECT FROM cons => WITH r: v SELECT FROM record => { subNode: Tree.Index = GetNode[tb[node].son[2]]; attrs: FieldAttrs = CollectAttrs[tb[subNode].son[1], prefixAttrs]; UpdateHints[LOOPHOLE[type], attrs]; r.hints.default ← TRUE; tb[subNode].attr1 ← attrs.positions[explicit]; mergedAttrs ← MergeAttrs[mergedAttrs, attrs]}; ENDCASE; id => NULL; ENDCASE}; ScanList[tb[node].son[1], ProcessLabel]}; mergedAttrs ← prefixAttrs; ScanList[list, ProcessVariant]; mergedAttrs.default ← prefixAttrs.default; RETURN}; -- type construction MakeLongType: PUBLIC PROC [rType: SEIndex, hint: CSEIndex] RETURNS [type: CSEIndex] = { subType: CSEIndex = UnderType[rType]; WITH t: seb[hint] SELECT FROM long => IF TargetType[UnderType[t.rangeType]] = TargetType[subType] THEN RETURN [hint]; ENDCASE; WITH t: seb[subType] SELECT FROM relative => { oType: CSEIndex = MakeLongType[UnderType[t.offsetType], UnderType[t.resultType]]; type ← MakeNonCtxSe[SERecord.cons.relative.SIZE]; seb[type] ← [mark3: TRUE, mark4: TRUE, body: cons[relative[ baseType: t.baseType, offsetType: oType, resultType: oType]]]}; ENDCASE => { type ← MakeNonCtxSe[SERecord.cons.long.SIZE]; seb[type] ← [mark3: TRUE, mark4: TRUE, body: cons[long[rangeType: rType]]]}; RETURN}; MakeRefType: PUBLIC PROC [ cType: SEIndex, hint: CSEIndex, readOnly, counted, var: BOOL] RETURNS [type: RefSEIndex] = { WITH t: seb[hint] SELECT FROM ref => IF ~t.ordered AND t.readOnly = readOnly AND t.counted = counted AND t.var = var AND UnderType[t.refType] = UnderType[cType] THEN RETURN [LOOPHOLE[hint]]; ENDCASE; type ← LOOPHOLE[MakeNonCtxSe[SERecord.cons.ref.SIZE]]; seb[type] ← [mark3: TRUE, mark4: TRUE, body: cons[ref[ counted: counted, var: var, readOnly: readOnly, ordered: FALSE, list: FALSE, basing: FALSE, refType: cType]]]; RETURN}; }.