Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions analysis/src/Utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ let identifyPexp pexp =
| Pexp_open _ -> "Pexp_open"
| Pexp_await _ -> "Pexp_await"
| Pexp_jsx_element _ -> "Pexp_jsx_element"
| Pexp_jsx_text _ -> "Pexp_jsx_text"

let identifyPpat pat =
match pat with
Expand Down
4 changes: 4 additions & 0 deletions compiler/frontend/bs_ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,10 @@ module E = struct
jsx_container_element ~loc ~attrs name (map_jsx_props sub props) ote
(map_jsx_children sub children)
closing_tag
| Pexp_jsx_text
{jsx_text_content; jsx_text_leading_space; jsx_text_trailing_space} ->
jsx_text ~loc ~attrs ~leading_space:jsx_text_leading_space
~trailing_space:jsx_text_trailing_space jsx_text_content
end

module P = struct
Expand Down
10 changes: 10 additions & 0 deletions compiler/ml/ast_helper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,16 @@ module Exp = struct
jsx_container_element_closing_tag = e;
}))

let jsx_text ?loc ?attrs ?(leading_space = false) ?(trailing_space = false)
text =
mk ?loc ?attrs
(Pexp_jsx_text
{
jsx_text_content = text;
jsx_text_leading_space = leading_space;
jsx_text_trailing_space = trailing_space;
})

let case ?bar lhs ?guard rhs =
{pc_bar = bar; pc_lhs = lhs; pc_guard = guard; pc_rhs = rhs}

Expand Down
8 changes: 8 additions & 0 deletions compiler/ml/ast_helper.mli
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,14 @@ module Exp : sig
Parsetree.jsx_closing_container_tag option ->
expression

val jsx_text :
?loc:loc ->
?attrs:attrs ->
?leading_space:bool ->
?trailing_space:bool ->
string ->
expression

val case :
?bar:Lexing.position -> pattern -> ?guard:expression -> expression -> case
val await : ?loc:loc -> ?attrs:attrs -> expression -> expression
Expand Down
1 change: 1 addition & 0 deletions compiler/ml/ast_iterator.ml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ module E = struct
iter_loc sub name;
iter_jsx_props sub props;
iter_jsx_children sub children
| Pexp_jsx_text _ -> ()
end

module P = struct
Expand Down
4 changes: 4 additions & 0 deletions compiler/ml/ast_mapper.ml
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ module E = struct
(map_jsx_props sub props) ote
(map_jsx_children sub children)
closing_tag
| Pexp_jsx_text
{jsx_text_content; jsx_text_leading_space; jsx_text_trailing_space} ->
jsx_text ~loc ~attrs ~leading_space:jsx_text_leading_space
~trailing_space:jsx_text_trailing_space jsx_text_content
end

module P = struct
Expand Down
26 changes: 23 additions & 3 deletions compiler/ml/ast_mapper_from0.ml
Original file line number Diff line number Diff line change
Expand Up @@ -310,24 +310,44 @@ module E = struct
| _ -> true)
attrs

let try_map_jsx_text (sub : mapper) (e : expression) : Pt.expression option =
match e.pexp_desc with
| Pexp_apply
( {
pexp_desc =
Pexp_ident {txt = Longident.Ldot (Lident "React", "string")};
},
[
( Asttypes.Noloc.Nolabel,
{pexp_desc = Pexp_constant (Pconst_string (text, None))} );
] ) ->
let loc = sub.location sub e.pexp_loc in
Some (Ast_helper.Exp.jsx_text ~loc text)
| _ -> None

let map_jsx_children sub (e : expression) : Pt.jsx_children =
let map_jsx_child (e : expression) : Pt.expression =
match try_map_jsx_text sub e with
| Some jsx_text -> jsx_text
| None -> sub.expr sub e
in
let rec visit (e : expression) : Pt.expression list =
match e.pexp_desc with
| Pexp_construct
({txt = Longident.Lident "::"}, Some {pexp_desc = Pexp_tuple [e1; e2]})
->
sub.expr sub e1 :: visit e2
map_jsx_child e1 :: visit e2
| Pexp_construct ({txt = Longident.Lident "[]"}, ext_opt) -> (
match ext_opt with
| None -> []
| Some e -> visit e)
| _ -> [sub.expr sub e]
| _ -> [map_jsx_child e]
in
match e.pexp_desc with
| Pexp_construct ({txt = Longident.Lident "[]" | Longident.Lident "::"}, _)
->
visit e
| _ -> [sub.expr sub e]
| _ -> [map_jsx_child e]

