langutils/src/SimpleValueEnv.i3


---------------------------------------------------------------------------
INTERFACE SimpleValueEnv;

IMPORT Rd, TextList, TextSeq, TextTextTbl, Wr;
IMPORT MsgIF;

EXCEPTION E(TEXT);

TYPE
  Type = {None, Int, Nat, Text, List, Seq, Ref};

  IntObj = OBJECT
    val : INTEGER;
  METHODS
    init(v : INTEGER) : IntObj := IntObjInit;
  END;

  T <: Public;
  (*
    A SimpleTextEnv.T is a mapping from names to values. Values can
    be of Type.Int (INTEGER), Type.Nat (CARDINAL), Type.Text (TEXT),
    Type.List (TextList.T), Type.Seq (TextSeq.T), and Type.Ref (REFANY).
    Each name can be bound to at most one value. An undefined name is
    of Type.None.

    Several types of values can be converted at lookup time, but the
    internally stored representation is only changed when a new
    binding is defined. All impossible conversions are fatal and cause
    a checked runtime error. This is done on purpose to facilitate the
    use of these value environments and avoid exceptions. If you don't
    want automatic conversions or program aborts, use the type()
    method.

    Environments may be hierarchically structured into a tree, so
    any T object can keep track of its parent environment. Lookups
    of values are recursively by default; definitions and deletions
    of bindings are not.

    The procedures in this module are thread-safe, i.e. they may be
    called by multiple concurrent threads without data corruption.
  *)

  Public = OBJECT
  METHODS
    (*-----------------------------------------------------------------------*)
    init(parent : T := NIL; msgif : MsgIF.T := NIL) : T;
    (* initialize an empty environment *)

    (*-----------------------------------------------------------------------*)
    parent() : T;
    (* Returns the parent environment, if defined, else NIL. *)

    (*-----------------------------------------------------------------------*)
    copy(env : T; deep := TRUE; rec := TRUE);
    (* copy all values from `env' overwriting existing bindings *)

    (*-----------------------------------------------------------------------*)
    defined(name : TEXT; rec := TRUE) : BOOLEAN;
    (* <=> `name' is bound to a value. If `rec' is TRUE, do recursive
       lookups in all parent environments, if needed.
       The type of `name' is `None' iff it is not defined. *)

    (*-----------------------------------------------------------------------*)
    type(name : TEXT; rec := TRUE) : Type;
    (* <=> the type of `name'. If `rec' is TRUE, do recursive
       lookups in all parent environments, if needed.
       The type of `name' is `None' iff it is not defined. *)

    (*-----------------------------------------------------------------------*)
    intVal(name : TEXT; rec := TRUE) : INTEGER;
    natVal(name : TEXT; rec := TRUE) : CARDINAL;
    refVal(name : TEXT; rec := TRUE) : REFANY;
    textVal(name : TEXT; rec := TRUE) : TEXT;
    listVal(name : TEXT; rec := TRUE) : TextList.T;
    seqVal(name : TEXT; rec := TRUE) : TextSeq.T;
    (* These methods look up a binding in the environment and return
       the value associated with `name', if needed converted to the
       appropriate type.

       `revVal' returns an `IntObj' for integer and cardinal values.

       'textVal' returns decimal denotations for Int and Nat, and
       element lists separated by ' ' for List and Seq. Unknown Ref
       values cannot be converted to Text, List, Seq, Int, or Nat.

       `seqVal' and `listVal' return lists and sequences with one
       element for types Nat, Int, and Text. Ref cannot be converted
       to List and Seq.

       `intVal' and `natVal' return the value of decimal denotations
       of Text, and the length of List and Seq.

       List and Seq can be converted into each other.

       All other conversions are illegal and cause a checked runtime
       error. Use the `defined' and `type' methods to check in advance.
    *)

    (*-----------------------------------------------------------------------*)
    substTextVal(name : TEXT; rec := TRUE) : TEXT;
    (* Get a text value from the environment and substitute all
       variable references.

       The value is the mapping from the environment
       after substitution of all process environment variables,
       internal environment variables, and the special variables
       {HOME} and {USER}.

       The procedures TextUtils.SubstEnvVars() and
       SubstituteVariables() are used to perform the actual
       substitutions, which means that environment variables of the
       form $name and ${name} are recognized and internal variable
       names of the form {:name}, {!name}, and {?name}.
    *)

    (*-----------------------------------------------------------------------*)
    textValOrNil(name : TEXT; rec := TRUE) : TEXT;
    (* Like textVal, but returns NIL if no value is found. *)

    (*-----------------------------------------------------------------------*)
    substTextValOrNil(name : TEXT; rec := TRUE) : TEXT;
    (* Like substTextVal, but returns NIL if no value is found. *)

    (*-----------------------------------------------------------------------*)
    setIntVal(name : TEXT; val : INTEGER);
    setNatVal(name : TEXT; val : CARDINAL);
    setRefVal(name : TEXT; val : REFANY);
    setTextVal(name : TEXT; val : TEXT);
    setListVal(name : TEXT; val : TextList.T);
    setSeqVal(name : TEXT; val : TextSeq.T);
    (* Define a new binding of `name' to the given value: (name, val),
       which replaces any existing binding. *)

    (*-----------------------------------------------------------------------*)
    delVal(name : TEXT);
    (* Delete the binding of `name' in this environment. Do nothing
       if no binding exists. *)

    (*-----------------------------------------------------------------------*)
    setFromTextTextTbl(tbl : TextTextTbl.T) : T;
    (* Define text bindings in this environment by converting `tbl'
       appropriately. *)

    (*-----------------------------------------------------------------------*)
    toTextTextTbl(plain := TRUE; rec := TRUE) : TextTextTbl.T;
    (* Convert this environment to a TextTextTbl.T, ignoring all bindings
       with incompatible values. If `plain', then all variable references
       are substituted in the resulting mapping. *)

    (*-----------------------------------------------------------------------*)
    toText(rec := TRUE; plain := TRUE) : TEXT;
    (* Convert the bindings to a readable representation (if possible)
       for debugging purposes. *)

    (*-----------------------------------------------------------------------*)
    keys(rec := TRUE) : TextSeq.T;
    (* Returns all binding names as a sequence. *)

    (*-----------------------------------------------------------------------*)
    keyList(rec := TRUE) : TextList.T;
    (* Returns all binding names as a list. *)
  END;
---------------------------------------------------------------------------
EXCEPTION Error(TEXT);
---------------------------------------------------------------------------
PROCEDURE SubstituteVariables(t : TEXT; parameters : T) : TEXT
  RAISES {Error};
  (* Substitute all variable references of the form {!name},
     {:name}, and {?name} in the text `t' with the values bound in
     `parameters'. *)
---------------------------------------------------------------------------
PROCEDURE TextSeq1(t : TEXT) : TextSeq.T;
  (* Return a text sequence of length 1. *)
---------------------------------------------------------------------------
PROCEDURE IntObjInit(self : IntObj; v : INTEGER) : IntObj;
  (* Initalize an integer object with value `v'. *)
---------------------------------------------------------------------------
PROCEDURE ListToSeq(l : TextList.T) : TextSeq.T;
  (* Convert a TextList.T to a TextSeq.T. *)
---------------------------------------------------------------------------
PROCEDURE SeqToList(s : TextSeq.T) : TextList.T;
  (* Convert a TextSeq.T to a TextList.T. *)
---------------------------------------------------------------------------
PROCEDURE ReadTextList(rd : Rd.T) : TextList.T RAISES {E};
  (* Read a text list denotation, which is either "NIL" or a comma-separated
     list of double-quoted encoded strings (non-printable characters
     appropriately escaped). *)
---------------------------------------------------------------------------
PROCEDURE ReadTextSeq(rd : Rd.T) : TextSeq.T RAISES {E};
  (* Read a text sequence denotation, which is either "EMPTY"
     or a comma-separated list of double-quoted encoded strings
     (non-printable characters appropriately escaped). *)
---------------------------------------------------------------------------
PROCEDURE Write(wr : Wr.T; env : T; keys : TextList.T := NIL; rec := TRUE)
  RAISES {E};
  (* Write environment `env' to writer `T'. Use only the elements in `keys'
     if the list is not NIL. Do recursive lookups if `rec' is TRUE. *)
---------------------------------------------------------------------------
PROCEDURE Read(rd : Rd.T; VAR env : T) RAISES {E};
  (* Read bindings for the environment `env' from reader `rd' until
     EOF is encountered or an environment separator is found. The
     bindings must have been written with Write (see above). *)
---------------------------------------------------------------------------
PROCEDURE WriteFile(fn : TEXT; env : T; keys : TextList.T := NIL; rec := TRUE)
  RAISES {E};
  (* As Write, but creates a file. *)
---------------------------------------------------------------------------
PROCEDURE ReadFile(fn : TEXT; VAR env : T) RAISES {E};
  (* As Read, but reads directly from a file until EOF. *)

END SimpleValueEnv.