From 70197c81d31338597678b6ef76dee5131a9aeefe Mon Sep 17 00:00:00 2001 From: Paul IANNETTA <paul.iannetta@ens-lyon.fr> Date: Mon, 29 Jun 2015 10:45:14 +0200 Subject: [PATCH] clean up. Partial support for for and while construct. --- generator/js_of_ast.ml | 326 ++++++++++++++++++++++++++--------------- 1 file changed, 207 insertions(+), 119 deletions(-) diff --git a/generator/js_of_ast.ml b/generator/js_of_ast.ml index e81f165..6dc52c5 100644 --- a/generator/js_of_ast.ml +++ b/generator/js_of_ast.ml @@ -11,8 +11,12 @@ open Mytools open Attributes let hashtlb_size = 256 -let type_tbl = Hashtbl.create hashtlb_size;; +let type_tbl = Hashtbl.create hashtlb_size +(** + * Debug-purpose functions + *) + let print_tbl () = let rec print_str_list = function | [] -> "" @@ -20,6 +24,10 @@ let print_tbl () = | x :: xs -> (Format.sprintf {|"%s", |} x) ^ print_str_list xs in Hashtbl.iter (fun cstr elems -> Printf.printf ({|%s -> [%s]|} ^^ "\n") cstr (print_str_list elems)) type_tbl; () +(** + * Useful functions (shadow show_list from Mytools) + *) + let show_list_f f sep l = l |> List.map f |> List.fold_left (fun acc x -> acc ^ (if acc = "" then "" else sep) ^ x) "" @@ -27,36 +35,218 @@ let show_list_f f sep l = l let show_list sep l = List.fold_left (fun acc x -> acc ^ (if acc = "" then "" else sep) ^ x) "" l -let js_of_constant = function - | Const_int n -> string_of_int n - | Const_char c -> String.make 1 c - | Const_string (s, _) -> "\"" ^ s ^ "\"" - | Const_float f -> f - | Const_int32 n -> Int32.to_string n - | Const_int64 n -> Int64.to_string n - | Const_nativeint n -> Nativeint.to_string n +let is_sbool x = List.mem x ["true" ; "false"] + +(** + * Before-hand definitions of Pretty-Printer-Format for converting ocaml + * to ECMAScript, therefore all of them are in a single place. + *) + +let ppf_branch case binders expr = + Format.sprintf "@[<v 2>%s: @[<v 4>%s@,return %s;@]@,@]" + case binders expr -let js_of_longident loc = +let ppf_let_in decl exp = + Format.sprintf "@[<v 0>(function () {@,@[<v 4>@,%s@,@,return %s;@,@]@,})()@]" + decl exp + +let ppf_function args body= + Format.sprintf "@[function (%s) {@,@[<v 4>@,return %s;@,@]@,}@]" + args body + +let ppf_apply f args = + Format.sprintf "@[<v 0>%s(%s)@]" + f args + +let ppf_match value cases = + Format.sprintf "@[<v 0>(function () {@,@[<v 4>@,switch (%s.type) {@,@[<v 4>@,%s@,@]@,}@]@,})()@]" + value cases + +let ppf_array values = + Format.sprintf "[%s]" + values + +let ppf_tuple = ppf_array + +let ppf_ifthen cond iftrue = + Format.sprintf "@[<v 0>(function () {@,@[<v 4>@,if (%s) {@,@[<v 4>@,return %s;@]@,}@]@,})()@]" + cond iftrue + +let ppf_ifthenelse cond iftrue iffalse = + Format.sprintf "@[<v 0>(function () {@,@[<v 4>@,if (%s) {@,@[<v 4>@,return %s;@]@,} else {@,@[<v 4>@,return %s;@]@,}@]@]@,})()@]" + cond iftrue iffalse + +let ppf_sequence exp1 exp2 = + Format.sprintf "@[<v 0>return %s,@,%s@]" + exp1 exp2 + +let ppf_while cd body = + Format.sprintf "@[<v 0> function () {@,@[<v 3>@,while(%s) {@,@[<v 4>@,%s@]@]@,@]}@,)()@]" + cd body + +let ppf_for id start ed flag body = + let fl_to_string = function + | Upto -> "++" + | Downto -> "--" in + let fl_to_symbl = function + | Upto -> "<=" + | Downto -> ">=" + in Format.sprintf "@[<v 0>(function () {@,@[<v 3>@,for (%s = %s ; %s %s %s ; %s%s) {@,@[@,%s @]@,} @,@]})() @]" + id start id (fl_to_symbl flag) ed (fl_to_string flag) id body + +let ppf_single_cstr tag = + Format.sprintf "%s" + tag + +let ppf_cstr tag value = + Format.sprintf "%s: %s" + tag value + +let ppf_single_cstrs typ = + Format.sprintf "{type: \"%s\"}" + typ + + +let ppf_multiple_cstrs typ rest = + Format.sprintf "{type: \"%s\", %s}" + typ rest + +(** + * Main part + *) + +let rec show_value_binding vb = + js_of_let_pattern vb.vb_pat vb.vb_expr + +and js_of_structure s = + show_list_f js_of_structure_item lin2 s.str_items + +and js_of_structure_item s = match s.str_desc with + | Tstr_eval (e, _) -> Format.sprintf "%s" @@ js_of_expression e + | Tstr_value (_, vb_l) -> String.concat lin2 @@ List.map show_value_binding @@ vb_l + | Tstr_type tl -> + let explore_type = function + | [] -> () + | x :: xs -> + (match x.typ_kind with + | Ttype_variant cdl -> + let cl = List.map (fun cstr -> extract_cstr_attrs cstr) cdl in + List.iter (fun (name, cstrs_name) -> Hashtbl.add type_tbl name cstrs_name) cl + | _ -> unsupported "open types, record and abstract type" + ) + in explore_type tl; "" + | Tstr_primitive _ -> out_of_scope "primitive functions" + | Tstr_typext _ -> out_of_scope "type extensions" + | Tstr_exception _ -> out_of_scope "exceptions" + | Tstr_module _ -> out_of_scope "modules" + | Tstr_recmodule _ -> out_of_scope "recursive modules" + | Tstr_modtype _ -> out_of_scope "module type" + | Tstr_open _ -> out_of_scope "open statements" + | Tstr_class _ -> out_of_scope "objects" + | Tstr_class_type _ -> out_of_scope "class types" + | Tstr_include _ -> out_of_scope "includes" + | Tstr_attribute _ -> out_of_scope "attributes" + +and js_of_branch b obj = + let spat, binders = js_of_pattern b.c_lhs obj in + let se = js_of_expression b.c_rhs in + ppf_branch spat binders se + +and js_of_expression e = match e.exp_desc with + | Texp_ident (_, loc, _) -> js_of_longident loc + | Texp_constant c -> js_of_constant c + | Texp_let (_, vb_l, e) -> + let sd = String.concat lin1 @@ List.map show_value_binding @@ vb_l in + let se = js_of_expression e + in ppf_let_in sd se + | Texp_function (_, c :: [], Total) -> + let rec explore pats e = match e.exp_desc with + | Texp_function (_, c :: [], Total) -> + let p, e = c.c_lhs, c.c_rhs + in explore (p :: pats) e + | _ -> + String.concat ", " @@ List.map ident_of_pat @@ List.rev @@ pats, js_of_expression e in + let args, body = explore [c.c_lhs] c.c_rhs + in ppf_function args body + | Texp_apply (f, exp_l) -> + let sl = exp_l + |> List.map (fun (_, eo, _) -> match eo with None -> out_of_scope "optional apply arguments" | Some ei -> js_of_expression ei) + |> String.concat ", " in + let se = js_of_expression f in + ppf_apply se sl + | Texp_match (exp, l, [], Total) -> + let se = js_of_expression exp in + let sb = List.fold_left (fun acc x -> acc ^ js_of_branch x se) "" l in + ppf_match se sb + | Texp_tuple (tl) -> ppf_tuple @@ show_list_f js_of_expression ", " tl + | Texp_construct (loc, cd, el) -> + let value = js_of_longident loc in + if el = [] then + if is_sbool value + then value + else ppf_single_cstr value + else + let rec expand_constructor_list fields exprs = match fields, exprs with + | [], [] -> [] + | [], x :: xs | x :: xs , [] -> failwith "argument lists should have the same length." + | x :: xs, y :: ys -> (if y = "" then ppf_single_cstr x else ppf_cstr x y) :: expand_constructor_list xs ys in + let names = Hashtbl.find type_tbl value + in ppf_multiple_cstrs value (show_list ", " (expand_constructor_list names (List.map js_of_expression el))) + | Texp_array (exp_l) -> ppf_array @@ show_list_f js_of_expression ", " exp_l + | Texp_ifthenelse (e1, e2, None) -> ppf_ifthen (js_of_expression e1) (js_of_expression e2) + | Texp_ifthenelse (e1, e2, Some e3) -> ppf_ifthenelse (js_of_expression e1) (js_of_expression e2) (js_of_expression e3) + | Texp_sequence (e1, e2) -> ppf_sequence (js_of_expression e1) (js_of_expression e2) + | Texp_while (cd, body) -> ppf_while (js_of_expression cd) (js_of_expression body) + | Texp_for (id, _, st, ed, fl, body) -> ppf_for (Ident.name id) (js_of_expression st) (js_of_expression ed) fl (js_of_expression body) + | Texp_match (_,_,_, Partial) -> out_of_scope "partial matching" + | Texp_match (_,_,_,_) -> out_of_scope "matching with exception branches" + | Texp_try (_,_) -> out_of_scope "exceptions" + | Texp_function (_,_,_) -> out_of_scope "powered-up functions" + | Texp_variant (_,_) -> out_of_scope "polymorphic variant" + | Texp_record (_, _) -> out_of_scope "records" + | Texp_field (_,_,_) -> out_of_scope "accessing field" + | Texp_setfield (_,_,_,_) -> out_of_scope "setting field" + | Texp_send (_,_,_) -> out_of_scope "objects" + | Texp_new (_,_,_) -> out_of_scope "objects" + | Texp_instvar (_,_,_) -> out_of_scope "objects" + | Texp_setinstvar (_,_,_,_) -> out_of_scope "objects" + | Texp_override (_,_) -> out_of_scope "objects" + | Texp_letmodule (_,_,_,_) -> out_of_scope "local modules" + | Texp_assert _ -> out_of_scope "assert" + | Texp_lazy _ -> out_of_scope "lazy expressions" + | Texp_object (_,_) -> out_of_scope "objects" + | Texp_pack _ -> out_of_scope "packing" + +and js_of_constant = function + | Const_int n -> string_of_int n + | Const_char c -> String.make 1 c + | Const_string (s, _) -> "\"" ^ s ^ "\"" + | Const_float f -> f + | Const_int32 n -> Int32.to_string n + | Const_int64 n -> Int64.to_string n + | Const_nativeint n -> Nativeint.to_string n + +and js_of_longident loc = let res = String.concat "." @@ Longident.flatten loc.txt in - if res = "()" then "" else res + if res = "()" then "undefined" else res -let ident_of_pat pat = match pat.pat_desc with +and ident_of_pat pat = match pat.pat_desc with | Tpat_var (id, _) -> Ident.name id | _ -> error "functions can't deconstruct values" - -let rec js_of_let_pattern pat expr = + +and js_of_let_pattern pat expr = let expr_type pat expr = match expr.exp_desc with | Texp_construct (loc, cd, el) -> let value = js_of_longident loc in if el = [] then - if value = "true" || value = "false" then value else Format.sprintf "{type: \"%s}\"" value + if is_sbool value then value else ppf_single_cstr value else let rec expand_constructor_list fields exprs = match fields, exprs with | [], [] -> [] | [], x :: xs | x :: xs , [] -> failwith "argument lists should have the same length." - | x :: xs, y :: ys -> Format.sprintf "@[%s:@,%s@]" x y :: expand_constructor_list xs ys in + | x :: xs, y :: ys -> ppf_cstr x y :: expand_constructor_list xs ys in let names = Hashtbl.find type_tbl value - in Format.sprintf "{type: \"%s\",@, %s}" value (show_list ", " (expand_constructor_list names (List.map js_of_expression el))) + in ppf_multiple_cstrs value (show_list ", " (expand_constructor_list names (List.map js_of_expression el))) | _ -> string_of_type_exp pat.pat_type in let sexpr = js_of_expression expr in match pat.pat_desc with @@ -91,105 +281,3 @@ and js_of_pattern pat obj = match pat.pat_desc with | Tpat_record (_,_) -> out_of_scope "record" | Tpat_or (_,_,_) -> failwith "not implemented yet" | Tpat_lazy (_) -> out_of_scope "lazy-pattern" - -and js_of_expression (e:expression) = - let js_of_branch b obj = - let spat, binders = js_of_pattern b.c_lhs obj in - let se = js_of_expression b.c_rhs in - Format.sprintf "@[<v 2>%s: @[<v 4>%s@,return %s;@]@,@]" spat binders se in - match e.exp_desc with - | Texp_ident (_, loc, _) -> js_of_longident loc - | Texp_constant c -> js_of_constant c - | Texp_let (_, vb_l, e) -> - let show_val vb = js_of_let_pattern vb.vb_pat vb.vb_expr in - let sd = String.concat "\n" @@ List.map show_val @@ vb_l in - let se = js_of_expression e in - Format.sprintf - "@[<v 0>(function () {@,@[<v 4>@,%s@,@,return %s;@,@]@,})()@]" sd se - | Texp_function (_, c :: [], Total) -> - let rec explore pats e = match e.exp_desc with - | Texp_function (_, c :: [], Total) -> - let p = c.c_lhs - and e = c.c_rhs in - explore (p :: pats) e - | _ -> String.concat ", " @@ List.map ident_of_pat @@ List.rev @@ pats, - js_of_expression e in - let names, body = explore [c.c_lhs] c.c_rhs in - Format.sprintf - "@[function (%s) {@,@[<v 4>@,return %s;@,@]@,}@]" names body - | Texp_function (_, _, _) -> out_of_scope "powered-up functions" - | Texp_apply (f, exp_l) -> - let sl = exp_l - |> List.map (fun (_, eo, _) -> match eo with None -> out_of_scope "optional apply arguments" | Some ei -> js_of_expression ei) - |> String.concat ", " in - let se = js_of_expression f in - Format.sprintf "@[<v 0>%s(%s)@]" se sl - | Texp_match (exp, l, [], Total) -> - let se = js_of_expression exp in - let sb = List.fold_left (fun acc x -> acc ^ js_of_branch x se) "" l in - Format.sprintf "@[<v 0>(function () {@,@[<v 4>@,switch (%s.type) {@,@[<v 4>@,%s@,@]@,}@]@,})()@]" se sb - | Texp_match (_, _, _, Partial) -> out_of_scope "partial matching" - | Texp_match (_,_,_,_) -> out_of_scope "matching with exception branches" - | Texp_try (_, _) -> out_of_scope "exceptions" - | Texp_tuple (tl) -> - "[" ^ show_list_f js_of_expression ", " tl ^ "]" - | Texp_construct (loc, cd, el) -> (*TODO: Modifs*) - let value = js_of_longident loc in - if el = [] then - if value = "true" || value = "false" then value else Format.sprintf "{type: \"%s\"}" value - else let rec expand_constructor_list fields exprs = match fields, exprs with - | [], [] -> [] - | [], x :: xs | x :: xs , [] -> failwith "argument lists should have the same length." - | x :: xs, y :: ys -> (if y = "" then Format.sprintf "%s" x else Format.sprintf "%s: %s" x y) :: expand_constructor_list xs ys - in let names = Hashtbl.find type_tbl value - in Format.sprintf "{type: \"%s\", %s}" value (show_list ", " (expand_constructor_list names (List.map js_of_expression el))) - | Texp_variant (_,_) -> out_of_scope "polymorphic variant" - | Texp_record (_, _) -> failwith "not implemented yet" - | Texp_field (_,_,_) -> failwith "not implemented yet" - | Texp_setfield (_,_,_,_) -> failwith "not implemented yet" - | Texp_array (exp_l) -> - "[" ^ show_list_f js_of_expression ", " exp_l ^ "]" - | Texp_ifthenelse (e1, e2, None) -> Format.sprintf - "@[<v 0>(function () {@,@[<v 4>@,if (%s) {@,@[<v 4>@,return %s;@]@,}@]@,})()@]" (js_of_expression e1) (js_of_expression e2) - | Texp_ifthenelse (e1, e2, Some e3) -> Format.sprintf - "@[<v 0>(function () {@,@[<v 4>@,if (%s) {@,@[<v 4>@,return %s;@]@,} else {@,@[<v 4>@,return %s;@]@,}@]@]@,})()@]" - (js_of_expression e1) (js_of_expression e2) (js_of_expression e3) - | Texp_sequence (_, _) -> unsupported "sequences" - | Texp_while (_, _) -> unsupported "while loops" - | Texp_for (_,_,_,_,_,_) -> unsupported "for loops" - | Texp_send (_, _, _) -> out_of_scope "objects" - | Texp_new (_, _, _) -> out_of_scope "objects" - | Texp_instvar (_,_,_) -> out_of_scope "objects" - | Texp_setinstvar (_,_,_,_) -> out_of_scope "objects" - | Texp_override (_,_) -> out_of_scope "objects" - | Texp_letmodule (_,_,_,_) -> out_of_scope "local modules" - | Texp_assert _ -> out_of_scope "assert" - | Texp_lazy _ -> out_of_scope "lazy expressions" - | Texp_object (_, _) -> out_of_scope "objects" - | Texp_pack _ -> out_of_scope "packing" -let rec js_of_structure s = show_list_f js_of_structure_item "\n\n" s.str_items -and js_of_structure_item s = match s.str_desc with - | Tstr_eval (e, _) -> Format.sprintf "%s" @@ js_of_expression e - | Tstr_value (_, vb_l) -> - let show_val vb = js_of_let_pattern vb.vb_pat vb.vb_expr in - String.concat "\n\n" @@ List.map show_val @@ vb_l - | Tstr_type tl -> - let explore_type = function - | [] -> () - | x :: xs -> (match x.typ_kind with - | Ttype_variant cdl -> - let cl = List.map (fun cstr -> extract_cstr_attrs cstr) cdl in - List.iter (fun (name, cstrs_name) -> Hashtbl.add type_tbl name cstrs_name) cl - | _ -> unsupported "open types, record and abstract type") - in explore_type tl; print_tbl (); "" - | Tstr_primitive _ -> out_of_scope "primitive functions" - | Tstr_typext _ -> out_of_scope "type extensions" - | Tstr_exception _ -> out_of_scope "exceptions" - | Tstr_module _ -> out_of_scope "modules" - | Tstr_recmodule _ -> out_of_scope "recursive modules" - | Tstr_modtype _ -> out_of_scope "module type" - | Tstr_open _ -> out_of_scope "open statements" - | Tstr_class _ -> out_of_scope "objects" - | Tstr_class_type _ -> out_of_scope "class types" - | Tstr_include _ -> out_of_scope "includes" - | Tstr_attribute _ -> out_of_scope "attributes" -- GitLab