diff --git a/analysis/src/Utils.ml b/analysis/src/Utils.ml index 863598dc56..33bee9ad16 100644 --- a/analysis/src/Utils.ml +++ b/analysis/src/Utils.ml @@ -95,6 +95,8 @@ let identifyPexp pexp = | Pexp_record _ -> "Pexp_record" | Pexp_field _ -> "Pexp_field" | Pexp_setfield _ -> "Pexp_setfield" + | Pexp_index _ -> "Pexp_index" + | Pexp_setindex _ -> "Pexp_setindex" | Pexp_array _ -> "Pexp_array" | Pexp_ifthenelse _ -> "Pexp_ifthenelse" | Pexp_sequence _ -> "Pexp_sequence" diff --git a/compiler/frontend/bs_ast_mapper.ml b/compiler/frontend/bs_ast_mapper.ml index 292e199b5a..afa7a7559f 100644 --- a/compiler/frontend/bs_ast_mapper.ml +++ b/compiler/frontend/bs_ast_mapper.ml @@ -350,6 +350,10 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) + | Pexp_index (e1, e2) -> + index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) + | Pexp_setindex (e1, e2, e3) -> + setindex ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) (sub.expr sub e3) | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/ast_helper.ml b/compiler/ml/ast_helper.ml index 2fae640eb0..cd55b743ca 100644 --- a/compiler/ml/ast_helper.ml +++ b/compiler/ml/ast_helper.ml @@ -174,6 +174,8 @@ module Exp = struct let record ?loc ?attrs a b = mk ?loc ?attrs (Pexp_record (a, b)) let field ?loc ?attrs a b = mk ?loc ?attrs (Pexp_field (a, b)) let setfield ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_setfield (a, b, c)) + let index ?loc ?attrs a b = mk ?loc ?attrs (Pexp_index (a, b)) + let setindex ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_setindex (a, b, c)) let array ?loc ?attrs a = mk ?loc ?attrs (Pexp_array a) let ifthenelse ?loc ?attrs a b c = mk ?loc ?attrs (Pexp_ifthenelse (a, b, c)) let sequence ?loc ?attrs a b = mk ?loc ?attrs (Pexp_sequence (a, b)) diff --git a/compiler/ml/ast_helper.mli b/compiler/ml/ast_helper.mli index 11227b903a..ba3830aac0 100644 --- a/compiler/ml/ast_helper.mli +++ b/compiler/ml/ast_helper.mli @@ -163,6 +163,14 @@ module Exp : sig val field : ?loc:loc -> ?attrs:attrs -> expression -> lid -> expression val setfield : ?loc:loc -> ?attrs:attrs -> expression -> lid -> expression -> expression + val index : ?loc:loc -> ?attrs:attrs -> expression -> expression -> expression + val setindex : + ?loc:loc -> + ?attrs:attrs -> + expression -> + expression -> + expression -> + expression val array : ?loc:loc -> ?attrs:attrs -> expression list -> expression val ifthenelse : ?loc:loc -> diff --git a/compiler/ml/ast_iterator.ml b/compiler/ml/ast_iterator.ml index a430bb0b7b..ad61a99377 100644 --- a/compiler/ml/ast_iterator.ml +++ b/compiler/ml/ast_iterator.ml @@ -321,6 +321,13 @@ module E = struct sub.expr sub e1; iter_loc sub lid; sub.expr sub e2 + | Pexp_index (e1, e2) -> + sub.expr sub e1; + sub.expr sub e2 + | Pexp_setindex (e1, e2, e3) -> + sub.expr sub e1; + sub.expr sub e2; + sub.expr sub e3 | Pexp_array el -> List.iter (sub.expr sub) el | Pexp_ifthenelse (e1, e2, e3) -> sub.expr sub e1; diff --git a/compiler/ml/ast_mapper.ml b/compiler/ml/ast_mapper.ml index 673465477b..20683bfa98 100644 --- a/compiler/ml/ast_mapper.ml +++ b/compiler/ml/ast_mapper.ml @@ -313,6 +313,10 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) + | Pexp_index (e1, e2) -> + index ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) + | Pexp_setindex (e1, e2, e3) -> + setindex ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) (sub.expr sub e3) | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/ast_mapper_to0.ml b/compiler/ml/ast_mapper_to0.ml index d0ac43d737..3f0b10345f 100644 --- a/compiler/ml/ast_mapper_to0.ml +++ b/compiler/ml/ast_mapper_to0.ml @@ -439,6 +439,24 @@ module E = struct field ~loc ~attrs (sub.expr sub e) (map_loc sub lid) | Pexp_setfield (e1, lid, e2) -> setfield ~loc ~attrs (sub.expr sub e1) (map_loc sub lid) (sub.expr sub e2) + | Pexp_index (e1, e2) -> + (* Map back to Array.get for parsetree0 compatibility *) + let container = sub.expr sub e1 in + let index = sub.expr sub e2 in + let array_get = + ident ~loc (mknoloc (Longident.Ldot (Longident.Lident "Array", "get"))) + in + apply ~loc ~attrs array_get [(Nolabel, container); (Nolabel, index)] + | Pexp_setindex (e1, e2, e3) -> + (* Map back to Array.set for parsetree0 compatibility *) + let container = sub.expr sub e1 in + let index = sub.expr sub e2 in + let value_expr = sub.expr sub e3 in + let array_set = + ident ~loc (mknoloc (Longident.Ldot (Longident.Lident "Array", "set"))) + in + apply ~loc ~attrs array_set + [(Nolabel, container); (Nolabel, index); (Nolabel, value_expr)] | Pexp_array el -> array ~loc ~attrs (List.map (sub.expr sub) el) | Pexp_ifthenelse (e1, e2, e3) -> ifthenelse ~loc ~attrs (sub.expr sub e1) (sub.expr sub e2) diff --git a/compiler/ml/depend.ml b/compiler/ml/depend.ml index e5e39eb4b5..6b396bb618 100644 --- a/compiler/ml/depend.ml +++ b/compiler/ml/depend.ml @@ -248,6 +248,13 @@ let rec add_expr bv exp = add_expr bv e1; add bv fld; add_expr bv e2 + | Pexp_index (e1, e2) -> + add_expr bv e1; + add_expr bv e2 + | Pexp_setindex (e1, e2, e3) -> + add_expr bv e1; + add_expr bv e2; + add_expr bv e3 | Pexp_array el -> List.iter (add_expr bv) el | Pexp_ifthenelse (e1, e2, opte3) -> add_expr bv e1; diff --git a/compiler/ml/parsetree.ml b/compiler/ml/parsetree.ml index 78c9899f74..1d35143d99 100644 --- a/compiler/ml/parsetree.ml +++ b/compiler/ml/parsetree.ml @@ -279,6 +279,8 @@ and expression_desc = *) | Pexp_field of expression * Longident.t loc (* E.l *) | Pexp_setfield of expression * Longident.t loc * expression (* E1.l <- E2 *) + | Pexp_index of expression * expression (* E1[E2] *) + | Pexp_setindex of expression * expression * expression (* E1[E2] = E3 *) | Pexp_array of expression list (* [| E1; ...; En |] *) | Pexp_ifthenelse of expression * expression * expression option (* if E1 then E2 else E3 *) diff --git a/compiler/ml/pprintast.ml b/compiler/ml/pprintast.ml index 585ac64b81..9688f606cd 100644 --- a/compiler/ml/pprintast.ml +++ b/compiler/ml/pprintast.ml @@ -691,6 +691,11 @@ and expression ctxt f x = | Pexp_setfield (e1, li, e2) -> pp f "@[<2>%a.%a@ <-@ %a@]" (simple_expr ctxt) e1 longident_loc li (simple_expr ctxt) e2 + | Pexp_index (e1, e2) -> + pp f "%a.(%a)" (simple_expr ctxt) e1 (expression ctxt) e2 + | Pexp_setindex (e1, e2, e3) -> + pp f "%a.(%a)@ <-@ %a" (simple_expr ctxt) e1 (expression ctxt) e2 + (simple_expr ctxt) e3 | Pexp_ifthenelse (e1, e2, eo) -> (* @;@[<2>else@ %a@]@] *) let fmt : (_, _, _) format = diff --git a/compiler/ml/printast.ml b/compiler/ml/printast.ml index 44d699eb38..22d7aaa8a3 100644 --- a/compiler/ml/printast.ml +++ b/compiler/ml/printast.ml @@ -294,6 +294,18 @@ and expression i ppf x = expression i ppf e1; longident_loc i ppf li; expression i ppf e2 + | Pexp_index (e1, e2) -> + line i ppf "Pexp_index\n"; + expression i ppf e1; + line i ppf "index:\n"; + expression i ppf e2 + | Pexp_setindex (e1, e2, e3) -> + line i ppf "Pexp_setindex\n"; + expression i ppf e1; + line i ppf "index:\n"; + expression i ppf e2; + line i ppf "value:\n"; + expression i ppf e3 | Pexp_array l -> line i ppf "Pexp_array\n"; list i expression ppf l diff --git a/compiler/ml/printtyped.ml b/compiler/ml/printtyped.ml index 6e36b4276c..a334dd07ab 100644 --- a/compiler/ml/printtyped.ml +++ b/compiler/ml/printtyped.ml @@ -329,6 +329,18 @@ and expression i ppf x = expression i ppf e1; longident i ppf li; expression i ppf e2 + | Texp_index (e1, e2) -> + line i ppf "Texp_index\n"; + expression i ppf e1; + line i ppf "index:\n"; + expression i ppf e2 + | Texp_setindex (e1, e2, e3) -> + line i ppf "Texp_setindex\n"; + expression i ppf e1; + line i ppf "index:\n"; + expression i ppf e2; + line i ppf "value:\n"; + expression i ppf e3 | Texp_array l -> line i ppf "Texp_array\n"; list i expression ppf l diff --git a/compiler/ml/rec_check.ml b/compiler/ml/rec_check.ml index 3d016a7438..95217d1318 100644 --- a/compiler/ml/rec_check.ml +++ b/compiler/ml/rec_check.ml @@ -196,8 +196,8 @@ let rec classify_expression : Typedtree.expression -> sd = classify_expression e | Texp_ident _ | Texp_for _ | Texp_constant _ | Texp_tuple _ | Texp_array _ | Texp_construct _ | Texp_variant _ | Texp_record _ | Texp_setfield _ - | Texp_while _ | Texp_pack _ | Texp_function _ | Texp_extension_constructor _ - -> + | Texp_index _ | Texp_setindex _ | Texp_while _ | Texp_pack _ + | Texp_function _ | Texp_extension_constructor _ -> Static | Texp_apply {funct = {exp_desc = Texp_ident (_, _, vd)}} when is_ref vd -> Static @@ -273,6 +273,13 @@ let rec expression : Env.env -> Typedtree.expression -> Use.t = (join (expression env ifso) (option expression env ifnot))) | Texp_setfield (e1, _, _, e2) -> Use.(join (inspect (expression env e1)) (inspect (expression env e2))) + | Texp_index (e1, e2) -> + Use.(join (inspect (expression env e1)) (inspect (expression env e2))) + | Texp_setindex (e1, e2, e3) -> + Use.( + join + (join (inspect (expression env e1)) (inspect (expression env e2))) + (inspect (expression env e3))) | Texp_sequence (e1, e2) -> Use.(join (discard (expression env e1)) (expression env e2)) | Texp_while (e1, e2) -> diff --git a/compiler/ml/tast_iterator.ml b/compiler/ml/tast_iterator.ml index 5c12d3da4d..56658826f1 100644 --- a/compiler/ml/tast_iterator.ml +++ b/compiler/ml/tast_iterator.ml @@ -176,6 +176,13 @@ let expr sub {exp_extra; exp_desc; exp_env; _} = | Texp_setfield (exp1, _, _, exp2) -> sub.expr sub exp1; sub.expr sub exp2 + | Texp_index (exp1, exp2) -> + sub.expr sub exp1; + sub.expr sub exp2 + | Texp_setindex (exp1, exp2, exp3) -> + sub.expr sub exp1; + sub.expr sub exp2; + sub.expr sub exp3 | Texp_array list -> List.iter (sub.expr sub) list | Texp_ifthenelse (exp1, exp2, expo) -> sub.expr sub exp1; diff --git a/compiler/ml/tast_mapper.ml b/compiler/ml/tast_mapper.ml index 54eba02869..8547012c97 100644 --- a/compiler/ml/tast_mapper.ml +++ b/compiler/ml/tast_mapper.ml @@ -232,6 +232,10 @@ let expr sub x = | Texp_field (exp, lid, ld) -> Texp_field (sub.expr sub exp, lid, ld) | Texp_setfield (exp1, lid, ld, exp2) -> Texp_setfield (sub.expr sub exp1, lid, ld, sub.expr sub exp2) + | Texp_index (exp1, exp2) -> + Texp_index (sub.expr sub exp1, sub.expr sub exp2) + | Texp_setindex (exp1, exp2, exp3) -> + Texp_setindex (sub.expr sub exp1, sub.expr sub exp2, sub.expr sub exp3) | Texp_array list -> Texp_array (List.map (sub.expr sub) list) | Texp_ifthenelse (exp1, exp2, expo) -> Texp_ifthenelse diff --git a/compiler/ml/translcore.ml b/compiler/ml/translcore.ml index 078cbf133a..4f31957aa1 100644 --- a/compiler/ml/translcore.ml +++ b/compiler/ml/translcore.ml @@ -891,6 +891,17 @@ and transl_exp0 (e : Typedtree.expression) : Lambda.lambda = Psetfield (lbl.lbl_pos + 1, Lambda.fld_record_extension_set lbl) in Lprim (access, [transl_exp arg; transl_exp newval], e.exp_loc) + | Texp_index (container, index) -> + (* Read: translate to Parrayrefu primitive (unsafe array get) *) + let container_lambda = transl_exp container in + let index_lambda = transl_exp index in + Lprim (Parrayrefu, [container_lambda; index_lambda], e.exp_loc) + | Texp_setindex (container, index, value) -> + (* Write: translate to Parraysetu primitive (unsafe array set) *) + let container_lambda = transl_exp container in + let index_lambda = transl_exp index in + let value_lambda = transl_exp value in + Lprim (Parraysetu, [container_lambda; index_lambda; value_lambda], e.exp_loc) | Texp_array expr_list -> let ll = transl_list expr_list in Lprim (Pmakearray Mutable, ll, e.exp_loc) diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index ee304dff7d..96adf873ff 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -178,10 +178,16 @@ let iter_expression f e = | Pexp_letexception (_, e) | Pexp_field (e, _) -> expr e - | Pexp_while (e1, e2) | Pexp_sequence (e1, e2) | Pexp_setfield (e1, _, e2) - -> + | Pexp_while (e1, e2) + | Pexp_sequence (e1, e2) + | Pexp_setfield (e1, _, e2) + | Pexp_index (e1, e2) -> expr e1; expr e2 + | Pexp_setindex (e1, e2, e3) -> + expr e1; + expr e2; + expr e3 | Pexp_ifthenelse (e1, e2, eo) -> expr e1; expr e2; @@ -2834,6 +2840,51 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected) exp_attributes = sexp.pexp_attributes; exp_env = env; } + | Pexp_index (scontainer, sindex) -> + (* Read access: arr[i] -> array<'a> -> int -> 'a *) + let container = type_exp ~context:None env scontainer in + let index = + type_expect ~context:None env sindex (instance_def Predef.type_int) + in + let element_type = newgenvar () in + let array_type = instance_def (Predef.type_array element_type) in + unify_exp ~context:None env container array_type; + rue + { + exp_desc = Texp_index (container, index); + exp_loc = loc; + exp_extra = []; + exp_type = instance env element_type; + exp_attributes = sexp.pexp_attributes; + exp_env = env; + } + | Pexp_setindex (scontainer, sindex, svalue) -> + (* Write access: arr[i] = v -> array<'a> -> int -> 'a -> unit *) + let container = type_exp ~context:None env scontainer in + let index = + type_expect ~context:None env sindex (instance_def Predef.type_int) + in + (* Extract element type from container to preserve arity information *) + let element_type = + match (expand_head env container.exp_type).desc with + | Tconstr (Pident {name = "array"}, [element_ty], _) -> element_ty + | _ -> + (* Fallback: create fresh type variable and unify *) + let element_type = newgenvar () in + let array_type = instance_def (Predef.type_array element_type) in + unify_exp ~context:None env container array_type; + element_type + in + let value = type_expect ~context:None env svalue element_type in + rue + { + exp_desc = Texp_setindex (container, index, value); + exp_loc = loc; + exp_extra = []; + exp_type = instance_def Predef.type_unit; + exp_attributes = sexp.pexp_attributes; + exp_env = env; + } | Pexp_array sargl -> let ty = newgenvar () in let to_unify = Predef.type_array ty in diff --git a/compiler/ml/typedtree.ml b/compiler/ml/typedtree.ml index e7274f1245..2c9c8b5433 100644 --- a/compiler/ml/typedtree.ml +++ b/compiler/ml/typedtree.ml @@ -106,6 +106,8 @@ and expression_desc = | Texp_field of expression * Longident.t loc * label_description | Texp_setfield of expression * Longident.t loc * label_description * expression + | Texp_index of expression * expression + | Texp_setindex of expression * expression * expression | Texp_array of expression list | Texp_ifthenelse of expression * expression * expression option | Texp_sequence of expression * expression diff --git a/compiler/ml/typedtree.mli b/compiler/ml/typedtree.mli index b1e7083fc7..13f5fcaba3 100644 --- a/compiler/ml/typedtree.mli +++ b/compiler/ml/typedtree.mli @@ -207,6 +207,8 @@ and expression_desc = | Texp_field of expression * Longident.t loc * label_description | Texp_setfield of expression * Longident.t loc * label_description * expression + | Texp_index of expression * expression + | Texp_setindex of expression * expression * expression | Texp_array of expression list | Texp_ifthenelse of expression * expression * expression option | Texp_sequence of expression * expression diff --git a/compiler/ml/typedtreeIter.ml b/compiler/ml/typedtreeIter.ml index 9a31b9b5b9..5596b4dda3 100644 --- a/compiler/ml/typedtreeIter.ml +++ b/compiler/ml/typedtreeIter.ml @@ -261,6 +261,13 @@ end = struct | Texp_setfield (exp1, _, _label, exp2) -> iter_expression exp1; iter_expression exp2 + | Texp_index (exp1, exp2) -> + iter_expression exp1; + iter_expression exp2 + | Texp_setindex (exp1, exp2, exp3) -> + iter_expression exp1; + iter_expression exp2; + iter_expression exp3 | Texp_array list -> List.iter iter_expression list | Texp_ifthenelse (exp1, exp2, expo) -> ( iter_expression exp1; diff --git a/compiler/syntax/src/res_ast_debugger.ml b/compiler/syntax/src/res_ast_debugger.ml index 52a57b89c5..8d283c9f7f 100644 --- a/compiler/syntax/src/res_ast_debugger.ml +++ b/compiler/syntax/src/res_ast_debugger.ml @@ -641,6 +641,16 @@ module SexpAst = struct longident longident_loc.Asttypes.txt; expression expr2; ] + | Pexp_index (e1, e2) -> + Sexp.list [Sexp.atom "Pexp_index"; expression e1; expression e2] + | Pexp_setindex (e1, e2, e3) -> + Sexp.list + [ + Sexp.atom "Pexp_setindex"; + expression e1; + expression e2; + expression e3; + ] | Pexp_array exprs -> Sexp.list [Sexp.atom "Pexp_array"; Sexp.list (map_empty ~f:expression exprs)] diff --git a/compiler/syntax/src/res_comments_table.ml b/compiler/syntax/src/res_comments_table.ml index 6774b2bc2b..c14b6a1852 100644 --- a/compiler/syntax/src/res_comments_table.ml +++ b/compiler/syntax/src/res_comments_table.ml @@ -476,6 +476,8 @@ let rec is_block_expr expr = | Pexp_constraint (expr, _) when is_block_expr expr -> true | Pexp_field (expr, _) when is_block_expr expr -> true | Pexp_setfield (expr, _, _) when is_block_expr expr -> true + | Pexp_index (expr, _) when is_block_expr expr -> true + | Pexp_setindex (expr, _, _) when is_block_expr expr -> true | _ -> false let is_if_then_else_expr expr = @@ -1313,6 +1315,75 @@ and walk_expression expr t comments = attach t.leading expr2.pexp_loc leading; walk_expression expr2 t inside; attach t.trailing expr2.pexp_loc trailing + | Pexp_index (container, index) -> + let leading, inside, trailing = + partition_by_loc comments container.pexp_loc + in + let rest = + if is_block_expr container then ( + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + walk_expression container t (List.concat [leading; inside; after_expr]); + rest) + else + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + attach t.leading container.pexp_loc leading; + walk_expression container t inside; + attach t.trailing container.pexp_loc after_expr; + rest + in + if is_block_expr index then walk_expression index t rest + else + let leading, inside, trailing = partition_by_loc rest index.pexp_loc in + attach t.leading index.pexp_loc leading; + walk_expression index t inside; + attach t.trailing index.pexp_loc trailing + | Pexp_setindex (container, index, value) -> + let leading, inside, trailing = + partition_by_loc comments container.pexp_loc + in + let rest = + if is_block_expr container then ( + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + walk_expression container t (List.concat [leading; inside; after_expr]); + rest) + else + let after_expr, rest = + partition_adjacent_trailing container.pexp_loc trailing + in + attach t.leading container.pexp_loc leading; + walk_expression container t inside; + attach t.trailing container.pexp_loc after_expr; + rest + in + let leading, inside, trailing = partition_by_loc rest index.pexp_loc in + let rest = + if is_block_expr index then ( + let after_expr, rest = + partition_adjacent_trailing index.pexp_loc trailing + in + walk_expression index t (List.concat [leading; inside; after_expr]); + rest) + else + let after_expr, rest = + partition_adjacent_trailing index.pexp_loc trailing + in + attach t.leading index.pexp_loc leading; + walk_expression index t inside; + attach t.trailing index.pexp_loc after_expr; + rest + in + if is_block_expr value then walk_expression value t rest + else + let leading, inside, trailing = partition_by_loc rest value.pexp_loc in + attach t.leading value.pexp_loc leading; + walk_expression value t inside; + attach t.trailing value.pexp_loc trailing | Pexp_ifthenelse (if_expr, then_expr, else_expr) -> ( let leading, rest = partition_leading_trailing comments expr.pexp_loc in attach t.leading expr.pexp_loc leading; diff --git a/compiler/syntax/src/res_core.ml b/compiler/syntax/src/res_core.ml index aab15e930f..3ab19af28f 100644 --- a/compiler/syntax/src/res_core.ml +++ b/compiler/syntax/src/res_core.ml @@ -2156,7 +2156,6 @@ and parse_first_class_module_expr ~start_pos p = and parse_bracket_access p expr start_pos = Parser.leave_breadcrumb p Grammar.ExprArrayAccess; - let lbracket = p.start_pos in Parser.expect Lbracket p; let string_start = p.start_pos in match p.Parser.token with @@ -2189,38 +2188,22 @@ and parse_bracket_access p expr start_pos = let access_expr = parse_constrained_or_coerced_expr p in Parser.expect Rbracket p; Parser.eat_breadcrumb p; - let rbracket = p.prev_end_pos in - let array_loc = mk_loc lbracket rbracket in match p.token with | Equal -> Parser.leave_breadcrumb p ExprArrayMutation; Parser.next p; let rhs_expr = parse_expr p in - (* FIXME: Do not implicitly rely on specific module name, even primitive one - - This can be abused like - module Array = MyModule - - Find better mechanism to support it - *) - let array_set = - Location.mkloc (Longident.Ldot (Lident "Array", "set")) array_loc - in let end_pos = p.prev_end_pos in - let array_set = - Ast_helper.Exp.apply ~loc:(mk_loc start_pos end_pos) - (Ast_helper.Exp.ident ~loc:array_loc array_set) - [(Nolabel, expr); (Nolabel, access_expr); (Nolabel, rhs_expr)] + let setindex_expr = + Ast_helper.Exp.setindex ~loc:(mk_loc start_pos end_pos) expr access_expr + rhs_expr in Parser.eat_breadcrumb p; - array_set + setindex_expr | _ -> let end_pos = p.prev_end_pos in let e = - Ast_helper.Exp.apply ~loc:(mk_loc start_pos end_pos) - (Ast_helper.Exp.ident ~loc:array_loc - (Location.mkloc (Longident.Ldot (Lident "Array", "get")) array_loc)) - [(Nolabel, expr); (Nolabel, access_expr)] + Ast_helper.Exp.index ~loc:(mk_loc start_pos end_pos) expr access_expr in parse_primary_expr ~operand:e p) diff --git a/compiler/syntax/src/res_parsetree_viewer.ml b/compiler/syntax/src/res_parsetree_viewer.ml index 391e51bede..1715bd0cf4 100644 --- a/compiler/syntax/src/res_parsetree_viewer.ml +++ b/compiler/syntax/src/res_parsetree_viewer.ml @@ -429,6 +429,8 @@ let has_attributes attrs = let is_array_access expr = match expr.pexp_desc with + | Pexp_index _ -> true + (* TODO: Now we have dedicated index access, we can clean up the below AST? *) | Pexp_apply { funct = diff --git a/compiler/syntax/src/res_printer.ml b/compiler/syntax/src/res_printer.ml index 2010d23f6d..5541031c71 100644 --- a/compiler/syntax/src/res_printer.ml +++ b/compiler/syntax/src/res_printer.ml @@ -3374,6 +3374,88 @@ and print_expression ~state (e : Parsetree.expression) cmt_tbl = | Pexp_setfield (expr1, longident_loc, expr2) -> print_set_field_expr ~state e.pexp_attributes expr1 longident_loc expr2 e.pexp_loc cmt_tbl + | Pexp_index (container, index) -> + (* Read: container[index] *) + let container_doc = + let doc = print_expression_with_comments ~state container cmt_tbl in + match Parens.field_expr container with + | Parens.Parenthesized -> add_parens doc + | Braced braces -> print_braces doc container braces + | Nothing -> doc + in + let index_has_braces, index_doc = + let doc = print_expression_with_comments ~state index cmt_tbl in + match Parens.expr index with + | Parens.Parenthesized -> (false, add_parens doc) + | Braced braces -> (true, print_braces doc index braces) + | Nothing -> (false, doc) + in + if index_has_braces then + Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] + else + Doc.concat + [ + container_doc; + Doc.group + (Doc.concat + [ + Doc.lbracket; + Doc.indent (Doc.concat [Doc.soft_line; index_doc]); + Doc.soft_line; + Doc.rbracket; + ]); + ] + | Pexp_setindex (container, index, value) -> + (* Write: container[index] = value *) + let container_doc = + let doc = print_expression_with_comments ~state container cmt_tbl in + match Parens.field_expr container with + | Parens.Parenthesized -> add_parens doc + | Braced braces -> print_braces doc container braces + | Nothing -> doc + in + let index_has_braces, index_doc = + let doc = print_expression_with_comments ~state index cmt_tbl in + match Parens.expr index with + | Parens.Parenthesized -> (false, add_parens doc) + | Braced braces -> (true, print_braces doc index braces) + | Nothing -> (false, doc) + in + let value_has_braces, value_doc = + let doc = print_expression_with_comments ~state value cmt_tbl in + match Parens.set_field_expr_rhs value with + | Parens.Parenthesized -> (false, add_parens doc) + | Braced braces -> (true, print_braces doc value braces) + | Nothing -> (false, doc) + in + let should_indent = + (not value_has_braces) && ParsetreeViewer.is_binary_expression value + in + let bracket_doc = + if index_has_braces then + Doc.concat [container_doc; Doc.lbracket; index_doc; Doc.rbracket] + else + Doc.concat + [ + container_doc; + Doc.group + (Doc.concat + [ + Doc.lbracket; + Doc.indent (Doc.concat [Doc.soft_line; index_doc]); + Doc.soft_line; + Doc.rbracket; + ]); + ] + in + Doc.concat + [ + bracket_doc; + Doc.text " ="; + (if should_indent then + Doc.group (Doc.indent (Doc.concat [Doc.line; value_doc])) + else Doc.concat [Doc.space; value_doc]); + ] | Pexp_ifthenelse (_ifExpr, _thenExpr, _elseExpr) when ParsetreeViewer.is_ternary_expr e -> let parts, alternate = ParsetreeViewer.collect_ternary_parts e in