Skip to content

Commit 84e9cbe

Browse files
committed
prop punning conversion
1 parent e565ca7 commit 84e9cbe

File tree

2 files changed

+84
-11
lines changed

2 files changed

+84
-11
lines changed

compiler/ml/ast_mapper_from0.ml

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ module E = struct
310310
in
311311
visit e
312312

313+
let skip_last_two_elements elements =
314+
let length = List.length elements in
315+
List.filteri (fun i _ -> i < length - 2) elements
316+
313317
let map sub e =
314318
let {pexp_loc = loc; pexp_desc = desc; pexp_attributes = attrs} = e in
315319
let open Exp in
@@ -330,10 +334,35 @@ module E = struct
330334
(map_opt (sub.expr sub) def)
331335
(sub.pat sub p) (sub.expr sub e)
332336
| Pexp_function _ -> assert false
333-
| Pexp_apply ({pexp_desc = Pexp_ident tag_name}, _args)
337+
| Pexp_apply ({pexp_desc = Pexp_ident tag_name}, args)
334338
when has_jsx_attribute () ->
335339
let attrs = attrs |> List.filter (fun ({txt}, _) -> txt <> "JSX") in
336-
jsx_unary_element ~loc ~attrs tag_name []
340+
let props =
341+
args
342+
(* The last args are children and unit *)
343+
|> skip_last_two_elements
344+
|> List.filter_map (fun (lbl, e) ->
345+
match (lbl, e) with
346+
| ( Asttypes.Noloc.Labelled name,
347+
{
348+
pexp_desc = Pexp_ident {txt = Longident.Lident v};
349+
pexp_loc = name_loc;
350+
} )
351+
when name = v ->
352+
Some
353+
(Parsetree.JSXPropPunning
354+
(false, {txt = name; loc = name_loc}))
355+
| ( Asttypes.Noloc.Optional name,
356+
{
357+
pexp_desc = Pexp_ident {txt = Longident.Lident v};
358+
pexp_loc = name_loc;
359+
} )
360+
when name = v ->
361+
Some
362+
(Parsetree.JSXPropPunning (true, {txt = name; loc = name_loc}))
363+
| _ -> None)
364+
in
365+
jsx_unary_element ~loc ~attrs tag_name props
337366
| Pexp_apply (e, l) ->
338367
let e =
339368
match (e.pexp_desc, l) with

compiler/ml/ast_mapper_to0.ml

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,29 @@ module E = struct
284284
let jsx_attr sub =
285285
sub.attribute sub (Location.mknoloc "JSX", Parsetree.PStr [])
286286

287+
let offset_position (pos : Lexing.position) (offset : int) : Lexing.position =
288+
if offset <= 0 then pos
289+
else
290+
let open Lexing in
291+
let rec aux pos offset =
292+
if offset <= 0 then pos
293+
else if offset <= pos.pos_cnum - pos.pos_bol then
294+
(* We're on the same line *)
295+
{pos with pos_cnum = pos.pos_cnum - offset}
296+
else
297+
(* Move to previous line and continue *)
298+
let remaining = offset - (pos.pos_cnum - pos.pos_bol) in
299+
aux
300+
{
301+
pos with
302+
pos_lnum = pos.pos_lnum - 1;
303+
pos_cnum = pos.pos_bol;
304+
pos_bol = max 0 (pos.pos_bol - remaining);
305+
}
306+
remaining
307+
in
308+
aux pos offset
309+
287310
(* Value expressions for the core language *)
288311

289312
let map sub {pexp_loc = loc; pexp_desc = desc; pexp_attributes = attrs} =
@@ -426,24 +449,45 @@ module E = struct
426449

427450
{mapped with pexp_attributes = jsx_attr sub :: attrs}
428451
| Pexp_jsx_unary_element
429-
{
430-
jsx_unary_element_tag_name = tag_name;
431-
jsx_unary_element_props = _props;
432-
} ->
452+
{jsx_unary_element_tag_name = tag_name; jsx_unary_element_props = props}
453+
->
433454
let tag_ident = map_loc sub tag_name in
455+
let props =
456+
props
457+
|> List.map (function
458+
| JSXPropPunning (is_optional, name) ->
459+
let ident =
460+
ident ~loc:name.loc
461+
{txt = Longident.Lident name.txt; loc = name.loc}
462+
in
463+
let label =
464+
if is_optional then Asttypes.Noloc.Optional name.txt
465+
else Asttypes.Noloc.Labelled name.txt
466+
in
467+
(label, ident)
468+
| _ -> failwith "todo")
469+
in
434470
let children_expr =
435-
Ast_helper0.Exp.construct ~loc {txt = Lident "()"; loc} None
471+
let loc =
472+
{
473+
loc_ghost = true;
474+
loc_start = offset_position loc.loc_end 2;
475+
loc_end = offset_position loc.loc_end 1;
476+
}
477+
in
478+
Ast_helper0.Exp.construct ~loc {txt = Lident "[]"; loc} None
436479
in
437480
let unit_expr =
438481
Ast_helper0.Exp.construct ~loc:!Ast_helper0.default_loc
439482
{txt = Lident "()"; loc = !Ast_helper0.default_loc}
440483
None
441484
in
442485
apply ~loc ~attrs:(jsx_attr sub :: attrs) (ident tag_ident)
443-
[
444-
(Asttypes.Noloc.Labelled "children", children_expr);
445-
(Asttypes.Noloc.Nolabel, unit_expr);
446-
]
486+
(props
487+
@ [
488+
(Asttypes.Noloc.Labelled "children", children_expr);
489+
(Asttypes.Noloc.Nolabel, unit_expr);
490+
])
447491
| Pexp_jsx_container_element _ ->
448492
failwith "TODO: Pexp_jsx_container_element 1"
449493
end

0 commit comments

Comments
 (0)