diff --git a/src/arrange_ir.ml b/src/arrange_ir.ml new file mode 100644 index 00000000000..ff6fc5174dd --- /dev/null +++ b/src/arrange_ir.ml @@ -0,0 +1,74 @@ +open Source +open Ir +open Wasm.Sexpr + +let ($$) head inner = Node (head, inner) + +let rec exp e = match e.it with + | VarE i -> "VarE" $$ [id i] + | LitE l -> "LitE" $$ [Arrange.lit l] + | UnE (uo, e) -> "UnE" $$ [Arrange.unop uo; exp e] + | BinE (e1, bo, e2) -> "BinE" $$ [exp e1; Arrange.binop bo; exp e2] + | RelE (e1, ro, e2) -> "RelE" $$ [exp e1; Arrange.relop ro; exp e2] + | TupE es -> "TupE" $$ List.map exp es + | ProjE (e, i) -> "ProjE" $$ [exp e; Atom (string_of_int i)] + | ObjE (s, i, efs) -> "ObjE" $$ [Arrange.obj_sort s; id i] @ List.map exp_field efs + | DotE (e, n) -> "DotE" $$ [exp e; name n] + | AssignE (e1, e2) -> "AssignE" $$ [exp e1; exp e2] + | ArrayE es -> "ArrayE" $$ List.map exp es + | IdxE (e1, e2) -> "IdxE" $$ [exp e1; exp e2] + | CallE (e1, ts, e2) -> "CallE" $$ [exp e1] @ List.map Arrange.typ ts @ [exp e2] + | BlockE ds -> "BlockE" $$ List.map dec ds + | IfE (e1, e2, e3) -> "IfE" $$ [exp e1; exp e2; exp e3] + | SwitchE (e, cs) -> "SwitchE" $$ [exp e] @ List.map case cs + | WhileE (e1, e2) -> "WhileE" $$ [exp e1; exp e2] + | LoopE (e1, None) -> "LoopE" $$ [exp e1] + | LoopE (e1, Some e2) -> "LoopE" $$ [exp e1; exp e2] + | ForE (p, e1, e2) -> "ForE" $$ [pat p; exp e1; exp e2] + | LabelE (i, t, e) -> "LabelE" $$ [id i; Arrange.typ t; exp e] + | BreakE (i, e) -> "BreakE" $$ [id i; exp e] + | RetE e -> "RetE" $$ [exp e] + | AsyncE e -> "AsyncE" $$ [exp e] + | AwaitE e -> "AwaitE" $$ [exp e] + | AssertE e -> "AssertE" $$ [exp e] + | IsE (e1, e2) -> "IsE" $$ [exp e1; exp e2] + | DecE d -> "DecE" $$ [dec d] + | OptE e -> "OptE" $$ [exp e] + | PrimE p -> "PrimE" $$ [Atom p] + | DeclareE (i, t, e1) -> "DeclareE" $$ [id i; exp e1] + | DefineE (i, m, e1) -> "DefineE" $$ [id i; Arrange.mut m; exp e1] + | NewObjE (s, nameids)-> "NewObjE" $$ (Arrange.obj_sort s :: + List.fold_left (fun flds (n,i) -> + (name n)::(id i):: flds) [] nameids) +and pat p = match p.it with + | WildP -> Atom "WildP" + | VarP i -> "VarP" $$ [ id i] + | TupP ps -> "TupP" $$ List.map pat ps + | LitP l -> "LitP" $$ [ Arrange.lit l ] + | SignP (uo, l) -> "SignP" $$ [ Arrange.unop uo ; Arrange.lit l ] + | OptP p -> "OptP" $$ [ pat p ] + | AltP (p1,p2) -> "AltP" $$ [ pat p1; pat p2 ] + +and case c = "case" $$ [pat c.it.pat; exp c.it.exp] + +and prim p = Atom (Type.string_of_prim p) + +and exp_field (ef : exp_field) + = (Syntax.string_of_name ef.it.name.it) $$ [id ef.it.id; exp ef.it.exp; Arrange.mut ef.it.mut; Arrange.priv ef.it.priv] + +and id i = Atom i.it + +and name n = Atom (Syntax.string_of_name n.it) + +and dec d = match d.it with + | ExpD e -> "ExpD" $$ [exp e ] + | LetD (p, e) -> "LetD" $$ [pat p; exp e] + | VarD (i, e) -> "VarD" $$ [id i; exp e] + | FuncD (s, i, tp, p, t, e) -> + "FuncD" $$ [Atom (Arrange.sharing s.it); id i] @ List.map Arrange.typ_bind tp @ [pat p; Arrange.typ t; exp e] + | TypD (i, tp, t) -> + "TypD" $$ [id i] @ List.map Arrange.typ_bind tp @ [Arrange.typ t] + | ClassD (i, j, tp, s, p, i', efs) -> + "ClassD" $$ id i :: id j :: List.map Arrange.typ_bind tp @ [Arrange.obj_sort s; pat p; id i'] @ List.map exp_field efs + +and prog prog = "BlockE" $$ List.map dec prog.it diff --git a/src/compile.ml b/src/compile.ml index 96e1de763f4..c5d349480bf 100644 --- a/src/compile.ml +++ b/src/compile.ml @@ -2,7 +2,7 @@ open Wasm.Ast open Wasm.Types open Source -open Syntax +open Ir open CustomModule @@ -22,7 +22,6 @@ let (@@) x at = let at = { Wasm.Source.left = left; Wasm.Source.right = right } in { Wasm.Source.it = x; Wasm.Source.at = at } let nr_ x = { it = x; at = no_region; note = () } -let nr__ x = { it = x; at = no_region; note = {note_typ = Type.Any; note_eff = Type.Triv } } let todo fn se x = Printf.eprintf "%s: %s" fn (Wasm.Sexpr.to_string 80 se); x @@ -1431,7 +1430,7 @@ module Array = struct set_ni ^^ Object.lit env1 None None - [ (nr_ "next", nr__ Public, fun _ -> get_ni) ] + [ (nr_ "next", nr_ Syntax.Public, fun _ -> get_ni) ] ) in E.define_built_in env "array_keys_next" @@ -2710,7 +2709,7 @@ open PatCode (* The actual compiler code that looks at the AST *) -let compile_lit env lit = match lit with +let compile_lit env lit = Syntax.(match lit with | BoolLit false -> BoxedInt.lit_false env | BoolLit true -> BoxedInt.lit_true env (* This maps int to int32, instead of a proper arbitrary precision library *) @@ -2723,8 +2722,9 @@ let compile_lit env lit = match lit with | NullLit -> compile_null | TextLit t -> Text.lit env t | _ -> todo "compile_lit" (Arrange.lit lit) G.i_ Unreachable + ) -let compile_unop env op = match op with +let compile_unop env op = Syntax.(match op with | NegOp -> BoxedInt.lift_unboxed_unary env ( set_tmp env ^^ compile_unboxed_zero ^^ @@ -2732,8 +2732,9 @@ let compile_unop env op = match op with G.i_ (Binary (Wasm.Values.I32 Wasm.Ast.I32Op.Sub))) | PosOp -> G.nop | _ -> todo "compile_unop" (Arrange.unop op) G.i_ Unreachable + ) -let compile_binop env op = match op with +let compile_binop env op = Syntax.(match op with | AddOp -> BoxedInt.lift_unboxed_binary env (G.i_ (Binary (Wasm.Values.I32 Wasm.Ast.I32Op.Add))) | SubOp -> BoxedInt.lift_unboxed_binary env (G.i_ (Binary (Wasm.Values.I32 Wasm.Ast.I32Op.Sub))) | MulOp -> BoxedInt.lift_unboxed_binary env (G.i_ (Binary (Wasm.Values.I32 Wasm.Ast.I32Op.Mul))) @@ -2741,8 +2742,9 @@ let compile_binop env op = match op with | ModOp -> BoxedInt.lift_unboxed_binary env (G.i_ (Binary (Wasm.Values.I32 Wasm.Ast.I32Op.RemU))) | CatOp -> Text.concat env | _ -> todo "compile_binop" (Arrange.binop op) G.i_ Unreachable + ) -let compile_relop env op = BoxedInt.lift_unboxed_binary env (match op with +let compile_relop env op = Syntax.(BoxedInt.lift_unboxed_binary env (match op with | EqOp -> G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.Eq)) | NeqOp -> G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.Eq)) ^^ G.if_ [I32Type] compile_unboxed_false compile_unboxed_true @@ -2750,7 +2752,7 @@ let compile_relop env op = BoxedInt.lift_unboxed_binary env (match op with | GtOp -> G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.GtS)) | LeOp -> G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.LeS)) | LtOp -> G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.LtS)) - ) + )) (* compile_lexp is used for expressions on the left of an @@ -2764,11 +2766,11 @@ let rec compile_lexp (env : E.t) exp = match exp.it with compile_exp env e2 ^^ (* idx *) BoxedInt.unbox env ^^ Array.idx env - | DotE (e, {it = Name n;_}) -> + | DotE (e, {it = Syntax.Name n;_}) -> compile_exp env e ^^ (* Only real objects have mutable fields, no need to branch on the tag *) Object.idx env n - | _ -> todo "compile_lexp" (Arrange.exp exp) G.i_ Unreachable + | _ -> todo "compile_lexp" (Arrange_ir.exp exp) G.i_ Unreachable (* compile_exp returns an *value*. Currently, number (I32Type) are just repesented as such, but other @@ -2781,7 +2783,7 @@ and compile_exp (env : E.t) exp = match exp.it with | IdxE _ -> compile_lexp env exp ^^ load_ptr - | DotE (e, ({it = Name n;_} as id)) -> + | DotE (e, ({it = Syntax.Name n;_} as id)) -> compile_exp env e ^^ Tagged.branch env [I32Type] ( [ Tagged.Object, Object.load_idx env n ] @ @@ -2794,24 +2796,24 @@ and compile_exp (env : E.t) exp = match exp.it with ) (* We only allow prims of certain shapes, as they occur in the prelude *) (* Binary prims *) - | CallE ({ it = AnnotE ({ it = PrimE p; _} as pe, _); _}, _, { it = TupE [e1;e2]; _}) -> + | CallE ({ it = PrimE p; _} as pe, _, { it = TupE [e1;e2]; _}) -> begin compile_exp env e1 ^^ compile_exp env e2 ^^ match p with | "Array.init" -> Array.init env | "Array.tabulate" -> Array.tabulate env - | _ -> todo "compile_exp" (Arrange.exp pe) (G.i_ Unreachable) + | _ -> todo "compile_exp" (Arrange_ir.exp pe) (G.i_ Unreachable) end (* Unary prims *) - | CallE ({ it = AnnotE ({ it = PrimE p; _} as pe, _); _}, _, e) -> + | CallE ({ it = PrimE p; _} as pe, _, e) -> begin compile_exp env e ^^ match p with | "abs" -> Prim.prim_abs env | "printInt" -> Dfinity.prim_printInt env | "print" -> Dfinity.prim_print env - | _ -> todo "compile_exp" (Arrange.exp pe) (G.i_ Unreachable) + | _ -> todo "compile_exp" (Arrange_ir.exp pe) (G.i_ Unreachable) end | VarE var -> Var.get_val env var.it @@ -2820,16 +2822,12 @@ and compile_exp (env : E.t) exp = match exp.it with compile_exp env e2 ^^ store_ptr ^^ compile_unit - | LitE l_ref -> - compile_lit env !l_ref + | LitE l -> + compile_lit env l | AssertE e1 -> compile_exp env e1 ^^ BoxedInt.unbox env ^^ G.if_ [I32Type] compile_unit (G.i (Unreachable @@ exp.at)) - | NotE e -> - compile_exp env e ^^ - BoxedInt.unbox env ^^ - G.if_ [I32Type] (BoxedInt.lit_false env) (BoxedInt.lit_true env) | UnE (op, e1) -> compile_exp env e1 ^^ compile_unop env op @@ -2841,16 +2839,6 @@ and compile_exp (env : E.t) exp = match exp.it with compile_exp env e1 ^^ compile_exp env e2 ^^ compile_relop env op - | OrE (e1, e2) -> - let code1 = compile_exp env e1 in - let code2 = compile_exp env e2 in - code1 ^^ BoxedInt.unbox env ^^ - G.if_ [I32Type] (BoxedInt.lit_true env) code2 - | AndE (e1, e2) -> - let code1 = compile_exp env e1 in - let code2 = compile_exp env e2 in - code1 ^^ BoxedInt.unbox env ^^ - G.if_ [I32Type] code2 (BoxedInt.lit_false env) | IfE (e1, e2, e3) -> let code1 = compile_exp env e1 in let code2 = compile_exp env e2 in @@ -2929,7 +2917,6 @@ and compile_exp (env : E.t) exp = match exp.it with G.if_ [] (code2 ^^ G.i_ Drop ^^ G.i_ (Br (nr 1l))) G.nop ) ^^ compile_unit - | AnnotE (e, t) -> compile_exp env e | RetE e -> compile_exp env e ^^ G.i (Return @@ exp.at) | OptE e -> Opt.inject env (compile_exp env e) @@ -2941,16 +2928,16 @@ and compile_exp (env : E.t) exp = match exp.it with | ArrayE es -> Array.lit env (List.map (compile_exp env) es) | ObjE ({ it = Type.Object _ (*sharing*); _}, name, fs) -> (* TBR - really the same for local and shared? *) let fs' = List.map - (fun (f : Syntax.exp_field) -> + (fun (f : Ir.exp_field) -> (f.it.id, f.it.priv, fun env -> compile_exp env f.it.exp) ) fs in Object.lit env (Some name) None fs' | ObjE ({ it = Type.Actor; _}, name, fs) -> - let captured = Freevars.exp exp in + let captured = Freevars_ir.exp exp in let prelude_names = find_prelude_names env in if Freevars.S.is_empty (Freevars.S.diff captured prelude_names) then actor_lit env name fs - else todo "non-closed actor" (Arrange.exp exp) G.i_ Unreachable + else todo "non-closed actor" (Arrange_ir.exp exp) G.i_ Unreachable | CallE (e1, _, e2) when isDirectCall env e1 <> None -> let fi = Lib.Option.value (isDirectCall env e1) in compile_exp env e2 ^^ @@ -3019,16 +3006,15 @@ and compile_exp (env : E.t) exp = match exp.it with compile_unit | NewObjE ({ it = Type.Object _ (*sharing*); _}, fs) -> (* TBR - really the same for local and shared? *) let fs' = List.map - (fun ({ it = Name name; _}, id) -> (name, fun env -> + (fun ({ it = Syntax.Name name; _}, id) -> (name, fun env -> Var.get_payload_loc env id.it ^^ load_ptr )) fs in Object.lit_raw env fs' - | _ -> todo "compile_exp" (Arrange.exp exp) (G.i_ Unreachable) + | _ -> todo "compile_exp" (Arrange_ir.exp exp) (G.i_ Unreachable) and isDirectCall env e = match e.it with - | AnnotE (e, _) -> isDirectCall env e | VarE var -> begin match E.lookup_var env var.it with | Some (Deferred d) -> d.is_direct_call @@ -3066,21 +3052,21 @@ enabled mutual recursion. and compile_lit_pat env opo l = match opo, l with - | None, NullLit -> + | None, Syntax.NullLit -> compile_lit env l ^^ G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.Eq)) - | None, (NatLit _ | IntLit _ | BoolLit _) -> + | None, Syntax.(NatLit _ | IntLit _ | BoolLit _) -> BoxedInt.unbox env ^^ compile_lit env l ^^ BoxedInt.unbox env ^^ G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.Eq)) - | Some uo, (NatLit _ | IntLit _) -> + | Some uo, Syntax.(NatLit _ | IntLit _) -> BoxedInt.unbox env ^^ compile_lit env l ^^ compile_unop env uo ^^ BoxedInt.unbox env ^^ G.i_ (Compare (Wasm.Values.I32 Wasm.Ast.I32Op.Eq)) - | None, (TextLit t) -> + | None, Syntax.(TextLit t) -> Text.lit env t ^^ Text.compare env | _ -> todo "compile_lit_pat" (Arrange.lit l) (G.i_ Unreachable) @@ -3095,7 +3081,6 @@ and compile_pat env pat : E.t * G.t * patternCode = match pat.it with If the pattern does not match, it branches to the depth at fail_depth. *) | WildP -> (env, G.nop, CannotFail (G.i_ Drop)) - | AnnotP (p, _) -> compile_pat env p | OptP p -> let (env1, alloc_code1, code1) = compile_pat env p in let (set_i, get_i) = new_local env "opt_scrut" in @@ -3113,12 +3098,12 @@ and compile_pat env pat : E.t * G.t * patternCode = match pat.it with (env2, alloc_code1, code) | LitP l -> let code = CanFail (fun fail_code -> - compile_lit_pat env None !l ^^ + compile_lit_pat env None l ^^ G.if_ [] G.nop fail_code) in (env, G.nop, code) | SignP (op, l) -> let code = CanFail (fun fail_code -> - compile_lit_pat env (Some op) !l ^^ + compile_lit_pat env (Some op) l ^^ G.if_ [] G.nop fail_code) in (env, G.nop, code) @@ -3197,18 +3182,18 @@ and compile_dec last pre_env dec : E.t * G.t * (E.t -> G.t) = match dec.it with | FuncD (_, name, _, p, _rt, e) -> (* Get captured variables *) - let captured = Freevars.captured p e in + let captured = Freevars_ir.captured p e in let mk_pat env1 = compile_mono_pat env1 p in let mk_body env1 _ = compile_exp env1 e in Closure.dec pre_env last name captured mk_pat mk_body dec.at (* Classes are desguared to functions and objects. *) | ClassD (name, _, typ_params, s, p, self, efs) -> - let captured = Freevars.captured_exp_fields p efs in + let captured = Freevars_ir.captured_exp_fields p efs in let mk_pat env1 = compile_mono_pat env1 p in let mk_body env1 compile_fun_identifier = (* TODO: This treats actors like any old object *) - let fs' = List.map (fun (f : Syntax.exp_field) -> + let fs' = List.map (fun (f : Ir.exp_field) -> (f.it.id, f.it.priv, fun env -> compile_exp env f.it.exp) ) efs in (* this is run within the function. The class id is the function @@ -3247,7 +3232,7 @@ and find_prelude_names env = E.in_scope_set env2 -and compile_start_func env (progs : Syntax.prog list) : E.func_with_names = +and compile_start_func env (progs : Ir.prog list) : E.func_with_names = Func.of_body env [] [] (fun env1 -> let rec go env = function | [] -> G.nop @@ -3258,7 +3243,7 @@ and compile_start_func env (progs : Syntax.prog list) : E.func_with_names = go env1 progs ) -and compile_private_actor_field pre_env (f : Syntax.exp_field) = +and compile_private_actor_field pre_env (f : Ir.exp_field) = let ptr = E.reserve_static_memory pre_env (Int32.mul 2l Heap.word_size) in let pre_env1 = E.add_local_static pre_env f.it.id.it (Int32.add Heap.word_size ptr) in ( pre_env1, fun env -> @@ -3270,10 +3255,9 @@ and compile_private_actor_field pre_env (f : Syntax.exp_field) = Var.store ) -and compile_public_actor_field pre_env (f : Syntax.exp_field) = +and compile_public_actor_field pre_env (f : Ir.exp_field) = let (name, _, pat, _rt, exp) = - let rec find_func exp = match exp.it with - | AnnotE (exp, _) -> find_func exp + let find_func exp = match exp.it with | DecE {it = FuncD (s, name, ty_args, pat, rt, exp); _ } -> (name, ty_args, pat, rt, exp) | _ -> raise (Invalid_argument "public actor field not a function") in find_func f.it.exp in @@ -3301,8 +3285,8 @@ and compile_public_actor_field pre_env (f : Syntax.exp_field) = G.nop ) -and compile_actor_field pre_env (f : Syntax.exp_field) = - if f.it.priv.it = Private +and compile_actor_field pre_env (f : Ir.exp_field) = + if f.it.priv.it = Syntax.Private then compile_private_actor_field pre_env f else compile_public_actor_field pre_env f @@ -3438,7 +3422,7 @@ and conclude_module env module_name start_fi_o = locals_names = E.get_func_local_names env; } -let compile mode module_name (prelude : Syntax.prog) (progs : Syntax.prog list) : extended_module = +let compile mode module_name (prelude : Ir.prog) (progs : Ir.prog list) : extended_module = let env = E.mk_global mode prelude ClosureTable.table_end in if E.mode env = DfinityMode then Dfinity.system_imports env; diff --git a/src/compile.mli b/src/compile.mli index d9713ec3135..ce0789f661e 100644 --- a/src/compile.mli +++ b/src/compile.mli @@ -1,3 +1,3 @@ type mode = WasmMode | DfinityMode -val compile : mode -> string -> Syntax.prog -> Syntax.prog list -> CustomModule.extended_module +val compile : mode -> string -> Ir.prog -> Ir.prog list -> CustomModule.extended_module diff --git a/src/desugar.ml b/src/desugar.ml new file mode 100644 index 00000000000..90b3d618801 --- /dev/null +++ b/src/desugar.ml @@ -0,0 +1,91 @@ +module S = Syntax +module I = Ir + + +(* Combinators used in the desguaring *) + +let true_lit : Ir.exp = + Source.(I.LitE (S.BoolLit true) @@ no_region) +let false_lit : Ir.exp = + Source.(I.LitE (S.BoolLit false) @@ no_region) + + + +let phrase f x = Source.(f x.it @@ x.at) + +let + rec exps es = List.map exp es + and exp e = phrase exp' e + and exp' = function + | S.PrimE p -> I.PrimE p + | S.VarE i -> I.VarE i + | S.LitE l -> I.LitE !l + | S.UnE (o, e) -> I.UnE (o, exp e) + | S.BinE (e1, o, e2) -> I.BinE (exp e1, o, exp e2) + | S.RelE (e1, o, e2) -> I.RelE (exp e1, o, exp e2) + | S.TupE es -> I.TupE (exps es) + | S.ProjE (e, i) -> I.ProjE (exp e, i) + | S.OptE e -> I.OptE (exp e) + | S.ObjE (s, i, es) -> I.ObjE (s, i, exp_fields es) + | S.DotE (e, n) -> I.DotE (exp e, n) + | S.AssignE (e1, e2) -> I.AssignE (exp e1, exp e2) + | S.ArrayE es -> I.ArrayE (exps es) + | S.IdxE (e1, e2) -> I.IdxE (exp e1, exp e2) + | S.CallE (e1, inst, e2) -> I.CallE (exp e1, inst, exp e2) + | S.BlockE ds -> I.BlockE (decs ds) + | S.NotE e -> I.IfE (exp e, false_lit, true_lit) + | S.AndE (e1, e2) -> I.IfE (exp e1, exp e2, false_lit) + | S.OrE (e1, e2) -> I.IfE (exp e1, true_lit, exp e2) + | S.IfE (e1, e2, e3) -> I.IfE (exp e1, exp e2, exp e3) + | S.SwitchE (e1, cs) -> I.SwitchE (exp e1, cases cs) + | S.WhileE (e1, e2) -> I.WhileE (exp e1, exp e2) + | S.LoopE (e1, None) -> I.LoopE (exp e1, None) + | S.LoopE (e1, Some e2) -> I.LoopE (exp e1, Some (exp e2)) + | S.ForE (p, e1, e2) -> I.ForE (pat p, exp e1, exp e2) + | S.LabelE (l, t, e) -> I.LabelE (l, t, exp e) + | S.BreakE (l, e) -> I.BreakE (l, exp e) + | S.RetE e -> I.RetE (exp e) + | S.AsyncE e -> I.AsyncE (exp e) + | S.AwaitE e -> I.AwaitE (exp e) + | S.AssertE e -> I.AssertE (exp e) + | S.IsE (e1, e2) -> I.IsE (exp e1, exp e2) + | S.AnnotE (e, _) -> exp' e.Source.it + | S.DecE d -> I.DecE (dec d) + | S.DeclareE (i, t, e) -> I.DeclareE (i, t, exp e) + | S.DefineE (i, m, e) -> I.DefineE (i, m, exp e) + | S.NewObjE (s, fs) -> I.NewObjE (s, fs) + + and exp_fields fs = List.map exp_field fs + and exp_field f = phrase exp_field' f + and exp_field' (f : S.exp_field') = + S.{ I.name = f.name; I.id = f.id; I.exp = exp f.exp; I.mut = f.mut; I.priv = f.priv} + + and decs ds = List.map dec ds + and dec d = phrase dec' d + and dec' = function + | S.ExpD e -> I.ExpD (exp e) + | S.LetD (p, e) -> I.LetD (pat p, exp e) + | S.VarD (i, e) -> I.VarD (i, exp e) + | S.FuncD (s, i, tp, p, ty, e) -> I.FuncD (s, i, tp, pat p, ty, exp e) + | S.TypD (i, ty, t) -> I.TypD (i, ty, t) + | S.ClassD (i1, i2, ty, s, p, i3, es) -> I.ClassD (i1, i2, ty, s, pat p, i3, exp_fields es) + + + and cases cs = List.map case cs + and case c = phrase case' c + and case' c = S.{ I.pat = pat c.pat; I.exp = exp c.exp} + + and pats ps = List.map pat ps + and pat p = phrase pat' p + and pat' = function + | S.VarP v -> I.VarP v + | S.WildP -> I.WildP + | S.LitP l -> I.LitP !l + | S.SignP (o, l) -> I.SignP (o, !l) + | S.TupP ps -> I.TupP (pats ps) + | S.OptP p -> I.OptP (pat p) + | S.AltP (p1, p2) -> I.AltP (pat p1, pat p2) + | S.AnnotP (p, _) -> pat' p.Source.it + + and prog p = phrase decs p + diff --git a/src/desugar.mli b/src/desugar.mli new file mode 100644 index 00000000000..a2ec063ac2d --- /dev/null +++ b/src/desugar.mli @@ -0,0 +1 @@ +val prog : Syntax.prog -> Ir.prog diff --git a/src/freevars_ir.ml b/src/freevars_ir.ml new file mode 100644 index 00000000000..a7d07f0a4fb --- /dev/null +++ b/src/freevars_ir.ml @@ -0,0 +1,111 @@ +open Source +open Ir + +module S = Set.Make(String) + + +(* A set of free variables *) +type f = S.t + +(* Operations: Union and removal *) +let (++) x y = S.union x y +let unions f xs = List.fold_left S.union S.empty (List.map f xs) +let (//) x y = S.remove y x + +(* A combined set of free variables and defined variables, + e.g. in patterns and declaration *) +type fb = S.t * S.t + +(* Operations: *) + +(* This adds a set of free variables to a combined set *) +let (+++) ((f,b) : fb) x = (S.union f x, b) +(* This takes the union of two combined sets *) +let (++++) (f1, b1) (f2,b2) = (S.union f1 f2, S.union b1 b2) +let union_binders f xs = List.fold_left (++++) (S.empty, S.empty) (List.map f xs) + +(* The bound variables from the second argument scope over the first *) +let (///) (x : f) ((f,b) : fb) = f ++ S.diff x b + +(* This closes a combined set over itself (recursion or mutual recursion) *) +let close (f,b) = S.diff f b + +(* One traversal for each syntactic category, named by that category *) + +let rec exp e : f = match e.it with + | VarE i -> S.singleton i.it + | LitE l -> S.empty + | PrimE _ -> S.empty + | UnE (uo, e) -> exp e + | BinE (e1, bo, e2) -> exps [e1; e2] + | RelE (e1, ro, e2) -> exps [e1; e2] + | TupE es -> exps es + | ProjE (e, i) -> exp e + | ObjE (s, i, efs) -> close (exp_fields efs) // i.it + | DotE (e, i) -> exp e + | AssignE (e1, e2) -> exps [e1; e2] + | ArrayE es -> exps es + | IdxE (e1, e2) -> exps [e1; e2] + | CallE (e1, ts, e2) -> exps [e1; e2] + | BlockE ds -> close (decs ds) + | IfE (e1, e2, e3) -> exps [e1; e2; e3] + | SwitchE (e, cs) -> exp e ++ cases cs + | WhileE (e1, e2) -> exps [e1; e2] + | LoopE (e1, None) -> exp e1 + | LoopE (e1, Some e2) -> exps [e1; e2] + | ForE (p, e1, e2) -> exp e1 ++ (exp e2 /// pat p) + | LabelE (i, t, e) -> exp e + | BreakE (i, e) -> exp e + | RetE e -> exp e + | AsyncE e -> exp e + | AwaitE e -> exp e + | AssertE e -> exp e + | IsE (e, t) -> exp e + | DecE d -> close (dec d) + | OptE e -> exp e + | DeclareE (i, t, e) -> exp e // i.it + | DefineE (i, m, e) -> (id i) ++ exp e + | NewObjE (_,ids) -> unions id (List.map (fun (lab,id) -> id) ids) + +and exps es : f = unions exp es + +and pat p : fb = match p.it with + | WildP -> (S.empty, S.empty) + | VarP i -> (S.empty, S.singleton i.it) + | TupP ps -> pats ps + | LitP l -> (S.empty, S.empty) + | SignP (uo, l) -> (S.empty, S.empty) + | OptP p -> pat p + | AltP (p1, p2) -> pat p1 ++++ pat p2 + +and pats ps : fb = union_binders pat ps + +and case (c : case) = exp c.it.exp /// pat c.it.pat + +and cases cs : f = unions case cs + +and exp_field (ef : exp_field) : fb + = (exp ef.it.exp, S.singleton ef.it.id.it) + +and exp_fields efs : fb = union_binders exp_field efs + +and id i = S.singleton i.it + +and dec d = match d.it with + | ExpD e -> (exp e, S.empty) + | LetD (p, e) -> pat p +++ exp e + | VarD (i, e) -> (S.empty, S.singleton i.it) +++ exp e + | FuncD (s, i, tp, p, t, e) -> + (S.empty, S.singleton i.it) +++ (exp e /// pat p) + | TypD (i, tp, t) -> (S.empty, S.empty) + | ClassD (i, l, tp, s, p, i', efs) -> + (S.empty, S.singleton i.it) +++ (close (exp_fields efs) /// pat p // i'.it) + +(* The variables captured by a function. May include the function itself! *) +and captured p e = S.elements (exp e /// pat p) + +(* The variables captured by a class function. May include the function itself! *) +and captured_exp_fields p efs = S.elements (close (exp_fields efs) /// pat p) + + +and decs ps : fb = union_binders dec ps diff --git a/src/ir.ml b/src/ir.ml new file mode 100644 index 00000000000..462c836f901 --- /dev/null +++ b/src/ir.ml @@ -0,0 +1,72 @@ +(* Patterns *) + +type pat = pat' Source.phrase +and pat' = + | WildP (* wildcard *) + | VarP of Syntax.id (* variable *) + | LitP of Syntax.lit (* literal *) + | SignP of Syntax.unop * Syntax.lit (* signed literal *) + | TupP of pat list (* tuple *) + | OptP of pat (* option *) + | AltP of pat * pat (* disjunctive *) + +(* Expressions *) + +type exp = exp' Source.phrase +and exp' = + | PrimE of string (* primitive *) + | VarE of Syntax.id (* variable *) + | LitE of Syntax.lit (* literal *) + | UnE of Syntax.unop * exp (* unary operator *) + | BinE of exp * Syntax.binop * exp (* binary operator *) + | RelE of exp * Syntax.relop * exp (* relational operator *) + | TupE of exp list (* tuple *) + | ProjE of exp * int (* tuple projection *) + | OptE of exp (* option injection *) + | ObjE of Syntax.obj_sort * Syntax.id * exp_field list (* object *) + | DotE of exp * Syntax.name (* object projection *) + | AssignE of exp * exp (* assignment *) + | ArrayE of exp list (* array *) + | IdxE of exp * exp (* array indexing *) + | CallE of exp * Syntax.typ list * exp (* function call *) + | BlockE of dec list (* block *) + | IfE of exp * exp * exp (* conditional *) + | SwitchE of exp * case list (* switch *) + | WhileE of exp * exp (* while-do loop *) + | LoopE of exp * exp option (* do-while loop *) + | ForE of pat * exp * exp (* iteration *) + | LabelE of Syntax.id * Syntax.typ * exp (* label *) + | BreakE of Syntax.id * exp (* break *) + | RetE of exp (* return *) + | AsyncE of exp (* async *) + | AwaitE of exp (* await *) + | AssertE of exp (* assertion *) + | IsE of exp * exp (* instance-of *) + | DecE of dec (* declaration *) + | DeclareE of Syntax.id * Type.typ * exp (* local promise (internal) *) + | DefineE of Syntax.id * Syntax.mut * exp (* promise fulfillment (internal) *) + | NewObjE of Syntax.obj_sort * (Syntax.name * Syntax.id) list (* make an object, preserving mutable identity (internal) *) + +and exp_field = exp_field' Source.phrase +and exp_field' = {name : Syntax.name; id : Syntax.id; exp : exp; mut : Syntax.mut; priv : Syntax.priv} + +and case = case' Source.phrase +and case' = {pat : pat; exp : exp} + + +(* Declarations *) + +and dec = dec' Source.phrase +and dec' = + | ExpD of exp (* plain expression *) + | LetD of pat * exp (* immutable *) + | VarD of Syntax.id * exp (* mutable *) + | FuncD of Syntax.sharing * Syntax.id * Syntax.typ_bind list * pat * Syntax.typ * exp (* function *) + | TypD of Syntax.id * Syntax.typ_bind list * Syntax.typ (* type *) + | ClassD of Syntax.id (*term id*) * Syntax.id (*type id*) * Syntax.typ_bind list * Syntax.obj_sort * pat * Syntax.id * exp_field list (* class *) + + +(* Program *) + +type prog = prog' Source.phrase +and prog' = dec list diff --git a/src/pipeline.ml b/src/pipeline.ml index b00555e0cc6..d8e272fff8d 100644 --- a/src/pipeline.ml +++ b/src/pipeline.ml @@ -298,6 +298,8 @@ let compile_with check mode name : compile_result = print_messages msgs; let prog = await_lowering true prog name in let prog = async_lowering true prog name in + let prog = Desugar.prog prog in + let prelude = Desugar.prog prelude in phase "Compiling" name; let module_ = Compile.compile mode name prelude [prog] in Ok module_