(* This file is part of licht. licht is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. licht is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with licht. If not, see . *) (** Internal representation for each type *) type 'a value = | Bool: DataType.Bool.t -> DataType.Bool.t value | Num: DataType.Num.t ScTypes.DataFormat.t * DataType.Num.t -> DataType.Num.t value | String: DataType.String.t -> DataType.String.t value | List: 'a ScTypes.DataFormat.t * 'a list -> 'a list value | Matrix: 'a ScTypes.DataFormat.t * 'a list list -> 'a list list value type existencialResult = | Result : 'a value -> existencialResult [@@unboxed] type t = (Functions.C.t * (int * int -> ScTypes.Result.t option)) type repr = existencialResult type obs = ScTypes.Result.t module T:Sym_type.SYM_TYPE with type 'a obs = existencialResult = struct type 'a t = 'a value type 'a obs = existencialResult let str s = String s let num n = Num (ScTypes.DataFormat.Number, n) let date d = Num (ScTypes.DataFormat.Date, d) let bool b = Bool b let observe x = Result x end module R = Eval_ref (** Extract the type and the content from a value *) let get_argument: type a. a value -> a Functions.typ * a = function | Bool b -> Functions.t_bool, b | Num (_, n) -> Functions.t_int, n | String s -> Functions.t_string, s | List (t, l) -> Functions.t_list (Functions.typ_of_format t), l | Matrix (t, l) -> Functions.t_list (Functions.t_list (Functions.typ_of_format t)), l let wrap_call (Functions.C.R(ret, res)) type_builder = begin let returnType = ScTypes.ReturnType.guess_format_result ret type_builder in begin match returnType with | ScTypes.DataFormat.Bool -> T.observe (T.bool res) | ScTypes.DataFormat.String -> T.observe (T.str res) | ScTypes.DataFormat.Number -> T.observe (T.num res) | ScTypes.DataFormat.Date -> T.observe (T.date res) end end (** Extract the format from a list of results *) let build_format_list ll = List.map (fun (Result x) -> begin match x with | Bool _ -> ScTypes.DataFormat.F (ScTypes.DataFormat.Bool) | Num (x, _) -> ScTypes.DataFormat.F x | String _ -> ScTypes.DataFormat.F (ScTypes.DataFormat.String) | List (f, _) -> ScTypes.DataFormat.F f | Matrix (f, _) -> ScTypes.DataFormat.F f end ) ll let value v _ = T.observe v let ref r (_, mapper) = begin match R.observe r mapper with | R.Value (f, res) -> begin match f with | ScTypes.DataFormat.Bool -> T.observe (T.bool res) | ScTypes.DataFormat.String -> T.observe (T.str res) | ScTypes.DataFormat.Number -> T.observe (T.num res) | ScTypes.DataFormat.Date -> T.observe (T.date res) end | R.List (t, l) -> Result (List(t, l)) | R.Matrix (t, l) -> Result (Matrix(t, l)) end let call0 ident (catalog, _) = let name' = UTF8.to_utf8string ident in let arg1 = (Functions.t_unit, ()) in wrap_call (Functions.C.eval1 catalog name' arg1) (fun () -> raise Errors.TypeError) let call1 ident p1 (catalog, _) = let name' = UTF8.to_utf8string ident in let (Result r1) = p1 in let arg1 = get_argument r1 in wrap_call (Functions.C.eval1 catalog name' arg1) (fun () -> build_format_list [p1]) let call2 ident p1 p2 (catalog, _) = let name' = UTF8.to_utf8string ident in let (Result r1) = p1 in let (Result r2) = p2 in let arg1 = get_argument r1 and arg2 = get_argument r2 in wrap_call (Functions.C.eval2 catalog name' arg1 arg2) (fun () -> build_format_list [p1; p2]) let call3 ident p1 p2 p3 (catalog, _) = let name' = UTF8.to_utf8string ident in let (Result r1) = p1 in let (Result r2) = p2 in let (Result r3) = p3 in let arg1 = get_argument r1 and arg2 = get_argument r2 and arg3 = get_argument r3 in wrap_call (Functions.C.eval3 catalog name' arg1 arg2 arg3) (fun () -> build_format_list [p1; p2 ; p3]) let callN ident params (catalog, _) = let signature = List.map (fun (Result r) -> let formatter = Format.str_formatter in Functions.repr formatter (fst @@ get_argument r); Format.flush_str_formatter ()) params in raise (Errors.Undefined (ident, signature)) let expression e _ = e let observe repr = begin let Result r = repr in match r with | Bool b -> ScTypes.Result.Ok (ScTypes.Type.boolean b) | String s -> ScTypes.Result.Ok (ScTypes.Type.string s) | Num (format, n) -> begin match format with (* We can only match numeric formats here *) | ScTypes.DataFormat.Date -> ScTypes.Result.Ok (ScTypes.Type.date n) | ScTypes.DataFormat.Number -> ScTypes.Result.Ok (ScTypes.Type.number n) end | _ -> raise Errors.TypeError end