let try_map_jsx_prop (sub : mapper) (lbl : Asttypes.Noloc.arg_label)
(e : expression) : Parsetree.jsx_prop option =
Expand Down
11 changes: 11 additions & 0 deletions compiler/ml/ast_mapper_to0.ml
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,17 @@ module E = struct
(Asttypes.Noloc.Labelled "children", children_expr);
(Asttypes.Noloc.Nolabel, jsx_unit_expr);
])
| Pexp_jsx_text text ->
(* Transform JSX text to React.string("text") *)
let react_string_ident =
{loc; txt = Longident.Ldot (Lident "React", "string")}
in
let string_const =
Ast_helper0.Exp.constant ~loc
(Pconst_string (text.jsx_text_content, None))
in
apply ~loc ~attrs (ident react_string_ident)
[(Asttypes.Noloc.Nolabel, string_const)]
end

module P = struct
Expand Down
1 change: 1 addition & 0 deletions compiler/ml/depend.ml
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ let rec add_expr bv exp =
| JsxQualifiedLowerTag {path; _} | JsxUpperTag path -> add_path bv path);
and_jsx_props bv props;
add_jsx_children bv children
| Pexp_jsx_text _ -> ()

and add_jsx_children bv xs = List.iter (add_expr bv) xs

Expand Down
4 changes: 3 additions & 1 deletion compiler/ml/experimental_features.ml
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
type feature = LetUnwrap
type feature = LetUnwrap | JsxText

let to_string (f : feature) : string =
match f with
| LetUnwrap -> "LetUnwrap"
| JsxText -> "JsxText"

let from_string (s : string) : feature option =
match s with
| "LetUnwrap" -> Some LetUnwrap
| "JsxText" -> Some JsxText
| _ -> None

module FeatureSet = Set.Make (struct
Expand Down
2 changes: 1 addition & 1 deletion compiler/ml/experimental_features.mli
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type feature = LetUnwrap
type feature = LetUnwrap | JsxText

val enable_from_string : string -> unit
val is_enabled : feature -> bool
Expand Down
7 changes: 7 additions & 0 deletions compiler/ml/parsetree.ml
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,13 @@ and expression_desc =
(* . *)
| Pexp_await of expression
| Pexp_jsx_element of jsx_element
| Pexp_jsx_text of jsx_text

and jsx_text = {
jsx_text_content: string; (* The trimmed text content *)
jsx_text_leading_space: bool; (* Had whitespace before the text *)
jsx_text_trailing_space: bool; (* Had whitespace after the text *)
}

(* an element of a record pattern or expression *)
and 'a record_element = {lid: Longident.t loc; x: 'a; opt: bool (* optional *)}
Expand Down
4 changes: 4 additions & 0 deletions compiler/ml/printast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,10 @@ and expression i ppf x =
| Some closing_tag ->
line i ppf "closing_tag =%a\n" fmt_jsx_tag_name
closing_tag.jsx_closing_container_tag_name)
| Pexp_jsx_text
{jsx_text_content; jsx_text_leading_space; jsx_text_trailing_space} ->
line i ppf "Pexp_jsx_text %S (leading=%b, trailing=%b)\n" jsx_text_content
jsx_text_leading_space jsx_text_trailing_space

