-- file Pass3Xb.mesa -- last modified by Satterthwaite, March 9, 1983 3:13 pm -- last modified by Donahue, 9-Dec-81 15:32:12 DIRECTORY A3: TYPE USING [ Bundling, CanonicalType, IdentifiedType, IndexType, MarkedType, NullableType, OperandInline, OrderedType, PermanentType, TargetType, TypeForTree, Unbundle], Alloc: TYPE USING [Notifier], ComData: TYPE USING [ idCARDINAL, idTEXT, interface, ownSymbols, typeATOM, typeAtomRecord, typeBOOL, typeCHAR, typeINT, typeREAL, typeSTRING], LiteralOps: TYPE USING [FindHeapString], Log: TYPE USING [Error, ErrorHti, ErrorN, ErrorNode, ErrorSei, ErrorTree, Warning], P3: TYPE USING [ Attr, emptyAttr, fullAttr, voidAttr, NarrowOp, NPUse, BoundNP, MergeNP, SequenceNP, TextForm, phraseNP, AddrOp, All, And, Apply, Assignment, Case, CatchPhrase, ClearRefStack, Discrimination, Dot, EnterType, Extract, Id, MakeLongType, MakeRefType, MiscXfer, Narrowing, Range, RecordMention, SealRefStack, SearchCtxList, TextRep, TypeAppl, TypeExp, UnsealRefStack], P3S: TYPE USING [ImplicitInfo, implicitRecord, safety, self], SymLiteralOps: TYPE USING [EnterAtom, EnterText], Symbols: TYPE USING [ Base, HTIndex, SEIndex, ISEIndex, CSEIndex, RecordSEIndex, CSENull, RecordSENull, codeANY, codeCHAR, codeINT, typeANY, ctxType, seType], SymbolOps: TYPE USING [ConstantId, NormalType, RCType, TypeForm, TypeRoot, UnderType], Tree: TYPE USING [Base, Index, Link, Map, Null, NullIndex, treeType], TreeOps: TYPE USING [ FreeNode, GetHash, GetNode, ListLength, PopTree, PushTree, PushNode, SetAttr, SetInfo, UpdateList], Types: TYPE USING [SymbolTableBase, Assignable, Equivalent]; Pass3Xb: PROGRAM IMPORTS A3, LiteralOps, Log, P3, P3S, SymLiteralOps, SymbolOps, TreeOps, Types, dataPtr: ComData EXPORTS P3, P3S = { OPEN SymbolOps, Symbols, TreeOps, A3, P3; tb: Tree.Base; -- tree base address (local copy) seb: Base; -- se table base address (local copy) ctxb: Base; -- context table base address (local copy) own: Types.SymbolTableBase; zone: UNCOUNTED ZONE ← NIL; ExpBNotify: PUBLIC Alloc.Notifier = { -- called by allocator whenever table area is repacked seb ← base[seType]; ctxb ← base[ctxType]; tb ← base[Tree.treeType]}; -- intermediate result bookkeeping OperandDescriptor: TYPE = RECORD[ type: CSEIndex, -- type of operand attr: Attr]; -- attributes RStack: TYPE = RECORD [SEQUENCE length: NAT OF OperandDescriptor]; rStack: LONG POINTER TO RStack ← NIL; rI: INTEGER; -- index into rStack RPush: PUBLIC PROC [type: CSEIndex, attr: Attr] = { rI ← rI + 1; WHILE rI >= rStack.length DO newLength: NAT = rStack.length + 16; newStack: LONG POINTER TO RStack = zone.NEW[RStack[newLength]]; FOR i: INTEGER IN [0 .. rI) DO newStack[i] ← rStack[i] ENDLOOP; zone.FREE[@rStack]; rStack ← newStack; ENDLOOP; rStack[rI] ← [type:type, attr:attr]}; RPop: PUBLIC PROC = {IF rI < 0 THEN ERROR; rI ← rI-1}; RType: PUBLIC PROC RETURNS [CSEIndex] = {RETURN [rStack[rI].type]}; RAttr: PUBLIC PROC RETURNS [Attr] = {RETURN [rStack[rI].attr]}; longUnsigned: CSEIndex; -- a hint for mwconst textType: ARRAY TextForm OF CSEIndex; -- a hint for text literals ExpInit: PUBLIC PROC [scratchZone: UNCOUNTED ZONE] = { zone ← scratchZone; implicit ← [type: typeANY, tree: Tree.Null, attr: emptyAttr]; P3S.implicitRecord ← RecordSENull; own ← dataPtr.ownSymbols; -- make a parameter? longUnsigned ← CSENull; textType ← ALL[CSENull]; rStack ← zone.NEW[RStack[32]]; rI ← -1}; ExpReset: PUBLIC PROC = { IF rStack # NIL THEN zone.FREE[@rStack]; zone ← NIL}; -- type manipulation EqualTypes: PROC [type1, type2: CSEIndex] RETURNS [BOOL] = { RETURN [Types.Equivalent[[own, type1], [own, type2]]]}; UnresolvedTypes: SIGNAL RETURNS [CSEIndex] = CODE; BalanceTypes: PROC [type1, type2: CSEIndex] RETURNS [type: CSEIndex] = { n1, n2: CARDINAL; SELECT TRUE FROM (type1 = type2), (type2 = typeANY) => type ← type1; (type1 = typeANY) => type ← type2; ENDCASE => { n1 ← Bundling[type1]; n2 ← Bundling[type2]; WHILE n1 > n2 DO type1 ← Unbundle[LOOPHOLE[type1]]; n1 ← n1-1 ENDLOOP; WHILE n2 > n1 DO type2 ← Unbundle[LOOPHOLE[type2]]; n2 ← n2-1 ENDLOOP; -- check bundling DO type1 ← TargetType[type1]; type2 ← TargetType[type2]; SELECT TRUE FROM Types.Assignable[[own, type1], [own, type2]] => {type ← type1; EXIT}; Types.Assignable[[own, type2], [own, type1]] => {type ← type2; EXIT}; ENDCASE; IF n1 = 0 THEN GO TO Fail; n1 ← n1-1; type1 ← Unbundle[LOOPHOLE[type1]]; type2 ← Unbundle[LOOPHOLE[type2]]; REPEAT Fail => type ← SIGNAL UnresolvedTypes; ENDLOOP}; RETURN}; ForceType: PUBLIC PROC [t: Tree.Link, type: CSEIndex] RETURNS [Tree.Link] = { PushTree[t]; IF t = Tree.Null THEN PushNode[cast, 1] ELSE WITH t SELECT FROM subtree => SELECT tb[index].name FROM construct, union, rowcons => PushNode[cast, 1]; openx => PushNode[cast, 1]; ENDCASE; ENDCASE => PushNode[cast, 1]; SetInfo[type]; RETURN [PopTree[]]}; -- operators UpArrow: PUBLIC PROC [node: Tree.Index] = { OPEN tb[node]; type, nType: CSEIndex; attr: Attr; son[1] ← Exp[son[1], typeANY]; type ← RType[]; attr ← RAttr[]; RPop[]; attr.const ← FALSE; DO nType ← NormalType[type]; WITH t: seb[nType] SELECT FROM ref => { RPush[UnderType[t.refType], attr]; attr2 ← seb[type].typeTag = long; IF P3S.safety = checked AND ~(t.counted OR PermanentType[t.refType]) THEN Log.ErrorNode[unsafeOperation, node]; EXIT}; record => { IF Bundling[nType] = 0 THEN GO TO fail; type ← Unbundle[LOOPHOLE[nType, RecordSEIndex]]}; ENDCASE => GO TO fail; REPEAT fail => { IF type # typeANY THEN Log.ErrorTree[typeClash, son[1]]; RPush[typeANY, attr]}; ENDLOOP}; -- arithmetic expression manipulation MakeNumeric: PROC [type: CSEIndex] RETURNS [CSEIndex] = { RETURN [SELECT seb[type].typeTag FROM long => MakeLongType[dataPtr.typeINT, type], ENDCASE => dataPtr.typeINT]}; EvalNumeric: PROC [t: Tree.Link] RETURNS [val: Tree.Link] = { val ← GenericRhs[t, dataPtr.typeINT]; SELECT NormalType[rStack[rI].type] FROM dataPtr.typeINT => NULL; typeANY => rStack[rI].type ← MakeNumeric[rStack[rI].type]; ENDCASE => Log.ErrorTree[typeClash, val]; RETURN}; ArithOp: PROC [node: Tree.Index] = { OPEN tb[node]; saveNP: NPUse; son[1] ← EvalNumeric[son[1]]; saveNP ← phraseNP; son[2] ← EvalNumeric[son[2]]; BalanceAttributes[node]; rStack[rI-1].attr ← And[rStack[rI-1].attr, rStack[rI].attr]; IF attr1 THEN rStack[rI-1].attr.const ← FALSE; RPop[]; phraseNP ← MergeNP[saveNP][phraseNP]}; ArithType: PROC [type: CSEIndex] RETURNS [CSEIndex] = { type ← NormalType[type]; RETURN [WITH seb[type] SELECT FROM relative => NormalType[UnderType[offsetType]], ENDCASE => type]}; Plus: PROC [node: Tree.Index] = { OPEN tb[node]; type: CSEIndex; lr: BOOL; saveNP: NPUse; son[1] ← GenericRhs[son[1], typeANY]; saveNP ← phraseNP; type ← ArithType[rStack[rI].type]; IF seb[type].typeTag = ref OR type = dataPtr.typeCHAR THEN { IF RCType[type] # none THEN Log.ErrorTree[typeClash, son[1]]; lr ← TRUE; son[2] ← EvalNumeric[son[2]]} ELSE { SELECT type FROM dataPtr.typeINT, typeANY => NULL; ENDCASE => Log.ErrorTree[typeClash, son[1]]; son[2] ← GenericRhs[son[2], typeANY]; lr ← FALSE; type ← ArithType[rStack[rI].type]; SELECT TRUE FROM type = dataPtr.typeINT, type = dataPtr.typeCHAR => NULL; seb[type].typeTag = ref => IF RCType[type] # none THEN Log.ErrorTree[typeClash, son[2]]; ENDCASE => { IF type # typeANY THEN Log.ErrorTree[typeClash, son[2]]; rStack[rI].type ← MakeNumeric[rStack[rI].type]}}; IF P3S.safety = checked AND seb[type].typeTag = ref THEN Log.ErrorNode[unsafeOperation, node]; BalanceAttributes[node]; rStack[rI-1].attr ← And[rStack[rI-1].attr, rStack[rI].attr]; IF attr1 THEN rStack[rI-1].attr.const ← FALSE; IF ~lr THEN rStack[rI-1].type ← rStack[rI].type; RPop[]; phraseNP ← MergeNP[saveNP][phraseNP]}; Minus: PROC [node: Tree.Index] = { OPEN tb[node]; type, lType, rType: CSEIndex; lr: BOOL; saveNP: NPUse; son[1] ← GenericRhs[son[1], typeANY]; saveNP ← phraseNP; type ← NormalType[rStack[rI].type]; lType ← ArithType[type]; lr ← TRUE; IF seb[lType].typeTag = ref OR lType = dataPtr.typeCHAR THEN { IF RCType[lType] # none THEN Log.ErrorTree[typeClash, son[1]]; son[2] ← GenericRhs[son[2], typeANY]; rType ← ArithType[rStack[rI].type]; SELECT TRUE FROM rType = typeANY => NULL; Types.Equivalent[[own, lType], [own, rType]] => lr ← FALSE; rType = dataPtr.typeINT => NULL; ENDCASE => Log.ErrorTree[typeClash, son[2]]} ELSE { SELECT type FROM dataPtr.typeINT, typeANY => NULL; ENDCASE => {Log.ErrorTree[typeClash, son[1]]; rStack[rI].type ← typeANY}; son[2] ← EvalNumeric[son[2]]}; IF P3S.safety = checked AND seb[lType].typeTag = ref THEN Log.ErrorNode[unsafeOperation, node]; BalanceAttributes[node]; rStack[rI-1].attr ← And[rStack[rI-1].attr, rStack[rI].attr]; IF attr1 THEN rStack[rI-1].attr.const ← FALSE; IF ~lr THEN rStack[rI-1].type ← IF attr2 THEN MakeLongType[dataPtr.typeINT, rStack[rI].type] ELSE dataPtr.typeINT; RPop[]; phraseNP ← MergeNP[saveNP][phraseNP]}; UnaryOp: PROC [node: Tree.Index] = { IF UniOperand[node] THEN { tb[node].son[1] ← EvalNumeric[tb[node].son[1]]; SetAttributes[node]; IF tb[node].attr1 THEN rStack[rI].attr.const ← FALSE}}; EnumOp: PROC [node: Tree.Index, target: CSEIndex] = { IF UniOperand[node] THEN { tb[node].son[1] ← GenericRhs[tb[node].son[1], target]; SetAttributes[node]; IF ~IndexType[RType[]] THEN Log.ErrorTree[typeClash, tb[node].son[1]]}}; RelOp: PROC [node: Tree.Index, ordered: BOOL] = { OPEN tb[node]; type: CSEIndex; attr: Attr; saveNP: NPUse; implicitOp: BOOL; son[1] ← GenericRhs[son[1], typeANY]; saveNP ← phraseNP; type ← NormalType[RType[]]; attr ← RAttr[]; implicitOp ← (son[1] = Tree.Null); son[2] ← GenericRhs[son[2], type]; type ← BalanceTypes[type, NormalType[RType[]] ! UnresolvedTypes => {Log.ErrorTree[typeClash, son[2]]; RESUME [typeANY]}]; IF (ordered AND ~OrderedType[type]) OR (~ordered AND ~IdentifiedType[type]) THEN Log.ErrorNode[relationType, node]; BalanceAttributes[node]; attr ← And[attr, RAttr[]]; IF implicitOp AND son[1] # Tree.Null THEN Log.ErrorTree[typeClash, son[2]]; SELECT seb[type].typeTag FROM basic, enumerated => NULL; transfer => { IF OperandInline[son[1]] THEN Log.ErrorTree[misusedInline, son[1]]; IF OperandInline[son[2]] THEN Log.ErrorTree[misusedInline, son[2]]; attr.const ← FALSE}; real => attr.const ← FALSE; ENDCASE; RPop[]; RPop[]; RPush[dataPtr.typeBOOL, attr]; phraseNP ← MergeNP[saveNP][phraseNP]}; In: PROC [node: Tree.Index] = { OPEN tb[node]; type: CSEIndex; saveNP: NPUse; son[1] ← GenericRhs[son[1], typeANY]; saveNP ← phraseNP; type ← RType[]; son[2] ← Range[son[2], CanonicalType[type]]; [] ← BalanceTypes[NormalType[type], NormalType[RType[]] ! UnresolvedTypes => {Log.ErrorTree[typeClash, tb[node].son[1]]; RESUME [typeANY]}]; BalanceAttributes[node]; rStack[rI-1].attr ← And[rStack[rI-1].attr, rStack[rI].attr]; RPop[]; rStack[rI].type ← dataPtr.typeBOOL; phraseNP ← MergeNP[saveNP][phraseNP]}; BoolOp: PROC [node: Tree.Index] = { OPEN tb[node]; attr: Attr; saveNP: NPUse; SealRefStack[]; son[1] ← Rhs[son[1], dataPtr.typeBOOL]; attr ← RAttr[]; saveNP ← phraseNP; ClearRefStack[]; son[2] ← Rhs[son[2], dataPtr.typeBOOL]; UnsealRefStack[]; attr ← And[attr, RAttr[]]; RPop[]; RPop[]; RPush[dataPtr.typeBOOL, attr]; phraseNP ← SequenceNP[saveNP][phraseNP]}; Interval: PUBLIC PROC [t: Tree.Link, target: CSEIndex, constant: BOOL] = { node: Tree.Index = GetNode[t]; type: CSEIndex; attr: Attr; saveNP: NPUse; target ← TargetType[target]; tb[node].son[1] ← BalancedRhs[tb[node].son[1], target]; saveNP ← phraseNP; type ← rStack[rI].type ← CanonicalType[rStack[rI].type]; attr ← RAttr[]; IF constant AND ~attr.const THEN Log.ErrorTree[nonConstant, tb[node].son[1]]; tb[node].son[2] ← BalancedRhs[tb[node].son[2], target]; rStack[rI].type ← CanonicalType[rStack[rI].type]; [] ← BalanceTypes[NormalType[type], NormalType[RType[]] ! UnresolvedTypes => {Log.ErrorTree[typeClash, tb[node].son[2]]; RESUME [typeANY]}]; attr ← And[attr, RAttr[]]; IF constant AND ~RAttr[].const THEN Log.ErrorTree[nonConstant, tb[node].son[2]]; BalanceAttributes[node]; IF tb[node].attr1 THEN attr.const ← FALSE; phraseNP ← MergeNP[saveNP][phraseNP]; RPop[]; rStack[rI].attr ← attr}; BalancedTarget: PROC [target, type: CSEIndex] RETURNS [CSEIndex] = { RETURN [IF target = typeANY OR (~EqualTypes[type, target] AND NormalType[type] = target) THEN TargetType[type] ELSE target]}; ResolveTypes: PROC [type1, type2, target: CSEIndex, t: Tree.Link] RETURNS [type: CSEIndex] = { failed: BOOL; IF target = typeANY THEN failed ← TRUE ELSE { ENABLE UnresolvedTypes => {failed ← TRUE; RESUME [typeANY]}; failed ← FALSE; type1 ← BalanceTypes[target, type1]; type2 ← BalanceTypes[target, type2]; type ← BalanceTypes[type1, type2]}; IF failed THEN {Log.ErrorTree[typeClash, t]; type ← typeANY}; RETURN}; IfExp: PROC [node: Tree.Index, target: CSEIndex] = { OPEN tb[node]; type: CSEIndex; attr: Attr; entryNP, saveNP: NPUse; SealRefStack[]; son[1] ← Rhs[son[1], dataPtr.typeBOOL]; attr ← RAttr[]; RPop[]; entryNP ← phraseNP; UnsealRefStack[]; son[2] ← BalancedRhs[son[2], target]; attr ← And[attr, RAttr[]]; saveNP ← SequenceNP[entryNP][phraseNP]; type ← RType[]; RPop[]; target ← BalancedTarget[target, type]; son[3] ← BalancedRhs[son[3], target]; attr ← And[attr, RAttr[]]; type ← BalanceTypes[type, RType[] ! UnresolvedTypes => {RESUME [ResolveTypes[type, RType[], target, son[3]]]}]; IF seb[type].typeTag = transfer THEN { IF OperandInline[son[2]] THEN Log.ErrorTree[misusedInline, son[2]]; IF OperandInline[son[3]] THEN Log.ErrorTree[misusedInline, son[3]]; attr.const ← FALSE}; phraseNP ← BoundNP[saveNP][SequenceNP[entryNP][phraseNP]]; RPop[]; RPush[type, attr]}; SelectExp: PROC [ node: Tree.Index, target: CSEIndex, driver: PROC [Tree.Index, Tree.Map], foldable: BOOL] = { type: CSEIndex; attr: Attr; saveNP: NPUse; started: BOOL; Selection: Tree.Map = { subType: CSEIndex; entryNP: NPUse = phraseNP; v ← BalancedRhs[t, target]; subType ← BalanceTypes[type, RType[] ! UnresolvedTypes => {RESUME [ResolveTypes[type, RType[], target, v]]}]; IF seb[subType].typeTag = transfer AND OperandInline[v] THEN Log.ErrorTree[misusedInline, v]; saveNP ← BoundNP[saveNP][SequenceNP[entryNP][phraseNP]]; IF subType # typeANY THEN type ← subType; IF ~started THEN target ← BalancedTarget[target, type]; attr ← And[attr, RAttr[]]; RPop[]; started ← TRUE; RETURN}; type ← typeANY; attr ← fullAttr; started ← FALSE; saveNP ← none; driver[node, Selection]; attr ← And[attr, RAttr[]]; RPop[]; attr.const ← foldable AND attr.const AND tb[node].attr2; RPush[type, attr]; phraseNP ← saveNP}; MinMax: PROC [node: Tree.Index, target: CSEIndex] = { OPEN tb[node]; attr: Attr; saveNP: NPUse; started: BOOL; type: CSEIndex; SubMinMax: Tree.Map = { subType: CSEIndex; v ← BalancedRhs[t, target]; attr ← And[attr, RAttr[]]; saveNP ← MergeNP[saveNP][phraseNP]; subType ← CanonicalType[RType[]]; subType ← BalanceTypes[subType, type ! UnresolvedTypes => {RESUME[ResolveTypes[subType, type, target, v]]}]; IF type # subType AND subType # typeANY THEN { IF ~OrderedType[subType] THEN Log.ErrorNode[relationType, node]; type ← subType; IF ~started THEN target ← BalancedTarget[target, type]}; RPop[]; started ← TRUE; RETURN}; attr ← fullAttr; saveNP ← none; started ← FALSE; type ← typeANY; son[1] ← UpdateList[son[1], SubMinMax]; SELECT seb[type].typeTag FROM long => {attr1 ← FALSE; attr2 ← TRUE}; real => {attr1 ← TRUE; attr2 ← FALSE; attr.const ← FALSE}; ENDCASE => attr1 ← attr2 ← FALSE; RPush[type, attr]; phraseNP ← saveNP}; TypeTest: PROC [node: Tree.Index, from, to: CSEIndex] = { subType: CSEIndex = CanonicalType[from]; op: NarrowOp = Narrowing[type: subType, target: to]; SELECT TRUE FROM op.error => Log.ErrorTree[typeClash, tb[node].son[1]]; op.computed => Log.ErrorTree[missingBinding, tb[node].son[1]]; op.unImpl => Log.Warning[unimplemented]; ENDCASE; IF subType # from THEN tb[node].son[1] ← ForceType[tb[node].son[1], subType]; tb[node].attr1 ← op.indirect; IF (tb[node].attr2 ← op.rtTest) THEN EnterType[MarkedType[to]]; tb[node].attr3 ← op.tagTest}; EndPoint: PROC [node: Tree.Index] = { OPEN tb[node]; type: CSEIndex; son[1] ← TypeExp[son[1]]; type ← UnderType[TypeForTree[son[1]]]; BEGIN WITH seb[type] SELECT FROM basic => SELECT code FROM codeINT, codeCHAR => NULL; ENDCASE => GO TO fail; enumerated => NULL; relative => IF TypeForm[offsetType] # subrange THEN GO TO fail; subrange => NULL; long => IF NormalType[UnderType[rangeType]] # dataPtr.typeINT THEN GO TO fail; ENDCASE => GO TO fail; EXITS fail => Log.ErrorTree[typeClash, son[1]]; END; RPush[type, fullAttr]}; Unspec: PROC [type: CSEIndex] RETURNS [BOOL] = { RETURN [WITH t: seb[type] SELECT FROM basic => t.code = codeANY, ENDCASE => FALSE]}; SafeForUnspec: PROC [target: CSEIndex] RETURNS [BOOL] = { RETURN [P3S.safety # checked OR RCType[target] = none]}; Rhs: PUBLIC PROC [exp: Tree.Link, lhsType: CSEIndex] RETURNS [val: Tree.Link] = { rhsType: CSEIndex; val ← Exp[exp, lhsType]; rhsType ← rStack[rI].type; SELECT TRUE FROM (lhsType = rhsType), Unspec[lhsType] => NULL; ENDCASE => { -- immediate matching is inconclusive UNTIL Types.Assignable[[own, lhsType], [own, rhsType]] DO WITH t: seb[rhsType] SELECT FROM subrange => rhsType ← UnderType[t.rangeType]; record => { IF Bundling[rhsType] = 0 THEN GO TO nomatch; rhsType ← Unbundle[LOOPHOLE[rhsType, RecordSEIndex]]; val ← ForceType[val, IF Unspec[rhsType] THEN typeANY ELSE rhsType]}; ref, arraydesc => { SELECT seb[lhsType].typeTag FROM long => { IF ~Types.Assignable[[own, NormalType[lhsType]], [own, rhsType]] THEN GO TO nomatch; val ← Lengthen[val, lhsType]}; ENDCASE => GO TO nomatch; rhsType ← lhsType}; basic => { IF Unspec[rhsType] AND SafeForUnspec[lhsType] THEN SELECT seb[lhsType].typeTag FROM long => val ← Lengthen[val, MakeLongType[typeANY, lhsType]]; ENDCASE ELSE SELECT seb[lhsType].typeTag FROM long => { IF ~Types.Assignable[[own, NormalType[lhsType]], [own, rhsType]] THEN GO TO nomatch; val ← Lengthen[val, lhsType]}; real => IF rhsType = dataPtr.typeINT THEN { val ← Float[val, rhsType, lhsType]; rStack[rI].attr.const ← FALSE} ELSE GO TO nomatch; ENDCASE => GO TO nomatch; rhsType ← lhsType}; long => { subType: CSEIndex = NormalType[rhsType]; SELECT seb[lhsType].typeTag FROM long => SELECT TRUE FROM Unspec[NormalType[lhsType]] => lhsType ← rhsType; Unspec[subType] AND SafeForUnspec[lhsType] => rhsType ← lhsType; ENDCASE => GO TO nomatch; real => IF subType = dataPtr.typeINT THEN { val ← Float[val, rhsType, lhsType]; rStack[rI].attr.const ← FALSE; rhsType ← lhsType} ELSE GO TO nomatch; basic, subrange => { IF ~Types.Assignable[[own, subType], [own, lhsType]] THEN GO TO nomatch; rhsType ← UnderType[t.rangeType]; val ← Shorten[val, rhsType]}; enumerated => IF EqualTypes[rhsType, dataPtr.typeATOM] THEN { Log.ErrorTree[missingCoercion, val]; rhsType ← lhsType} ELSE GOTO nomatch; ENDCASE => GO TO nomatch}; ENDCASE => GO TO nomatch; REPEAT nomatch => { -- no coercion is possible Log.ErrorTree[typeClash, IF exp = Tree.Null THEN implicit.tree ELSE val]; rhsType ← lhsType}; ENDLOOP; rStack[rI].type ← rhsType}; IF seb[rhsType].typeTag = transfer AND OperandInline[val] THEN Log.ErrorTree[misusedInline, val]; RETURN}; GenericRhs: PROC [exp: Tree.Link, target: CSEIndex] RETURNS [val: Tree.Link] = { type: CSEIndex; val ← Exp[exp, target]; type ← rStack[rI].type; -- put value in canonical form DO WITH seb[type] SELECT FROM subrange => type ← UnderType[rangeType]; record => { IF Bundling[type] = 0 THEN EXIT; type ← Unbundle[LOOPHOLE[type, RecordSEIndex]]; val ← ForceType[val, type]}; ENDCASE => EXIT; rStack[rI].type ← type; ENDLOOP; SELECT seb[target].typeTag FROM enumerated => IF EqualTypes[type, dataPtr.typeATOM] THEN { Log.ErrorTree[missingCoercion, val]; rStack[rI].type ← target}; ENDCASE; RETURN}; BalancedRhs: PROC [exp: Tree.Link, target: CSEIndex] RETURNS [val: Tree.Link] = { type: CSEIndex; val ← Exp[exp, target]; SELECT seb[target].typeTag FROM long, real => { type ← CanonicalType[rStack[rI].type]; IF type # typeANY AND seb[target].typeTag # seb[type].typeTag AND EqualTypes[NormalType[target], type] THEN { SELECT seb[target].typeTag FROM long => IF seb[type].typeTag # real THEN val ← Lengthen[val, target]; real => {val ← Float[val, type, target]; rStack[rI].attr.const ← FALSE}; ENDCASE; rStack[rI].type ← target}}; enumerated => IF EqualTypes[rStack[rI].type, dataPtr.typeATOM] THEN { Log.ErrorTree[missingCoercion, val]; rStack[rI].type ← target}; ENDCASE; RETURN}; AttrClass: PROC [type: CSEIndex] RETURNS [{short, long, real}] = { RETURN [WITH t: seb[type] SELECT FROM long => long, real => real, relative => AttrClass[UnderType[t.offsetType]], ENDCASE => short]}; SetAttributes: PROC [node: Tree.Index] = { SELECT AttrClass[rStack[rI].type] FROM long => {tb[node].attr1 ← FALSE; tb[node].attr2 ← TRUE}; real => {tb[node].attr1 ← TRUE; tb[node].attr2 ← FALSE}; ENDCASE => tb[node].attr1 ← tb[node].attr2 ← FALSE}; BalanceAttributes: PROC [node: Tree.Index] = { lType, rType: CSEIndex; lType ← rStack[rI-1].type; rType ← rStack[rI].type; SELECT AttrClass[lType] FROM long => { SELECT AttrClass[rType] FROM long => {tb[node].attr1 ← FALSE; tb[node].attr2 ← TRUE}; real => { rStack[rI-1].type ← rType; tb[node].son[1] ← Float[tb[node].son[1], lType, rType]; rStack[rI-1].attr.const ← FALSE; tb[node].attr1 ← TRUE; tb[node].attr2 ← FALSE}; ENDCASE => { rStack[rI].type ← rType ← MakeLongType[rType, lType]; tb[node].son[2] ← Lengthen[tb[node].son[2], rType]; tb[node].attr1 ← FALSE; tb[node].attr2 ← TRUE}}; real => { tb[node].attr1 ← TRUE; tb[node].attr2 ← FALSE; SELECT AttrClass[rType] FROM real => NULL; ENDCASE => { rStack[rI].type ← lType; tb[node].son[2] ← Float[tb[node].son[2], rType, lType]; rStack[rI].attr.const ← FALSE}}; ENDCASE => SELECT AttrClass[rType] FROM long => { rStack[rI-1].type ← lType ← MakeLongType[lType, rType]; tb[node].son[1] ← Lengthen[tb[node].son[1], lType]; tb[node].attr1 ← FALSE; tb[node].attr2 ← TRUE}; real => { rStack[rI-1].type ← rType; tb[node].son[1] ← Float[tb[node].son[1], lType, rType]; rStack[rI-1].attr.const ← FALSE; tb[node].attr1 ← TRUE; tb[node].attr2 ← FALSE}; ENDCASE => tb[node].attr1 ← tb[node].attr2 ← FALSE}; Lengthen: PROC [t: Tree.Link, target: CSEIndex] RETURNS [Tree.Link] = { PushTree[t]; PushNode[lengthen, 1]; SetInfo[target]; RETURN [PopTree[]]}; Shorten: PROC [t: Tree.Link, target: CSEIndex] RETURNS [Tree.Link] = { PushTree[t]; PushNode[shorten, 1]; SetInfo[target]; RETURN [PopTree[]]}; Float: PROC [t: Tree.Link, type, target: CSEIndex] RETURNS [Tree.Link] = { PushTree[IF seb[type].typeTag = long THEN t ELSE Lengthen[t, MakeLongType[type, typeANY]]]; SELECT NormalType[type] FROM dataPtr.typeINT => {PushNode[float, 1]; SetInfo[target]}; typeANY => NULL; ENDCASE => Log.ErrorTree[typeClash, t]; RETURN [PopTree[]]}; -- expressions implicit: PUBLIC P3S.ImplicitInfo; -- implied attributes of Tree.Null Exp: PUBLIC PROC [exp: Tree.Link, target: CSEIndex] RETURNS [val: Tree.Link] = { type: CSEIndex; phraseNP ← none; IF exp = Tree.Null THEN {RPush[implicit.type, implicit.attr]; RETURN [Tree.Null]}; WITH e: exp SELECT FROM symbol => { sei: ISEIndex = e.index; attr: Attr; attr.noXfer ← attr.noAssign ← TRUE; RecordMention[sei]; type ← UnderType[seb[sei].idType]; SELECT ctxb[seb[sei].idCtx].ctxType FROM included => IF ~(attr.const←ConstantId[sei]) THEN Log.ErrorSei[unimplemented, sei]; imported => attr.const ← ConstantId[sei]; ENDCASE => attr.const ← seb[sei].constant; RPush[type, attr]; val ← exp}; hash => WITH t: seb[target] SELECT FROM enumerated => { sei: ISEIndex; IF ([sei: sei] ← SearchCtxList[e.index, t.valueCtx]).found THEN { RPush[target, fullAttr]; val ← [symbol[sei]]} ELSE val ← Id[e.index]}; ENDCASE => val ← Id[e.index]; literal => { attr: Attr; attr.noXfer ← attr.noAssign ← TRUE; WITH e.index SELECT FROM string => { [val, type] ← StringRef[exp, target]; attr.const ← FALSE; IF dataPtr.interface THEN Log.ErrorTree[unimplemented, exp]}; ENDCASE => {type ← dataPtr.typeINT; attr.const ← TRUE; val ← exp}; RPush[type, attr]}; subtree => { node: Tree.Index ← e.index; val ← exp; -- the default SELECT tb[node].name FROM dot => {node ← Dot[node, target]; val ← [subtree[node]]}; uparrow => UpArrow[node]; apply => { node ← Apply[node, target, FALSE]; val ← [subtree[node]]; CheckNonVoid[node, target]}; uminus, abs => UnaryOp[node]; plus => Plus[node]; minus => Minus[node]; times, div, mod => ArithOp[node]; relE, relN => RelOp[node, FALSE]; relL, relGE, relG, relLE => RelOp[node, TRUE]; in, notin => In[node]; not => tb[node].son[1] ← Rhs[tb[node].son[1], dataPtr.typeBOOL]; or, and => BoolOp[node]; ifx => IfExp[node, target]; casex => SelectExp[node, target, Case, TRUE]; bindx => SelectExp[node, target, Discrimination, FALSE]; assignx => Assignment[node]; extractx => {Extract[node]; CheckNonVoid[node, target]}; min, max => MinMax[node, target]; pred, succ => EnumOp[node, target]; addr, base, length, arraydesc => AddrOp[node, target]; all => All[node, target]; mwconst => IF tb[node].attr1 THEN RPush[dataPtr.typeREAL, fullAttr] ELSE { IF longUnsigned = CSENull THEN longUnsigned ← MakeLongType[dataPtr.idCARDINAL, typeANY]; RPush[longUnsigned, fullAttr]}; void => RPush[target, voidAttr]; clit => RPush[dataPtr.typeCHAR, fullAttr]; llit => { attr: Attr ← fullAttr; attr.const ← FALSE; RPush[dataPtr.typeSTRING, attr]}; atom => { hti: HTIndex = GetHash[tb[node].son[1]]; WITH t: seb[target] SELECT FROM enumerated => { sei: ISEIndex; IF ~([sei: sei]←SearchCtxList[hti, t.valueCtx]).found THEN Log.ErrorHti[unknownId, hti]; tb[node].son[1] ← Tree.Null; FreeNode[node]; node ← Tree.NullIndex; val ← [symbol[index: sei]]; RPush[target, fullAttr]}; ENDCASE => { SymLiteralOps.EnterAtom[hti]; EnterType[dataPtr.typeAtomRecord, FALSE]; RPush[dataPtr.typeATOM, fullAttr]}}; nil => { OPEN tb[node]; SELECT TRUE FROM (son[1] # Tree.Null) => { son[1] ← TypeExp[son[1]]; type ← UnderType[TypeForTree[son[1]]]}; (target # typeANY) => type ← target; ENDCASE => type ← MakeRefType[typeANY, typeANY]; IF ~NullableType[type] THEN Log.ErrorTree[typeClash, val]; RPush[type, fullAttr]}; new, signalx, errorx, fork, joinx, create, startx, cons, listcons => { val ← MiscXfer[node, target]; node ← GetNode[val]; CheckNonVoid[node, target]}; syserrorx => { RPush[CSENull, emptyAttr]; CheckNonVoid[node, target]}; lengthen => { OPEN tb[node]; subType: CSEIndex; son[1] ← GenericRhs[ son[1], WITH seb[target] SELECT FROM long => TargetType[UnderType[rangeType]], ENDCASE => target]; subType ← TargetType[rStack[rI].type]; IF subType = dataPtr.typeINT OR seb[subType].typeTag = ref OR seb[subType].typeTag = arraydesc OR subType = typeANY THEN rStack[rI].type ← MakeLongType[subType, target] ELSE {Log.ErrorTree[typeClash, son[1]]; rStack[rI].type ← typeANY}}; narrow => { OPEN tb[node]; IF son[2] = Tree.Null THEN { IF target = typeANY THEN Log.ErrorNode[noTarget, node]; type ← target} ELSE {son[2] ← TypeExp[son[2]]; type ← UnderType[TypeForTree[son[2]]]}; son[1] ← Exp[son[1], TargetType[type]]; TypeTest[node: node, from: rStack[rI].type, to: type]; IF attr3 AND ~attr1 AND son[2] = Tree.Null THEN Log.ErrorNode[noTarget, node]; IF RCType[type] = simple THEN { nType: CSEIndex = NormalType[type]; WITH t: seb[nType] SELECT FROM ref => EnterType[t.refType, FALSE]; ENDCASE => NULL}; IF tb[node].nSons > 2 THEN [] ← CatchPhrase[tb[node].son[3]]; rStack[rI].type ← type; rStack[rI].attr.const ← rStack[rI].attr.noXfer ← FALSE}; istype => { OPEN tb[node]; son[1] ← Exp[son[1], typeANY]; son[2] ← TypeExp[son[2]]; type ← UnderType[TypeForTree[son[2]]]; TypeTest[node: node, from: RType[], to: type]; rStack[rI].type ← dataPtr.typeBOOL; rStack[rI].attr.const ← FALSE}; safen => tb[node].son[1] ← Exp[tb[node].son[1], target]; loophole => { OPEN tb[node]; subType: CSEIndex; son[1] ← Exp[son[1], typeANY]; subType ← RType[]; IF seb[subType].typeTag = transfer AND OperandInline[son[1]] THEN Log.ErrorTree[misusedInline, son[1]]; IF son[2] = Tree.Null THEN { IF target = typeANY THEN Log.ErrorNode[noTarget, node]; rStack[rI].type ← target} ELSE { son[2] ← TypeExp[son[2]]; rStack[rI].type ← UnderType[TypeForTree[son[2]]]}; IF RCType[rStack[rI].type] # none THEN { rStack[rI].attr.const ← FALSE; IF P3S.safety = checked THEN Log.ErrorNode[unsafeOperation, node]}}; size => { OPEN tb[node]; attr: Attr; son[1] ← TypeAppl[son[1]]; attr ← RAttr[]; RPop[]; IF son[2] # Tree.Null THEN { saveNP: NPUse = phraseNP; son[2] ← Rhs[son[2], dataPtr.typeINT]; attr ← And[attr, RAttr[]]; RPop[]; phraseNP ← MergeNP[saveNP][phraseNP]}; RPush[dataPtr.typeINT, attr]}; first, last => EndPoint[node]; typecode => { tb[node].son[1] ← TypeExp[tb[node].son[1]]; EnterType[TypeForTree[tb[node].son[1]], FALSE]; RPush[typeANY, fullAttr]}; self => { val ← P3S.self.tree; P3S.self.tree ← Tree.Null; phraseNP ← P3S.self.np; RPush[P3S.self.type, P3S.self.attr]; FreeNode[node]; node ← Tree.NullIndex}; val, cast => { tb[node].son[1] ← Exp[tb[node].son[1], target]; rStack[rI].type ← target}; ord => IF UniOperand[node] THEN { tb[node].son[1] ← Exp[tb[node].son[1], typeANY]; SetAttributes[node]; IF ~IndexType[RType[]] THEN Log.ErrorTree[typeClash, tb[node].son[1]]; rStack[rI].type ← MakeNumeric[RType[]]}; -- val => -- IF UniOperand[node] THEN { -- IF ~IndexType[target] THEN Log.ErrorNode[noTarget, node]; -- tb[node].son[1] ← EvalNumeric[tb[node].son[1]]; -- rStack[rI].type ← target}; stringinit => { tb[node].son[2] ← Rhs[tb[node].son[2], dataPtr.typeINT]; IF ~RAttr[].const THEN Log.ErrorTree[nonConstant, tb[node].son[2]]; RPop[]; RPush[dataPtr.typeSTRING, voidAttr]}; ENDCASE => IF tb[node].name = item THEN tb[node].son[2] ← Exp[tb[node].son[2], target] ELSE {Log.Error[unimplemented]; RPush[typeANY, emptyAttr]}; IF node # Tree.NullIndex THEN tb[node].info ← rStack[rI].type}; ENDCASE; RETURN}; CheckNonVoid: PROC [node: Tree.Index, target: CSEIndex] = { IF rStack[rI].type = CSENull THEN SELECT tb[node].name FROM error => {tb[node].name ← errorx; rStack[rI].type ← target}; errorx, syserrorx => rStack[rI].type ← target; ENDCASE => {Log.ErrorNode[typeClash, node]; rStack[rI].type ← typeANY}}; VoidExp: PUBLIC PROC [exp: Tree.Link] RETURNS [val: Tree.Link] = { val ← Exp[exp, typeANY]; RPop[]; RETURN}; UniOperand: PROC [node: Tree.Index] RETURNS [valid: BOOL] = { l: CARDINAL = ListLength[tb[node].son[1]]; IF ~(valid ← l=1) THEN { IF l > 1 THEN Log.ErrorN[listLong, l-1] ELSE Log.ErrorN[listShort, l+1]; tb[node].son[1] ← UpdateList[tb[node].son[1], VoidExp]; RPush[typeANY, emptyAttr]}; RETURN}; -- overloaded string literals StringRef: PROC [t: Tree.Link, target: CSEIndex] RETURNS [v: Tree.Link, type: CSEIndex] = { IF RCType[target] = none THEN {type ← dataPtr.typeSTRING; v ← t} ELSE { nType: CSEIndex = NormalType[target]; rType: SEIndex = WITH t: seb[nType] SELECT FROM ref => t.refType, ENDCASE => dataPtr.idTEXT; form: TextForm = TextRep[rType]; cType: SEIndex = IF form = text THEN dataPtr.idTEXT ELSE rType; type ← textType[form]; IF type = CSENull THEN { type ← MakeLongType[MakeRefType[cType: cType, hint: nType, counted: TRUE], target]; textType[form] ← type}; EnterType[TypeRoot[cType], FALSE]; WITH e: t SELECT FROM literal => WITH e.index SELECT FROM string => { sti ← LiteralOps.FindHeapString[sti, TypeRoot[cType]]; SymLiteralOps.EnterText[sti]}; ENDCASE; ENDCASE; PushTree[t]; PushNode[textlit, 1]; SetAttr[2, TRUE]; SetInfo[type]; v ← PopTree[]}; RETURN}; }.