<commit_before>open Prelude

module E = Exprjs_syntax
module S = Es5_syntax

let rec exprjs_to_ljs (e : E.expr) : S.exp = match e with
  | E.True (p) -> S.True (p)
  | E.False (p) -> S.False (p)
  | E.Num (p, n) -> S.Num (p, n)
  | E.Undefined (p) -> S.Undefined (p)
  | E.Null (p) -> S.Null (p)
  | E.String (p, s) -> S.String (p, s)
  | E.RegExpr (p, s) -> 
    let re_attrs = { S.code = None;
                     S.proto = Some (S.Id (p, "%RegexpProto"));
                     S.klass = "Regexp"; (* correct? *)
                     S.extensible = true; } in
    let lit_data = S.Data ({S.value = S.String (p, s); S.writable = false;}, false, false) in
    S.Object (p, re_attrs, [("%lit", lit_data)])
  | E.ArrayExpr (p, el) ->
    let rec e_to_p e n = (
      string_of_int n, 
      S.Data ({ S.value = e; S.writable = true; }, true, true))
    and el_to_pl l n = match l with
      | [] -> []
      | first :: rest -> (e_to_p first n) :: el_to_pl rest (n + 1) in
    let desugared = List.map exprjs_to_ljs el
    and a_attrs = {
        S.code = None;
        S.proto = 
          Some (S.GetField (p, S.Id (p, "%context"), S.String (p, "Array"),
          S.Null (p))); (* TODO: null args obj *)
        S.klass = "Array";
        S.extensible = true; } in
    let exp_props = el_to_pl desugared 0 in
    let lfloat = float_of_int (List.length exp_props) in
    let l_prop = (* TODO: is array length prop writ/enum/configurable? *)
      S.Data (
        { S.value = S.Num (p, lfloat); S.writable = true; },
        false,
        false) in
    S.Object (p, a_attrs, ("length", l_prop) :: exp_props)
  | E.ObjectExpr (p, pl) ->
    (* Given a tuple, if it's a getter/setter, create a name-accessor pair and add to
     * sofar *)
    let add_accessor pr sofar = match pr with
      | (_, _, E.Getter (nm, exp)) ->
        let gval = get_fobj p [] exp (S.Id (p, "%context")) in
        let a = { S.getter = gval; S.setter = S.Undefined (p); } in
        (nm, S.Accessor (a, true, true)) :: sofar
      | (_, _, E.Setter (nm, exp)) ->
        let (param_name, sfunc) = match exp with
          | E.LetExpr (_, nm, _, body) -> (nm, body)
          | _ -> failwith "setter desugaring error: expected LetExpr here" in
        let sval = get_fobj p [param_name] sfunc (S.Id (p, "%context")) in
        let a = { S.getter = S.Undefined (p); S.setter = sval; } in
        (nm, S.Accessor (a, true, true)) :: sofar
      | _ -> sofar in
    (* Given a list of tuples, produce a list of name, accessor pairs *)
    let rec accessors tl sofar = match tl with
      | [] -> sofar
      | t :: rest -> accessors rest (add_accessor t sofar) in
    (* Get only those pairs with name = nm *)
    let tuples tl nm = List.filter (fun (n, _) -> n = nm) tl in
    (* Given a list of name-accessor pairs, reduce them to one *)
    let rec reduce al result = match al with
      | [] -> result
      | (nm, S.Accessor (a, wr, cfg)) :: rest ->
        let result_a = match result with
          | S.Accessor (aa, _, _) -> aa in
        let next = match a with
          | { S.getter = S.Undefined _; S.setter = s; } ->
            S.Accessor ({ S.getter = result_a.S.getter; S.setter = s; }, wr, cfg)
          | { S.getter = g; S.setter = S.Undefined _; } ->
            S.Accessor ({ S.getter = g; S.setter = result_a.S.setter; }, wr, cfg)
          | _ -> S.Accessor (a, wr, cfg) in
        reduce rest next in
    let dup_pairs = accessors pl [] in
    let name_lst = remove_dupes (map (fun (n, _) -> n) dup_pairs) in
    let name_assoc = map (fun n -> (n, tuples dup_pairs n)) name_lst in
    let dummy_prop = 
      S.Accessor (
        { S.getter = S.Undefined (p); S.setter = S.Undefined (p); }, true, true) in
    let reduced_assoc = map (fun (n, al) -> (n, reduce al dummy_prop)) name_assoc in
    let data_props = 
      List.filter (fun p -> let result = 
        match p with (_, _, E.Data _) -> true | _ -> false in result) pl in
    let rec ejsprop_to_sprop pr = match pr with
      | E.Data (e) -> 
          let rec v = exprjs_to_ljs e
          and d = { S.value = v; S.writable = true; } in
          S.Data (d, true, true)
      | E.Getter (nm, e) -> failwith "getters unimplemented"
      | E.Setter (nm, e) -> failwith "setters unimplemented"
    and tuple_to_prop t = match t with
      (p, s, pr) -> (s, ejsprop_to_sprop pr)
    and form_props props = match props with
      | [] -> []
      | first :: rest -> (tuple_to_prop first) :: form_props rest in
    let data_result = form_props data_props in
    let o_attrs = {
      S.code = None;
      S.proto = Some (S.GetField (p, S.Id (p, "%context"), S.String (p, "Object"),
      S.Null (p)));
      S.klass = "Object";
      S.extensible = true; } in
    S.Object (p, o_attrs, List.append reduced_assoc data_result)
  | E.ThisExpr (p) -> failwith "This NYI"
  | E.IdExpr (p, nm) -> S.Id (p, nm)
  | E.BracketExpr (p, l, r) -> 
    let o = exprjs_to_ljs l
    and f = S.Op1 (p, "prim->str", exprjs_to_ljs r) in
    let argsobj = S.Object (p, S.d_attrs, []) in
    S.GetField (p, o, f, argsobj)
  | E.NewExpr _ -> failwith "New NYI"
  | E.PrefixExpr (p, op, exp) -> let result = match op with
    | "postfix:++" ->
      let lhs = match exp with
        | E.BracketExpr (_, E.IdExpr (_, "%context"), E.String (_, nm)) ->
          S.String (p, nm)
        | _ -> failwith "postfix ++ not yet fully implemented"
      and sexp = exprjs_to_ljs exp in
      let bop = S.Op2 (p, "+", sexp, S.Num (p, 1.)) in
      let rec arecd = { S.value = bop; S.writable = true; }
      and aprop = S.Data (arecd, true, true)
      and aobj = S.Object (p, S.d_attrs, [("0", aprop)]) in
      S.SetField (p, S.Id (p, "%context"), lhs, bop, aobj)
    | _ -> S.Op1 (p, op, exprjs_to_ljs exp) in result
  | E.InfixExpr (p, op, l, r) ->
    let sl = exprjs_to_ljs l and sr = exprjs_to_ljs r
    and this = S.Id (p, "%this") in
    let result = match op with
      | "&&" ->
        S.Let (p, "%l-evaled", sl,
          S.If (p, 
            S.App (p, S.Id (p, "%ToBoolean"), [S.Id (p, "%l-evaled")]),
            sr, 
            S.Id (p, "%l-evaled")))
      | "||" ->
        S.Let (p, "%l-evaled", sl,
          S.If (p,
            S.App (p, S.Id (p, "%ToBoolean"), [S.Id (p, "%l-evaled")]),
            S.Id (p, "%l-evaled"),
            sr))
      | "!==" -> S.Op1 (p, "!", S.Op2 (p, "stx=", sl, sr))
      | _ -> let op = match op with
        | "===" -> "abs="
        | "==" -> "stx="
        | _ -> op in S.Op2 (p, op, sl, sr) in result
  | E.IfExpr (p, e1, e2, e3) -> let e1 = exprjs_to_ljs e1
    and e2 = exprjs_to_ljs e2
    and e3 = exprjs_to_ljs e3 in 
    S.If (p, 
      S.App (p, S.Id (p, "%ToBoolean"), [e1]),
      e2, 
      e3)
  | E.AssignExpr (p, obj, pr, vl) -> 
    let sobj = exprjs_to_ljs obj
    and spr = exprjs_to_ljs pr
    and svl = exprjs_to_ljs vl in
    let arecd = { S.value = svl; S.writable = true; } in
    let aprop = S.Data (arecd, true, true) in
    let aobj = S.Object (p, S.d_attrs, [("0", aprop)]) in
    S.SetField (p, sobj, spr, svl, aobj)
  | E.AppExpr (p, e, el) -> 
    let sl = List.map (fun x -> exprjs_to_ljs x) el
    and f = exprjs_to_ljs e in 
    let n_args = List.length sl in
    let indices = Prelude.iota n_args in
    let combined = List.combine indices sl in
    let records =
      List.map (fun (n, arg) -> (n, {S.value = arg; S.writable = true})) combined in
    let props = 
      List.map 
        (fun (n, rcrd) -> (string_of_int n, S.Data (rcrd, true, true))) records in
    let a_attrs = {
        S.code = None;
        S.proto = 
          Some (S.GetField (p, S.Id (p, "%context"), S.String (p, "Array"),
          S.Null (p))); (* TODO: null args obj *)
        S.klass = "Array";
        S.extensible = true; } in
    let lfloat = float_of_int (List.length props) in
    let l_prop = (* TODO: is array length prop writ/enum/configurable? *)
      S.Data (
        { S.value = S.Num (p, lfloat); S.writable = true; },
        false,
        false) in
    let args_obj = S.Object (p, a_attrs, ("length", l_prop) :: props) in
    let this = match f with
      | S.GetField (p, l, r, args) -> l
      | _ -> S.Id (p, "%this") in
    S.App (p, f, [this; args_obj])
  | E.FuncExpr (p, args, body) -> get_fobj p args body (S.Id (p, "%context"))
  | E.LetExpr (p, nm, vl, body) ->
    let sv = exprjs_to_ljs vl
    and sb = exprjs_to_ljs body in
    let result_obj = match nm with
      | "%context" -> let orig_props = match sv with
        | S.Object (_, _, pl) -> pl
        | _ -> failwith "let bound %context to a non-object" in
        let c_attrs = { S.code = None;
                        S.proto = Some (S.Id (p, "%context"));
                        S.klass = "Object";
                        S.extensible = true; } in
        S.Object (p, c_attrs, orig_props)
      | _ -> sv in
    S.Let (p, nm, result_obj, sb)
  | E.SeqExpr (p, e1, e2) -> S.Seq (p, exprjs_to_ljs e1, exprjs_to_ljs e2)
  | E.WhileExpr (p, tst, bdy) ->
    let t = exprjs_to_ljs tst and b = exprjs_to_ljs bdy in get_while t b
  | E.LabelledExpr (p, lbl, exp) -> S.Label (p, lbl, exprjs_to_ljs exp)
  | E.BreakExpr (p, id, e) -> S.Break (p, id, exprjs_to_ljs e)
  | E.ForInExpr (p, nm, vl, bdy) ->
    get_forin p nm (exprjs_to_ljs vl) (exprjs_to_ljs bdy)
  | E.TryCatchExpr (p, body, ident, catch) -> 
    let new_ctxt = 
      S.Object (p, { S.d_attrs with S.proto = Some (S.Id (p, "%parent")) },
                [(ident, 
                  S.Data ({ S.value = S.Id (p, ident); S.writable = true }, 
                         false, false) );])
    in
    S.TryCatch (p, exprjs_to_ljs body, 
                S.Lambda(p, [ident], 
                         S.Let (p, "%parent", S.Id (p, "%context") ,
                                S.Let (p, "%context", new_ctxt, 
                                       exprjs_to_ljs catch))))
  | E.FuncStmtExpr (p, nm, args, body) -> 
    let fobj = get_fobj p args body (S.Id (p, "%context")) in
    let arcrd = { S.value = fobj; S.writable = true; } in
    let aprop = S.Data (arcrd, true, true) in
    let aprops = [("0", aprop)] in
    let argsobj = S.Object (p, S.d_attrs, aprops) in
    S.SetField (p, S.Id (p, "%context"), S.String (p, nm), fobj, argsobj)
  | E.TryFinallyExpr (p, body, finally) -> 
    S.TryFinally (p, exprjs_to_ljs body, exprjs_to_ljs finally)
  | E.ThrowExpr (p, e) -> S.Throw (p, exprjs_to_ljs e)
  | E.HintExpr _ -> failwith "Bizarre error: Hint found somehow"

