From 9219d326d69c3f971e5692016b67341a06390dcf Mon Sep 17 00:00:00 2001 From: Konstantin Olkhovskiy Date: Sun, 13 Dec 2020 18:03:15 +0300 Subject: [PATCH] Generalized program tree --- CHANGES.md | 1 + compiler/lib/driver.ml | 1 + compiler/lib/generate.ml | 294 +++++++++++++--------------- compiler/lib/generate.mli | 2 +- compiler/lib/id.ml | 34 ++++ compiler/lib/id.mli | 32 +++ compiler/lib/ir.ml | 158 +++++++++++++++ compiler/lib/ir.mli | 168 ++++++++++++++++ compiler/lib/javascript.ml | 90 +-------- compiler/lib/javascript.mli | 39 +--- compiler/lib/javascript_from_ir.ml | 190 ++++++++++++++++++ compiler/lib/javascript_from_ir.mli | 20 ++ compiler/lib/js_output.ml | 17 ++ compiler/lib/js_simpl.ml | 53 +++-- compiler/lib/js_simpl.mli | 14 +- compiler/lib/js_traverse.ml | 3 +- compiler/lib/loc.ml | 23 +++ compiler/lib/loc.mli | 23 +++ compiler/lib/num.ml | 70 +++++++ compiler/lib/num.mli | 47 +++++ 20 files changed, 974 insertions(+), 305 deletions(-) create mode 100644 compiler/lib/id.ml create mode 100644 compiler/lib/id.mli create mode 100644 compiler/lib/ir.ml create mode 100644 compiler/lib/ir.mli create mode 100644 compiler/lib/javascript_from_ir.ml create mode 100644 compiler/lib/javascript_from_ir.mli create mode 100644 compiler/lib/loc.ml create mode 100644 compiler/lib/loc.mli create mode 100644 compiler/lib/num.ml create mode 100644 compiler/lib/num.mli diff --git a/CHANGES.md b/CHANGES.md index adc15f5494..de18479fbc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,7 @@ # ??? (??) - ?? ## Features/Changes * Compiler: complete support for OCaml 4.12 +* Compiler: add JavaScript agnosting intermediate representaton (IR) * Lib: expose API to attached and retrieve js errors to/from ocaml exceptions # 3.8.0 (2020-10-21) - London diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 9b8f775bf2..cfde125ba1 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -447,6 +447,7 @@ let f +> Generate_closure.f +> deadcode' +> generate d ~exported_runtime + +> Javascript_from_ir.run +> link ~standalone ~linkall ~export_runtime:dynlink +> pack ~global +> coloring diff --git a/compiler/lib/generate.ml b/compiler/lib/generate.ml index 4f7497bf7d..99e653f377 100644 --- a/compiler/lib/generate.ml +++ b/compiler/lib/generate.ml @@ -40,7 +40,7 @@ let debug = Debug.find "gen" let times = Debug.find "times" open Code -module J = Javascript +module J = Ir (****) @@ -84,7 +84,7 @@ module Share = struct type t = { mutable count : int aux - ; mutable vars : J.ident aux + ; mutable vars : Id.t aux ; alias_prims : bool ; alias_strings : bool ; alias_apply : bool @@ -180,7 +180,7 @@ module Share = struct try J.EVar (StringMap.find s t.vars.strings) with Not_found -> let x = Var.fresh_n (Printf.sprintf "cst_%s" s) in - let v = J.V x in + let v = Id.V x in t.vars <- { t.vars with strings = StringMap.add s v t.vars.strings }; J.EVar v) else gen s @@ -198,7 +198,7 @@ module Share = struct try J.EVar (StringMap.find s t.vars.prims) with Not_found -> let x = Var.fresh_n s in - let v = J.V x in + let v = Id.V x in t.vars <- { t.vars with prims = StringMap.add s v t.vars.prims }; J.EVar v) else gen s @@ -211,7 +211,7 @@ module Share = struct try J.EVar (IntMap.find n t.vars.applies) with Not_found -> let x = Var.fresh_n (Printf.sprintf "caml_call%d" n) in - let v = J.V x in + let v = Id.V x in t.vars <- { t.vars with applies = IntMap.add n v t.vars.applies }; J.EVar v end @@ -229,58 +229,61 @@ module Ctx = struct { blocks; live; share; debug; exported_runtime } end -let var x = J.EVar (J.V x) +let var x = J.EVar (Id.V x) -let int n = J.ENum (J.Num.of_int32 (Int32.of_int n)) +let int n = J.EInt n -let int32 n = J.ENum (J.Num.of_int32 n) +let int32 n = J.EInt (Int32.to_int n) -let to_int cx = J.EBin (J.Bor, cx, int 0) +let to_int cx = J.EUn (J.ToInt, cx) let unsigned' x = J.EBin (J.Lsr, x, int 0) let unsigned x = let pos_int32 = match x with - | J.ENum num -> ( try Int32.(J.Num.to_int32 num >= 0l) with _ -> false) + | J.EInt num -> ( try Int32.(of_int num >= 0l) with _ -> false) | _ -> false in if pos_int32 then x else unsigned' x +let is_int x = J.EUn (J.IsInt, x) + let one = int 1 let zero = int 0 let plus_int x y = match x, y with - | J.ENum y, x when J.Num.is_zero y -> x - | x, J.ENum y when J.Num.is_zero y -> x - | J.ENum x, J.ENum y -> J.ENum (J.Num.add x y) + | J.EInt 0, x | x, J.EInt 0 -> x + | J.EInt x, J.EInt y -> J.EInt (x + y) | x, y -> J.EBin (J.Plus, x, y) let bool e = J.ECond (e, one, zero) +let arity_test x = J.EArityTest x + (****) let source_location ctx ?after pc = match Parse_bytecode.Debug.find_loc ctx.Ctx.debug ?after pc with - | Some pi -> J.Pi pi - | None -> J.N + | Some pi -> Loc.Pi pi + | None -> Loc.N (****) -let float_const f = J.ENum (J.Num.of_float f) +let float_const f = J.EFloat f -let s_var name = J.EVar (J.ident name) +let s_var name = J.EVar (Id.ident name) let runtime_fun ctx name = match ctx.Ctx.exported_runtime with - | Some runtime -> J.EDot (J.EVar (J.V runtime), name) + | Some runtime -> J.EDot (J.EVar (Id.V runtime), name) | None -> s_var name let str_js s = J.EStr (s, `Bytes) -let ecall f args loc = J.ECall (f, List.map args ~f:(fun x -> x, `Not_spread), loc) +let ecall f args loc = J.ECall (f, args, loc) (****) @@ -323,14 +326,14 @@ let rec constant_rec ~ctx x level instrs = match x with | String s -> let e = Share.get_string str_js s ctx.Ctx.share in - let e = ocaml_string ~ctx ~loc:J.N e in + let e = ocaml_string ~ctx ~loc:Loc.N e in e, instrs | IString s -> Share.get_string str_js s ctx.Ctx.share, instrs | Float f -> float_const f, instrs | Float_array a -> - ( Mlvalue.Array.make - ~tag:Obj.double_array_tag - ~args:(Array.to_list (Array.map a ~f:float_const)) + ( J.EStruct + (int Obj.double_array_tag + :: Array.to_list (Array.map a ~f:(fun f -> float_const f))) , instrs ) | Int64 i -> let p = @@ -339,7 +342,7 @@ let rec constant_rec ~ctx x level instrs = let lo = int (Int64.to_int i land 0xffffff) and mi = int (Int64.to_int (Int64.shift_right i 24) land 0xffffff) and hi = int (Int64.to_int (Int64.shift_right i 48) land 0xffff) in - ecall p [ lo; mi; hi ] J.N, instrs + ecall p [ lo; mi; hi ] Loc.N, instrs | Tuple (tag, a, _) -> ( let constant_max_depth = Config.Param.constant_max_depth () in let rec detect_list n acc = function @@ -357,7 +360,7 @@ let rec constant_rec ~ctx x level instrs = let p = Share.get_prim (runtime_fun ctx) "caml_list_of_js_array" ctx.Ctx.share in - ecall p [ J.EArr arr ] J.N, instrs + ecall p [ J.EArr arr ] Loc.N, instrs | None -> let split = level = constant_max_depth in let level = if split then 0 else level + 1 in @@ -374,13 +377,14 @@ let rec constant_rec ~ctx x level instrs = | J.EArr _ -> let v = Code.Var.fresh_n "partial" in let instrs = - (J.Variable_statement [ J.V v, Some (js, J.N) ], J.N) :: instrs + (J.Variable_statement [ Id.V v, Some (js, Loc.N) ], Loc.N) + :: instrs in - J.EVar (J.V v) :: acc, instrs + J.EVar (Id.V v) :: acc, instrs | _ -> js :: acc, instrs) else List.rev l, instrs in - Mlvalue.Block.make ~tag ~args:l, instrs) + J.EStruct (int tag :: l), instrs) | Int i -> int32 i, instrs let constant ~ctx x level = @@ -391,7 +395,7 @@ type queue_elt = { prop : int ; cardinal : int ; ce : J.expression - ; loc : J.location + ; loc : Loc.t ; deps : Code.Var.Set.t } @@ -426,7 +430,7 @@ let access_queue_may_flush queue v x = if Code.Var.Set.exists (fun p -> Code.Var.Set.mem p deps) elt.deps then ( Code.Var.Set.add y deps - , (J.Variable_statement [ J.V y, Some (elt.ce, elt.loc) ], elt.loc) :: instrs + , (J.Variable_statement [ Id.V y, Some (elt.ce, elt.loc) ], elt.loc) :: instrs , queue ) else deps, instrs, eq :: queue) in @@ -442,7 +446,7 @@ let flush_queue expr_queue prop (l : J.statement_list) = in let instrs = List.map instrs ~f:(fun (x, elt) -> - J.Variable_statement [ J.V x, Some (elt.ce, elt.loc) ], elt.loc) + J.Variable_statement [ Id.V x, Some (elt.ce, elt.loc) ], elt.loc) in List.rev_append instrs l, expr_queue @@ -468,7 +472,7 @@ type state = ; backs : (int, Addr.Set.t) Hashtbl.t ; preds : (int, int) Hashtbl.t ; mutable loops : Addr.Set.t - ; mutable loop_stack : (Addr.t * (J.Label.t * bool ref)) list + ; mutable loop_stack : (Addr.t * (Javascript.Label.t * bool ref)) list ; mutable visited_blocks : Addr.Set.t ; mutable interm_idx : int ; ctx : Ctx.t @@ -486,7 +490,7 @@ let protect_preds st pc = Hashtbl.replace st.preds pc (get_preds st pc + 1000000 let unprotect_preds st pc = Hashtbl.replace st.preds pc (get_preds st pc - 1000000) module DTree = struct - (* This as to be kept in sync with the way we build conditionals + (* This has to be kept in sync with the way we build conditionals and switches! *) type cond = @@ -696,7 +700,7 @@ let parallel_renaming params args continuation queue = flush_queue queue px - (instrs @ [ J.Variable_statement [ J.V y, Some (cx, J.N) ], J.N ]) + (instrs @ [ J.Variable_statement [ Id.V y, Some (cx, Loc.N) ], Loc.N ]) in st @ continuation queue) ~init:continuation @@ -707,29 +711,29 @@ let parallel_renaming params args continuation queue = let apply_fun_raw ctx f params = let n = List.length params in J.ECond - ( J.EBin (J.EqEq, J.EDot (f, "length"), int n) - , ecall f params J.N - , ecall - (runtime_fun ctx "caml_call_gen") - [ f; J.EArr (List.map params ~f:(fun x -> Some x)) ] - J.N ) + ( J.EBin (J.EqEq, arity_test f, J.EInt n) + , J.ECall (f, params, Loc.N) + , J.ECall + ( runtime_fun ctx "caml_call_gen" + , [ f; J.EArr (List.map params ~f:(fun x -> Some x)) ] + , Loc.N ) ) let generate_apply_fun ctx n = let f' = Var.fresh_n "f" in - let f = J.V f' in + let f = Id.V f' in let params = Array.to_list (Array.init n ~f:(fun i -> let a = Var.fresh_n (Printf.sprintf "a%d" i) in - J.V a)) + Id.V a)) in let f' = J.EVar f in let params' = List.map params ~f:(fun x -> J.EVar x) in J.EFun ( None , f :: params - , [ J.Statement (J.Return_statement (Some (apply_fun_raw ctx f' params'))), J.N ] - , J.N ) + , [ J.Statement (J.Return_statement (Some (apply_fun_raw ctx f' params'))), Loc.N ] + , Loc.N ) let apply_fun ctx f params loc = if Config.Flag.inline_callgen () @@ -761,7 +765,7 @@ let _ = ; "caml_int32_of_int", "%identity" ; "caml_int32_to_int", "%identity" ; "caml_int32_of_float", "caml_int_of_float" - ; "caml_int32_to_float", "%identity" + ; "caml_int32_to_float", "caml_float_of_int" ; "caml_int32_format", "caml_format_int" ; "caml_int32_of_string", "caml_int_of_string" ; "caml_int32_compare", "caml_int_compare" @@ -780,7 +784,7 @@ let _ = ; "caml_nativeint_of_int", "%identity" ; "caml_nativeint_to_int", "%identity" ; "caml_nativeint_of_float", "caml_int_of_float" - ; "caml_nativeint_to_float", "%identity" + ; "caml_nativeint_to_float", "caml_float_of_int" ; "caml_nativeint_of_int32", "%identity" ; "caml_nativeint_to_int32", "%identity" ; "caml_nativeint_format", "caml_format_int" @@ -791,7 +795,6 @@ let _ = ; "caml_int64_to_int", "caml_int64_to_int32" ; "caml_int64_of_nativeint", "caml_int64_of_int32" ; "caml_int64_to_nativeint", "caml_int64_to_int32" - ; "caml_float_of_int", "%identity" ; "caml_array_get_float", "caml_array_get" ; "caml_floatarray_get", "caml_array_get" ; "caml_array_get_addr", "caml_array_get" @@ -863,10 +866,10 @@ let register_bin_math_prim name prim = let _ = register_un_prim_ctx "%caml_format_int_special" `Pure (fun ctx cx loc -> - let s = J.EBin (J.Plus, str_js "", cx) in + let s = J.EUn (J.IntToString, cx) in ocaml_string ~ctx ~loc s); register_bin_prim "caml_array_unsafe_get" `Mutable (fun cx cy _ -> - Mlvalue.Array.field cx cy); + J.EArrAccess (cx, plus_int one cy)); register_bin_prim "%int_add" `Pure (fun cx cy _ -> to_int (plus_int cx cy)); register_bin_prim "%int_sub" `Pure (fun cx cy _ -> to_int (J.EBin (J.Minus, cx, cy))); register_bin_prim "%direct_int_mul" `Pure (fun cx cy _ -> @@ -882,25 +885,31 @@ let _ = register_bin_prim "%int_lsr" `Pure (fun cx cy _ -> to_int (J.EBin (J.Lsr, cx, cy))); register_bin_prim "%int_asr" `Pure (fun cx cy _ -> J.EBin (J.Asr, cx, cy)); register_un_prim "%int_neg" `Pure (fun cx _ -> to_int (J.EUn (J.Neg, cx))); - register_bin_prim "caml_eq_float" `Pure (fun cx cy _ -> bool (J.EBin (J.EqEq, cx, cy))); + register_bin_prim "caml_eq_float" `Pure (fun cx cy _ -> + bool (J.EBin (J.FloatEqEq, cx, cy))); register_bin_prim "caml_neq_float" `Pure (fun cx cy _ -> - bool (J.EBin (J.NotEq, cx, cy))); - register_bin_prim "caml_ge_float" `Pure (fun cx cy _ -> bool (J.EBin (J.Le, cy, cx))); - register_bin_prim "caml_le_float" `Pure (fun cx cy _ -> bool (J.EBin (J.Le, cx, cy))); - register_bin_prim "caml_gt_float" `Pure (fun cx cy _ -> bool (J.EBin (J.Lt, cy, cx))); - register_bin_prim "caml_lt_float" `Pure (fun cx cy _ -> bool (J.EBin (J.Lt, cx, cy))); - register_bin_prim "caml_add_float" `Pure (fun cx cy _ -> J.EBin (J.Plus, cx, cy)); - register_bin_prim "caml_sub_float" `Pure (fun cx cy _ -> J.EBin (J.Minus, cx, cy)); - register_bin_prim "caml_mul_float" `Pure (fun cx cy _ -> J.EBin (J.Mul, cx, cy)); - register_bin_prim "caml_div_float" `Pure (fun cx cy _ -> J.EBin (J.Div, cx, cy)); - register_un_prim "caml_neg_float" `Pure (fun cx _ -> J.EUn (J.Neg, cx)); - register_bin_prim "caml_fmod_float" `Pure (fun cx cy _ -> J.EBin (J.Mod, cx, cy)); + bool (J.EBin (J.FloatNotEq, cx, cy))); + register_bin_prim "caml_ge_float" `Pure (fun cx cy _ -> + bool (J.EBin (J.FloatLe, cy, cx))); + register_bin_prim "caml_le_float" `Pure (fun cx cy _ -> + bool (J.EBin (J.FloatLe, cx, cy))); + register_bin_prim "caml_gt_float" `Pure (fun cx cy _ -> + bool (J.EBin (J.FloatLt, cy, cx))); + register_bin_prim "caml_lt_float" `Pure (fun cx cy _ -> + bool (J.EBin (J.FloatLt, cx, cy))); + register_bin_prim "caml_add_float" `Pure (fun cx cy _ -> J.EBin (J.FloatPlus, cx, cy)); + register_bin_prim "caml_sub_float" `Pure (fun cx cy _ -> J.EBin (J.FloatMinus, cx, cy)); + register_bin_prim "caml_mul_float" `Pure (fun cx cy _ -> J.EBin (J.FloatMul, cx, cy)); + register_bin_prim "caml_div_float" `Pure (fun cx cy _ -> J.EBin (J.FloatDiv, cx, cy)); + register_un_prim "caml_neg_float" `Pure (fun cx _ -> J.EUn (J.FloatNeg, cx)); + register_bin_prim "caml_fmod_float" `Pure (fun cx cy _ -> J.EBin (J.FloatMod, cx, cy)); register_tern_prim "caml_array_unsafe_set" (fun cx cy cz _ -> - J.EBin (J.Eq, Mlvalue.Array.field cx cy, cz)); + J.EBin (J.Eq, J.EArrAccess (cx, plus_int one cy), cz)); register_un_prim "caml_alloc_dummy" `Pure (fun _ _ -> J.EArr []); register_un_prim "caml_obj_dup" `Mutable (fun cx loc -> J.ECall (J.EDot (cx, "slice"), [], loc)); - register_un_prim "caml_int_of_float" `Pure (fun cx _loc -> to_int cx); + register_un_prim "caml_int_of_float" `Pure (fun cx _loc -> J.EUn (J.FloatToInt, cx)); + register_un_prim "caml_float_of_int" `Pure (fun cx _loc -> J.EUn (J.IntToFloat, cx)); register_un_math_prim "caml_abs_float" "abs"; register_un_math_prim "caml_acos_float" "acos"; register_un_math_prim "caml_asin_float" "asin"; @@ -995,7 +1004,7 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = let prop = or_p prop prop' in let e = apply_fun ctx f args loc in (e, prop, queue), [] - | Block (tag, a, array_or_not) -> + | Block (tag, a, _array_or_not) -> let contents, prop, queue = List.fold_right ~f:(fun x (args, prop, queue) -> @@ -1004,24 +1013,19 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = (Array.to_list a) ~init:([], const_p, queue) in - let x = - match array_or_not with - | Array -> Mlvalue.Array.make ~tag ~args:contents - | NotArray | Unknown -> Mlvalue.Block.make ~tag ~args:contents - in - (x, prop, queue), [] + (J.ETag (tag, contents), prop, queue), [] | Field (x, n) -> let (px, cx), queue = access_queue queue x in - (Mlvalue.Block.field cx n, or_p px mutable_p, queue), [] + (J.EStructAccess (cx, n + 1), or_p px mutable_p, queue), [] | Closure (args, ((pc, _) as cont)) -> let loc = source_location ctx ~after:true pc in let clo = compile_closure ctx cont in let clo = match clo with - | (st, J.N) :: rem -> (st, J.U) :: rem + | (st, Loc.N) :: rem -> (st, Loc.U) :: rem | _ -> clo in - let clo = J.EFun (None, List.map args ~f:(fun v -> J.V v), clo, loc) in + let clo = J.EFun (None, List.map args ~f:(fun v -> Id.V v), clo, loc) in (clo, flush_p, queue), [] | Constant c -> let js, instrs = constant ~ctx c level in @@ -1036,47 +1040,23 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = match p, l with | Vectlength, [ x ] -> let (px, cx), queue = access_queue' ~ctx queue x in - Mlvalue.Array.length cx, px, queue + J.EVectlength cx, px, queue | Array_get, [ x; y ] -> let (px, cx), queue = access_queue' ~ctx queue x in let (py, cy), queue = access_queue' ~ctx queue y in - Mlvalue.Array.field cx cy, or_p mutable_p (or_p px py), queue + J.EArrAccess (cx, plus_int one cy), or_p mutable_p (or_p px py), queue | Extern "caml_js_var", [ Pc (String nm | IString nm) ] | Extern ("caml_js_expr" | "caml_pure_js_expr"), [ Pc (String nm | IString nm) ] -> ( try - let lexbuf = Lexing.from_string nm in - let lexbuf = - match loc with - | J.N | J.U -> lexbuf - | J.Pi pi -> ( - (* [pi] is the position of the call, not the - string. We don't have enough information to - recover the start column *) - match pi.src with - | Some pos_fname -> - { lexbuf with - lex_curr_p = - { pos_fname - ; pos_lnum = pi.line - ; pos_cnum = pi.idx - ; pos_bol = pi.idx - } - } - | None -> lexbuf) - in - let lex = Parse_js.Lexer.of_lexbuf lexbuf in - let e = Parse_js.parse_expr lex in + let e = J.ERaw nm in e, const_p, queue with Parse_js.Parsing_error pi -> failwith (Printf.sprintf - "Parsing error %S%s at l:%d col:%d" + "Parsing error %S at l:%d col:%d" nm - (match pi.Parse_info.src with - | None -> "" - | Some s -> Printf.sprintf ", file %S" s) - pi.Parse_info.line + (pi.Parse_info.line + 1) pi.Parse_info.col)) | Extern "%js_array", l -> let args, prop, queue = @@ -1131,23 +1111,24 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = List.fold_right ~f:(fun x (args, prop, queue) -> let (prop', cx), queue = access_queue' ~ctx queue x in - (cx, `Not_spread) :: args, or_p prop prop', queue) + cx :: args, or_p prop prop', queue) l ~init:([], mutator_p, queue) in ( J.ENew (cc, if List.is_empty args then None else Some args) , or_p pc prop , queue ) - | Extern "caml_js_get", [ Pv o; Pc (String f | IString f) ] when J.is_ident f -> + | Extern "caml_js_get", [ Pv o; Pc (String f | IString f) ] + when Javascript.is_ident f -> let (po, co), queue = access_queue queue o in J.EDot (co, f), or_p po mutable_p, queue - | Extern "caml_js_set", [ Pv o; Pc (String f | IString f); v ] when J.is_ident f - -> + | Extern "caml_js_set", [ Pv o; Pc (String f | IString f); v ] + when Javascript.is_ident f -> let (po, co), queue = access_queue queue o in let (pv, cv), queue = access_queue' ~ctx queue v in J.EBin (J.Eq, J.EDot (co, f), cv), or_p (or_p po pv) mutator_p, queue - | Extern "caml_js_delete", [ Pv o; Pc (String f | IString f) ] when J.is_ident f - -> + | Extern "caml_js_delete", [ Pv o; Pc (String f | IString f) ] + when Javascript.is_ident f -> let (po, co), queue = access_queue queue o in J.EUn (J.Delete, J.EDot (co, f)), or_p po mutator_p, queue | Extern "%overrideMod", [ Pc (String m | IString m); Pc (String f | IString f) ] @@ -1161,7 +1142,7 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = | Pc (String nm | IString nm) :: x :: r -> let (prop, cx), queue = access_queue' ~ctx queue x in let prop', r', queue = build_fields queue r in - or_p prop prop', (J.PNS nm, cx) :: r', queue + or_p prop prop', (nm, cx) :: r', queue | _ -> assert false in let prop, fields, queue = build_fields queue fields in @@ -1170,17 +1151,20 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = let i, queue = let (_px, cx), queue = access_queue' ~ctx queue size in match cx with - | J.ENum i -> Int32.to_int (J.Num.to_int32 i), queue + | J.EInt i -> i, queue | _ -> assert false in - let args = Array.to_list (Array.init i ~f:(fun _ -> J.V (Var.fresh ()))) in - let f = J.V (Var.fresh ()) in + let args = Array.to_list (Array.init i ~f:(fun _ -> Id.V (Var.fresh ()))) in + let f = Id.V (Var.fresh ()) in let call = ecall (J.EDot (J.EVar f, "fun")) (List.map args ~f:(fun v -> J.EVar v)) loc in let e = J.EFun - (Some f, args, [ J.Statement (J.Return_statement (Some call)), J.N ], J.N) + ( Some f + , args + , [ J.Statement (J.Return_statement (Some call)), Loc.N ] + , Loc.N ) in e, const_p, queue | Extern "caml_alloc_dummy_function", _ -> assert false @@ -1223,7 +1207,7 @@ let rec translate_expr ctx queue loc _x e level : _ * J.statement_list = bool (J.EBin (J.NotEqEq, cx, cy)), or_p px py, queue | IsInt, [ x ] -> let (px, cx), queue = access_queue' ~ctx queue x in - bool (Mlvalue.is_immediate cx), px, queue + bool (is_int cx), px, queue | Ult, [ x; y ] -> let (px, cx), queue = access_queue' ~ctx queue x in let (py, cy), queue = access_queue' ~ctx queue y in @@ -1261,28 +1245,21 @@ and translate_instr ctx expr_queue loc instr = flush_queue expr_queue prop - (instrs @ [ J.Variable_statement [ J.V x, Some (ce, loc) ], loc ])) + (instrs @ [ J.Variable_statement [ Id.V x, Some (ce, loc) ], loc ])) | Set_field (x, n, y) -> let (_px, cx), expr_queue = access_queue expr_queue x in let (_py, cy), expr_queue = access_queue expr_queue y in flush_queue expr_queue mutator_p - [ J.Expression_statement (J.EBin (J.Eq, Mlvalue.Block.field cx n, cy)), loc ] - | Offset_ref (x, 1) -> - (* FIX: may overflow.. *) - let (_px, cx), expr_queue = access_queue expr_queue x in - flush_queue - expr_queue - mutator_p - [ J.Expression_statement (J.EUn (J.IncrA, Mlvalue.Block.field cx 0)), loc ] + [ J.Expression_statement (J.EBin (J.Eq, J.EStructAccess (cx, n + 1), cy)), loc ] | Offset_ref (x, n) -> (* FIX: may overflow.. *) let (_px, cx), expr_queue = access_queue expr_queue x in flush_queue expr_queue mutator_p - [ J.Expression_statement (J.EBin (J.PlusEq, Mlvalue.Block.field cx 0, int n)), loc + [ J.Expression_statement (J.EBin (J.PlusEq, J.EStructAccess (cx, 1), int n)), loc ] | Array_set (x, y, z) -> let (_px, cx), expr_queue = access_queue expr_queue x in @@ -1291,7 +1268,9 @@ and translate_instr ctx expr_queue loc instr = flush_queue expr_queue mutator_p - [ J.Expression_statement (J.EBin (J.Eq, Mlvalue.Array.field cx cy, cz)), loc ] + [ ( J.Expression_statement (J.EBin (J.Eq, J.EArrAccess (cx, plus_int one cy), cz)) + , loc ) + ] and translate_instrs ctx expr_queue loc instr = match instr with @@ -1321,8 +1300,8 @@ and compile_block st queue (pc : Addr.t) frontier interm = then let lab = match st.loop_stack with - | (_, (l, _)) :: _ -> J.Label.succ l - | [] -> J.Label.zero + | (_, (l, _)) :: _ -> Javascript.Label.succ l + | [] -> Javascript.Label.zero in st.loop_stack <- (pc, (lab, ref false)) :: st.loop_stack); let succs = Hashtbl.find st.succs pc in @@ -1439,15 +1418,15 @@ and compile_block st queue (pc : Addr.t) frontier interm = ( J.Expression_statement (J.EBin ( J.Eq - , J.EVar (J.V x) + , J.EVar (Id.V x) , ecall (Share.get_prim (runtime_fun st.ctx) "caml_wrap_exception" st.ctx.Ctx.share) - [ J.EVar (J.V x) ] - J.N )) - , J.N ) + [ J.EVar (Id.V x) ] + Loc.N )) + , Loc.N ) :: handler else handler in @@ -1455,13 +1434,12 @@ and compile_block st queue (pc : Addr.t) frontier interm = match exn_escape with | Some x' -> handler - @ [ J.Variable_statement [ J.V x', Some (EVar (J.V x), J.N) ], J.N ] + @ [ J.Variable_statement [ Id.V x', Some (EVar (Id.V x), Loc.N) ], Loc.N ] | None -> handler in flush_all queue - (( J.Try_statement (body, Some (J.V x, handler), None) - , source_location st.ctx pc ) + ((J.Try_statement (body, (Id.V x, handler)), source_location st.ctx pc) :: after) | _ -> let prefix, new_frontier, new_interm = @@ -1502,24 +1480,22 @@ and compile_block st queue (pc : Addr.t) frontier interm = | [] -> assert false in let st = - ( J.For_statement - ( J.Left None - , None - , None - , Js_simpl.block + ( J.Loop_statement + ( J.Block (if Addr.Set.cardinal frontier > 0 then ( if debug () then Format.eprintf "@ break (%d); }@]" (Addr.Set.choose new_frontier); - body @ [ J.Break_statement None, J.N ]) + body @ [ J.Break_statement None, Loc.N ]) else ( if debug () then Format.eprintf "}@]"; - body)) ) + body)) + , Loc.N ) , source_location st.ctx pc ) in match label with | None -> [ st ] - | Some label -> [ J.Labelled_statement (label, st), J.N ] + | Some label -> [ J.Labelled_statement (label, st), Loc.N ] else body) and colapse_frontier st new_frontier interm = @@ -1563,7 +1539,7 @@ and colapse_frontier st new_frontier interm = Addr.Set.iter (fun pc -> protect_preds st pc) new_frontier; Hashtbl.add st.succs idx (Addr.Set.elements new_frontier); Hashtbl.add st.backs idx Addr.Set.empty; - ( [ J.Variable_statement [ J.V x, Some (int default, J.N) ], J.N ] + ( [ J.Variable_statement [ Id.V x, Some (int default, Loc.N) ], Loc.N ] , Addr.Set.singleton idx , List.fold_right pc_i ~init:interm ~f:(fun (pc, i) interm -> Addr.Map.add pc (idx, (x, i, default = i)) interm) )) @@ -1613,7 +1589,7 @@ and compile_decision_tree st _queue handler backs frontier interm succs loc cx d let cont = if never || (* default case *) i = last_index then cont - else cont @ [ J.Break_statement None, J.N ] + else cont @ [ J.Break_statement None, Loc.N ] in ints, cont) in @@ -1624,14 +1600,14 @@ and compile_decision_tree st _queue handler backs frontier interm succs loc cx d (List.map l ~f:(fun (ints, br) -> map_last (fun last i -> int i, if last then br else []) ints)) in - !all_never, [ J.Switch_statement (cx, l, Some last, []), loc ] + !all_never, [ J.Switch_statement (cx, l, last), loc ] in let cx, binds = match cx with | (J.EVar _ | _) when DTree.nbcomp dtree <= 1 -> cx, [] | _ -> - let v = J.V (Code.Var.fresh ()) in - J.EVar v, [ J.Variable_statement [ v, Some (cx, J.N) ], J.N ] + let v = Id.V (Code.Var.fresh ()) in + J.EVar v, [ J.Variable_statement [ v, Some (cx, Loc.N) ], Loc.N ] in binds @ snd (loop cx dtree) @@ -1688,7 +1664,7 @@ and compile_conditional st queue pc last handler backs frontier interm succs = interm succs loc - (Mlvalue.Block.tag cx) + (J.EStructAccess (cx, 0)) (DTree.build_switch a2) in flush_all queue code @@ -1734,12 +1710,12 @@ and compile_conditional st queue pc last handler backs frontier interm succs = interm succs loc - (Mlvalue.Block.tag (var x)) + (J.EStructAccess (var x, 0)) (DTree.build_switch a2) in let code = Js_simpl.if_statement - (Mlvalue.is_immediate (var x)) + (is_int (var x)) loc (Js_simpl.block b1) false @@ -1811,7 +1787,7 @@ and compile_exn_handling ctx queue (pc, args) handler continuation = queue px [ (let loc = source_location ctx pc in - J.Variable_statement [ J.V y, Some (cx, loc) ], loc) + J.Variable_statement [ Id.V y, Some (cx, loc) ], loc) ] in st @ loop continuation old args params queue @@ -1840,7 +1816,7 @@ and compile_branch st queue ((pc, _) as cont) handler backs frontier interm = if Option.is_none label then Format.eprintf "continue;@ " else Format.eprintf "continue (%d);@ " pc; - flush_all queue [ J.Continue_statement label, J.N ]) + flush_all queue [ J.Continue_statement label, Loc.N ]) else if Addr.Set.mem pc frontier || Addr.Map.mem pc interm then ( if debug () then Format.eprintf "(br %d)@ " pc; @@ -1854,7 +1830,7 @@ and compile_branch_selection pc interm = let branch = compile_branch_selection pc interm in if default then branch - else (J.Expression_statement (EBin (Eq, EVar (J.V x), int i)), J.N) :: branch + else (J.Expression_statement (EBin (Eq, EVar (Id.V x), int i)), Loc.N) :: branch with Not_found -> [] and compile_closure ctx (pc, args) = @@ -1891,16 +1867,14 @@ let generate_shared_value ctx = (J.Variable_statement ((match ctx.Ctx.exported_runtime with | None -> [] - | Some v -> - [ J.V v, Some (J.EDot (s_var Constant.global_object, "jsoo_runtime"), J.N) - ]) + | Some v -> [ Id.V v, Some (J.ERuntime, Loc.N) ]) @ List.map (StringMap.bindings ctx.Ctx.share.Share.vars.Share.strings) - ~f:(fun (s, v) -> v, Some (str_js s, J.N)) + ~f:(fun (s, v) -> v, Some (str_js s, Loc.N)) @ List.map (StringMap.bindings ctx.Ctx.share.Share.vars.Share.prims) - ~f:(fun (s, v) -> v, Some (runtime_fun ctx s, J.N)))) - , J.U ) + ~f:(fun (s, v) -> v, Some (runtime_fun ctx s, Loc.N)))) + , Loc.U ) in if not (Config.Flag.inline_callgen ()) then @@ -1908,7 +1882,7 @@ let generate_shared_value ctx = List.map (IntMap.bindings ctx.Ctx.share.Share.vars.Share.applies) ~f:(fun (n, v) -> match generate_apply_fun ctx n with | J.EFun (_, param, body, nid) -> - J.Function_declaration (v, param, body, nid), J.U + J.Function_declaration (v, param, body, nid), Loc.U | _ -> assert false) in strings :: applies diff --git a/compiler/lib/generate.mli b/compiler/lib/generate.mli index 5aa72939dd..4b5168facc 100644 --- a/compiler/lib/generate.mli +++ b/compiler/lib/generate.mli @@ -23,4 +23,4 @@ val f : -> exported_runtime:bool -> live_vars:int array -> Parse_bytecode.Debug.t - -> Javascript.program + -> Ir.program diff --git a/compiler/lib/id.ml b/compiler/lib/id.ml new file mode 100644 index 0000000000..0d90b7e088 --- /dev/null +++ b/compiler/lib/id.ml @@ -0,0 +1,34 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +type identifier = string + +type ident_string = + { name : identifier + ; var : Code.Var.t option + ; loc : Loc.t + } + +type t = + | S of ident_string + | V of Code.Var.t + +let ident = + (fun ?(loc = N) ?var name -> S { name; var; loc } + : ?loc:Loc.t -> ?var:Code.Var.t -> identifier -> t) diff --git a/compiler/lib/id.mli b/compiler/lib/id.mli new file mode 100644 index 0000000000..1c08c33a2a --- /dev/null +++ b/compiler/lib/id.mli @@ -0,0 +1,32 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +type identifier = string + +type ident_string = + { name : identifier + ; var : Code.Var.t option + ; loc : Loc.t + } + +type t = + | S of ident_string + | V of Code.Var.t + +val ident : ?loc:Loc.t -> ?var:Code.Var.t -> identifier -> t diff --git a/compiler/lib/ir.ml b/compiler/lib/ir.ml new file mode 100644 index 0000000000..ccebbc8f6e --- /dev/null +++ b/compiler/lib/ir.ml @@ -0,0 +1,158 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +open Stdlib + +type array_literal = element_list + +and element_list = expression option list + +and binop = + | Eq + | StarEq + | SlashEq + | ModEq + | PlusEq + | MinusEq + | Or + | And + | Bor + | Bxor + | Band + | EqEq + | NotEq + | EqEqEq + | NotEqEq + | InstanceOf + | Lsl + | Lsr + | Asr + | Plus + | Minus + | Mul + | Div + | Mod + | Lt + | Le + | Gt + | Ge + | FloatPlus + | FloatMinus + | FloatMul + | FloatDiv + | FloatMod + | FloatLt + | FloatLe + | FloatGt + | FloatGe + | FloatEqEq + | FloatNotEq + +and unop = + | Not + | Neg + | FloatNeg + | Typeof + | IsInt + | ToInt + | ToBool + | IntToString + | FloatToInt + | IntToFloat + | Void + | Delete + | Bnot + +and arguments = expression list + +and property_name_and_value_list = (Id.identifier * expression) list + +and expression = + | ERaw of string + | ESeq of expression * expression + | ECond of expression * expression * expression + | EBin of binop * expression * expression + | EUn of unop * expression + | ECall of expression * arguments * Loc.t + | ECopy of expression * Loc.t + | EVar of Id.t + | EFun of function_expression + | EArityTest of expression + | EStr of string * [ `Bytes | `Utf8 ] + | EVectlength of expression + | EArrAccess of expression * expression + | EArrLen of expression + | EArr of array_literal + | EStructAccess of expression * int + | EStruct of arguments + | ETag of int * arguments + | EDot of expression * Id.identifier + | EAccess of expression * expression + | ENew of expression * arguments option + | EObj of property_name_and_value_list + | EBool of bool + | EFloat of float + | EInt of int + | EQuote of string + | ERegexp of string * string option + | ERuntime + +and statement = + | Block of block + | Variable_statement of variable_declaration list + | Empty_statement + | Expression_statement of expression + | If_statement of expression * (statement * Loc.t) * (statement * Loc.t) option + | Loop_statement of statement * Loc.t + | Continue_statement of Javascript.Label.t option + | Break_statement of Javascript.Label.t option + | Return_statement of expression option + | Labelled_statement of Javascript.Label.t * (statement * Loc.t) + | Switch_statement of expression * case_clause list * statement_list + | Throw_statement of expression + | Try_statement of block * (Id.t * block) + | Debugger_statement + +and block = statement_list + +and statement_list = (statement * Loc.t) list + +and variable_declaration = Id.t * initialiser option + +and case_clause = expression * statement_list + +and initialiser = expression * Loc.t + +and var_info = (int StringMap.t * int Code.Var.Map.t) option + +and function_declaration = Id.t * formal_parameter_list * function_body * Loc.t + +and function_expression = Id.t option * formal_parameter_list * function_body * Loc.t + +and formal_parameter_list = Id.t list + +and function_body = source_elements + +and program = source_elements + +and source_elements = (source_element * Loc.t) list + +and source_element = + | Statement of statement + | Function_declaration of function_declaration diff --git a/compiler/lib/ir.mli b/compiler/lib/ir.mli new file mode 100644 index 0000000000..2995b1445f --- /dev/null +++ b/compiler/lib/ir.mli @@ -0,0 +1,168 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) + +(* + * IR: A constrained intermediate language to model various language backends. + * + * IR has semantics similar to a very narrow subset of JavaScript, with the + * addition of special nodes that track types, externs, and different shapes of + * structures emitted by the ocaml compiler. + * + *) + +open Stdlib + +type array_literal = element_list + +and element_list = expression option list + +and binop = + | Eq + | StarEq + | SlashEq + | ModEq + | PlusEq + | MinusEq + | Or + | And + | Bor + | Bxor + | Band + | EqEq + | NotEq + | EqEqEq + | NotEqEq + | InstanceOf + | Lsl + | Lsr + | Asr + | Plus + | Minus + | Mul + | Div + | Mod + | Lt + | Le + | Gt + | Ge + | FloatPlus + | FloatMinus + | FloatMul + | FloatDiv + | FloatMod + | FloatLt + | FloatLe + | FloatGt + | FloatGe + | FloatEqEq + | FloatNotEq + +and unop = + | Not + | Neg + | FloatNeg + | Typeof + | IsInt + | ToInt + | ToBool + | IntToString + | FloatToInt + | IntToFloat + | Void + | Delete + | Bnot + +and arguments = expression list + +and property_name_and_value_list = (Id.identifier * expression) list + +and expression = + | ERaw of string + | ESeq of expression * expression + | ECond of expression * expression * expression + | EBin of binop * expression * expression + | EUn of unop * expression + | ECall of expression * arguments * Loc.t + | ECopy of expression * Loc.t + | EVar of Id.t + | EFun of function_expression + | EArityTest of expression + | EStr of string * [ `Bytes | `Utf8 ] + | EVectlength of expression + | EArrAccess of expression * expression + | EArrLen of expression + | EArr of array_literal + | EStructAccess of expression * int + | EStruct of arguments + | ETag of int * arguments + | EDot of expression * Id.identifier + | EAccess of expression * expression + | ENew of expression * arguments option + | EObj of property_name_and_value_list + | EBool of bool + | EFloat of float + | EInt of int + | EQuote of string + | ERegexp of string * string option + | ERuntime + +and statement = + | Block of block + | Variable_statement of variable_declaration list + | Empty_statement + | Expression_statement of expression + | If_statement of expression * (statement * Loc.t) * (statement * Loc.t) option + | Loop_statement of statement * Loc.t + | Continue_statement of Javascript.Label.t option + | Break_statement of Javascript.Label.t option + | Return_statement of expression option + | Labelled_statement of Javascript.Label.t * (statement * Loc.t) + | Switch_statement of expression * case_clause list * statement_list + | Throw_statement of expression + | Try_statement of block * (Id.t * block) + | Debugger_statement + +and block = statement_list + +and statement_list = (statement * Loc.t) list + +and variable_declaration = Id.t * initialiser option + +and case_clause = expression * statement_list + +and initialiser = expression * Loc.t + +and var_info = (int StringMap.t * int Code.Var.Map.t) option + +and function_declaration = Id.t * formal_parameter_list * function_body * Loc.t + +and function_expression = Id.t option * formal_parameter_list * function_body * Loc.t + +and formal_parameter_list = Id.t list + +and function_body = source_elements + +and program = source_elements + +and source_elements = (source_element * Loc.t) list + +and source_element = + | Statement of statement + | Function_declaration of function_declaration diff --git a/compiler/lib/javascript.ml b/compiler/lib/javascript.ml index 16f7b49e58..5cc4793088 100644 --- a/compiler/lib/javascript.ml +++ b/compiler/lib/javascript.ml @@ -18,86 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) open! Stdlib - -module Num : sig - type t - - (** Conversions *) - - val of_string_unsafe : string -> t - - val of_int32 : int32 -> t - - val of_float : float -> t - - val to_string : t -> string - - val to_int32 : t -> int32 - - (** Predicates *) - - val is_zero : t -> bool - - val is_one : t -> bool - - val is_neg : t -> bool - - (** Arithmetic *) - - val add : t -> t -> t - - val neg : t -> t -end = struct - type t = string - - let of_string_unsafe s = s - - let to_string s = s - - let to_int32 s = - if String.is_prefix s ~prefix:"0" - && String.length s > 1 - && String.for_all s ~f:(function - | '0' .. '7' -> true - | _ -> false) - then (* octal notation *) - Int32.of_string ("0o" ^ s) - else Int32.of_string s - - let of_int32 = Int32.to_string - - let of_float v = - match Float.classify_float v with - | FP_nan -> "NaN" - | FP_zero -> - (* [1/-0] < 0. seems to be the only way to detect -0 in JavaScript *) - if Float.(1. /. v < 0.) then "-0." else "0." - | FP_infinite -> if Float.(v < 0.) then "-Infinity" else "Infinity" - | FP_normal | FP_subnormal -> - let vint = int_of_float v in - if Float.equal (float_of_int vint) v - then Printf.sprintf "%d." vint - else - let s1 = Printf.sprintf "%.12g" v in - if Float.equal v (float_of_string s1) - then s1 - else - let s2 = Printf.sprintf "%.15g" v in - if Float.equal v (float_of_string s2) then s2 else Printf.sprintf "%.18g" v - - let is_zero s = String.equal s "0" - - let is_one s = String.equal s "1" - - let is_neg s = Char.equal s.[0] '-' - - let neg s = - match String.drop_prefix s ~prefix:"-" with - | None -> "-" ^ s - | Some s -> s - - let add a b = of_int32 (Int32.add (to_int32 a) (to_int32 b)) -end +module Num = Num module Label = struct type t = @@ -119,21 +40,21 @@ module Label = struct let of_string s = S s end -type location = +type location = Loc.t = | Pi of Parse_info.t | N | U type identifier = string -type ident_string = +type ident_string = Id.ident_string = { name : identifier ; var : Code.Var.t option ; loc : location } -type ident = - | S of ident_string +type ident = Id.t = + | S of Id.ident_string | V of Code.Var.t (* A.3 Expressions *) @@ -206,6 +127,7 @@ and property_name = | PNN of Num.t and expression = + | ERaw of string | ESeq of expression * expression | ECond of expression * expression * expression | EBin of binop * expression * expression diff --git a/compiler/lib/javascript.mli b/compiler/lib/javascript.mli index 106bfd45dd..6a3cb83484 100644 --- a/compiler/lib/javascript.mli +++ b/compiler/lib/javascript.mli @@ -18,35 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -module Num : sig - type t - - (** Conversions *) - - val of_string_unsafe : string -> t - - val of_int32 : int32 -> t - - val of_float : float -> t - - val to_string : t -> string - - val to_int32 : t -> int32 - - (** Predicates *) - - val is_zero : t -> bool - - val is_one : t -> bool - - val is_neg : t -> bool - - (** Arithmetic *) - - val add : t -> t -> t - - val neg : t -> t -end +module Num = Num module Label : sig type t @@ -60,7 +32,7 @@ module Label : sig val of_string : string -> t end -type location = +type location = Loc.t = | Pi of Parse_info.t | N (* No location; use the one above *) @@ -72,14 +44,14 @@ type location = type identifier = string -type ident_string = +type ident_string = Id.ident_string = { name : identifier ; var : Code.Var.t option ; loc : location } -type ident = - | S of ident_string +type ident = Id.t = + | S of Id.ident_string | V of Code.Var.t and array_litteral = element_list @@ -151,6 +123,7 @@ and property_name = | PNN of Num.t and expression = + | ERaw of string | ESeq of expression * expression | ECond of expression * expression * expression | EBin of binop * expression * expression diff --git a/compiler/lib/javascript_from_ir.ml b/compiler/lib/javascript_from_ir.ml new file mode 100644 index 0000000000..99de7d099d --- /dev/null +++ b/compiler/lib/javascript_from_ir.ml @@ -0,0 +1,190 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +open Javascript +open! Stdlib + +module Expand = struct + let isIntCheck jsExpr = EBin (EqEqEq, EUn (Typeof, jsExpr), EStr ("number", `Bytes)) + + let toInt jsExpr = EBin (Bor, jsExpr, ENum (Num.of_int32 0l)) + + let intToString jsExpr = EBin (Plus, EStr ("", `Bytes), jsExpr) +end + +let rec from_statement_list lst = + List.map ~f:(fun (stmt, loc) -> from_statement stmt, loc) lst + +and from_arguments args = List.map ~f:(fun x -> from_expression x, `Not_spread) args + +and from_unop unop jsExpr = + match unop with + | Ir.Not -> EUn (Javascript.Not, jsExpr) + | IsInt -> Expand.isIntCheck jsExpr + | ToBool | FloatToInt | ToInt -> Expand.toInt jsExpr + | IntToFloat -> jsExpr + | IntToString -> Expand.intToString jsExpr + | FloatNeg | Neg -> EUn (Javascript.Neg, jsExpr) + | Typeof -> EUn (Javascript.Typeof, jsExpr) + | Void -> EUn (Javascript.Void, jsExpr) + | Delete -> EUn (Javascript.Delete, jsExpr) + | Bnot -> EUn (Javascript.Bnot, jsExpr) + +and from_binop = function + | Ir.Eq -> Javascript.Eq + | StarEq -> StarEq + | SlashEq -> SlashEq + | ModEq -> ModEq + | PlusEq -> PlusEq + | MinusEq -> MinusEq + | Or -> Or + | And -> And + | Bor -> Bor + | Bxor -> Bxor + | Band -> Band + | EqEq -> EqEq + | NotEq -> NotEq + | FloatEqEq -> EqEq + | FloatNotEq -> NotEq + | EqEqEq -> EqEqEq + | NotEqEq -> NotEqEq + | Lt -> Lt + | Le -> Le + | Gt -> Gt + | Ge -> Ge + | FloatLt -> Lt + | FloatLe -> Le + | FloatGt -> Gt + | FloatGe -> Ge + | InstanceOf -> InstanceOf + | Lsl -> Lsl + | Lsr -> Lsr + | Asr -> Asr + | Plus -> Plus + | FloatPlus -> Plus + | Minus -> Minus + | FloatMinus -> Minus + | Mul -> Mul + | FloatMul -> Mul + | Div -> Div + | FloatDiv -> Div + | Mod -> Mod + | FloatMod -> Mod + +and from_expression_loc (e, loc) = from_expression e, loc + +and from_expression e = + match e with + | Ir.ERaw s -> Javascript.ERaw s + | Ir.ESeq (e1, e2) -> Javascript.ESeq (from_expression e1, from_expression e2) + | ETag (index, itms) -> + Javascript.EArr + (Some (Javascript.ENum (Num.of_int32 (Int32.of_int index))) + :: List.map ~f:(fun itm -> Some (from_expression itm)) itms) + | EStruct itms -> + Javascript.EArr (List.map ~f:(fun itm -> Some (from_expression itm)) itms) + | EAccess (e1, e2) -> Javascript.EAccess (from_expression e1, from_expression e2) + | EStructAccess (e, i) -> + Javascript.EAccess + (from_expression e, Javascript.ENum (Num.of_int32 (Int32.of_int i))) + | EArrAccess (e1, e2) -> Javascript.EAccess (from_expression e1, from_expression e2) + | EVectlength e -> + EBin (Minus, EDot (from_expression e, "length"), ENum (Num.of_int32 1l)) + | EArrLen e -> EDot (from_expression e, "length") + | EArityTest e -> EDot (from_expression e, "length") + | ECond (e1, e2, e3) -> + ECond (from_expression e1, from_expression e2, from_expression e3) + | EBin (binop, e1, e2) -> EBin (from_binop binop, from_expression e1, from_expression e2) + | EUn (unop, e) -> from_unop unop (from_expression e) + | ECall (e, args, loc) -> ECall (from_expression e, from_arguments args, loc) + | ECopy (e, loc) -> ECall (EDot (from_expression e, "slice"), [], loc) + | EVar ident -> EVar ident + | EFun (ident_opt, ident_lst, body, loc) -> + EFun (ident_opt, ident_lst, from_source_elements_and_locs body, loc) + | EStr (x, y) -> EStr (x, y) + | EArr arr_literal -> + EArr (List.map ~f:(Stdlib.Option.map ~f:from_expression) arr_literal) + | EDot (e, ident) -> EDot (from_expression e, ident) + | ENew (e, optargs) -> + ENew (from_expression e, Stdlib.Option.map ~f:from_arguments optargs) + | EObj lst -> EObj (List.map ~f:(fun (nm, e) -> PNS nm, from_expression e) lst) + | EBool b -> EBool b + | EFloat flt -> ENum (Num.of_float flt) + | EInt i -> ENum (Num.of_int32 (Int32.of_int i)) + | EQuote s -> EQuote s + | ERegexp (s, sopt) -> ERegexp (s, sopt) + | ERuntime -> EDot (EVar (Id.ident Constant.global_object), "jsoo_runtime") + +and from_statement e = + match e with + | Ir.Block stms -> Block (from_statement_list stms) + | Ir.Variable_statement lst -> + Javascript.Variable_statement + (List.map + ~f:(fun (ident, initopt) -> + ident, Stdlib.Option.map ~f:from_expression_loc initopt) + lst) + | Ir.Empty_statement -> Empty_statement + | Ir.Expression_statement expr -> Expression_statement (from_expression expr) + | Ir.If_statement (expr, (ifstmt, ifloc), elsopt) -> + If_statement + ( from_expression expr + , (from_statement ifstmt, ifloc) + , match elsopt with + | None -> None + | Some (elstmt, elloc) -> Some (from_statement elstmt, elloc) ) + | Ir.Loop_statement (stmt, loc) -> + For_statement (Left None, None, None, (from_statement stmt, loc)) + | Ir.Continue_statement lbl -> Continue_statement lbl + | Ir.Break_statement lbl -> Break_statement lbl + | Ir.Return_statement eo -> Return_statement (Stdlib.Option.map ~f:from_expression eo) + | Ir.Labelled_statement (lbl, (stmt, loc)) -> + Labelled_statement (lbl, (from_statement stmt, loc)) + | Ir.Switch_statement (e, case_clause_list, stmt_lst) -> + let e = from_expression e in + let case_clause_lst = from_case_clause_list case_clause_list in + let stmt_lst = + match stmt_lst with + | [] -> None + | _ -> Some (from_statement_list stmt_lst) + in + Switch_statement (e, case_clause_lst, stmt_lst, []) + | Ir.Throw_statement e -> Throw_statement (from_expression e) + | Ir.Try_statement (b1, (ident, b2)) -> + let b1 = from_statement_list b1 in + let ident_block = ident, from_statement_list b2 in + Try_statement (b1, Some ident_block, None) + | Ir.Debugger_statement -> Debugger_statement + +and from_case_clause_list lst = + List.map ~f:(fun (e, stmts) -> from_expression e, from_statement_list stmts) lst + +and from_source_element = function + | Ir.Statement stmt -> Statement (from_statement stmt) + | Ir.Function_declaration (ident, formal_parameter_list, function_body, location) -> + Javascript.Function_declaration + ( ident + , formal_parameter_list + , from_source_elements_and_locs function_body + , location ) + +and from_source_elements_and_locs lst = + List.map ~f:(fun (src, loc) -> from_source_element src, loc) lst + +let run = from_source_elements_and_locs diff --git a/compiler/lib/javascript_from_ir.mli b/compiler/lib/javascript_from_ir.mli new file mode 100644 index 0000000000..f100d7f29b --- /dev/null +++ b/compiler/lib/javascript_from_ir.mli @@ -0,0 +1,20 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +val run : Ir.program -> Javascript.program diff --git a/compiler/lib/js_output.ml b/compiler/lib/js_output.ml index e750634fc3..a6fa1b49e7 100644 --- a/compiler/lib/js_output.ml +++ b/compiler/lib/js_output.ml @@ -275,6 +275,7 @@ struct let rec need_paren l e = match e with + | ERaw _ -> true | ESeq (e, _) -> l <= 0 && need_paren 0 e | ECond (e, _, _) -> l <= 2 && need_paren 3 e | EBin (op, e, _) -> @@ -340,6 +341,7 @@ struct let rec expression l f e = match e with + | ERaw s -> PP.string f s | EVar v -> ident f v | ESeq (e1, e2) -> if l > 0 @@ -1005,6 +1007,21 @@ struct last_semi (); PP.end_group f; PP.end_group f + (* Because raw macros can have newlines in them, we should always make + * sure a return has a guarding paren immediately after it *) + | Some (ERaw s) -> + PP.start_group f 0; + PP.string f "return"; + PP.non_breaking_space f; + PP.string f "("; + PP.start_group f 2; + PP.break f; + expression 1 f (ERaw s); + PP.end_group f; + PP.break f; + PP.string f ")"; + last_semi (); + PP.end_group f | Some e -> PP.start_group f 7; PP.string f "return"; diff --git a/compiler/lib/js_simpl.ml b/compiler/lib/js_simpl.ml index f0284295e5..64cf128d07 100644 --- a/compiler/lib/js_simpl.ml +++ b/compiler/lib/js_simpl.ml @@ -18,7 +18,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) open! Stdlib -module J = Javascript +module J = Ir let rec enot_rec e = let ((_, cost) as res) = @@ -55,12 +55,20 @@ let rec enot_rec e = *) | _ -> J.EUn (J.Not, e), 1) | J.EUn (J.Not, e) -> e, 0 - | J.EUn ((J.Neg | J.Pl | J.Typeof | J.Void | J.Delete | J.Bnot), _) -> - J.EUn (J.Not, e), 0 + | J.EUn ((J.Neg | J.Typeof | J.Void | J.Delete | J.Bnot), _) -> J.EUn (J.Not, e), 0 | J.EBool b -> J.EBool (not b), 0 | J.ECall _ | J.EAccess _ | J.EDot _ | J.ENew _ | J.EVar _ | J.EFun _ | J.EStr _ - | J.EArr _ | J.ENum _ | J.EObj _ | J.EQuote _ | J.ERegexp _ - | J.EUn ((J.IncrA | J.IncrB | J.DecrA | J.DecrB), _) -> + | J.EArr _ | J.EInt _ | J.EObj _ | J.EQuote _ | J.ERegexp _ + | EUn ((FloatNeg | IsInt | ToInt | ToBool | IntToString | FloatToInt | IntToFloat), _) + | ERuntime + | ECopy (_, _) + | EArityTest _ | EVectlength _ + | EArrAccess (_, _) + | EArrLen _ + | EStructAccess (_, _) + | EStruct _ + | ETag (_, _) + | EFloat _ | ERaw _ -> J.EUn (J.Not, e), 1 in if cost <= 1 then res else J.EUn (J.Not, e), 1 @@ -75,7 +83,7 @@ let unblock st = let block l = match l with | [ x ] -> x - | l -> J.Block l, J.N + | l -> J.Block l, Loc.N exception Not_expression @@ -108,12 +116,11 @@ let assignment_of_statement st = | _ -> raise Not_assignment let simplify_condition = function - | J.ECond (e, J.ENum one, J.ENum zero) when J.Num.is_one one && J.Num.is_zero zero -> e - | J.ECond (e, J.ENum zero, J.ENum one) when J.Num.is_one one && J.Num.is_zero zero -> - J.EUn (J.Not, e) - | J.ECond (J.EBin ((J.NotEqEq | J.NotEq), J.ENum n, y), e1, e2) - | J.ECond (J.EBin ((J.NotEqEq | J.NotEq), y, J.ENum n), e1, e2) -> - J.ECond (J.EBin (J.Band, y, J.ENum n), e1, e2) + | J.ECond (e, J.EInt one, J.EInt zero) when one = 1 && zero = 0 -> e + | J.ECond (e, J.EInt zero, J.EInt one) when one = 1 && zero = 0 -> J.EUn (J.Not, e) + | J.ECond (J.EBin ((J.NotEqEq | J.NotEq), J.EInt n, y), e1, e2) + | J.ECond (J.EBin ((J.NotEqEq | J.NotEq), y, J.EInt n), e1, e2) -> + J.ECond (J.EBin (J.Band, y, J.EInt n), e1, e2) | cond -> cond let rec if_statement_2 e loc iftrue truestop iffalse falsestop = @@ -149,7 +156,7 @@ let rec if_statement_2 e loc iftrue truestop iffalse falsestop = let unopt b = match b with | Some b -> b - | None -> J.Block [], J.N + | None -> J.Block [], Loc.N let if_statement e loc iftrue truestop iffalse falsestop = (*FIX: should be done at an earlier stage*) @@ -186,12 +193,20 @@ let rec get_variable acc = function | J.ECond (e1, e2, e3) -> get_variable (get_variable (get_variable acc e1) e2) e3 | J.EUn (_, e1) | J.EDot (e1, _) | J.ENew (e1, None) -> get_variable acc e1 | J.ECall (e1, el, _) | J.ENew (e1, Some el) -> - (e1, `Not_spread) :: el - |> List.map ~f:(fun (a, _) -> a) - |> List.fold_left ~init:acc ~f:get_variable - | J.EVar (J.V v) -> Code.Var.Set.add v acc - | J.EVar (J.S _) -> acc - | J.EFun _ | J.EStr _ | J.EBool _ | J.ENum _ | J.EQuote _ | J.ERegexp _ -> acc + e1 :: el |> List.fold_left ~init:acc ~f:get_variable + | J.EVar (Id.V v) -> Code.Var.Set.add v acc + | J.EVar (Id.S _) -> acc + | J.ERuntime + | J.ECopy (_, _) + | J.EArityTest _ | J.EVectlength _ + | J.EArrAccess (_, _) + | J.EArrLen _ + | J.EStructAccess (_, _) + | J.EStruct _ + | J.ETag (_, _) + | J.EFloat _ | J.ERaw _ | J.EFun _ | J.EStr _ | J.EBool _ | J.EInt _ | J.EQuote _ + | J.ERegexp _ -> + acc | J.EArr a -> List.fold_left ~f:(fun acc i -> diff --git a/compiler/lib/js_simpl.mli b/compiler/lib/js_simpl.mli index a54ceb6202..2806f810f8 100644 --- a/compiler/lib/js_simpl.mli +++ b/compiler/lib/js_simpl.mli @@ -18,19 +18,19 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -open Javascript +open Ir val if_statement : expression - -> location - -> statement * location + -> Loc.t + -> statement * Loc.t -> bool - -> statement * location + -> statement * Loc.t -> bool - -> (statement * location) list + -> (statement * Loc.t) list val get_variable : Code.Var.Set.t -> expression -> Code.Var.Set.t -val block : (Javascript.statement * location) list -> Javascript.statement * location +val block : (statement * Loc.t) list -> statement * Loc.t -val unblock : Javascript.statement * location -> (Javascript.statement * location) list +val unblock : statement * Loc.t -> (statement * Loc.t) list diff --git a/compiler/lib/js_traverse.ml b/compiler/lib/js_traverse.ml index a223e90015..13a9b15e64 100644 --- a/compiler/lib/js_traverse.ml +++ b/compiler/lib/js_traverse.ml @@ -155,7 +155,8 @@ class map : mapper = | (EBool _ as x) | (ENum _ as x) | (EQuote _ as x) - | (ERegexp _ as x) -> + | (ERegexp _ as x) + | (ERaw _ as x) -> x method expression_o x = diff --git a/compiler/lib/loc.ml b/compiler/lib/loc.ml new file mode 100644 index 0000000000..c4d7e56011 --- /dev/null +++ b/compiler/lib/loc.ml @@ -0,0 +1,23 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +type t = + | Pi of Parse_info.t + | N + | U diff --git a/compiler/lib/loc.mli b/compiler/lib/loc.mli new file mode 100644 index 0000000000..c4d7e56011 --- /dev/null +++ b/compiler/lib/loc.mli @@ -0,0 +1,23 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +type t = + | Pi of Parse_info.t + | N + | U diff --git a/compiler/lib/num.ml b/compiler/lib/num.ml new file mode 100644 index 0000000000..38968d9d1a --- /dev/null +++ b/compiler/lib/num.ml @@ -0,0 +1,70 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) +open! Stdlib + +type t = string + +let of_string_unsafe s = s + +let to_string s = s + +let to_int32 s = + if String.is_prefix s ~prefix:"0" + && String.length s > 1 + && String.for_all s ~f:(function + | '0' .. '7' -> true + | _ -> false) + then (* octal notation *) + Int32.of_string ("0o" ^ s) + else Int32.of_string s + +let of_int32 = Int32.to_string + +let of_float v = + match Float.classify_float v with + | FP_nan -> "NaN" + | FP_zero -> + (* [1/-0] < 0. seems to be the only way to detect -0 in JavaScript *) + if Float.(1. /. v < 0.) then "-0." else "0." + | FP_infinite -> if Float.(v < 0.) then "-Infinity" else "Infinity" + | FP_normal | FP_subnormal -> + let vint = int_of_float v in + if Float.equal (float_of_int vint) v + then Printf.sprintf "%d." vint + else + let s1 = Printf.sprintf "%.12g" v in + if Float.equal v (float_of_string s1) + then s1 + else + let s2 = Printf.sprintf "%.15g" v in + if Float.equal v (float_of_string s2) then s2 else Printf.sprintf "%.18g" v + +let is_zero s = String.equal s "0" + +let is_one s = String.equal s "1" + +let is_neg s = Char.equal s.[0] '-' + +let neg s = + match String.drop_prefix s ~prefix:"-" with + | None -> "-" ^ s + | Some s -> s + +let add a b = of_int32 (Int32.add (to_int32 a) (to_int32 b)) diff --git a/compiler/lib/num.mli b/compiler/lib/num.mli new file mode 100644 index 0000000000..b29146e8b1 --- /dev/null +++ b/compiler/lib/num.mli @@ -0,0 +1,47 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2010 Jérôme Vouillon + * Laboratoire PPS - CNRS Université Paris Diderot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) + +type t + +(** Conversions *) + +val of_string_unsafe : string -> t + +val of_int32 : int32 -> t + +val of_float : float -> t + +val to_string : t -> string + +val to_int32 : t -> int32 + +(** Predicates *) + +val is_zero : t -> bool + +val is_one : t -> bool + +val is_neg : t -> bool + +(** Arithmetic *) + +val add : t -> t -> t + +val neg : t -> t