-- file SakuraDriver.Mesa
-- last modified by Satterthwaite, January 13, 1981  9:29 AM
-- last edit by Russ Atkinson,  9-Jul-81 14:50:32
-- last edited by Suzuki,  7-Mar-82 21:36:56

DIRECTORY
  Convert: TYPE USING [MapValue, Value],
  ConvertUnsafe: TYPE USING [ToRope],
  IOStream: TYPE USING [Handle, Close, CreateFileStream, SetLength],
  PPLeaves: TYPE USING [ISEIndex, HTIndex, LTIndex],
--  PPP1 USING [OpenTest, CloseTest],
  PPRopeFile: TYPE USING [Create],
  Rope: TYPE USING [Concat, Equal, Flatten, Index, Map, Ref, Size, Substr, Text],
  SafeStorage: TYPE USING [ReclaimCollectibleObjects, SetCollectionInterval],
  SakuraCommon,
  SakuraOps: TYPE USING [ParseStream, SetLog],
  SakuraRewrite: TYPE USING [PutChoiceDecl, Rewrite],
  SakuraTree: TYPE USING [Handle, Link],
  SakuraTreeOps: TYPE USING [Initialize, Finalize],
  SakuraUtil: TYPE USING [PrettyPrint],
  TTY: TYPE USING [Create, Destroy, GetLine, Handle, PutChar, PutCR];

SakuraDriver: MONITOR
    IMPORTS Convert, ConvertUnsafe, IOStream, SakuraOps, 
      SakuraRewrite, SakuraTreeOps, SakuraUtil, PPRopeFile, Rope, SafeStorage, TTY 
    EXPORTS SakuraCommon = 
  BEGIN OPEN Tree: SakuraTree, SakuraTreeOps, PPLeaves, TTY;

