-- file SakuraDebug.Mesa
-- last modified by Satterthwaite, January 13, 1981  9:28 AM
-- last edit by Russ Atkinson,  9-Jul-81 14:58:20
-- last edited by Suzuki, 15-Nov-81 19:59:33

DIRECTORY
  IOStream: TYPE USING [CR, TAB, Handle, PutChar],
  Inline: TYPE USING [LowHalf],
  PPCommentTable: TYPE
    USING [Explode, FindNextComment, Index, Ref, Text],
  SakuraOps USING [GetLog],
  SakuraUtil: TYPE USING [
    AcquireTable, PutDecimal, PutRope, ReleaseTable],
  SakuraDebugTable: TYPE USING [CSRptr],
  PPLeaves: TYPE USING [HTIndex, ISEIndex, HTNull, LTIndex],
  SakuraTree: TYPE USING [AttrId, Handle, Link, NodeName, Scan, Null],
  SakuraTreeOps: TYPE USING [ScanSons],
  Rope: TYPE USING [Size, Ref, Text];

SakuraDebug: PROGRAM
    IMPORTS IOStream, Inline, Rope, SakuraUtil, SakuraTreeOps, CT: PPCommentTable, SakuraOps
    EXPORTS SakuraUtil =
  BEGIN
  OPEN IOStream, IOStream, Tree: SakuraTree, PPLeaves;

  SourceIndex: TYPE = PPCommentTable.Index;
  
 -- basic io

  errorStream: IOStream.Handle ← NIL;

  WriteChar: PROC [c: CHARACTER] =
    {PutChar[errorStream, c]};

  WriteString: PROC [s: Rope.Ref] = {
    SakuraUtil.PutRope[errorStream, s]};

  WriteQuotedText: PROC [s: Rope.Ref] = {
    EachChar: PROC [c: CHARACTER] RETURNS [BOOLEAN] = {
      IF c = '" THEN WriteChar['"];
      WriteChar[c]; RETURN [FALSE]};
    IF s # NIL THEN {
       WriteChar['"];
       SakuraUtil.PutRope[errorStream, s];
       WriteChar['"]}};

  WriteDecimal: PROC [n: LONG INTEGER] = {
    SakuraUtil.PutDecimal[errorStream, n]};

  NewLine: PROC = INLINE {WriteChar[CR]};

  Indent: PROC [n: NAT] = {
    NewLine[];
    THROUGH [1..n/8] DO WriteChar[TAB] ENDLOOP;
    THROUGH [1..n MOD 8] DO WriteChar[' ] ENDLOOP};


  -- errorStream, csrP and desc.base are set by Enter

  csrP: SakuraDebugTable.CSRptr;
  ss: LONG STRING ← NIL;

  LockStringTable: PROC = {
    csrP ← SakuraUtil.AcquireTable[debug];
    ss ← @csrP[csrP.stringOffset]};

  UnlockStringTable: PROC =
    {SakuraUtil.ReleaseTable[debug]; csrP ← NIL; ss ← NIL};

  Enter: PROC = {
    errorStream ← SakuraOps.GetLog[];  LockStringTable[]};

  Exit: PROC = {
    UnlockStringTable[];  errorStream ← NIL};

  WriteSubString: PROC [offset,length: CARDINAL] = {
    FOR i: CARDINAL IN [offset..offset+length)
      DO WriteChar[ss[i]] ENDLOOP};

  -- tree printing

  PrintTree: PUBLIC PROC [t: Tree.Link] = {
    Enter[];  PrintSubTree[t, 0];  NewLine[];  NewLine[];
    {index: SourceIndex ← 0;
     DO
        ref: CT.Ref ← CT.FindNextComment[index];
        IF ref = NIL THEN EXIT;
        PrintCommentInfo[ref];
        NewLine[];
        index ← CT.Explode[ref].start+1;
        ENDLOOP};
    NewLine[];  NewLine[];
    Exit[]};

  PrintSubTree: PROC [t: Tree.Link, nBlanks: NAT] = {
    OPEN Tree;

    Printer: Tree.Scan = {
      Indent[nBlanks];
      IF t = Tree.Null
	THEN WriteString["<empty>"]
	ELSE
	  WITH t SELECT FROM
	    hti: HTIndex => PrintHti[hti];
	    sei: ISEIndex => PrintSei[sei];
	    node: Tree.Handle => {
	      WriteNodeName[node.name];
	      IF node.info # 0 THEN {
                 WriteString["  info="];
                 WriteDecimal[node.info]};
	      IF node.attr # ALL[FALSE]
		THEN {
		  IF node.info = 0 THEN WriteChar[' ];
		  WriteChar['(];
		  FOR i: Tree.AttrId IN Tree.AttrId
		    DO IF node.attr[i] THEN WriteChar[i+'0] ENDLOOP;
		  WriteChar[')]};
	      nBlanks ← nBlanks + 2;
	      SakuraTreeOps.ScanSons[t, Printer];
	      nBlanks ← nBlanks - 2};
            lti: LTIndex => PrintLti[lti];
	    ENDCASE => PrintLiteral[t]};

    Printer[t]};

  WriteNodeName: PROC [n: Tree.NodeName] = {
    WriteSubString[csrP.NodePrintName[n].offset, csrP.NodePrintName[n].length]};

  PrintLiteral: PROC [t: Tree.Link] = {
    WITH t SELECT FROM
      s: Rope.Text => {
	WriteChar['"];
	FOR i: NAT IN [0..Inline.LowHalf[Rope.Size[s]]) DO WriteChar[s[i]] ENDLOOP;
	WriteChar['"]};
      n: REF CARDINAL => WriteDecimal[n↑];
      ENDCASE => WriteChar['?]};

  PrintLti: PROC [lti: LTIndex] = {
    val: REF ← lti.value;
    WITH val SELECT FROM
      txt: Rope.Ref => WriteQuotedText[txt];
      ENDCASE => WriteString[lti.literal];
    PrintIndex[lti.index];
    };

  PrintIndex: PROC [index: SourceIndex] = {
    IF index # LAST[SourceIndex] THEN {
       WriteString[" {index: "];
       WriteDecimal[index];
       WriteString["}"]}};

  PrintHti: PROC [hti: HTIndex] = {
    IF hti = HTNull
      THEN WriteString["(anon)"]
      ELSE {
	WriteString[hti.name];
        PrintIndex[hti.index]}};

  PrintSei: PROC [sei: ISEIndex] = {
    IF sei = NIL
      THEN WriteString["(anon)"]
      ELSE {WriteString[sei]}};

  PrintCommentInfo: PROC [ref: CT.Ref] = {
    IF ref # NIL THEN {
       start,lastToken,prefix: SourceIndex;
       text: CT.Text;
       [start,text,lastToken,prefix] ← CT.Explode[ref];
       WriteString[" {start: "]; WriteDecimal[start];
       WriteString[", lastToken: "]; WriteDecimal[lastToken];
       WriteString[", prefix: "]; WriteDecimal[prefix];
       WriteString["}"]};
    };

  END. 
~~~~~~~~~~