DIRECTORY
Alloc: TYPE USING [Handle, Notifier, AddNotify, DropNotify, Top, Words],
ComData:
TYPE
USING [
idINT, interface, mainCtx, ownSymbols, typeATOM, typeRefANY],
ConvertUnsafe: TYPE USING [SubString],
Literals: TYPE USING [STIndex],
LiteralOps: TYPE USING [Find],
RTBcd: TYPE USING [RefLitIndex, TypeIndex],
Symbols:
TYPE
USING [
Base, SERecord,
Name, Type, ISEIndex, CSEIndex, CTXIndex, MDIndex, BitAddress,
nullType, 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: BOOL, typeCode: Type],
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: Type] RETURNS [BOOL] = CODE;
NameEqual:
PROC [key, entry: Type]
RETURNS [
BOOL] = {
RETURN [(key = entry) OR Isomorphic[key, entry ! Matched => {RESUME [FALSE]}]]};
Isomorphic:
PROC [key, entry: Type]
RETURNS [
BOOL] = {
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 [
BOOL] = {
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: Type]
RETURNS [
BOOL] = {
RETURN [(key = entry)
OR (
Types.Equivalent[
[dataPtr.ownSymbols, SymbolOps.UnderType[key]],
[dataPtr.ownSymbols, SymbolOps.UnderType[entry]]]
AND ~Fuzzy[key, entry])]};
Fuzzy:
PROC [sei1, sei2: Type]
RETURNS [
BOOL] =
INLINE {
RETURN [SymbolOps.TypeForm[sei1] = array AND (~seb[sei1].mark4 OR ~seb[sei2].mark4)]};
universal type fingers
UTypeId:
PUBLIC
PROC [type: Type]
RETURNS [mdi: MDIndex, index: Type] = {
sei: Type = 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 [type: Type]
RETURNS [
BOOL] = {
RETURN [type = nullType
OR (
WITH se: seb[type]
SELECT
FROM
id => se.idCtx IN (CTXNull .. StandardContext.LAST],
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: Type, canonical:
BOOL] = {
sei: Type = SymbolOps.ClusterSe[type];
slLimit: SymLitIndex = table.Top[SymbolSegment.atType];
nTypeRefs ← nTypeRefs + 1;
FOR sli: SymLitIndex ← SymLitIndex.
FIRST, sli+SymLitRecord.
SIZE
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: Type, canonical:
BOOL]
RETURNS [RTBcd.TypeIndex] = {
sei: Type = SymbolOps.ClusterSe[type];
i: CARDINAL ← 0;
FOR sli: SymLitIndex ← SymLitIndex.
FIRST, sli+SymLitRecord.
SIZE
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: Type, canonical:
BOOL]
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:
BOOL, type: Type]] = {
i: CARDINAL ← 0;
FOR sli: SymLitIndex ← SymLitIndex.
FIRST, sli+SymLitRecord.
SIZE
WHILE i < nTypes
DO
WITH s: slb[sli]
SELECT
FROM
type => scan[s.canonical, s.typeCode];
ENDCASE;
i ← i + 1;
ENDLOOP};
InsertType:
PROC [type: Type, canonical:
BOOL] = {
sli: SymLitIndex = table.Words[atType, SymLitRecord.SIZE];
slb[sli] ← [type[canonical: canonical, typeCode: type]];
nTypes ← nTypes + 1};
PadTypes:
PROC [pad:
BOOL] =
INLINE {
IF nTypes # 0
THEN {
totalTypes: CARDINAL = (IF pad THEN ((nTypes+3)/4)*4 ELSE nTypes);
FOR i:
NAT
IN [nTypes ..
MAX[minTypes, totalTypes])
DO
InsertType[Symbols.nullType, 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; -- tight bound after Reset
litMapId: ISEIndex;
EnterLit:
PROC [item: RefLitItem] = {
key: SymLitRecord = [lit[item]];
slLimit: SymLitIndex = table.Top[SymbolSegment.atType];
nLitRefs ← nLitRefs + 1;
FOR sli: SymLitIndex ← SymLitIndex.
FIRST, sli+SymLitRecord.
SIZE
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+SymLitRecord.
SIZE
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, SymLitRecord.SIZE];
slb[sli] ← [lit[item]];
nLits ← nLits + 1};
EnterAtom: PUBLIC PROC [name: Name] = {EnterLit[[atom[pName: name]]]};
AtomIndex:
PUBLIC
PROC [name: Name]
RETURNS [RTBcd.RefLitIndex] = {
RETURN [LitIndex[[atom[pName: name]]]]};
AtomRef:
PUBLIC
PROC [name: Name]
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+SymLitRecord.
SIZE
WHILE i < nLits
DO
WITH s: slb[sli]
SELECT
FROM
lit => {scan[s.info]; i ← i+1};
ENDCASE;
ENDLOOP};
PadRefLits:
PROC [pad:
BOOL] =
INLINE {
IF nLits # 0
THEN {
totalLits: CARDINAL = (IF pad THEN ((nLits+3)/4)*4 ELSE nLits);
someLit: RefLitItem; -- need a null RefLitItem
FindLit: PROC [item: RefLitItem] = {someLit ← item};
EnumerateRefLits[FindLit];
FOR i:
NAT
IN [nLits ..
MAX[minLitRefs, totalLits])
DO
InsertLit[someLit] ENDLOOP}};
state transitions
Initialize:
PUBLIC
PROC [ownTable: Alloc.Handle] = {
table ← ownTable; table.AddNotify[UpdateBases];
nLits ← nLitRefs ← 0; nTypes ← nTypeRefs ← 0;
firstLit ← SymLitIndex.FIRST; -- see Reset
typeMapId ← litMapId ← ISENull};
Reset:
PUBLIC
PROC [pad:
BOOL] = {
PadTypes[pad]; PadRefLits[pad];
IF nLits # 0
AND ~dataPtr.interface
THEN
litMapId ← CreateMap["&refs"L, dataPtr.typeRefANY, nLits, nLitRefs];
IF nTypes # 0
THEN {
slLimit: SymLitIndex = table.Top[atType];
lastType: SymLitIndex;
t: SymLitRecord;
lastType ← slLimit - SymLitRecord.SIZE;
DO
UNTIL firstLit = slLimit
OR slb[firstLit].tag = lit
DO
firstLit ← firstLit + SymLitRecord.SIZE ENDLOOP;
UNTIL slb[lastType].tag = type
DO
lastType ← lastType - SymLitRecord.SIZE ENDLOOP;
IF lastType < firstLit THEN EXIT;
t ← slb[firstLit]; slb[firstLit] ← slb[lastType]; slb[lastType] ← t;
ENDLOOP;
IF ~dataPtr.interface
THEN typeMapId ← CreateMap["&types"L, typeANY, nTypes, nTypeRefs]}};
Finalize: PUBLIC PROC = {table.DropNotify[UpdateBases]; table ← NIL};
utility routines
CreateMap:
PROC [id:
LONG
STRING, cType: Type, nEntries, nRefs:
CARDINAL]
RETURNS [sei: ISEIndex] = {
desc: ConvertUnsafe.SubString ← [base:id, offset:0, length:id.length];
mapType, iType: CSEIndex;
sei ← SymbolOps.MakeCtxSe[SymbolOps.EnterString[desc], dataPtr.mainCtx];
iType ← SymbolOps.MakeNonCtxSe[SERecord.cons.subrange.SIZE];
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[SERecord.cons.array.SIZE];
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[]]};
}.