and get_fobj p args body context = 
  let call = get_lambda p args body in
  let fproto = 
    S.GetField (p, S.Id (p, "%context"), S.String(p, "Function"), S.Null (p)) in
  let fobj_attrs = 
    { S.code = Some (call); S.proto = Some (fproto); S.klass = "Function"; 
    S.extensible = true; } in
  let param_len = List.length args in
  let indices = Prelude.iota param_len in
  let combined = List.combine indices args in
  let rcds =
    List.map (fun (n, prm) -> (n, {S.value = S.String (p, prm); S.writable =
      true;})) combined in<commit_msg>proto links don't look up in context<commit_after>open Prelude

module E = Exprjs_syntax
module S = Es5_syntax

let rec exprjs_to_ljs (e : E.expr) : S.exp = match e with
  | E.True (p) -> S.True (p)
  | E.False (p) -> S.False (p)
  | E.Num (p, n) -> S.Num (p, n)
  | E.Undefined (p) -> S.Undefined (p)
  | E.Null (p) -> S.Null (p)
  | E.String (p, s) -> S.String (p, s)
  | E.RegExpr (p, s) -> 
    let re_attrs = { S.code = None;
                     S.proto = Some (S.Id (p, "%RegexpProto"));
                     S.klass = "Regexp"; (* correct? *)
                     S.extensible = true; } in
    let lit_data = S.Data ({S.value = S.String (p, s); S.writable = false;}, false, false) in
    S.Object (p, re_attrs, [("%lit", lit_data)])
  | E.ArrayExpr (p, el) ->
    let rec e_to_p e n = (
      string_of_int n, 
      S.Data ({ S.value = e; S.writable = true; }, true, true))
    and el_to_pl l n = match l with
      | [] -> []
      | first :: rest -> (e_to_p first n) :: el_to_pl rest (n + 1) in
    let desugared = List.map exprjs_to_ljs el
    and a_attrs = {
        S.code = None;
        S.proto = Some (S.Id (p, "%ArrayProto")); 
        S.klass = "Array";
        S.extensible = true; } in
    let exp_props = el_to_pl desugared 0 in
    let lfloat = float_of_int (List.length exp_props) in
    let l_prop = (* TODO: is array length prop writ/enum/configurable? *)
      S.Data (
        { S.value = S.Num (p, lfloat); S.writable = true; },
        false,
        false) in
    S.Object (p, a_attrs, ("length", l_prop) :: exp_props)
  | E.ObjectExpr (p, pl) ->
    (* Given a tuple, if it's a getter/setter, create a name-accessor pair and add to
     * sofar *)
    let add_accessor pr sofar = match pr with
      | (_, _, E.Getter (nm, exp)) ->
        let gval = get_fobj p [] exp (S.Id (p, "%context")) in
        let a = { S.getter = gval; S.setter = S.Undefined (p); } in
        (nm, S.Accessor (a, true, true)) :: sofar
      | (_, _, E.Setter (nm, exp)) ->
        let (param_name, sfunc) = match exp with
          | E.LetExpr (_, nm, _, body) -> (nm, body)
          | _ -> failwith "setter desugaring error: expected LetExpr here" in
        let sval = get_fobj p [param_name] sfunc (S.Id (p, "%context")) in
        let a = { S.getter = S.Undefined (p); S.setter = sval; } in
        (nm, S.Accessor (a, true, true)) :: sofar
      | _ -> sofar in
    (* Given a list of tuples, produce a list of name, accessor pairs *)
    let rec accessors tl sofar = match tl with
      | [] -> sofar
      | t :: rest -> accessors rest (add_accessor t sofar) in
    (* Get only those pairs with name = nm *)
    let tuples tl nm = List.filter (fun (n, _) -> n = nm) tl in
    (* Given a list of name-accessor pairs, reduce them to one *)
    let rec reduce al result = match al with
      | [] -> result
      | (nm, S.Accessor (a, wr, cfg)) :: rest ->
        let result_a = match result with
          | S.Accessor (aa, _, _) -> aa in
        let next = match a with
          | { S.getter = S.Undefined _; S.setter = s; } ->
            S.Accessor ({ S.getter = result_a.S.getter; S.setter = s; }, wr, cfg)
          | { S.getter = g; S.setter = S.Undefined _; } ->
            S.Accessor ({ S.getter = g; S.setter = result_a.S.setter; }, wr, cfg)
          | _ -> S.Accessor (a, wr, cfg) in
        reduce rest next in
    let dup_pairs = accessors pl [] in
    let name_lst = remove_dupes (map (fun (n, _) -> n) dup_pairs) in
    let name_assoc = map (fun n -> (n, tuples dup_pairs n)) name_lst in
    let dummy_prop = 
      S.Accessor (
        { S.getter = S.Undefined (p); S.setter = S.Undefined (p); }, true, true) in
    let reduced_assoc = map (fun (n, al) -> (n, reduce al dummy_prop)) name_assoc in
    let data_props = 
      List.filter (fun p -> let result = 
        match p with (_, _, E.Data _) -> true | _ -> false in result) pl in
    let rec ejsprop_to_sprop pr = match pr with
      | E.Data (e) -> 
          let rec v = exprjs_to_ljs e
          and d = { S.value = v; S.writable = true; } in
          S.Data (d, true, true)
      | E.Getter (nm, e) -> failwith "getters unimplemented"
      | E.Setter (nm, e) -> failwith "setters unimplemented"
    and tuple_to_prop t = match t with
      (p, s, pr) -> (s, ejsprop_to_sprop pr)
    and form_props props = match props with
      | [] -> []
      | first :: rest -> (tuple_to_prop first) :: form_props rest in
    let data_result = form_props data_props in
    let o_attrs = {
      S.code = None;
      S.proto = Some (S.Id (p, "%ObjectProto"));
      S.klass = "Object";
      S.extensible = true; } in
    S.Object (p, o_attrs, List.append reduced_assoc data_result)
  | E.ThisExpr (p) -> failwith "This NYI"
  | E.IdExpr (p, nm) -> S.Id (p, nm)
  | E.BracketExpr (p, l, r) -> 
    let o = exprjs_to_ljs l
    and f = S.Op1 (p, "prim->str", exprjs_to_ljs r) in
    let argsobj = S.Object (p, S.d_attrs, []) in
    S.GetField (p, o, f, argsobj)
  | E.NewExpr _ -> failwith "New NYI"
  | E.PrefixExpr (p, op, exp) -> let result = match op with
    | "postfix:++" ->
      let lhs = match exp with
        | E.BracketExpr (_, E.IdExpr (_, "%context"), E.String (_, nm)) ->
          S.String (p, nm)
        | _ -> failwith "postfix ++ not yet fully implemented"
      and sexp = exprjs_to_ljs exp in
      let bop = S.Op2 (p, "+", sexp, S.Num (p, 1.)) in
      let rec arecd = { S.value = bop; S.writable = true; }
      and aprop = S.Data (arecd, true, true)
      and aobj = S.Object (p, S.d_attrs, [("0", aprop)]) in
      S.SetField (p, S.Id (p, "%context"), lhs, bop, aobj)
    | _ -> S.Op1 (p, op, exprjs_to_ljs exp) in result
  | E.InfixExpr (p, op, l, r) ->
    let sl = exprjs_to_ljs l and sr = exprjs_to_ljs r
    and this = S.Id (p, "%this") in
    let result = match op with
      | "&&" ->
        S.Let (p, "%l-evaled", sl,
          S.If (p, 
            S.App (p, S.Id (p, "%ToBoolean"), [S.Id (p, "%l-evaled")]),
            sr, 
            S.Id (p, "%l-evaled")))
      | "||" ->
        S.Let (p, "%l-evaled", sl,
          S.If (p,
            S.App (p, S.Id (p, "%ToBoolean"), [S.Id (p, "%l-evaled")]),
            S.Id (p, "%l-evaled"),
            sr))
      | "!==" -> S.Op1 (p, "!", S.Op2 (p, "stx=", sl, sr))
      | _ -> let op = match op with
        | "===" -> "abs="
        | "==" -> "stx="
        | _ -> op in S.Op2 (p, op, sl, sr) in result
  | E.IfExpr (p, e1, e2, e3) -> let e1 = exprjs_to_ljs e1
    and e2 = exprjs_to_ljs e2
    and e3 = exprjs_to_ljs e3 in 
    S.If (p, 
      S.App (p, S.Id (p, "%ToBoolean"), [e1]),
      e2, 
      e3)
  | E.AssignExpr (p, obj, pr, vl) -> 
    let sobj = exprjs_to_ljs obj
    and spr = exprjs_to_ljs pr
    and svl = exprjs_to_ljs vl in
    let arecd = { S.value = svl; S.writable = true; } in
    let aprop = S.Data (arecd, true, true) in
    let aobj = S.Object (p, S.d_attrs, [("0", aprop)]) in
    S.SetField (p, sobj, spr, svl, aobj)
  | E.AppExpr (p, e, el) -> 
    let sl = List.map (fun x -> exprjs_to_ljs x) el
    and f = exprjs_to_ljs e in 
    let n_args = List.length sl in
    let indices = Prelude.iota n_args in
    let combined = List.combine indices sl in
    let records =
      List.map (fun (n, arg) -> (n, {S.value = arg; S.writable = true})) combined in
    let props = 
      List.map 
        (fun (n, rcrd) -> (string_of_int n, S.Data (rcrd, true, true))) records in
    let a_attrs = {
        S.code = None;
        S.proto = Some (S.Id (p, "%ArrayProto"));
        S.klass = "Array";
        S.extensible = true; } in
    let lfloat = float_of_int (List.length props) in
    let l_prop = (* TODO: is array length prop writ/enum/configurable? *)
      S.Data (
        { S.value = S.Num (p, lfloat); S.writable = true; },
        false,
        false) in
    let args_obj = S.Object (p, a_attrs, ("length", l_prop) :: props) in
    let this = match f with
      | S.GetField (p, l, r, args) -> l
      | _ -> S.Id (p, "%this") in
    S.App (p, f, [this; args_obj])
  | E.FuncExpr (p, args, body) -> get_fobj p args body (S.Id (p, "%context"))
  | E.LetExpr (p, nm, vl, body) ->
    let sv = exprjs_to_ljs vl
    and sb = exprjs_to_ljs body in
    let result_obj = match nm with
      | "%context" -> let orig_props = match sv with
        | S.Object (_, _, pl) -> pl
        | _ -> failwith "let bound %context to a non-object" in
        let c_attrs = { S.code = None;
                        S.proto = Some (S.Id (p, "%context"));
                        S.klass = "Object";
                        S.extensible = true; } in
        S.Object (p, c_attrs, orig_props)
      | _ -> sv in
    S.Let (p, nm, result_obj, sb)
  | E.SeqExpr (p, e1, e2) -> S.Seq (p, exprjs_to_ljs e1, exprjs_to_ljs e2)
  | E.WhileExpr (p, tst, bdy) ->
    let t = exprjs_to_ljs tst and b = exprjs_to_ljs bdy in get_while t b
  | E.LabelledExpr (p, lbl, exp) -> S.Label (p, lbl, exprjs_to_ljs exp)
  | E.BreakExpr (p, id, e) -> S.Break (p, id, exprjs_to_ljs e)
  | E.ForInExpr (p, nm, vl, bdy) ->
    get_forin p nm (exprjs_to_ljs vl) (exprjs_to_ljs bdy)
  | E.TryCatchExpr (p, body, ident, catch) -> 
    let new_ctxt = 
      S.Object (p, { S.d_attrs with S.proto = Some (S.Id (p, "%parent")) },
                [(ident, 
                  S.Data ({ S.value = S.Id (p, ident); S.writable = true }, 
                         false, false) );])
    in
    S.TryCatch (p, exprjs_to_ljs body, 
                S.Lambda(p, [ident], 
                         S.Let (p, "%parent", S.Id (p, "%context") ,
                                S.Let (p, "%context", new_ctxt, 
                                       exprjs_to_ljs catch))))
  | E.FuncStmtExpr (p, nm, args, body) -> 
    let fobj = get_fobj p args body (S.Id (p, "%context")) in
    let arcrd = { S.value = fobj; S.writable = true; } in
    let aprop = S.Data (arcrd, true, true) in
    let aprops = [("0", aprop)] in
    let argsobj = S.Object (p, S.d_attrs, aprops) in
    S.SetField (p, S.Id (p, "%context"), S.String (p, nm), fobj, argsobj)
  | E.TryFinallyExpr (p, body, finally) -> 
    S.TryFinally (p, exprjs_to_ljs body, exprjs_to_ljs finally)
  | E.ThrowExpr (p, e) -> S.Throw (p, exprjs_to_ljs e)
  | E.HintExpr _ -> failwith "Bizarre error: Hint found somehow"

and get_fobj p args body context = 
  let call = get_lambda p args body in
  let fproto = S.Id (p, "%FunctionProto") in
  let fobj_attrs = 
    { S.code = Some (call); S.proto = Some (fproto); S.klass = "Function"; 
    S.extensible = true; } in
  let param_len = List.length args in
  let indices = Prelude.iota param_len in
  let combined = List.combine indices args in
  let rcds =
    List.map (fun (n, prm) -> (n, {S.value = S.String (p, prm); S.writable =
      true;})) combined in
{'fraction_non_alphanumeric': 0.15837333825701624, 'fraction_numerical': 0.00267725258493353, 'mean_word_length': 1.997371333702269, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 163, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '194684', 'n_tokens_mistral': 8427, 'n_tokens_neox': 8285, 'n_words': 2548}