Skip to content

Commit 9daabe0

Browse files
committed
Normalize PPX-rewritten template segments
Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent 5eae0c5 commit 9daabe0

2 files changed

Lines changed: 54 additions & 8 deletions

File tree

compiler/ml/ast_mapper_from0.ml

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,11 @@ let semantic_string semantic =
122122
let source_string ~loc source =
123123
Pt.Pconst_string {source; semantic = decode_js_string ~loc source}
124124

125+
let template_source_from0 = function
126+
| source, Some ("js" | "*j") -> source
127+
| semantic, _ ->
128+
String_literal.encode_js_template (normalize_ppx_semantic_string semantic)
129+
125130
let map_constant ~loc = function
126131
| Pconst_integer (s, suffix) -> Pt.Pconst_integer (s, suffix)
127132
| Pconst_char semantic ->
@@ -600,9 +605,10 @@ module E = struct
600605
let inner = sub.expr sub {e with pexp_attributes = inner_attrs0} in
601606
await ~loc ~attrs:(sub.attributes sub await_attrs0) inner
602607
| Pexp_ident x -> ident ~loc ~attrs (map_loc sub x)
603-
| Pexp_constant (Pconst_string (source, Some "js"))
604-
when has_template_attr attrs ->
608+
| Pexp_constant (Pconst_string (text, delimiter))
609+
when has_template_attr attrs && delimiter <> Some "json" ->
605610
let attrs = remove_template_attr attrs in
611+
let source = template_source_from0 (text, delimiter) in
606612
template ~loc ~attrs [{txt = source; loc}] []
607613
| Pexp_constant x ->
608614
let template = has_template_attr attrs in
@@ -751,26 +757,31 @@ module E = struct
751757
"`json` literals do not support interpolation"
752758
in
753759
let rec collect sources values = function
760+
| [{pexp_desc = Pexp_constant (Pconst_string (_, Some "json"))}] ->
761+
reject_json_interpolation ()
754762
| [
755763
{
756-
pexp_desc = Pexp_constant (Pconst_string (txt, Some "js"));
764+
pexp_desc = Pexp_constant (Pconst_string (text, delimiter));
757765
pexp_loc;
758766
};
759767
] ->
768+
let txt = template_source_from0 (text, delimiter) in
760769
Some
761770
( List.rev
762771
({Location.txt; loc = sub.location sub pexp_loc} :: sources),
763772
List.rev values )
764-
| [{pexp_desc = Pexp_constant (Pconst_string (_, Some "json"))}] ->
773+
| {pexp_desc = Pexp_constant (Pconst_string (_, Some "json"))}
774+
:: _value :: _rest ->
765775
reject_json_interpolation ()
766-
| {pexp_desc = Pexp_constant (Pconst_string (txt, Some "js")); pexp_loc}
776+
| {
777+
pexp_desc = Pexp_constant (Pconst_string (text, delimiter));
778+
pexp_loc;
779+
}
767780
:: value :: rest ->
781+
let txt = template_source_from0 (text, delimiter) in
768782
collect
769783
({Location.txt; loc = sub.location sub pexp_loc} :: sources)
770784
(value :: values) rest
771-
| {pexp_desc = Pexp_constant (Pconst_string (_, Some "json"))}
772-
:: _value :: _rest ->
773-
reject_json_interpolation ()
774785
| _ -> None
775786
in
776787
begin match collect [] [] parts with

tests/ounit_tests/ounit_ast_mapper0_tests.ml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,39 @@ let test_ppx_rewritten_tagged_template_segments _ =
444444
OUnit.assert_equal ~printer:(Printf.sprintf "%S") {e|\${value}\`\\|e} txt
445445
| _ -> assert_failure "Expected a rewritten tagged template after roundtrip"
446446

447+
let test_ppx_rewritten_template_segments _ =
448+
let template_attr = attr "res.template" (Parsetree0.PStr []) in
449+
let semantic = "${value}`\\" in
450+
let uninterpolated =
451+
Ast_helper0.Exp.constant ~loc ~attrs:[template_attr]
452+
(Ast_helper0.Const.string semantic)
453+
in
454+
assert_template_expr ~expected:{e|\${value}\`\\|e} (map_expr0 uninterpolated);
455+
let segment semantic =
456+
Ast_helper0.Exp.constant ~loc ~attrs:[template_attr]
457+
(Ast_helper0.Const.string semantic)
458+
in
459+
let concat lhs rhs =
460+
Ast_helper0.Exp.apply ~loc ~attrs:[template_attr]
461+
(Ast_helper0.Exp.ident ~loc (Location.mknoloc (Longident.Lident "^")))
462+
[(Asttypes.Noloc.Nolabel, lhs); (Asttypes.Noloc.Nolabel, rhs)]
463+
in
464+
let value =
465+
Ast_helper0.Exp.ident ~loc (Location.mknoloc (Longident.Lident "value"))
466+
in
467+
let interpolated =
468+
concat (concat (segment "${head}") value) (segment "`\\")
469+
in
470+
match (map_expr0 interpolated).pexp_desc with
471+
| Pexp_template
472+
{
473+
source_segments = [{txt = head}; {txt = tail}];
474+
values = [{pexp_desc = Pexp_ident {txt = Longident.Lident "value"}}];
475+
} ->
476+
OUnit.assert_equal ~printer:(Printf.sprintf "%S") {e|\${head}|e} head;
477+
OUnit.assert_equal ~printer:(Printf.sprintf "%S") {e|\`\\|e} tail
478+
| _ -> assert_failure "Expected a rewritten template after roundtrip"
479+
447480
let test_interpolated_templates_roundtrip_through_ast0 _ =
448481
let head_loc = source_loc 1 8 in
449482
let tail_loc = source_loc 12 16 in
@@ -646,6 +679,8 @@ let suites =
646679
>:: test_tagged_templates_roundtrip_through_ast0;
647680
"ppx_rewritten_tagged_template_segments"
648681
>:: test_ppx_rewritten_tagged_template_segments;
682+
"ppx_rewritten_template_segments"
683+
>:: test_ppx_rewritten_template_segments;
649684
"interpolated_templates_roundtrip_through_ast0"
650685
>:: test_interpolated_templates_roundtrip_through_ast0;
651686
"ast0_json_interpolation_is_rejected"

0 commit comments

Comments
 (0)