(* $Id$
 * ----------------------------------------------------------------------
 *
 *)

(** Parses META files *)

open Fl_metatoken

type formal_pred =
    [ `Pred of string     (** Positive occurence of a formal predicate var *)
    | `NegPred of string  (** Negative occurence of a formal predicate var *)
    ]

type flavour =
    [ `BaseDef 
    | `Appendix 
    ]
  (** [`BaseDef] refers to META definitions using the "=" operator,
   * and [`Appendix] refers to definitions using the "+=" operator.
   *)

type pkg_definition =
    { def_var : string;              (** The name of the defined variable *)
      def_flav : flavour;            (** The flavour of the definition *)
      def_preds : formal_pred list;  (** The formal predicates of the def *)
      def_value : string;            (** The value assigned to the variable *)
    }
  (** A [pkg_definition] is expressed by the syntax
   *  {[ var(p1,p2,...) = "value" ]} (flavour `BaseDef), 
   *  or the syntax
   *  {[ var(p1,p2,...) += "value" ]} (flavour `Appendix)
   *  in the META file. The list of predicates may be omitted. Predicates
   *  may be negated by using "-", e.g. "-x".
   *)

type pkg_expr =
    { pkg_defs : pkg_definition list;
      pkg_children : (string * pkg_expr) list;
    }
  (** A value of type [pkg_expr] denotes the contents of a META file.
   *  The component [pkg_defs] are the variable definitions.
   *  The component [pkg_children] contains
   *  the definitions of the subpackages.
   *)

exception Error of string


val parse : in_channel -> pkg_expr
  (** [parse ch:] 
   * scans and parses the file connected with channel [ch]. The file must
   * have a syntax compatible with the META format. The return value
   * contains the found definitions for the package and all subpackages.
   *
   * [exception Error of string:] is
   * raised on syntax errors. The string explains the error.
   *)

val parse_lexing : Lexing.lexbuf -> pkg_expr


val print_def : out_channel -> pkg_definition -> unit
  (** [print_def ch def]:
    * Outputs the definition to a channel.
   *)

val print : out_channel -> pkg_expr -> unit
  (** [print ch expr]:
    * Outputs the package expression to a channel.
   *)


val lookup : 
    string -> string list -> pkg_definition list -> string
  (** [lookup variable_name predicate_list def]:
   *
   * Returns the value of [variable_name] in [def] under the assumption
   * that the predicates in [predicate_list] hold, but no other predicates.
   *
   * The rules are as follows: In the step (A), only the [`BaseDef]
   * definitions are considered. The first base definition is determined where
   * all predicates are satisfied and that has the longest predicate list.
   * In the step (B) only the [`Appendix] definitions are considered.
   * All definitions are determined where all predicates are satisfied.
   * The final result is the concatenation of the single result of (A)
   * and all results of (B) (in the order they are defined). A space
   * character is inserted between two concatenated strings.
   *
   * When step (A) does not find any matching definition, the exception
   * [Not_found] is raised.
   *)


val lookup_2 : 
    string -> string list -> pkg_definition list -> string * formal_pred list
  (** Like [lookup], but also returns the list of predicates that had to
      be considered to select the particular variable definition.
   *)


val predicate_exists :
    string -> pkg_definition list -> bool
  (** [predicate_exists variable_name def]:

      Whether [variable_name] is explicitly mentioned in [def].
   *)
