(** All the types used in the spreadsheet. *) let u = UTF8.from_utf8string exception Error module DataFormat = struct type _ t = | Date: DataType.Num.t t (* Date *) | Number: DataType.Num.t t (* Number *) | String: DataType.String.t t(* String *) | Bool: DataType.Bool.t t (* Boolean *) type formats = F : 'a t -> formats [@@unboxed] let priority: type a. a t -> int = function | Date -> 1 | Number -> 0 | String -> 0 | Bool -> 0 let collect_format: DataType.Num.t t -> formats -> DataType.Num.t t = begin fun dataFormat -> function | F Date -> Date | _ -> dataFormat end let default_value_for: type a. a t -> a = function | Date -> DataType.Num.zero | Number -> DataType.Num.zero | Bool -> false | String -> UTF8.empty type ('a, 'b) equality = Eq : ('a, 'a) equality let compare_format: type a b. a t -> b t -> (a, b) equality = fun a b -> begin match a, b with | Date, Date -> Eq | String, String -> Eq | Number, Number -> Eq | Date, Number -> Eq | Number, Date -> Eq | Bool, Bool -> Eq | _, _ -> raise Errors.TypeError end end module Type = struct type 'a t = | Num : DataType.Num.t DataFormat.t * DataType.Num.t -> DataType.Num.t t (** A number *) | Str : DataType.String.t -> DataType.String.t t (** A string *) | Bool : DataType.Bool.t -> DataType.Bool.t t (** A boolean *) let number n = Num (Number, n) let string s = Str s let date d = Num (Date, d) let boolean b = Bool b let (=) : type a b. a t -> b t -> bool = fun t1 t2 -> match t1, t2 with | Num (_, n1), Num (_, n2) -> DataType.Num.eq n1 n2 | Bool b1, Bool b2 -> b1 = b2 | Str s1, Str s2 -> s1 = s2 | _, _ -> false module Eval(T:Sym_type.SYM_TYPE) = struct let eval_type : type a. a t -> a T.t = function | Str s -> T.str s | Bool b -> T.bool b | Num (f, n) -> match f with | DataFormat.Number -> T.num n | DataFormat.Date -> T.date n let eval t = T.observe (eval_type t) end end module Refs = struct type t = | Cell of Cell.t (** A cell *) | Range of Cell.t * Cell.t (** An area of cells *) let shift (vector_x, vector_y) ref = let _shift ((x, y), (fixed_x, fixed_y)) = let x' = if fixed_x then x else x + vector_x and y' = if fixed_y then y else y + vector_y in (x', y'), (fixed_x, fixed_y) in match ref with | Cell x -> Cell (_shift x) | Range (fst, snd) -> Range (_shift fst, _shift snd) let cell c = Cell c let range c1 c2 = Range (c1, c2) module Eval(R:Sym_ref.SYM_REF) = struct let eval_ref = function | Cell c -> R.cell c | Range(c1, c2) -> R.range c1 c2 let eval t = R.observe (eval_ref t) end end module Expr = struct type ident = UTF8.t type t = | Value : 'a Type.t -> t (** A direct value *) | Ref : Refs.t -> t (** A reference to another cell *) | Call0 : ident -> t (** A call to a 0 arg function *) | Call1 : ident * t -> t (** A call to a 1 arg function *) | Call2 : ident * t * t -> t (** A call to a 2 arg function *) | Call3 : ident * t * t * t -> t (** A call to a 3 arg function *) | CallN : ident * t list -> t (** A call to a function *) | Expression : t -> t (** An expression *) let value v = Value v let ref r = Ref r let call0 ident = Call0 ident let call1 ident expr = Call1 (ident, expr) let call2 ident expr1 expr2 = Call2(ident, expr1, expr2) let call3 ident expr1 expr2 expr3 = Call3(ident, expr1, expr2, expr3) let callN ident params = CallN(ident, params) let expression e = Expression e let rec shift_exp vector = function | Value v -> Value v | Call0 ident -> Call0 ident | Call1 (ident, p1) -> Call1 (ident, shift_exp vector p1) | Call2 (ident, p1, p2) -> Call2 (ident, shift_exp vector p1, shift_exp vector p2) | Call3 (ident, p1, p2, p3) -> Call3 (ident, shift_exp vector p1, shift_exp vector p2, shift_exp vector p3) | CallN (ident, params) -> CallN (ident, List.map (shift_exp vector) params) | Ref r -> Ref (Refs.shift vector r) | Expression expr -> Expression (shift_exp vector expr) module Eval(E:Sym_expr.SYM_EXPR) = struct module T = Type.Eval(E.T) module R = Refs.Eval(E.R) let eval e t = begin let rec eval_expr : t -> E.repr = function | Ref r -> E.ref (R.eval_ref r) t | Value v -> E.value (T.eval_type v) t | Call0 ident -> E.call0 ident t | Call1 (ident, p1) -> E.call1 ident (eval_expr p1) t | Call2 (ident, p1, p2) -> E.call2 ident (eval_expr p1) (eval_expr p2) t | Call3 (ident, p1, p2, p3) -> E.call3 ident (eval_expr p1) (eval_expr p2) (eval_expr p3) t | CallN (ident, exprs) -> E.callN ident (List.map (fun x -> eval_expr x) exprs) t | Expression e -> E.expression (eval_expr e) t in E.observe (eval_expr e) end end end module TypeRepr = Type.Eval(Show_type) module Result = struct (** Result from a computation *) type t = | Ok : 'a Type.t -> t | Error : exn -> t let (=) t1 t2 = match t1, t2 with | Ok v1, Ok v2 -> Type.(=) v1 v2 | _, _ -> t1 = t2 let show = begin function | Error x -> (* let buffer = Buffer.create 16 in let b = Format.formatter_of_buffer buffer in Errors.printf b x; Format.pp_print_flush b (); u(Buffer.contents buffer) *) u"#Error" | Ok v -> let buffer = UTF8.Buffer.create 16 in TypeRepr.eval v buffer; UTF8.Buffer.contents buffer end end module ReturnType = struct type 'a t = | Num : DataType.Num.t DataFormat.t option -> DataType.Num.t t (** A number *) | Str : DataType.String.t t (** A string *) | Bool : DataType.Bool.t t (** A boolean *) let f_num: DataType.Num.t t = Num None let f_date: DataType.Num.t t = Num (Some Date) let f_number: DataType.Num.t t = Num (Some Number) let f_string: DataType.String.t t = Str let f_bool: DataType.Bool.t t = Bool let guess_format_result: type a. a t -> (unit -> DataFormat.formats list) -> a DataFormat.t = fun return params -> begin match return with | Str -> DataFormat.String | Bool -> DataFormat.Bool | Num (Some x) -> x | Num None -> List.fold_left DataFormat.collect_format DataFormat.Number (params ()) end end