and jsx_children i ppf children =
line i ppf "jsx_children =\n";
Expand Down
4 changes: 2 additions & 2 deletions compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ let iter_expression f e =
module_expr me
| Pexp_pack me -> module_expr me
| Pexp_await _ -> assert false (* should be handled earlier *)
| Pexp_jsx_element _ ->
| Pexp_jsx_element _ | Pexp_jsx_text _ ->
raise (Error (e.pexp_loc, Env.empty, Jsx_not_enabled))
and case {pc_lhs = _; pc_guard; pc_rhs} =
may expr pc_guard;
Expand Down Expand Up @@ -3256,7 +3256,7 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected)
| Pexp_extension ext ->
raise (Error_forward (Builtin_attributes.error_of_extension ext))
| Pexp_await _ -> (* should be handled earlier *) assert false
| Pexp_jsx_element _ ->
| Pexp_jsx_element _ | Pexp_jsx_text _ ->
raise (Error (sexp.pexp_loc, Env.empty, Jsx_not_enabled))

and type_function ?in_function ~arity ~async loc attrs env ty_expected_ l
Expand Down
13 changes: 12 additions & 1 deletion compiler/syntax/src/jsx_v4.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1274,7 +1274,7 @@ let mk_react_jsx (config : Jsx_common.jsx_config) mapper loc attrs
let args = [(nolabel, elementTag); (nolabel, props_record)] @ key_and_unit in
Exp.apply ~loc ~attrs ~transformed_jsx:true jsx_expr args

(* In most situations, the component name is the make function from a module.
(* In most situations, the component name is the make function from a module.
However, if the name contains a lowercase letter, it means it probably an external component.
In this case, we use the name as is.
See tests/syntax_tests/data/ppx/react/externalWithCustomName.res
Expand Down Expand Up @@ -1348,6 +1348,17 @@ let expr ~(config : Jsx_common.jsx_config) mapper expression =
| JsxTagInvalid name ->
Jsx_common.raise_error ~loc
"JSX: element name is neither upper- or lowercase, got \"%s\"" name))
| {
pexp_desc = Pexp_jsx_text {jsx_text_content = text};
pexp_loc = loc;
pexp_attributes = attrs;
} ->
(* Transform JSX text to React.string("text") *)
let react_string_ident =
Exp.ident ~loc {loc; txt = module_access_name config "string"}
in
let string_const = Exp.constant ~loc (Pconst_string (text, None)) in
Exp.apply ~loc ~attrs react_string_ident [(Nolabel, string_const)]
| e -> default_mapper.expr mapper e

let module_binding ~(config : Jsx_common.jsx_config) mapper module_binding =
Expand Down
9 changes: 9 additions & 0 deletions compiler/syntax/src/res_ast_debugger.ml
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,15 @@ module SexpAst = struct
Sexp.list (map_empty ~f:jsx_prop props);
Sexp.list (map_empty ~f:expression xs);
]
| Pexp_jsx_text
{jsx_text_content; jsx_text_leading_space; jsx_text_trailing_space} ->
Sexp.list
[
Sexp.atom "Pexp_jsx_text";
Sexp.atom jsx_text_content;
Sexp.atom (Printf.sprintf "leading=%b" jsx_text_leading_space);
Sexp.atom (Printf.sprintf "trailing=%b" jsx_text_trailing_space);
]
in
Sexp.list [Sexp.atom "expression"; desc]

Expand Down
9 changes: 5 additions & 4 deletions compiler/syntax/src/res_comments_table.ml
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ let attach tbl loc comments =
*
* When splitting around the location of `x = 5`:
* - leading: [comment1]
* - inside: [comment2]
* - inside: [comment2]
* - trailing: [comment3]
*
*
* This is the primary comment partitioning function used for associating comments
* with AST nodes during the tree traversal.
*
Expand Down Expand Up @@ -1800,13 +1800,14 @@ and walk_expression expr t comments =
let children_nodes = List.map (fun e -> Expression e) children in

walk_list children_nodes t comments_for_children
(* It is less likely that there are comments inside the closing tag,
(* It is less likely that there are comments inside the closing tag,
so we don't process them right now,
if you ever need this, feel free to update process _rest.
if you ever need this, feel free to update process _rest.
Comments after the closing tag will already be taking into account by the parent node. *)
)
| Pexp_await expr -> walk_expression expr t comments
| Pexp_send _ -> ()
| Pexp_jsx_text _ -> ()

and walk_expr_parameter (_attrs, _argLbl, expr_opt, pattern) t comments =
let leading, inside, trailing = partition_by_loc comments pattern.ppat_loc in
Expand Down
Loading
Loading