ktoklib/src/PragmaRead.m3


 Copyright (c) 2000 California Institute of Technology 
 All rights reserved. See the file COPYRIGHT for a full description. 
 $Id: PragmaRead.m3.html,v 1.3 2010-04-29 17:18:51 wagner Exp $ 

MODULE PragmaRead;
IMPORT Rd;
IMPORT Pragma;
IMPORT PragmaTbl;
IMPORT CharRange;
IMPORT Text;
IMPORT Thread;
IMPORT FileRdErr;
IMPORT Term, Fmt;
FROM CharCodes IMPORT Q;
<* FATAL Rd.Failure, Thread.Alerted *>
REVEAL
  T = Public BRANDED OBJECT
    tab: PragmaTbl.T;
  OVERRIDES
    init := Init;
    add := Add;
    apply := Apply;
    error := Error;
  END;

PROCEDURE GetPragNames(tab: PragmaTbl.T): TEXT =
  VAR
    iterate := tab.iterate();
    result: TEXT := "";
    key: TEXT;
    prag: Pragma.T;
  BEGIN
    WHILE iterate.next(key, prag) DO
      IF NOT Text.Equal(key, "") THEN
        result := result & " " & key;
      END;
    END;
    RETURN result;
  END GetPragNames;

PROCEDURE Init(self: T): T =
  BEGIN
    self.tab := NEW(PragmaTbl.Default).init();
    RETURN self;
  END Init;

PROCEDURE Add(self: T; p: Pragma.T; name: TEXT) =
  BEGIN
    EVAL self.tab.put(name, p);
  END Add;

PROCEDURE ApplyOne(prag: Pragma.T; rd: Rd.T) =
  VAR
    pos: INTEGER;
  PROCEDURE LineStarts(c: CHAR): BOOLEAN =
    VAR
      peekLine: TEXT;
    BEGIN
      pos := Rd.Index(rd);
      TRY
        peekLine := CharRange.FilterText(Rd.GetLine(rd));
      EXCEPT
      | Rd.EndOfFile => RETURN c = '\000';
      END;
      IF Text.Length(peekLine) = 0 THEN
        RETURN c = '\000';
      ELSIF Text.GetChar(peekLine, 0) = c THEN
        Rd.Seek(rd, pos);
        TRY
          peekLine := Rd.GetLine(rd);
        EXCEPT
        | Rd.EndOfFile => <* ASSERT FALSE *>
        END;
        Rd.Seek(rd, pos + Text.FindChar(peekLine, c)+1);
        RETURN TRUE;
      ELSE
        RETURN FALSE;
      END;
    END LineStarts;
  BEGIN
    IF LineStarts('{') THEN
      WHILE NOT LineStarts('}') DO
        Rd.Seek(rd, pos);
        IF NOT LineStarts('\000') THEN
          Rd.Seek(rd, pos);
          prag.do(rd);
        END;
        IF pos = Rd.Index(rd) THEN
          Rd.Seek(rd, pos+1); (* avoid infinite loop *)
        END;
      END;
    ELSE
      Rd.Seek(rd, pos);
      prag.do(rd);
    END;
  END ApplyOne;

PROCEDURE Apply(self: T; rd: Rd.T) =
  VAR
    pos, len: INTEGER;
    key: TEXT;
    prag: Pragma.T;
  BEGIN
    TRY
      WHILE TRUE DO
        pos := Rd.Index(rd);
        CASE Rd.GetChar(rd) OF
        | '%' =>
          WHILE Rd.GetChar(rd) IN CharRange.Letter DO
          END;
          len := Rd.Index(rd) - pos - 1;
          Rd.Seek(rd, pos);
          key := Rd.GetText(rd, len);
          IF self.tab.get(key, prag) THEN
            ApplyOne(prag, rd);
          ELSE
            self.error(rd, "Found " & Q(key) &
              ", which is not" & GetPragNames(self.tab));
          END;
        | '\t', ' ', '\n' =>
        ELSE
          Rd.Seek(rd, pos);
          IF self.tab.get("", prag) THEN
            prag.do(rd);
          ELSE
            self.error(rd, "missing `%'");
          END;
        END;
      END;
    EXCEPT
      Rd.EndOfFile =>
    END;
  END Apply;

PROCEDURE Error(<*UNUSED*>self: T; rd: Rd.T; message: TEXT) =
  BEGIN
    FileRdErr.E(rd, message);
  END Error;

BEGIN
END PragmaRead.