-- file UtilsHot.Mesa
-- last modified by Bruce, October 28, 1980  12:17 PM
-- last modified by Johnsson,  July 18, 1980  8:57 AM

DIRECTORY
  ComData USING [typeCARDINAL, typeStringBody],
  Copier USING [SearchFileCtx],
  DContext USING [GetGlobal],
  DebugOps USING [BitAddress, LongCopyREAD],
  DI USING [Foo, SearchCtxForVal, UnionSEIndex, ValFormat, VType],
  DSyms USING [GFHandle, GFrameHti],
  Gf USING [],
  Init USING [],
  Inline USING [COPY, LowHalf],
  LiteralOps USING [DescriptorValue, StringValue],
  Literals USING [LitDescriptor, LitRecord, ltType],
  Lookup USING [HTIndex, HtiToString, MakeFoo],
  MachineDefs USING [FieldDescriptor, GFHandle, LCOPY, WordLength],
  Mopcodes USING [zRFS],
  Storage USING [CopyString, Node],
  String USING [WordsForString],
  Strings USING [AppendSubString, SubString, SubStringDescriptor],
  SymbolOps USING [BitsForType, EnterString, SearchContext, SubStringForHash, UnderType],
  SymbolPack,
  Symbols USING [codeANY, codeCHAR, codeINT, CSEIndex, CTXIndex, CTXNull, ctxType, HTIndex, ISEIndex, ISENull, mdType, RecordSEIndex, SEIndex, seType, TypeClass, typeTYPE],
  Table USING [AddNotify, Base, DropNotify, Notifier];

UtilsHot: PROGRAM
    IMPORTS
	com: ComData, Copier, DContext, DebugOps, DI, Strings, DSyms, Inline,
	LiteralOps, Lookup, MachineDefs, Storage, SymbolOps,
        myBase: SymbolPack, String, Table
    EXPORTS DI, Gf, Init, Lookup
    SHARES Copier = 
  BEGIN
  OPEN DI, SymbolOps, Symbols;

  LiteralProblem: ERROR = CODE;
  StrangeRecord: ERROR = CODE;
  WrongTypeClass: ERROR [f: Foo] = CODE;

  DefaultOutputFormat: PUBLIC ValFormat ← [card[]];

