Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
eval.ml1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226open Types open Errors open Util open Typecheck module T = ANSITerminal (** Boolean Primitives *) let bool_binop (x, y) (op : bool -> bool -> bool) = let a = unpack_bool x and b = unpack_bool y in EvtBool (op a b) let bool_unop x (op : bool -> bool) = let a = unpack_bool x in EvtBool (op a) let uniqueorfail l = if Dict.dup_exists l then iraise (DictError "Duplicate key in dictionary") else l (** Evaluate an expression in an environment *) let rec eval (e : expr) (state : evalstate) : evt = let state = { state with stack = push_stack state.stack e } in if state.verbosity >= 2 then print_message ~color:T.Blue ~loc:Nowhere "Reduction at depth" (Printf.sprintf "%d\nExpression:\n%s" (depth_of_stack state.stack) (show_expr e)) else (); let evaluated = match e with | Unit -> EvtUnit | Purity (allowed, ee) -> eval ee { state with purity = allowed } | NumInt n -> EvtInt n | NumFloat n -> EvtFloat n | NumComplex n -> EvtComplex n | Boolean b -> EvtBool b | String s -> EvtString s | Symbol x -> lookup x state | List x -> EvtList (List.map (fun x -> eval x state) x) | Binop (kind, e1, e2) -> eval_binop kind e1 e2 state (* Dictionaries and operations *) | Dict l -> let el = uniqueorfail (List.map (eval_assignment state) l) in EvtDict el | Not x -> bool_unop (eval x state) not | IfThenElse (guard, first, alt) -> let g = unpack_bool (eval guard state) in if g then eval first state else eval alt state | Let (assignments, body) -> eval body (eval_assignment_list assignments state) | Lambda (param, body) -> Closure (None, param, body, state.env) (* Function Application *) | Apply (f, arg) -> let closure = eval f state in let earg = eval arg state in applyfun closure earg state | ApplyPrimitive ((name, _, _), args) -> let eargs = List.map (fun x -> eval x state) args in let prim = get_primitive_function (match (Dict.get name Primitives.ocaml_table) with | None -> iraise (Fatal "Unbound primitive. This should never happen") | Some p -> p) in (try prim eargs with InternalError (loc, err, _) -> raise (InternalError(loc, err, state.stack))) (* Eval a sequence of expressions but return the last *) | Sequence (e1, e2) -> let _ = eval e1 state in eval e2 state in if state.verbosity >= 2 then print_message ~color:T.Cyan ~loc:Nowhere "Evaluates to at depth" (Printf.sprintf "%d\n%s\n" (depth_of_stack state.stack) (show_evt evaluated)) else (); evaluated and eval_binop (k: binop) (x: expr) (y: expr) state = match k with | Getkey -> let key = (match y with Symbol z -> z | _ -> iraise (Fatal "Dictionary access")) and ed = unpack_dict (eval x state) in (match Dict.get key ed with | None -> iraise (DictError "key not found") | Some (LazyExpression z) -> eval z state | Some z -> z) | Cons -> let ls = unpack_list (eval y state) in (match ls with | [] -> EvtList [ eval x state ] | lss -> EvtList (eval x state :: lss)) | Concat -> let ev1 = eval x state and ev2 = eval y state in let t1 = typeof ev1 and t2 = typeof ev2 in (match (t1, t2) with | TString, TString -> EvtString ((unpack_string ev1) ^ (unpack_string ev2)) | TList, TList -> EvtList ((unpack_list ev1) @ (unpack_list ev2)) | _ -> iraises (TypeError (Printf.sprintf "Cannot concatenate a two values of type %s and %s" (show_tinfo t1) (show_tinfo t2))) state.stack ) | Compose -> let ef1 = eval y state and ef2 = eval x state in stcheck (typeof ef1) TLambda; stcheck (typeof ef2) TLambda; let params1 = findevtparams ef1 in let appl1 = apply_from_exprlist (symbols_from_strings params1) y in eval (lambda_from_paramlist params1 (Apply (x, appl1))) state | Plus -> Numericalp.add [(eval x state); (eval y state)] | Sub -> Numericalp.sub [(eval x state); (eval y state)] | Div -> Numericalp.div [(eval x state); (eval y state)] | Mult -> Numericalp.mult [(eval x state); (eval y state)] | And -> bool_binop (eval x state, eval y state) ( && ) | Or -> bool_binop (eval x state, eval y state) ( || ) | Eq -> EvtBool (compare_evt (eval x state) (eval y state) = 0) | Gt -> EvtBool (compare_evt (eval x state) (eval y state) > 0) | Lt -> EvtBool (compare_evt (eval x state) (eval y state) < 0) | Ge -> EvtBool (compare_evt (eval x state) (eval y state) >= 0) | Le -> EvtBool (compare_evt (eval x state) (eval y state) <= 0) (* Search for a value in the primitives table and environment *) and lookup (ident : ide) (state : evalstate) : evt = match (Dict.get ident Primitives.table) with | None -> (match (Dict.get ident state.env) with | None -> iraises (UnboundVariable ident) state.stack | Some (LazyExpression e) -> eval e state | Some e -> e) | Some (LazyExpression e) -> eval e state | Some e -> e and applyfun (closure : evt) (arg : evt) (state : evalstate) : evt = (* Evaluate the argument and unpack the evt encapsuled in them *) match closure with | Closure (name, param, body, decenv) -> (* Create a recursion environment if the function is recursive *) let self_env = (match name with | None -> decenv | Some x -> Dict.insert decenv x closure) in let appl_env = Dict.insert self_env param arg in eval body { state with env = appl_env } | _ -> traise "Cannot apply a non functional value" and eval_assignment state (islazy,name,value) = if islazy then (name, LazyExpression value) else (match value with | Lambda(param, fbody) -> let rec_env = Dict.insert state.env name (Closure (Some name, param, fbody, state.env)) in name, eval value { state with env = rec_env } | _ -> name, eval value state) and eval_assignment_list assignment_list state : evalstate = match assignment_list with | [] -> state | (islazy, name, value)::xs -> let _, nval = eval_assignment state (islazy, name, value) in (eval_assignment_list xs { state with env = (Dict.insert state.env name nval) }) and eval_command command state dirscope = if state.verbosity >= 1 then print_message ~loc:(Nowhere) ~color:T.Yellow "AST equivalent" (Printf.sprintf "\n%s" (show_command command)) else (); match command with | Directive dir -> eval_directive dir state dirscope | Expr e -> (* Infer the expression purity and evaluate if appropriate to the current state *) let exprpurity = Puritycheck.infer e state in if (state.purity = Pure || state.purity = Numerical) && exprpurity = Impure then iraises (PurityError ("This expression contains a " ^ (show_puret exprpurity) ^ " expression but it is in " ^ (show_puret state.purity) ^ " state!")) state.stack else (); if state.verbosity >= 1 then Printf.eprintf "Has purity: %s\n%!" (show_puret exprpurity) else (); (* Normalize the expression *) let optimized_ast = Optimizer.iterate_optimizer e in (* If the expression is NOT already in normal state, print the optimized one if verbosity is enough *) if optimized_ast = e then () else if state.verbosity >= 1 then print_message ~loc:(Nowhere) ~color:T.Yellow "After AST optimization" (Printf.sprintf "\n%s" (show_expr optimized_ast)) else (); (* Evaluate the expression *) let evaluated = eval optimized_ast state in (* Print it in its raw form if verbosity is enabled *) if state.verbosity >= 1 then print_message ~color:T.Green ~loc:(Nowhere) "Result" (Printf.sprintf "\t%s" (show_evt evaluated)) else (); (* Print the fancy result if state.printresult is true *) if state.printresult then Printf.eprintf "result: %s - %s\n%!" (show_unpacked_evt evaluated) (show_tinfo (Typecheck.typeof evaluated)) else (); (evaluated, state) | Def dl -> let (islazyl, idel, vall) = unzip3 dl in (* Infer the values purity and evaluate if appropriate to the current state *) let new_purity_state = Puritycheck.infer_assignment_list dl state in let ovall = (List.map (Optimizer.iterate_optimizer) vall) in let odl = zip3 islazyl idel ovall in (* Print the definitions if verbosity is enough and they were optimized *) if ovall = vall then () else if state.verbosity >= 1 then print_message ~loc:(Nowhere) ~color:T.Yellow "After AST optimization" (Printf.sprintf "\n%s" (show_command (Def odl))) else (); let newstate = eval_assignment_list odl new_purity_state in (EvtUnit, newstate ) and eval_command_list cmdlst state dirscope = let mstate = ref state in List.iter (fun x -> mstate := snd (eval_command x !mstate dirscope)) cmdlst; (EvtUnit, !mstate) and eval_directive dir state dirscope = match dir with | Dumpenv -> Printf.eprintf "<env>: %s\n%!" (show_env_type state.env); (EvtUnit, state) | Dumppurityenv -> Printf.eprintf "<purity_env>: %s\n%!" (show_purityenv_type state.purityenv); (EvtUnit, state) | Includefileasmodule (f, m) -> let modulename = (match m with | Some m -> m | None -> Filename.remove_extension f |> Filename.basename |> String.capitalize_ascii) in let file_in_scope = if not (Filename.is_relative f) then f else Filename.concat (dirscope) f in let _, resulting_state = eval_command_list (Parsedriver.read_file file_in_scope) { state with env = []; purityenv = [] } dirscope in let newmodule = EvtDict resulting_state.env in (EvtUnit, { state with env = (Dict.insert state.env modulename newmodule ) }) | Includefile f -> let file_in_scope = if not (Filename.is_relative f) then f else Filename.concat (dirscope) f in (* Eval the file contents *) eval_command_list (Parsedriver.read_file file_in_scope) state dirscope | Setpurity p -> if state.verbosity >= 1 then Printf.eprintf "%s%!" (show_puret state.purity) else (); (EvtUnit, { state with purity = p }) | Setverbose v -> (EvtUnit, { state with verbosity = v})