| 1 |
open Ident
|
| 2 |
open Lambda
|
| 3 |
|
| 4 |
type env = {
|
| 5 |
cu: Types.CompUnit.t option; (* None: toplevel *)
|
| 6 |
vars: var_loc Env.t;
|
| 7 |
stack_size: int;
|
| 8 |
global_size: int
|
| 9 |
}
|
| 10 |
|
| 11 |
let global_size env = env.global_size
|
| 12 |
|
| 13 |
let dump ppf env =
|
| 14 |
Env.iter
|
| 15 |
(fun id loc ->
|
| 16 |
Format.fprintf ppf "Var %a : %a@\n" U.print (Id.value id) Lambda.print_var_loc loc)
|
| 17 |
env.vars
|
| 18 |
|
| 19 |
|
| 20 |
let mk cu = { cu = cu; vars = Env.empty; stack_size = 0; global_size = 0 }
|
| 21 |
let empty_toplevel = mk None
|
| 22 |
let empty x = mk (Some x)
|
| 23 |
|
| 24 |
|
| 25 |
let serialize s env =
|
| 26 |
assert (env.stack_size = 0);
|
| 27 |
(match env.cu with
|
| 28 |
| Some cu -> Types.CompUnit.serialize s cu
|
| 29 |
| None -> assert false);
|
| 30 |
Serialize.Put.env Id.serialize Lambda.Put.var_loc Env.iter s env.vars;
|
| 31 |
Serialize.Put.int s env.global_size
|
| 32 |
|
| 33 |
let deserialize s =
|
| 34 |
let cu = Types.CompUnit.deserialize s in
|
| 35 |
let vars =
|
| 36 |
Serialize.Get.env Id.deserialize Lambda.Get.var_loc Env.add Env.empty s in
|
| 37 |
let size = Serialize.Get.int s in
|
| 38 |
{ cu = Some cu; vars = vars; stack_size = 0; global_size = size }
|
| 39 |
|
| 40 |
|
| 41 |
let find x env =
|
| 42 |
try Env.find x env.vars
|
| 43 |
with Not_found ->
|
| 44 |
failwith ("Compile: cannot find " ^ (Ident.to_string x))
|
| 45 |
|
| 46 |
let from_comp_unit = ref (fun cu -> assert false)
|
| 47 |
|
| 48 |
let find_ext cu x =
|
| 49 |
let env = !from_comp_unit cu in
|
| 50 |
find x env
|
| 51 |
|
| 52 |
|
| 53 |
let rec compile env tail e = compile_aux env tail e.Typed.exp_descr
|
| 54 |
and compile_aux env tail = function
|
| 55 |
| Typed.Forget (e,_) -> compile env tail e
|
| 56 |
| Typed.Var x -> Var (find x env)
|
| 57 |
| Typed.ExtVar (cu,x) -> Var (find_ext cu x)
|
| 58 |
| Typed.Apply (e1,e2) -> Apply (tail, compile env false e1, compile env tail e2)
|
| 59 |
| Typed.Abstraction a -> compile_abstr env a
|
| 60 |
| Typed.Cst c -> Const c
|
| 61 |
| Typed.Pair (e1,e2) -> Pair(compile env false e1, compile env tail e2)
|
| 62 |
| Typed.Xml (e1, { Typed.exp_descr = Typed.Pair (e2,e3) }) ->
|
| 63 |
Xml (compile env false e1, compile env false e2, compile env tail e3)
|
| 64 |
| Typed.Xml (_,_) -> assert false
|
| 65 |
| Typed.RecordLitt r -> Record (LabelMap.map (compile env false) r)
|
| 66 |
| Typed.String (i,j,s,q) -> String (i,j,s,compile env tail q)
|
| 67 |
| Typed.Match (e,brs) -> Match (compile env false e, compile_branches env tail brs)
|
| 68 |
| Typed.Map (e,brs) -> Map (compile env false e, compile_branches env false brs)
|
| 69 |
| Typed.Transform (e,brs) -> Transform
|
| 70 |
(compile env false e, compile_branches env false brs)
|
| 71 |
| Typed.Xtrans (e,brs) -> Xtrans (compile env false e, compile_branches env false brs)
|
| 72 |
| Typed.Validate (e,k,sch,t) -> Validate (compile env tail e, k, sch, t)
|
| 73 |
| Typed.RemoveField (e,l) -> RemoveField (compile env tail e,l)
|
| 74 |
| Typed.Dot (e,l) -> Dot (compile env tail e, l)
|
| 75 |
| Typed.Try (e,brs) -> Try (compile env false e, compile_branches env tail brs)
|
| 76 |
| Typed.UnaryOp (op,e) -> UnaryOp (op, compile env tail e)
|
| 77 |
| Typed.BinaryOp (op,e1,e2) -> BinaryOp (op, compile env false e1, compile env tail e2)
|
| 78 |
| Typed.Ref (e,t) -> Ref (compile env tail e, t)
|
| 79 |
|
| 80 |
and compile_abstr env a =
|
| 81 |
let fun_env =
|
| 82 |
match a.Typed.fun_name with
|
| 83 |
| Some x -> Env.add x (Env 0) Env.empty
|
| 84 |
| None -> Env.empty in
|
| 85 |
|
| 86 |
let (slots,nb_slots,fun_env) =
|
| 87 |
List.fold_left
|
| 88 |
(fun (slots,nb_slots,fun_env) x ->
|
| 89 |
match find x env with
|
| 90 |
| (Stack _ | Env _) as p ->
|
| 91 |
p::slots,
|
| 92 |
succ nb_slots,
|
| 93 |
Env.add x (Env nb_slots) fun_env;
|
| 94 |
| Global _ | Ext _ as p ->
|
| 95 |
slots,
|
| 96 |
nb_slots,
|
| 97 |
Env.add x p fun_env
|
| 98 |
| Dummy -> assert false
|
| 99 |
)
|
| 100 |
([Dummy],1,fun_env) (IdSet.get a.Typed.fun_fv) in
|
| 101 |
|
| 102 |
|
| 103 |
let slots = Array.of_list (List.rev slots) in
|
| 104 |
let env = { env with vars = fun_env; stack_size = 0 } in
|
| 105 |
let body = compile_branches env true a.Typed.fun_body in
|
| 106 |
Abstraction (slots, a.Typed.fun_iface, body)
|
| 107 |
|
| 108 |
and compile_branches env tail (brs : Typed.branches) =
|
| 109 |
(* Don't compile unused branches, because they have not been
|
| 110 |
type checked. *)
|
| 111 |
let used = List.filter (fun br -> br.Typed.br_used) brs.Typed.br_branches in
|
| 112 |
{
|
| 113 |
brs = List.map (compile_branch env tail) used;
|
| 114 |
brs_tail = tail;
|
| 115 |
brs_accept_chars = not (Types.Char.is_empty brs.Typed.br_accept);
|
| 116 |
brs_input = brs.Typed.br_typ;
|
| 117 |
brs_compiled = None
|
| 118 |
}
|
| 119 |
|
| 120 |
and compile_branch env tail br =
|
| 121 |
let env =
|
| 122 |
List.fold_left
|
| 123 |
(fun env x ->
|
| 124 |
{ env with
|
| 125 |
vars = Env.add x (Stack env.stack_size) env.vars;
|
| 126 |
stack_size = env.stack_size + 1 }
|
| 127 |
|
| 128 |
) env (Patterns.fv br.Typed.br_pat) in
|
| 129 |
(br.Typed.br_pat, compile env tail br.Typed.br_body)
|
| 130 |
|
| 131 |
|
| 132 |
let enter_globals env n =
|
| 133 |
match env.cu with
|
| 134 |
| None ->
|
| 135 |
let env =
|
| 136 |
List.fold_left
|
| 137 |
(fun env x ->
|
| 138 |
{ env with
|
| 139 |
vars = Env.add x (Global env.stack_size) env.vars;
|
| 140 |
stack_size = env.stack_size + 1 })
|
| 141 |
env n in
|
| 142 |
(env,[])
|
| 143 |
| Some cu ->
|
| 144 |
List.fold_left
|
| 145 |
(fun (env,code) x ->
|
| 146 |
let code = SetGlobal (cu, env.global_size) :: code in
|
| 147 |
let env =
|
| 148 |
{ env with
|
| 149 |
vars = Env.add x (Ext (cu, env.global_size)) env.vars;
|
| 150 |
global_size = env.global_size + 1 } in
|
| 151 |
(env,code)
|
| 152 |
)
|
| 153 |
(env,[])
|
| 154 |
n
|
| 155 |
|
| 156 |
let compile_expr env = compile env false
|
| 157 |
|
| 158 |
let compile_eval env e = [ Push (compile_expr env e); Pop ]
|
| 159 |
|
| 160 |
let compile_let_decl env decl =
|
| 161 |
let pat = decl.Typed.let_pat in
|
| 162 |
let e = compile_expr env decl.Typed.let_body in
|
| 163 |
let (env,code) = enter_globals env (Patterns.fv pat) in
|
| 164 |
(env, (Push e) :: (Split pat) :: code)
|
| 165 |
|
| 166 |
let compile_rec_funs env funs =
|
| 167 |
let fun_name = function
|
| 168 |
| { Typed.exp_descr=Typed.Abstraction{Typed.fun_name = Some x}} -> x
|
| 169 |
| _ -> assert false in
|
| 170 |
let fun_a env = function
|
| 171 |
| { Typed.exp_descr=Typed.Abstraction a } ->
|
| 172 |
Push (compile_abstr env a)
|
| 173 |
| _ -> assert false in
|
| 174 |
let names = List.map fun_name funs in
|
| 175 |
let (env,code) = enter_globals env names in
|
| 176 |
let exprs = List.map (fun_a env) funs in
|
| 177 |
(env, exprs @ code)
|
| 178 |
|
| 179 |
|
| 180 |
(****************************************)
|
| 181 |
|
| 182 |
open Location
|
| 183 |
|
| 184 |
let eval ~run ~show (tenv,cenv,codes) e =
|
| 185 |
let (e,t) = Typer.type_expr tenv e in
|
| 186 |
let expr = compile_expr cenv e in
|
| 187 |
if run then
|
| 188 |
let v = Eval.expr expr in
|
| 189 |
show None t (Some v)
|
| 190 |
else
|
| 191 |
show None t None;
|
| 192 |
(tenv,cenv, Pop :: Push expr ::codes)
|
| 193 |
|
| 194 |
let run_show ~run ~show tenv cenv codes ids =
|
| 195 |
if run then
|
| 196 |
let () = Eval.code_items codes in
|
| 197 |
List.iter
|
| 198 |
(fun (id,_) -> show (Some id)
|
| 199 |
(Typer.find_value id tenv)
|
| 200 |
(Some (Eval.var (find id cenv)))) ids
|
| 201 |
else
|
| 202 |
List.iter
|
| 203 |
(fun (id,_) -> show (Some id)
|
| 204 |
(Typer.find_value id tenv)
|
| 205 |
None) ids
|
| 206 |
|
| 207 |
let let_decl ~run ~show (tenv,cenv,codes) p e =
|
| 208 |
let (tenv,decl,ids) = Typer.type_let_decl tenv p e in
|
| 209 |
let (cenv,code) = compile_let_decl cenv decl in
|
| 210 |
run_show ~run ~show tenv cenv code ids;
|
| 211 |
(tenv,cenv,List.rev_append code codes)
|
| 212 |
|
| 213 |
let let_funs ~run ~show (tenv,cenv,codes) funs =
|
| 214 |
let (tenv,funs,ids) = Typer.type_let_funs tenv funs in
|
| 215 |
let (cenv,code) = compile_rec_funs cenv funs in
|
| 216 |
run_show ~run ~show tenv cenv code ids;
|
| 217 |
(tenv,cenv,List.rev_append code codes)
|
| 218 |
|
| 219 |
let type_defs (tenv,cenv,codes) typs =
|
| 220 |
let tenv = Typer.enter_types (Typer.type_defs tenv typs) tenv in
|
| 221 |
(tenv,cenv,codes)
|
| 222 |
|
| 223 |
let namespace (tenv,cenv,codes) pr ns =
|
| 224 |
let tenv = Typer.enter_ns pr ns tenv in
|
| 225 |
(tenv,cenv,codes)
|
| 226 |
|
| 227 |
let find_cu (tenv,_,_) cu =
|
| 228 |
Typer.find_cu cu tenv
|
| 229 |
|
| 230 |
let using (tenv,cenv,codes) x cu =
|
| 231 |
let tenv = Typer.enter_cu x cu tenv in
|
| 232 |
(tenv,cenv,codes)
|
| 233 |
|
| 234 |
let rec collect_funs accu = function
|
| 235 |
| { descr = Ast.FunDecl e } :: rest -> collect_funs (e::accu) rest
|
| 236 |
| rest -> (accu,rest)
|
| 237 |
|
| 238 |
let rec collect_types accu = function
|
| 239 |
| { descr = Ast.TypeDecl (x,t) } :: rest ->
|
| 240 |
collect_types ((x,t) :: accu) rest
|
| 241 |
| rest -> (accu,rest)
|
| 242 |
|
| 243 |
let rec phrases ~run ~show ~loading ~directive =
|
| 244 |
let rec loop accu phs =
|
| 245 |
match phs with
|
| 246 |
| { descr = Ast.FunDecl _ } :: _ ->
|
| 247 |
let (funs,rest) = collect_funs [] phs in
|
| 248 |
loop (let_funs ~run ~show accu funs) rest
|
| 249 |
| { descr = Ast.TypeDecl (_,_) } :: _ ->
|
| 250 |
let (typs,rest) = collect_types [] phs in
|
| 251 |
loop (type_defs accu typs) rest
|
| 252 |
| { descr = Ast.SchemaDecl (name, schema) } :: rest ->
|
| 253 |
Typer.register_schema name schema;
|
| 254 |
loop accu rest
|
| 255 |
| { descr = Ast.Namespace (pr,ns) } :: rest ->
|
| 256 |
loop (namespace accu pr ns) rest
|
| 257 |
| { descr = Ast.Using (x,cu) } :: rest ->
|
| 258 |
let cu = find_cu accu cu in
|
| 259 |
loading cu;
|
| 260 |
loop (using accu x cu) rest
|
| 261 |
| { descr = Ast.EvalStatement e } :: rest ->
|
| 262 |
loop (eval ~run ~show accu e) rest
|
| 263 |
| { descr = Ast.LetDecl (p,e) } :: rest ->
|
| 264 |
loop (let_decl ~run ~show accu p e) rest
|
| 265 |
| { descr = Ast.Directive d } :: rest ->
|
| 266 |
let (tenv,cenv,_) = accu in
|
| 267 |
directive tenv cenv d;
|
| 268 |
loop accu rest
|
| 269 |
| [] ->
|
| 270 |
accu
|
| 271 |
in
|
| 272 |
loop
|
| 273 |
|
| 274 |
let comp_unit ?(run=false)
|
| 275 |
?(show=fun _ _ _ -> ())
|
| 276 |
?(loading=fun _ -> ())
|
| 277 |
?(directive=fun _ _ _ -> ()) tenv cenv phs =
|
| 278 |
let (tenv,cenv,codes) = phrases ~run ~show ~loading ~directive (tenv,cenv,[]) phs in
|
| 279 |
(tenv,cenv,List.rev codes)
|