-- tables defining the current symbol table

  seb: Table.Base;		-- se table
  mdb: Table.Base;		-- module table
  ltb: Table.Base;
  ctxb: Table.Base;		-- context table

  Notify: Table.Notifier =
    BEGIN
    ltb ← base[Literals.ltType];
    seb ← base[seType]; ctxb ← base[ctxType]; mdb ← base[mdType]
    END;

  entryDepth: CARDINAL ← 0;

  Enter: PROCEDURE =
    BEGIN
    IF entryDepth = 0 THEN Table.AddNotify[Notify];
    entryDepth ← entryDepth + 1;
    END;

  Exit: PROCEDURE =
    BEGIN
    IF (entryDepth ← entryDepth-1) = 0 THEN Table.DropNotify[Notify];
    END;

  Name: PUBLIC PROCEDURE [name: STRING, gf: MachineDefs.GFHandle ← NIL] =
    BEGIN
    hti: Symbols.HTIndex = DSyms.GFrameHti[IF gf = NIL THEN DContext.GetGlobal[] ELSE gf];
    Lookup.HtiToString[hti,name];
    END;
  
  CopyLiteral: PUBLIC PROCEDURE [info: Literals.LitRecord]
    RETURNS [p: POINTER, length: CARDINAL] =
    BEGIN
    Enter[];
    WITH info SELECT FROM
      word =>
	BEGIN
	lit: Literals.LitDescriptor ← LiteralOps.DescriptorValue[index];
	length ← lit.length;
	p ← Storage.Node[length];
	MachineDefs.LCOPY[from: @ltb[lit.offset], to: p, nwords: length];
	END;
      string =>
	BEGIN
	s: STRING ←
	  Storage.CopyString[LiteralOps.StringValue[index]];
	length ← String.WordsForString[s.length];
	p ← s;
	END;
      ENDCASE => ERROR LiteralProblem;
    Exit[];
    END;

  StringToHti: PUBLIC PROC [s: STRING] RETURNS [HTIndex] =
    BEGIN
    desc: Strings.SubStringDescriptor ← [base: s, offset: 0, length: s.length];
    RETURN[SymbolOps.EnterString[@desc]];
    END;

  HtiToString: PUBLIC PROC [hti: HTIndex, s: STRING] =
    BEGIN
    desc: Strings.SubStringDescriptor;
    ss: Strings.SubString ← @desc;
    SymbolOps.SubStringForHash[ss,hti];
    Strings.AppendSubString[s,ss];
    END;

  SearchCtxList: PUBLIC PROC [hti: HTIndex, ctx: CTXIndex]
      RETURNS [sei: ISEIndex] =
    BEGIN
    found: BOOLEAN ← TRUE;
    IF ctx = CTXNull THEN RETURN [ISENull];
    IF (sei ← SymbolOps.SearchContext[hti,ctx]) # ISENull THEN RETURN;
    Enter[];
    WITH ctxb[ctx] SELECT FROM
      included => IF ~complete THEN 
	[found, sei] ← Copier.SearchFileCtx[hti, LOOPHOLE[ctx]];
      imported => sei ← SearchCtxList[hti,includeLink];
      simple => NULL;
      ENDCASE => sei ← ISENull;
    Exit[];
    IF ~found THEN sei ← ISENull;
    RETURN;
    END;

  CheckClass: PUBLIC PROC [tc: TypeClass, f: Foo] RETURNS [UNSPECIFIED] =
    BEGIN
    csei: CSEIndex ← TypeForSe[f.tsei];
    Enter[];
    IF seb[csei].typeTag # tc THEN ERROR WrongTypeClass[f];
    Exit[];
    RETURN[csei];
    END;

  FindField: PUBLIC PROC [f: Foo, pad: CARDINAL, isei: ISEIndex]
      RETURNS [field: Foo] =
    BEGIN
    IF f.addr.useStack THEN field ← Lookup.MakeFoo[isei,f.addr]
    ELSE
      BEGIN
      Enter[];
      field ← Find[f,pad,isei];
      Exit[];
      END;
    IF field = NIL THEN RETURN;
    field.there ← f.there; field.xfer ← f.xfer; field.indent ← f.indent;
    IF ~f.there THEN FixupHeap[f,field];
    END;

  FixupHeap: PROC [old, new: Foo] = {
    OPEN Inline;
    words: CARDINAL ← old.words + (IF old.bits = 0 THEN 0 ELSE 1);
    new.addr.base ← Storage.Node[words];
    COPY[from: LowHalf[old.addr.base], nwords: words, to: LowHalf[new.addr.base]]};

  Find: PROC [f: Foo, pad: CARDINAL, isei: ISEIndex]
      RETURNS [field: Foo] = INLINE
    BEGIN
    ba: DebugOps.BitAddress ← f.addr;
    notNested: BOOLEAN = ba.offset = 0;
    first: BOOLEAN = seb[isei].idValue = 0;
    sizeInc: CARDINAL;
    IF first AND notNested THEN {sizeInc ← pad; ba.offset ← 0}
    ELSE {sizeInc ← 0; ba.offset ← pad};
    field ← Lookup.MakeFoo[isei, ba, sizeInc]
    END;

  Pad: PUBLIC PROC [f: Foo, rsei: RecordSEIndex] RETURNS [pad: CARDINAL] =
    BEGIN
    size: CARDINAL ← SymbolOps.BitsForType[rsei];
    pad ← 0;
    IF size > 0 AND size < 16 THEN
      BEGIN
      available: CARDINAL ← IF f.bits # 0 THEN f.bits ELSE 16;
      IF available < size THEN ERROR StrangeRecord;
      pad ← f.addr.offset + available - size;
      END;
    END;

  VariantType: PUBLIC PROC [usei: UnionSEIndex] RETURNS [v: VType] =
    BEGIN OPEN seb[usei];
    Enter[];
    IF ~controlled THEN v ← IF overlaid THEN overlaid ELSE computed
    ELSE v ← controlled;
    Exit[];
    END;

  TagIsei: PUBLIC PROC [f: Foo, pad: CARDINAL, usei: UnionSEIndex]
    RETURNS [isei: ISEIndex] =
    BEGIN OPEN SymbolOps;
    tag: Foo;
    val: CARDINAL;
    ictx: CTXIndex;
    Enter[];
    tag ← FindField[f,pad,seb[usei].tagSei];
    ictx ← seb[usei].caseCtx;
    Exit[];
    IF tag.bits + tag.addr.offset > MachineDefs.WordLength THEN
      ERROR StrangeRecord;
    GetValue[tag];
    val ← tag.addr.base↑;
    isei ← DI.SearchCtxForVal[val,ictx,none];
    END;

  TypeForSe: PUBLIC PROC [sei: SEIndex] RETURNS [type: CSEIndex] = 
    BEGIN
    Enter[];
    DO
      WITH seb[sei] SELECT FROM
	id => IF idType # typeTYPE THEN sei ← idType ELSE EXIT;
	ENDCASE => EXIT;
      ENDLOOP;
    Exit[];
    RETURN[UnderType[sei]];
    END;

  RFS: PROC [POINTER, MachineDefs.FieldDescriptor] RETURNS [UNSPECIFIED] =
    MACHINE CODE BEGIN Mopcodes.zRFS END;

  ReadField: PROCEDURE [f: Foo] =
    BEGIN OPEN f;
    fd: MachineDefs.FieldDescriptor ←
      [offset: 0, posn: addr.offset, size: bits];
    p: POINTER ← Inline.LowHalf[addr.base];
    p↑ ← RFS[p,fd];
    END;

  GetValue: PUBLIC PROCEDURE [f: Foo] =
    BEGIN OPEN f;
    p: LONG POINTER;
    cnt: CARDINAL ← words + (IF bits = 0 THEN 0 ELSE 1);
    IF there THEN {
      p ← Storage.Node[cnt];
      DebugOps.LongCopyREAD[from: addr.base, to: p, nwords: cnt];
      addr.base ← p;
      there ← FALSE};
    IF bits # 0 THEN ReadField[f];
    END;

