Module Lang_values


module Lang_values: sig .. end
Values in the Liquidsoap language.

exception Parse_error of ((Lexing.position * Lexing.position) * string)
A parsing error.
val debug : bool
Are we in debugging mode?
val errors_as_warnings : bool Pervasives.ref
Should errors be considered as simple warnings?

Kinds


module T: Lang_types
val ref_t : pos:T.pos option ->
level:int -> T.t -> T.t
val zero_t : T.t
val succ_t : T.t -> T.t
val variable_t : T.t
val add_t : int -> T.t -> T.t
val type_of_int : int -> T.t
val frame_kind_t : ?pos:T.pos option ->
?level:int ->
T.t -> T.t -> T.t -> T.t
A frame kind type is a purely abstract type representing a frame kind. The parameters audio,video,midi are intended to be multiplicity types, i.e. types of the form Succ*(Zero|Variable).
val of_frame_kind_t : T.t ->
(T.t, T.t, T.t) Frame.fields
val format_t : ?pos:T.pos option ->
?level:int -> T.t -> T.t
Type of audio formats that can encode frame of a given kind.
val source_t : ?active:bool ->
?pos:T.pos option ->
?level:int -> T.t -> T.t
Type of sources carrying frames of a given kind.
val of_source_t : T.t -> T.t
val request_t : ?pos:T.pos option ->
?level:int -> T.t -> T.t
val of_request_t : T.t -> T.t
val type_of_mul : pos:T.pos option ->
level:int -> Frame.multiplicity -> T.t
val type_of_format : pos:T.pos option ->
level:int -> Encoder.format -> T.t

Terms



The way we implement this mini-language is not very efficient. It should not matter, since very little computation is done here. It is mostly used for a single run on startup to build the sources, and then sometimes for building transitions. Terms are small, no recursion is possible. In order to report informative errors, including runtime errors (invalid values of a valid type given to a FF) we need to keep a complete AST all the way long. We actually don't need the types anymore after the static checking, but I don't want to bother with stripping down to another datatype.
module Vars: Set.Make(String)
Sets of variables.

type term = {
   mutable t : T.t;
   term : in_term;
}
type let_t = {
   doc : Doc.item * (string * string) list;
   var : string;
   mutable gen : (int * T.constraints) list;
   def : term;
   body : term;
}
type in_term =
| Unit
| Bool of bool
| Int of int
| String of string
| Float of float
| Encoder of Encoder.format
| List of term list
| Product of term * term
| Ref of term
| Get of term
| Set of term * term
| Let of let_t
| Var of string
| Seq of term * term
| App of term * (string * term) list
| Fun of Vars.t
* (string * string * T.t * term option) list
* term
val is_ground : term -> bool
val print_term : term -> string
Print terms, (almost) assuming they are in normal form.
val free_vars : ?bound:Vars.elt list -> term -> Vars.t
val free_vars : ?bound:Vars.elt list -> term -> Vars.t
val can_ignore : T.t -> bool
val is_fun : T.t -> bool
val is_source : T.t -> bool

Check that all let-bound variables are used. No check is performed for variable arguments. This cannot be done at parse-time (as for the computatin of the free variables of functions) because we need types, as well as the ability to distinguish toplevel and inner let-in terms.
exception Unused_variable of (string * Lexing.position)
val check_unused : lib:bool -> term -> unit
val map_types : ((int * T.constraints) list -> T.t -> T.t) ->
(int * T.constraints) list ->
term -> term
Maps a function on all types occurring in a term. Ignores variable generalizations.
val fold_types : ((int * T.constraints) list -> 'a -> T.t -> 'a) ->
(int * T.constraints) list -> 'a -> term -> 'a
Folds f over almost all types occurring in a term, skipping as much as possible while still guaranteeing that f will see all variables.
module V: sig .. end
Values are normal forms of terms.

Built-in values and toplevel definitions


val builtins : ((int * T.constraints) list * V.value) Plug.plug
val (<:) : T.t -> T.t -> unit
val (>:) : T.t -> T.t -> unit
val value_restriction : term -> bool
exception Unbound of T.pos option * string
exception Ignored of term
val raise_ignored : term -> unit
exception No_label of term * string * bool * term
No_label (f,lbl,first,x) indicates that the parameter x could not be passed to the function f because the latter has no label lbl. The first information tells whether lbl=x is the first parameter with label lbl in the considered application, which makes the message a bit more helpful.
val check : ?ignored:bool -> term -> unit
val check : ?ignored:bool -> term -> unit

Computations


exception F of string
For internal use. I want to give an ID to sources built by FFI application based on the name under which the FFI is registered. get_name f returns the name under which the FFI f is registered.
val get_name : (V.full_env -> T.t -> V.value) -> string
val remove_first : ('a -> bool) -> 'a list -> 'a * 'a list
remove_first f l removes the first element e of l such that f e, and returns e,l' where l' is the list without e. Asserts that there is such an element.

Evaluation has to be typed, because some FFI's have a behavior that depends on their return type (for example, source and request creations). This is annoying but we really need a type inference kind of mechanism to obtain the information that such functions need, so this seems like the right thing to do.

So, when we evaluate a variable of type T, we have to lookup a let-definition, whose type has T as an instance, instantiate it and unify it with T. But this is not enough: we need the types inside the definition to get instantiated properly too. This also requires to duplicate the definition before instantiation, to avoid sharing the instantiation with the definition itself and its future/past instantiations.

val instantiate : generalized:(int * T.constraints) list ->
V.value -> V.value
val lookup : (string * ((int * T.constraints) list * V.value))
list -> string -> T.t -> V.value
val eval : env:(Vars.elt *
((int * T.constraints) list * V.value))
list ->
term -> V.value
val apply : t:T.t ->
V.value ->
(string * V.value) list -> V.value
val toplevel_add : Doc.item * (string * string) list ->
string ->
generalized:(int * T.constraints) list ->
V.value -> unit
Add toplevel definitions to builtins so they can be looked during the evaluation of the next scripts. Also try to generate a structured documentation from the source code.
val eval_toplevel : ?interactive:bool -> term -> V.value