-- DumpType.mesa; modified by:
--   Hayes, October 16, 1980  11:25 PM
--   Bruce, August 29, 1980  1:12 PM
--   Mark, Oct 17, 1980 12:29 AM

DIRECTORY
  Ascii USING [SP],
  DI USING [Format, SEIndex],
  DOutput USING [Char, EOL, Octal, Text],
  Dump USING [HashVal, HtiVal, ModeName, TypedNum],
  Lookup USING [CopyMore],
  MachineDefs USING [WordLength],
  SymbolOps USING [FirstCtxSe, NextSe, TypeLink, UnderType],
  Symbols USING [
    BodyRecord, BTIndex, codeANY, CSEIndex, CTXIndex, HTIndex, HTNull, ISEIndex, ISENull, 
    lZ, RecordSEIndex, RecordSENull, SEIndex, SENull, TransferMode, typeTYPE],
  SymbolSegment USING [bodyType, ctxType, seType],
  Table USING [AddNotify, Base, Bounds, DropNotify, Notifier];
  
DumpType: PROGRAM
  IMPORTS DI, DOutput, Dump, Lookup, SymbolOps, Table
  EXPORTS Dump =
BEGIN OPEN DI, Dump, SymbolOps, Symbols;

Sub: TYPE = PROCEDURE;

NoSub: Sub = BEGIN RETURN END;

seb: Table.Base;
ctxb: Table.Base;
bb: Table.Base;

Notify: Table.Notifier =
  BEGIN OPEN SymbolSegment;
  seb ← base[seType];
  ctxb ← base[ctxType];
  bb ← base[bodyType];
  END;
  
Type: PUBLIC PROCEDURE [isei: ISEIndex,
    pub: BOOLEAN ← FALSE, nest: CARDINAL ← 0, recurring: BOOLEAN ← FALSE] =
  BEGIN OPEN seb[isei];
  IF ~recurring THEN Table.AddNotify[Notify];
  IF hash # HTNull THEN
    BEGIN HtiVal[hash]; DOutput.Text[": "L] END;
  IF ~recurring THEN
    BEGIN
    DOutput.Text[IF (pub ← public) THEN "PUBLIC "L ELSE "PRIVATE "L];
    DOutput.Text["TYPE = "L];
    END;
  PrintType[
    tsei: IF idType = typeTYPE THEN idInfo ELSE idType, pub: pub, nest: nest];
  IF ~recurring THEN Table.DropNotify[Notify];
  END;
  
  