Format: PUBLIC PROCEDURE [sei: SEIndex]
    RETURNS [vf: ValFormat, intSub: BOOLEAN] =
  BEGIN
  inSubrange: BOOLEAN ← FALSE;
  csei: CSEIndex;
  vf ← [none[]];
  intSub ← FALSE;
  csei ← TypeForSe[sei];
  Enter[];
  DO
    WITH seb[csei] SELECT FROM
      basic => 
	BEGIN
	SELECT code FROM
	  codeANY => vf ← DefaultOutputFormat;
	  codeINT => BEGIN intSub ← inSubrange; vf ← [int[]] END;
	  codeCHAR => vf ← [char[]];
	  ENDCASE;
	GOTO exit;
	END;
      subrange =>
	BEGIN
	IF csei = com.typeCARDINAL THEN { vf ← DefaultOutputFormat; GOTO exit };
	csei ← UnderType[rangeType];
	inSubrange ← TRUE
	END;
      enumerated =>
	BEGIN
	intSub ← FALSE;
	vf ← [enum[LOOPHOLE[csei]]];
	GOTO exit
	END;
      ref =>
	BEGIN
	IF UnderType[refType] = com.typeStringBody THEN vf ← [string[]]
	ELSE vf ← [pointer[]];
	GOTO exit
	END;
      relative => BEGIN vf ← [relative[]]; GOTO exit END;
      ENDCASE => GOTO exit;
    ENDLOOP;
  EXITS exit => {Exit[]; RETURN};
  END;

  END.