Skip to content

Commit 58c8ab4

Browse files
committed
Translate into AST compatible with react ppx
1 parent 89f5c9d commit 58c8ab4

File tree

9 files changed

+103
-51
lines changed

9 files changed

+103
-51
lines changed

.rgignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
merlin
2+
merlin-extend

mlx/jsx_helper.ml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
open Asttypes
2+
open Longident
3+
open Parsetree
4+
open Ast_helper
5+
6+
let make_loc (startpos, endpos) =
7+
{
8+
Location.loc_start = startpos;
9+
Location.loc_end = endpos;
10+
Location.loc_ghost = false;
11+
}
12+
13+
let mkloc = Location.mkloc
14+
let mkexp ~loc d = Exp.mk ~loc:(make_loc loc) d
15+
16+
let mkjsxexp ~loc e =
17+
let e = mkexp ~loc e in
18+
let attr =
19+
let loc = make_loc loc in
20+
Attr.mk ~loc { txt = "JSX"; loc } (PStr [])
21+
in
22+
{ e with pexp_attributes = [ attr ] }
23+
24+
let make_jsx_element ~loc ~tag ~props ~children () =
25+
let tag = mkexp ~loc (Pexp_ident tag) in
26+
let props =
27+
List.map
28+
(function
29+
| loc, `Prop_punned name ->
30+
let id = mkloc (Lident name) (make_loc loc) in
31+
Labelled name, mkexp ~loc (Pexp_ident id)
32+
| _loc, `Prop (name, expr) -> Labelled name, expr)
33+
props
34+
in
35+
let unit =
36+
mkexp ~loc
37+
(Pexp_construct ({ txt = Lident "()"; loc = make_loc loc }, None))
38+
in
39+
let props =
40+
match children with
41+
| None -> props
42+
| Some children -> (Labelled "children", children) :: props
43+
in
44+
Pexp_apply (tag, (Nolabel, unit) :: props)

mlx/parser.mly

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,7 @@ simple_expr:
23892389
| simple_expr_attrs
23902390
{ let desc, attrs = $1 in
23912391
mkexp_attrs ~loc:$sloc desc attrs }
2392+
| e = jsx_element { Jsx_helper.mkjsxexp ~loc:$loc(e) e }
23922393
| mkexp(simple_expr_)
23932394
{ $1 }
23942395
;
@@ -2499,36 +2500,23 @@ simple_expr:
24992500
| mod_longident DOT
25002501
LPAREN MODULE ext_attributes module_expr COLON error
25012502
{ unclosed "(" $loc($3) ")" $loc($8) }
2502-
| e = jsx_element { e }
25032503
;
25042504
jsx_element:
25052505
tag=mkrhs(jsx_longident) props=llist(jsx_prop) SLASHGREATER {
2506-
let tag = mkexp ~loc:$loc(tag) (Pexp_ident tag) in
2507-
let head = mkexp ~loc:$loc(tag) (Pexp_apply (tag, props)) in
2508-
Pexp_extension (mkloc "jsx" (make_loc $sloc), PStr [mkstrexp head []])
2509-
}
2506+
Jsx_helper.make_jsx_element () ~loc:$loc(tag) ~tag ~props ~children:None }
25102507
| tag=mkrhs(jsx_longident) props=llist(jsx_prop)
2511-
GREATER children=llist(jsx_content) LESSSLASH mkrhs(val_longident) GREATER {
2512-
let tag = mkexp ~loc:$loc(tag) (Pexp_ident tag) in
2513-
let head = mkexp ~loc:$loc(tag) (Pexp_apply (tag, props)) in
2514-
let children = List.map (fun e -> mkstrexp e []) children in
2515-
Pexp_extension (mkloc "jsx_with_children" (make_loc $sloc), PStr ((mkstrexp head [])::children))
2508+
GREATER children=llist(simple_expr) LESSSLASH mkrhs(val_longident) GREATER {
2509+
let children =
2510+
let children, loc = mktailexp $loc(children) children in
2511+
mkexp ~loc children
2512+
in
2513+
Jsx_helper.make_jsx_element () ~loc:$loc(tag) ~tag ~props ~children:(Some children)
25162514
}
25172515
;
2518-
jsx_content:
2519-
LPAREN seq_expr RPAREN
2520-
{ reloc_exp ~loc:$sloc $2 }
2521-
| mkexp(simple_expr_)
2522-
{ $1 }
2523-
;
25242516
jsx_prop:
2525-
id=LIDENT
2526-
{ let id = mkloc (Lident id) (make_loc $loc(id)) in
2527-
let e = mkexp ~loc:$loc(id) (Pexp_ident id) in
2528-
(Nolabel, e) }
2529-
| k=LIDENT EQUAL e=simple_expr
2530-
{ (Labelled k, e) }
2531-
2517+
name=LIDENT { $loc(name), `Prop_punned name }
2518+
| name=LIDENT EQUAL expr=simple_expr { $loc(name), `Prop (name, expr) }
2519+
;
25322520
labeled_simple_expr:
25332521
simple_expr %prec below_HASH
25342522
{ (Nolabel, $1) }

mlx/pp.ml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1+
let print_ml = ref false
2+
let input = ref None
3+
let speclist = [ "-print-ml", Arg.Set print_ml, "Print .ml syntax" ]
4+
15
let () =
2-
let fname = Sys.argv.(1) in
3-
let src = In_channel.with_open_bin fname In_channel.input_all in
6+
Arg.parse speclist
7+
(fun input' -> input := Some input')
8+
"mlx-pp [-print-ml] <input-file>";
9+
let fname, src =
10+
match !input with
11+
| None -> "*stdin*", In_channel.input_all stdin
12+
| Some fname ->
13+
fname, In_channel.with_open_bin fname In_channel.input_all
14+
in
415
let lexbuf = Lexing.from_string src in
516
Lexing.set_filename lexbuf fname;
617
let str =
@@ -12,10 +23,12 @@ let () =
1223
in
1324
match str with
1425
| Ok str ->
15-
let oc = stdout in
16-
output_string oc Config.ast_impl_magic_number;
17-
output_value oc fname;
18-
output_value oc str
26+
if !print_ml then Format.printf "%a@." Pprintast.structure str
27+
else
28+
let oc = stdout in
29+
output_string oc Config.ast_impl_magic_number;
30+
output_value oc fname;
31+
output_value oc str
1932
| Error `Already_displayed -> exit 1
2033
| Error (`Ok error) ->
2134
Format.eprintf "%a@." Location.print_report error;

