Source file jsx_helper.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
open Printf
open Asttypes
open Longident
open Parsetree
open Ast_helper
let make_loc (startpos, endpos) =
{
Location.loc_start = startpos;
Location.loc_end = endpos;
Location.loc_ghost = false;
}
let mkloc = Location.mkloc
let mkexp ~loc d = Exp.mk ~loc:(make_loc loc) d
let mkjsxexp ~loc:loc' e =
let e = mkexp ~loc:loc' e in
let loc = make_loc loc' in
let pexp_attributes = [ Attr.mk ~loc { txt = "JSX"; loc } (PStr []) ] in
{ e with pexp_attributes }
let rec equal_longindent a b =
match a, b with
| Longident.Lident a, Longident.Lident b -> String.equal a b
| Ldot (pa, a), Ldot (pb, b) ->
String.equal a b && equal_longindent pa pb
| Lapply _, _ | _, Lapply _ -> assert false
| _ -> false
let make_jsx_element ~raise ~loc:_ ~tag ~end_tag ~props ~children () =
let () =
match end_tag with
| None -> ()
| Some (end_tag, (_, end_loc_e)) ->
let eq =
match tag, end_tag with
| (`Module, _, s), (`Module, _, e) -> equal_longindent s e
| (`Value, _, s), (`Value, _, e) -> equal_longindent s e
| _ -> false
in
if not eq then
let _, (end_loc_s, _), _ = end_tag in
let end_loc = end_loc_s, end_loc_e in
let _, start_loc, tag = tag in
let tag = Longident.flatten tag |> String.concat "." in
raise
Syntaxerr.(
Error
(Unclosed
( make_loc start_loc,
sprintf "<%s>" tag,
make_loc end_loc,
sprintf "</%s>" tag )))
in
let tag =
match tag with
| `Value, loc, txt ->
mkexp ~loc (Pexp_ident { loc = make_loc loc; txt })
| `Module, loc, txt ->
let txt = Longident.Ldot (txt, "createElement") in
mkexp ~loc (Pexp_ident { loc = make_loc loc; txt })
in
let props =
let prop_exp ~loc name =
let id = mkloc (Lident name.txt) (make_loc loc) in
mkexp ~loc (Pexp_ident id)
in
List.map
(function
| loc, `Prop_punned name -> Labelled {txt=name.txt;loc = make_loc loc}, prop_exp ~loc name
| loc, `Prop_opt_punned name -> Optional {txt=name.txt;loc = make_loc loc}, prop_exp ~loc name
| _loc, `Prop (name, expr) -> Labelled name, expr
| _loc, `Prop_opt (name, expr) -> Optional name, expr)
props
in
let unit =
Exp.mk ~loc:Location.none
(Pexp_construct ({ txt = Lident "()"; loc = Location.none }, None))
in
let props = (Labelled {txt="children"; loc=children.pexp_loc}, children) :: props in
Pexp_apply (tag, (Nolabel, unit) :: props)