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