ocamlmerlin_mlx/dune

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
(action
4747
(run %{bin:cppo} -V OCAML:%{ocaml_version} %{deps} -o %{targets})))
4848

49+
(copy_files# ../mlx/jsx_helper.ml)
50+
4951
(copy_files# ../merlin-extend/*[!extend_helper].{ml,mli})
5052

5153
(copy_files# ../merlin/src/kernel/extension.{ml,mli})

ocamlmerlin_mlx/parser_raw.mly

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,6 +2533,7 @@ let_pattern [@recovery default_pattern ()]:
25332533
| simple_expr_attrs
25342534
{ let desc, attrs = $1 in
25352535
mkexp_attrs ~loc:$sloc desc attrs }
2536+
| e = jsx_element { Jsx_helper.mkjsxexp ~loc:$loc(e) e }
25362537
| mkexp(simple_expr_)
25372538
{ $1 }
25382539
;
@@ -2672,35 +2673,22 @@ let_pattern [@recovery default_pattern ()]:
26722673
LPAREN MODULE ext_attributes module_expr COLON error
26732674
{ unclosed "(" $loc($3) ")" $loc($8) }
26742675
*)
2675-
| e = jsx_element { e }
26762676
;
26772677
jsx_element:
26782678
tag=mkrhs(jsx_longident) props=llist(jsx_prop) SLASHGREATER {
2679-
let tag = mkexp ~loc:$loc(tag) (Pexp_ident tag) in
2680-
let head = mkexp ~loc:$loc(tag) (Pexp_apply (tag, props)) in
2681-
Pexp_extension (mkloc "jsx" (make_loc $sloc), PStr [mkstrexp head []])
2682-
}
2679+
Jsx_helper.make_jsx_element () ~loc:$loc(tag) ~tag ~props ~children:None }
26832680
| tag=mkrhs(jsx_longident) props=llist(jsx_prop)
2684-
GREATER children=llist(jsx_content) LESSSLASH mkrhs(val_longident) GREATER {
2685-
let tag = mkexp ~loc:$loc(tag) (Pexp_ident tag) in
2686-
let head = mkexp ~loc:$loc(tag) (Pexp_apply (tag, props)) in
2687-
let children = List.map (fun e -> mkstrexp e []) children in
2688-
Pexp_extension (mkloc "jsx_with_children" (make_loc $sloc), PStr ((mkstrexp head [])::children))
2681+
GREATER children=llist(simple_expr) LESSSLASH mkrhs(val_longident) GREATER {
2682+
let children =
2683+
let children, loc = mktailexp $loc(children) children in
2684+
mkexp ~loc children
2685+
in
2686+
Jsx_helper.make_jsx_element () ~loc:$loc(tag) ~tag ~props ~children:(Some children)
26892687
}
26902688
;
2691-
jsx_content:
2692-
LPAREN seq_expr RPAREN
2693-
{ reloc_exp ~loc:$sloc $2 }
2694-
| mkexp(simple_expr_)
2695-
{ $1 }
2696-
;
26972689
jsx_prop:
2698-
id=LIDENT
2699-
{ let id = mkloc (Lident id) (make_loc $loc(id)) in
2700-
let e = mkexp ~loc:$loc(id) (Pexp_ident id) in
2701-
(Nolabel, e) }
2702-
| k=LIDENT EQUAL e=simple_expr
2703-
{ (Labelled k, e) }
2690+
name=LIDENT { $loc(name), `Prop_punned name }
2691+
| name=LIDENT EQUAL expr=simple_expr { $loc(name), `Prop (name, expr) }
27042692
;
27052693
labeled_simple_expr:
27062694
simple_expr %prec below_HASH

test/dune

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(cram
2+
(deps (package mlx) ./mlx))
3+

test/mlx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/bin/bash
2+
3+
mlx-pp -print-ml | ocamlformat - --impl --enable-outside-detected-project

test/mlx.t

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
$ echo 'let _ = <div />' | ./mlx
3+
let _ = div () [@JSX]
4+
5+
$ echo 'let _ = <div>hello world</div>' | ./mlx
6+
let _ = div () ~children:[ hello; world ] [@JSX]
7+
8+
$ echo 'let _ = <div attr with_value=1 />' | ./mlx
9+
let _ = div () ~attr ~with_value:1 [@JSX]

0 commit comments

Comments
 (0)