TypedFieldCtx: PROCEDURE [
    ctx: CTXIndex, pub: BOOLEAN, rec: BOOLEAN ← TRUE, nest: CARDINAL ← 0] =
  BEGIN
  isei: ISEIndex ← FirstCtxSe[ctx]; 
  first: BOOLEAN ← TRUE;
  IF isei # ISENull AND seb[isei].idCtx # ctx THEN isei ← NextSe[isei];
  IF isei = ISENull THEN
    BEGIN IF rec THEN DOutput.Text["[]"L]; RETURN END;
  IF rec THEN DOutput.Char['[];
  FOR isei ← isei, NextSe[isei] UNTIL isei = ISENull DO
    IF first THEN first ← FALSE
    ELSE IF rec THEN DOutput.Text[", "L] ELSE DOutput.EOL[];
    Type[isei, pub, nest, TRUE];
    ENDLOOP;
  IF rec THEN DOutput.Char[']];
  END;
  
Indent: PROCEDURE [level: CARDINAL] =
  BEGIN
  i: CARDINAL;
  FOR i IN [0..level] DO DOutput.Text["  "L] ENDLOOP;
  END;
  
PrintType: PROCEDURE [
    tsei: SEIndex, pub: BOOLEAN,
    dosub: Sub ← NoSub, arraySub: BOOLEAN ← FALSE, nest: CARDINAL ← 0] =
  BEGIN OPEN DOutput;
  WITH t: seb[tsei] SELECT FROM
    id => 
      BEGIN
      IF dosub = NoSub OR ~Format[LOOPHOLE[tsei]].intSub THEN
	BEGIN
	HashVal[LOOPHOLE[tsei]];
	UNTIL (tsei ← TypeLink[tsei]) = SENull DO
	  WITH seb[tsei] SELECT FROM
	    id =>
	      BEGIN
	      Char[' ];
	      HashVal[LOOPHOLE[tsei]];
	      IF ~mark3 OR ctxb[idCtx].level # lZ THEN
		BEGIN dosub[]; RETURN END;
	      END;
	    ENDCASE;
	  ENDLOOP;
	END;
      dosub[];
      END;
    cons =>
      BEGIN
      WITH t SELECT FROM
	basic => NULL;
	  ENDCASE => Lookup.CopyMore[tsei, TRUE];
      WITH t SELECT FROM
	--basic =>  won't see one, see the id first.
	enumerated =>
	  BEGIN isei: ISEIndex; first: BOOLEAN ← TRUE;
	  Char['{];
	  FOR isei ← FirstCtxSe[valueCtx], NextSe[isei] UNTIL isei= ISENull DO
	    IF first THEN first ← FALSE ELSE Text[", "L];
	    HashVal[isei];
	    ENDLOOP;
	  Char['}];
	  END;
	record =>
	  BEGIN
	  IF ctxb[fieldCtx].level # lZ THEN
	    BEGIN
	    fctx: CTXIndex = fieldCtx;
	    bti: BTIndex ← FIRST[BTIndex];
	    btlimit: BTIndex = bti+Table.Bounds[SymbolSegment.bodyType].size;
	    Text["FRAME ["L];
	    UNTIL bti = btlimit DO
	      WITH entry: bb[bti] SELECT FROM
		Callable =>
		  BEGIN 
		  IF entry.localCtx = fctx THEN 
		    BEGIN 
		    HashVal[entry.id]; Char[']];
		    EXIT 
		    END;
		  bti ← bti + (WITH entry SELECT FROM
		    Inner => SIZE[Inner Callable BodyRecord],
		    ENDCASE => SIZE[Outer Callable BodyRecord]);
		  END;
		ENDCASE => bti ← bti + SIZE[Other BodyRecord];
	      ENDLOOP;
	    END
	  ELSE
	    BEGIN
	    IF monitored THEN Text["MONITORED "L];
	    IF machineDep THEN Text["MACHINE DEPENDENT "L];
	    Text["RECORD "L];
	    TypedFieldCtx[fieldCtx, pub];
	    END;
	  END;
	ref =>
	  BEGIN
	  IF readOnly THEN Text["READ ONLY "L];
	  IF ordered THEN Text["ORDERED "L];
	  IF basing THEN Text["BASE "L];
	  Text["POINTER"L];
	  IF dosub # NoSub THEN
	    BEGIN
	    Char[Ascii.SP];
	    dosub[];
	    END;
	  WITH seb[UnderType[refType]] SELECT FROM
	    basic => IF code = Symbols.codeANY THEN GO TO noprint;
	    ENDCASE;
	  Text[" TO "L];
	  PrintType[refType, pub];
	  EXITS
	    noprint => NULL;
	  END;
	array =>
	  BEGIN
	  IF packed THEN Text["PACKED "L];
	  Text["ARRAY "L];
	  PrintType[indexType, pub, NoSub, TRUE];
	  Text[" OF "L];
	  PrintType[componentType, pub];
	  END;
	arraydesc =>
	  BEGIN
	  Text["DESCRIPTOR FOR "L];
	  PrintType[describedType, pub];
	  END;
	transfer =>
	  BEGIN
	  ModeName[mode];
	  IF inRecord # RecordSENull THEN
	    BEGIN Char[' ];
	    TypedFieldCtx[seb[inRecord].fieldCtx, pub];
	    END;
	  IF outRecord # RecordSENull THEN
	    BEGIN
	    Text[" RETURNS "L];
	    TypedFieldCtx[seb[outRecord].fieldCtx, pub];
	    END;
	  END;
	union =>
	  BEGIN
	  tagType: SEIndex;
	  Text["SELECT "L];
	  IF ~controlled THEN
	    IF overlaid THEN Text["OVERLAID "L]
	    ELSE Text["COMPUTED "L]
	  ELSE 
	    BEGIN HashVal[tagSei]; Text[": "L] END;
	  tagType ← seb[tagSei].idType;
	  IF pub # seb[tagSei].public THEN Text[
	    IF ~pub THEN "PUBLIC "L ELSE "PRIVATE "L];
	  WITH seb[tagType] SELECT FROM
	    id => PrintType[tagType, seb[tagSei].public];
	    cons => Char['*];
	    ENDCASE;
	  Text[" FROM "L];
	  BEGIN temp, isei: ISEIndex; varRec: RecordSEIndex;
	  FOR isei ← FirstCtxSe[caseCtx], temp UNTIL isei = ISENull DO
	    EOL[];
	    Indent[nest];
	    HashVal[isei];
	    varRec ← seb[isei].idInfo;
	    FOR temp ← NextSe[isei], NextSe[temp]
		UNTIL temp = ISENull OR seb[temp].idInfo # isei DO
	      Text[", "L];
	      HashVal[temp];
	      ENDLOOP;
	    Text[" => "L];
	    TypedFieldCtx[
	      ctx: seb[varRec].fieldCtx, pub: pub, nest: nest+1];
	    Char[',];
	    ENDLOOP;
	  EOL[];
	  Indent[nest];
	  Text["ENDCASE"L];
	  END;
	  END;
	sequence => {
	  IF packed THEN Text["PACKED "L];
	  Text["SEQUENCE "L];
	  IF ~controlled THEN Text["COMPUTED "L]
	  ELSE {HashVal[tagSei]; Text[": "L]};
	  IF pub # seb[tagSei].public THEN Text[
	    IF ~pub THEN "PUBLIC "L ELSE "PRIVATE "L];
	  PrintType[seb[tagSei].idType, seb[tagSei].public];
	  Text[" OF "L];
	  PrintType[componentType, pub]};
	relative =>
	  BEGIN
	  IF baseType # SENull THEN PrintType[baseType, pub];
	  Text["RELATIVE "L];
	  PrintType[offsetType, pub, dosub];
	  END;
	subrange =>
	  BEGIN
	  org: INTEGER ← origin;
	  size: CARDINAL ← range;
	  type: SEIndex ← rangeType;
	  doit: Sub =
	    BEGIN
	    Text[" ["L];
	    TypedNum[org, type];
	    Text[".."L];
	    IF arraySub AND size = 177777B THEN
	      BEGIN TypedNum[org, type]; Char[')] END
	    ELSE
	      BEGIN TypedNum[org+size, type]; Char[']] END;
	    END;
      PrintType[rangeType, pub, doit];
	  END;
	long =>
	  BEGIN
	  Text["LONG "L];
	  PrintType[rangeType, pub];
	  END;
	real => Text["REAL"L];
	opaque => {
	  Text["TYPE "L];
      IF lengthKnown THEN {
	    Text["["L];
	    Octal[length/MachineDefs.WordLength];
	    Char[']]}};
	zone => {
	  IF mds THEN Text["MDSZone "L]
	  ELSE 
	    {IF ~counted THEN Text["UNCOUNTED "L];
	    Text["ZONE "L]}};
	ENDCASE
      END;
    ENDCASE;
  END;
  
END.