-- main loop

  CR: CHARACTER = 15C;

  Unimplemented: SIGNAL = CODE;
  
  tty: PUBLIC Handle ← Create["Sakura"];

  CharAction: PROC [c: CHARACTER] RETURNS [BOOLEAN] = {
    PutChar[tty, c]; RETURN [FALSE]};
    
  Char1: PROC [c: CHARACTER] = {PutChar[tty, c]};
    
  PutRope: PROC [r: Rope.Ref, newLine: BOOLEAN ← FALSE] = {
    [] ← Rope.Map[base: r, action: CharAction];
    IF newLine THEN PutChar[tty, CR];
    };
    
  GetFileName: PROC [prompt,suffix,last: Rope.Ref] RETURNS [Rope.Text] = {
    line: STRING ← [80];
    pos: LONG INTEGER ← 0;
    name: Rope.Ref ← NIL;
    PutRope[prompt];
    GetLine[tty, line];
    IF line.length=0 THEN RETURN[NIL];
    name ← ConvertUnsafe.ToRope[line];
    IF name.Equal["$"] THEN
       name ← last.Substr[0, last.Index[0, "."]];
    pos ← name.Index[0, "."];
    IF pos = name.Size[] THEN {
       name ← name.Concat[suffix]};
    RETURN [name.Flatten[]]; 
    };

  GetInfo: PROC [t: Tree.Link] RETURNS [info: LONG INTEGER] = {
    DO WITH t SELECT FROM 
         hti: HTIndex => info ← hti.index;
         lti: LTIndex => info ← lti.index;
         x: Tree.Handle => 
             {info ← x.info; 
              IF info = 0 THEN 
                 FOR i: NAT IN [1..x.sonLimit) WHILE info = 0 DO
                     info ← GetInfo[x[i]]
                     ENDLOOP};
         ENDCASE => info ← 0; 
       EXIT
       ENDLOOP}; 
  
  GetAttrs: PROC [t: Tree.Link] RETURNS [a1: BOOLEAN, a2: BOOLEAN, a3: BOOLEAN] = {
    WITH t SELECT FROM 
      x: Tree.Handle => RETURN [x.attr[1], x.attr[2], x.attr[3]];
      ENDCASE => a1 ← a2 ← a3 ← FALSE};
 
   SetExtension: PROC [name: STRING, ext: STRING] = {
    IF name = NIL OR ext = NIL OR name.length = 0 OR ext.length = 0 THEN RETURN;
    FOR i: NAT IN [0..name.length) DO
        IF name[i] = '. THEN RETURN;
        ENDLOOP;
    FOR i: NAT IN [0..ext.length) DO
        name[name.length] ← ext[i];
        name.length ← name.length + 1;
        ENDLOOP;
    };

  TreeComp: PROC [out: IOStream.Handle, t1,t2: Tree.Link] RETURNS [BOOLEAN] = {
    oops: LONG INTEGER ← 0;
    IF t1 = t2 THEN RETURN [TRUE];
    WITH t1 SELECT FROM
      hti1: HTIndex => {
        WITH t2 SELECT FROM
          hti2: HTIndex => IF Rope.Equal[hti1.name, hti2.name] THEN RETURN [TRUE];
          ise: ISEIndex => IF Rope.Equal[hti1.name, ise] THEN RETURN [TRUE];
          ENDCASE;
        oops ← hti1.index};     
      lti1: LTIndex => {
        WITH t2 SELECT FROM
          lti2: LTIndex => IF Rope.Equal[lti1.literal, lti2.literal] THEN RETURN [TRUE];
          ENDCASE;
        oops ← lti1.index};
      x1: Tree.Handle => {
        WITH t2 SELECT FROM
          x2: Tree.Handle => {
            same: BOOLEAN ← x1.name = x2.name AND
              x1.sonLimit = x2.sonLimit AND x1.attr = x2.attr;
            FOR i: NAT IN [1..x1.sonLimit) WHILE same DO
                same ← TreeComp[out, x1[i], x2[i]];
                ENDLOOP;
            IF same THEN RETURN [TRUE]};
          ENDCASE;
        oops ← GetInfo[t1]};
      ise1: ISEIndex => {
        WITH t2 SELECT FROM
          hti2: HTIndex => IF Rope.Equal[ise1, hti2.name] THEN RETURN [TRUE];
          ise2: ISEIndex => IF Rope.Equal[ise1, ise2] THEN RETURN [TRUE];
          ENDCASE;
        PutRope["Atomic difference, no index"];
        PutCR[tty]};   
      ENDCASE => ERROR;
    PutRope["Difference found near source index "];
    Convert.MapValue[Char1, [signed[oops]]];
    PutCR[tty];
    RETURN [FALSE];
    };
  
  croaker: PROC = {[] ← SafeStorage.ReclaimCollectibleObjects[]};

  oldTree: Tree.Link ← NIL;
  newTree: Tree.Link ← NIL;
  
  
  Main: PUBLIC ENTRY PROC = {
    DO -- just keep processing the files
    in, out: IOStream.Handle ← NIL;
    source, name, tree, check: Rope.Ref ← NIL;
    oldTree ← newTree ← NIL;
    PutCR[tty];
    name ← GetFileName["Input file: ", ".sak", NIL ! ANY => EXIT];
    IF name=NIL THEN EXIT;
    in ← IOStream.CreateFileStream[name, read
           ! ANY => {PutRope["Can't open '"];
                     PutRope[LOOPHOLE[name]];
                     PutChar[tty, '']; PutCR[tty]; LOOP}];
    tree ← GetFileName["Output file: ", ".mesa", name ! ANY => LOOP];
    out ← IOStream.CreateFileStream[tree, write];
    IOStream.SetLength[out, 0];
    source ← PPRopeFile.Create[in, 4096, 4, TRUE].rope;
    -- PPP1.OpenTest[];
    oldTree ← SakuraOps.ParseStream[source, out, FALSE];
    -- PPP1.CloseTest[];
    SakuraTreeOps.Initialize[];
    oldTree ← SakuraRewrite.Rewrite[oldTree];
    oldTree ← SakuraRewrite.PutChoiceDecl[oldTree];
    SakuraOps.SetLog[out];
    SakuraUtil.PrettyPrint[oldTree];
    SakuraOps.SetLog[NIL];
    SakuraTreeOps.Finalize[];
    IOStream.Close[in];
    IOStream.Close[out];
    ENDLOOP;
    TTY.Destroy[tty]}; 
    
[] ← SafeStorage.SetCollectionInterval[1000000];
    
END.