-- file SymLiteralPack.Mesa -- last modified by Satterthwaite, 20-Apr-82 14:43:18 DIRECTORY Alloc: TYPE USING [Handle, Notifier, AddNotify, DropNotify, Top, Words], ComData: TYPE USING [ definitionsOnly, idINT, mainCtx, ownSymbols, typeATOM, typeRefANY], Literals: TYPE USING [LTIndex, STIndex], LiteralOps: TYPE USING [Find], RTBcd: TYPE USING [RefLitIndex, TypeIndex], Strings: TYPE USING [String, SubStringDescriptor], Symbols: TYPE USING [ Base, SERecord, HTIndex, SEIndex, ISEIndex, CSEIndex, CTXIndex, MDIndex, BitAddress, SENull, ISENull, CTXNull, StandardContext, lZ, OwnMdi, MDNull, typeANY, ctxType, seType], SymbolOps: TYPE USING [ ClusterSe, EnterString, FirstCtxSe, MakeCtxSe, MakeNonCtxSe, NextSe, TypeForm, UnderType], SymbolSegment: TYPE USING [atType], SymLiteralOps: TYPE USING [RefLitItem], Table: TYPE USING [Base, Limit, Selector], Tree: TYPE USING [Link, NullIndex], TreeOps: TYPE USING [PopTree, PushLit, PushNode, PushSe, SetAttr, SetInfo], Types: TYPE USING [Equivalent]; SymLiteralPack: PROGRAM IMPORTS Alloc, LiteralOps, SymbolOps, TreeOps, Types, dataPtr: ComData EXPORTS SymLiteralOps = { OPEN Symbols; RefLitItem: TYPE = SymLiteralOps.RefLitItem; -- types SymLitRecord: TYPE = RECORD [ SELECT tag: * FROM type => [canonical: BOOLEAN, typeCode: SEIndex], lit => [info: RefLitItem] ENDCASE]; SymLitIndex: TYPE = Table.Base RELATIVE ORDERED POINTER [0..Table.Limit) TO SymLitRecord; -- bases table: Alloc.Handle; atType: Table.Selector = SymbolSegment.atType; slb: Table.Base; seb: Symbols.Base; ctxb: Symbols.Base; UpdateBases: Alloc.Notifier = { seb ← base[seType]; ctxb ← base[ctxType]; slb ← base[atType]; seb ← base[seType]}; -- auxiliary type predicates Matched: SIGNAL [m1, m2: SEIndex] RETURNS [BOOLEAN] = CODE; NameEqual: PROC [key, entry: SEIndex] RETURNS [BOOLEAN] = { RETURN [(key = entry) OR Isomorphic[key, entry ! Matched => {RESUME [FALSE]}]]}; Isomorphic: PROC [key, entry: SEIndex] RETURNS [BOOLEAN] = { RETURN [WITH type1: seb[key] SELECT FROM id => (SymbolOps.ClusterSe[key] = SymbolOps.ClusterSe[entry]), cons => WITH type2: seb[entry] SELECT FROM cons => WITH t1: type1 SELECT FROM record => WITH t2: type2 SELECT FROM record => (t1.fieldCtx = t2.fieldCtx) OR (~t1.painted AND ~t2.painted AND ( (SIGNAL Matched[key, entry]) OR IsoFields[t1.fieldCtx, t2.fieldCtx ! Matched => {IF m1=key AND m2=entry THEN RESUME [TRUE]}])), ENDCASE => FALSE, ref => WITH t2: type2 SELECT FROM ref => (t1.counted = t2.counted) AND (t1.ordered = t2.ordered) AND (t1.readOnly = t2.readOnly) AND Isomorphic[t1.refType, t2.refType], ENDCASE => FALSE, long => WITH t2: type2 SELECT FROM long => Isomorphic[t1.rangeType, t2.rangeType], ENDCASE => FALSE, any => WITH t2: type2 SELECT FROM any => TRUE, ENDCASE => FALSE, ENDCASE => (key = entry), ENDCASE => FALSE, ENDCASE => ERROR]}; IsoFields: PROC [ctx1, ctx2: CTXIndex] RETURNS [BOOLEAN] = { sei1: ISEIndex ← SymbolOps.FirstCtxSe[ctx1]; sei2: ISEIndex ← SymbolOps.FirstCtxSe[ctx2]; UNTIL sei1 = sei2 DO IF seb[sei1].hash # seb[sei2].hash OR ~Isomorphic[seb[sei1].idType, seb[sei2].idType] THEN RETURN [FALSE]; sei1 ← SymbolOps.NextSe[sei1]; sei2 ← SymbolOps.NextSe[sei2]; ENDLOOP; RETURN [sei1 = sei2]}; Equivalent: PROC [key, entry: SEIndex] RETURNS [BOOLEAN] = { RETURN [(key = entry) OR ( Types.Equivalent[ [dataPtr.ownSymbols, SymbolOps.UnderType[key]], [dataPtr.ownSymbols, SymbolOps.UnderType[entry]]] AND ~Fuzzy[key, entry])]}; Fuzzy: PROC [sei1, sei2: SEIndex] RETURNS [BOOLEAN] = INLINE { RETURN [SymbolOps.TypeForm[sei1] = array AND (~seb[sei1].mark4 OR ~seb[sei2].mark4)]}; -- universal type fingers UTypeId: PUBLIC PROC [type: SEIndex] RETURNS [mdi: MDIndex, index: SEIndex] = { sei: SEIndex = SymbolOps.ClusterSe[type]; WITH se: seb[sei] SELECT FROM id => { ctx: CTXIndex = se.idCtx; WITH c: ctxb[ctx] SELECT FROM included => IF c.level = lZ THEN {index ← sei; mdi ← OwnMdi} ELSE {index ← se.idValue; mdi ← c.module}; ENDCASE => { index ← sei; mdi ← IF Predeclared[sei] THEN MDNull ELSE OwnMdi}}; cons => { index ← sei; mdi ← WITH t: se SELECT FROM basic => MDNull, enumerated => IF t.valueCtx IN StandardContext THEN MDNull ELSE OwnMdi, record => IF t.fieldCtx IN StandardContext THEN MDNull ELSE OwnMdi, opaque => IF Predeclared[t.id] THEN MDNull ELSE OwnMdi, ENDCASE => OwnMdi}; ENDCASE; RETURN}; Predeclared: PROC [sei: SEIndex] RETURNS [BOOLEAN] = { RETURN [sei = SENull OR ( WITH se: seb[sei] SELECT FROM id => se.idCtx IN (CTXNull .. LAST[StandardContext]], ENDCASE => FALSE)]}; -- typeIds minTypes: CARDINAL = 2; -- type fragment, if any, at least this big (avoid global 0) nTypes: CARDINAL; nTypeRefs: CARDINAL; typeMapId: ISEIndex; EnterType: PUBLIC PROC [type: SEIndex, canonical: BOOLEAN] = { sei: SEIndex = SymbolOps.ClusterSe[type]; slLimit: SymLitIndex = table.Top[SymbolSegment.atType]; nTypeRefs ← nTypeRefs + 1; FOR sli: SymLitIndex ← FIRST[SymLitIndex], sli+SIZE[SymLitRecord] UNTIL sli = slLimit DO WITH s: slb[sli] SELECT FROM type => IF canonical = s.canonical AND (IF canonical THEN Equivalent ELSE NameEqual)[sei, s.typeCode] THEN EXIT; ENDCASE; REPEAT FINISHED => InsertType[sei, canonical]; ENDLOOP}; TypeIndex: PUBLIC PROC [type: SEIndex, canonical: BOOLEAN] RETURNS [RTBcd.TypeIndex] = { sei: SEIndex = SymbolOps.ClusterSe[type]; i: CARDINAL ← 0; FOR sli: SymLitIndex ← FIRST[SymLitIndex], sli+SIZE[SymLitRecord] WHILE i < nTypes DO WITH s: slb[sli] SELECT FROM type => IF canonical = s.canonical AND (IF canonical THEN Equivalent ELSE NameEqual)[sei, s.typeCode] THEN EXIT; ENDCASE; i ← i+1; REPEAT FINISHED => ERROR; ENDLOOP; RETURN [[i]]}; TypeRef: PUBLIC PROC [type: SEIndex, canonical: BOOLEAN] RETURNS [Tree.Link] = { RETURN [IndexedRef[typeMapId, TypeIndex[type, canonical], typeANY]]}; DescribeTypes: PUBLIC PROC RETURNS [offset, length: CARDINAL] = { RETURN [offset: WordOffset[typeMapId], length: nTypes]}; EnumerateTypes: PUBLIC PROC [scan: PROC [canonical: BOOLEAN, type: SEIndex]] = { i: CARDINAL ← 0; FOR sli: SymLitIndex ← FIRST[SymLitIndex], sli+SIZE[SymLitRecord] WHILE i < nTypes DO WITH s: slb[sli] SELECT FROM type => scan[s.canonical, s.typeCode]; ENDCASE; i ← i + 1; ENDLOOP}; InsertType: PROC [type: SEIndex, canonical: BOOLEAN] = { sli: SymLitIndex = table.Words[atType, SIZE[SymLitRecord]]; slb[sli] ← [type[canonical: canonical, typeCode: type]]; nTypes ← nTypes + 1}; PadTypes: PROC = INLINE { IF nTypes # 0 THEN { FOR i: NAT IN [nTypes .. minTypes) DO InsertType[Symbols.SENull, FALSE] ENDLOOP}}; -- atoms and REFs to literals minLitRefs: CARDINAL = 1; -- ref lit fragment, if any, at least this big (avoid global 0) nLits: CARDINAL; nLitRefs: CARDINAL; firstLit: SymLitIndex; -- only after Reset litMapId: ISEIndex; EnterLit: PROC [item: RefLitItem] = { key: SymLitRecord = [lit[item]]; slLimit: SymLitIndex = table.Top[SymbolSegment.atType]; nLitRefs ← nLitRefs + 1; FOR sli: SymLitIndex ← FIRST[SymLitIndex], sli+SIZE[SymLitRecord] UNTIL sli = slLimit DO IF slb[sli] = key THEN EXIT; REPEAT FINISHED => InsertLit[item]; ENDLOOP}; LitIndex: PROC [item: RefLitItem] RETURNS [RTBcd.RefLitIndex] = { key: SymLitRecord = [lit[item]]; i: CARDINAL ← 0; FOR sli: SymLitIndex ← firstLit, sli+SIZE[SymLitRecord] WHILE i < nLits DO IF slb[sli] = key THEN EXIT; i ← i+1; REPEAT FINISHED => ERROR; ENDLOOP; RETURN [[i]]}; InsertLit: PROC [item: RefLitItem] = { sli: SymLitIndex = table.Words[atType, SIZE[SymLitRecord]]; slb[sli] ← [lit[item]]; nLits ← nLits + 1}; EnterAtom: PUBLIC PROC [name: HTIndex] = {EnterLit[[atom[pName: name]]]}; AtomIndex: PUBLIC PROC [name: HTIndex] RETURNS [RTBcd.RefLitIndex] = { RETURN [LitIndex[[atom[pName: name]]]]}; AtomRef: PUBLIC PROC [name: HTIndex] RETURNS [Tree.Link] = { RETURN [IndexedRef[litMapId, AtomIndex[name], dataPtr.typeATOM]]}; EnterText: PUBLIC PROC [sti: Literals.STIndex] = {EnterLit[[text[value: sti]]]}; TextIndex: PUBLIC PROC [sti: Literals.STIndex] RETURNS [RTBcd.RefLitIndex] = { RETURN [LitIndex[[text[value: sti]]]]}; TextRef: PUBLIC PROC [sti: Literals.STIndex] RETURNS [Tree.Link] = { RETURN [IndexedRef[litMapId, TextIndex[sti], dataPtr.typeRefANY]]}; DescribeRefLits: PUBLIC PROC RETURNS [offset, length: CARDINAL] = { RETURN [offset: WordOffset[litMapId], length: nLits]}; EnumerateRefLits: PUBLIC PROC [scan: PROC [RefLitItem]] = { i: CARDINAL ← 0; FOR sli: SymLitIndex ← firstLit, sli+SIZE[SymLitRecord] WHILE i < nLits DO WITH s: slb[sli] SELECT FROM lit => scan[s.info]; ENDCASE; i ← i + 1; ENDLOOP}; PadRefLits: PROC = INLINE {NULL}; -- for now -- state transitions Initialize: PUBLIC PROC [ownTable: Alloc.Handle] = { table ← ownTable; table.AddNotify[UpdateBases]; nLits ← nLitRefs ← 0; nTypes ← nTypeRefs ← 0; typeMapId ← litMapId ← ISENull}; Reset: PUBLIC PROC = { PadTypes[]; PadRefLits[]; IF nLits # 0 AND ~dataPtr.definitionsOnly THEN litMapId ← CreateMap["&refs"L, dataPtr.typeRefANY, nLits, nLitRefs]; firstLit ← FIRST[SymLitIndex]; IF nTypes # 0 THEN { slLimit: SymLitIndex = table.Top[atType]; lastType: SymLitIndex; t: SymLitRecord; lastType ← slLimit - SIZE[SymLitRecord]; DO UNTIL firstLit = slLimit OR slb[firstLit].tag = lit DO firstLit ← firstLit + SIZE[SymLitRecord] ENDLOOP; UNTIL slb[lastType].tag = type DO lastType ← lastType - SIZE[SymLitRecord] ENDLOOP; IF lastType < firstLit THEN EXIT; t ← slb[firstLit]; slb[firstLit] ← slb[lastType]; slb[lastType] ← t; ENDLOOP; IF ~dataPtr.definitionsOnly THEN typeMapId ← CreateMap["&types"L, typeANY, nTypes, nTypeRefs]}}; Finalize: PUBLIC PROC = {table.DropNotify[UpdateBases]; table ← NIL}; -- utility routines CreateMap: PROC [id: Strings.String, cType: SEIndex, nEntries, nRefs: CARDINAL] RETURNS [sei: ISEIndex] = { desc: Strings.SubStringDescriptor ← [base:id, offset:0, length:id.length]; mapType, iType: CSEIndex; sei ← SymbolOps.MakeCtxSe[SymbolOps.EnterString[@desc], dataPtr.mainCtx]; iType ← SymbolOps.MakeNonCtxSe[SIZE[subrange cons SERecord]]; seb[iType].typeInfo ← subrange[ filled: TRUE, empty: FALSE, rangeType: dataPtr.idINT, origin: 0, range: nEntries-1]; seb[iType].mark3 ← seb[iType].mark4 ← TRUE; mapType ← SymbolOps.MakeNonCtxSe[SIZE[array cons SERecord]]; seb[mapType].typeInfo ← array[packed: FALSE, indexType: iType, componentType: cType]; seb[mapType].mark3 ← seb[mapType].mark4 ← TRUE; seb[sei].idType ← mapType; seb[sei].public ← seb[sei].extended ← seb[sei].constant ← seb[sei].linkSpace ← FALSE; seb[sei].immutable ← TRUE; seb[sei].idValue ← Tree.NullIndex; seb[sei].idInfo ← nRefs; seb[sei].mark3 ← seb[sei].mark4 ← TRUE; RETURN}; WordOffset: PROC [sei: ISEIndex] RETURNS [offset: CARDINAL] = { IF sei = ISENull THEN offset ← 0 ELSE { addr: BitAddress = seb[sei].idValue; offset ← addr.wd}; RETURN}; IndexedRef: PROC [array: ISEIndex, item: CARDINAL, type: CSEIndex] RETURNS [Tree.Link] = { OPEN TreeOps; PushSe[array]; PushLit[LiteralOps.Find[item]]; PushNode[index, 2]; SetAttr[2, FALSE]; SetInfo[type]; RETURN [PopTree[]]}; }.