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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#### :rocket: New Feature

- Add `%raw(...)` arguments for externals, for example `external assign: (%raw("{}"), t) => t = "Object.assign"`. The string contains the raw JavaScript value supplied by the binding, and the argument is omitted at call sites. The legacy `` @as(json`...`) _ ``, `@as("...") _`, and `@as(1) _` forms now emit a deprecation warning and are formatted as `%raw(...)`. https://github.com/rescript-lang/rescript/pull/8606
- Support UTF-16 surrogate-pair escapes such as `"\uD83D\uDE00"` in ordinary string literals. https://github.com/rescript-lang/rescript/pull/8606
- Support dynamic imports of external bindings annotated with `@scope`; the generated import follows the complete property path. These imports were previously rejected. https://github.com/rescript-lang/rescript/pull/8582
- Add `@res.hoistedFunction` for emitting nested module functions as flat JavaScript exports. https://github.com/rescript-lang/rescript/pull/8402
Expand Down
2 changes: 1 addition & 1 deletion analysis/src/completion_front_end.ml
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ let find_arg_completables ~(args : arg list) ~end_pos ~pos_before_cursor
let rec expr_to_context_path_inner ~(in_jsx_context : bool)
(e : Parsetree.expression) =
match e.pexp_desc with
| Pexp_constant (Pconst_string _ | Pconst_json _ | Pconst_raw_source _) ->
| Pexp_constant (Pconst_string _ | Pconst_raw_source _) ->
Some Completable.CPString
| Pexp_template _ -> Some Completable.CPString
| Pexp_tagged_template {tag} -> (
Expand Down
2 changes: 1 addition & 1 deletion analysis/src/document_symbol.ml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let get_symbols ~source ~kind_file =
match exp.pexp_desc with
| Pexp_fun _ -> Lsp.Types.SymbolKind.Function
| Pexp_constraint (e, _) -> expr_kind e
| Pexp_constant (Pconst_string _ | Pconst_json _ | Pconst_raw_source _) ->
| Pexp_constant (Pconst_string _ | Pconst_raw_source _) ->
Lsp.Types.SymbolKind.String
| Pexp_template _ -> Lsp.Types.SymbolKind.String
| Pexp_constant (Pconst_float _ | Pconst_integer _) ->
Expand Down
1 change: 0 additions & 1 deletion analysis/src/dump_ast.ml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ let print_constant const =
^ ", semantic="
^ String_literal.string_semantic payload
^ ")"
| Pconst_json source -> "Pconst_json(" ^ source ^ ")"
| Pconst_raw_source source -> "Pconst_raw_source(" ^ source ^ ")"
| Pconst_float (s, _) -> "Pconst_float(" ^ s ^ ")"

Expand Down
59 changes: 32 additions & 27 deletions analysis/src/signature_help.ml
Original file line number Diff line number Diff line change
Expand Up @@ -114,33 +114,38 @@ let extract_parameters ~signature ~type_str_for_parser ~label_prefix_len =
Psig_value {pval_type = {ptyp_desc = Ptyp_arrow {params = args}}};
};
] ->
List.map
(fun (arg : Parsetree.arg) ->
let start_loc =
(* For a labeled argument the label precedes the type. *)
match arg.lbl with
| Asttypes.Labelled {loc} | Optional {loc} -> loc |> Loc.start
| Nolabel -> arg.typ.ptyp_loc |> Loc.start
in
let start_offset =
start_loc |> Pos.position_to_offset type_str_for_parser |> Option.get
in
let end_offset =
arg.typ.ptyp_loc |> Loc.end_
|> Pos.position_to_offset type_str_for_parser
|> Option.get
in
(* The AST locations does not account for "=?" of optional arguments, so add that to the offset here if needed. *)
let end_offset =
match arg.lbl with
| Asttypes.Optional _ -> end_offset + 2
| _ -> end_offset
in
( arg.lbl,
(* Remove the label prefix offset here, since we're not
showing that to the end user. *)
start_offset - label_prefix_len,
end_offset - label_prefix_len ))
List.filter_map
(function
| Parsetree.Parg_fixed _ -> None
| Parsetree.Parg_type {lbl; typ; _} ->
let start_loc =
(* For a labeled argument the label precedes the type. *)
match lbl with
| Asttypes.Labelled {loc} | Optional {loc} -> loc |> Loc.start
| Nolabel -> typ.ptyp_loc |> Loc.start
in
let start_offset =
start_loc
|> Pos.position_to_offset type_str_for_parser
|> Option.get
in
let end_offset =
typ.ptyp_loc |> Loc.end_
|> Pos.position_to_offset type_str_for_parser
|> Option.get
in
(* The AST locations does not account for "=?" of optional arguments, so add that to the offset here if needed. *)
let end_offset =
match lbl with
| Asttypes.Optional _ -> end_offset + 2
| _ -> end_offset
in
Some
( lbl,
(* Remove the label prefix offset here, since we're not
showing that to the end user. *)
start_offset - label_prefix_len,
end_offset - label_prefix_len ))
args
| _ -> []

Expand Down
7 changes: 3 additions & 4 deletions compiler/core/j.ml
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,9 @@ and expression_desc =
optimizations. Both are required because preserving backquoted
spelling is an output design goal. Tagged-template segments use
[Tagged_template] instead because their escapes need not be valid. *)
| Json_literal of string
(** Validated JavaScript literal source from a supported external
[json`...`] payload. For [json`{"ok": true}`], the string contains
[{"ok": true}] as JavaScript source, not as a decoded ReScript
| Fixed_literal of string
(** Validated JavaScript literal source supplied by a fixed external
argument. The string is JavaScript source, not a decoded ReScript
string. *)
| Raw_js_code of Js_raw_info.t
(** JavaScript source originating from [raw], [ffi], or [re]. For example,
Expand Down
4 changes: 2 additions & 2 deletions compiler/core/js_analyzer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) =
| Undefined _ | Null | Bool _ | Var _ -> true
| Fun _ -> true
| Number _ -> true (* Can be refined later *)
| Json_literal _ -> true
| Fixed_literal _ -> true
| Static_index (obj, (_name : string), (_pos : int32 option)) ->
no_side_effect obj
| String_index (a, b) | Array_index (a, b) ->
Expand Down Expand Up @@ -256,7 +256,7 @@ let rec eq_expression ({expression_desc = x0} : J.expression)
eq_expression_list ls0 ls1 && flag0 = flag1 && info0 = info1
| _ -> false)
| Length _ | Is_null_or_undefined _ | String_append _ | Typeof _ | Js_not _
| Js_bnot _ | In _ | Cond _ | New _ | Fun _ | Json_literal _ | Raw_js_code _
| Js_bnot _ | In _ | Cond _ | New _ | Fun _ | Fixed_literal _ | Raw_js_code _
| Array _ | Caml_block_tag _ | Object _ | Tagged_template _
| Interpolated_template _ | Await _ | Record_rest _ ->
false
Expand Down
6 changes: 3 additions & 3 deletions compiler/core/js_dump.ml
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ let rec exp_need_paren ?(arrow = false) (e : J.expression) =
| Blk_record_ext _ | Blk_record_inlined _ | Blk_constructor _ ) )
| Object _ ->
true
| Json_literal _ -> true
| Fixed_literal _ -> true
| Raw_js_code {code_info = Stmt _}
| Length _ | Call _ | Caml_block_tag _ | Seq _ | Static_index _ | Cond _
| Bin _ | Is_null_or_undefined _ | String_index _ | Array_index _
Expand Down Expand Up @@ -737,7 +737,7 @@ and expression_desc cxt ~(level : int) f x : cxt =
| Template_literal segment ->
P.string f ("`" ^ String_literal.template_source segment ^ "`");
cxt
| Json_literal source ->
| Fixed_literal source ->
P.string f source;
cxt
| Raw_js_code {code = s; code_info = info} -> (
Expand Down Expand Up @@ -1363,7 +1363,7 @@ and statement_desc top cxt f (s : J.statement_desc) : cxt =
| Some s -> P.string f s
| None -> ());
cxt
| Str _ | Template_literal _ | Json_literal _ -> cxt
| Str _ | Template_literal _ | Fixed_literal _ -> cxt
| _ ->
let cxt =
(if exp_need_paren e then P.paren_group f 1 else P.group f 0) (fun _ ->
Expand Down
6 changes: 3 additions & 3 deletions compiler/core/js_exp_make.ml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type t = J.expression
*)
let rec remove_pure_sub_exp (x : t) : t option =
match x.expression_desc with
| Var _ | Str _ | Template_literal _ | Json_literal _ | Number _ ->
| Var _ | Str _ | Template_literal _ | Fixed_literal _ | Number _ ->
None (* Can be refined later *)
| Array_index (a, b) ->
if is_pure_sub_exp a && is_pure_sub_exp b then None else Some x
Expand Down Expand Up @@ -201,8 +201,8 @@ let str ?comment txt : t =
let template_literal ?comment segment : t =
{expression_desc = Template_literal segment; comment; source_loc = None}

let json_literal ?comment source : t =
{expression_desc = Json_literal source; comment; source_loc = None}
let fixed_literal ?comment source : t =
{expression_desc = Fixed_literal source; comment; source_loc = None}

let raw_js_code ?comment info s : t =
{
Expand Down
2 changes: 1 addition & 1 deletion compiler/core/js_exp_make.mli
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ val str : ?comment:string -> string -> t

val template_literal : ?comment:string -> Asttypes.template_segment -> t

val json_literal : ?comment:string -> string -> t
val fixed_literal : ?comment:string -> string -> t

val record_rest : ?comment:string -> J.record_rest_field list -> t -> t

Expand Down
2 changes: 1 addition & 1 deletion compiler/core/js_record_fold.ml
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ let expression_desc : 'a. ('a, expression_desc) fn =
st
| Str _ -> st
| Template_literal _ -> st
| Json_literal _ -> st
| Fixed_literal _ -> st
| Raw_js_code _ -> st
| Array _x0 -> list _self.expression _self st _x0
| Optional_block (_x0, _x1) ->
Expand Down
2 changes: 1 addition & 1 deletion compiler/core/js_record_iter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ let expression_desc : expression_desc fn =
_self.block _self body
| Str _ -> ()
| Template_literal _ -> ()
| Json_literal _ -> ()
| Fixed_literal _ -> ()
| Raw_js_code _ -> ()
| Array _x0 -> list _self.expression _self _x0
| Optional_block (_x0, _x1) -> _self.expression _self _x0
Expand Down
2 changes: 1 addition & 1 deletion compiler/core/js_record_map.ml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ let expression_desc : expression_desc fn =
Fun {fun_ with params; body}
| Str _ as v -> v
| Template_literal _ as v -> v
| Json_literal _ as v -> v
| Fixed_literal _ as v -> v
| Raw_js_code _ as v -> v
| Array _x0 ->
let _x0 = list _self.expression _self _x0 in
Expand Down
4 changes: 1 addition & 3 deletions compiler/core/lam_compile_const.ml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,4 @@ and translate (x : Lambda.structured_constant) : J.expression =

let translate_arg_cst (cst : External_arg_spec.cst) =
match cst with
| Arg_int_lit i -> E.int (Int32.of_int i)
| Arg_string_lit s -> E.str s
| Arg_json_lit s -> E.json_literal s
| Arg_fixed_lit source -> E.fixed_literal source
80 changes: 44 additions & 36 deletions compiler/frontend/ast_attributes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -176,50 +176,58 @@ let iter_process_bs_int_as (attrs : t) =
| _ -> ());
!st

type as_const_payload = Int of int | Str of string | Json of string
type as_const_payload = Fixed of string

let iter_process_bs_string_or_int_as (attrs : Parsetree.attributes) =
let st = ref None in
Ext_list.iter attrs (fun (({txt; loc}, payload) as attr) ->
let set_fixed source =
match Classify_function.classify source with
| Js_literal _ -> st := Some (Fixed source)
| _ ->
Location.raise_errorf ~loc
"The fixed-value @as payload must be a JavaScript literal"
in
match txt with
| "as" ->
if !st = None then (
Used_attributes.mark_used_attribute attr;
match Ast_payload.is_single_int payload with
| Some v -> st := Some (Int v)
| None -> (
match Ast_payload.semantic_string_of_payload payload with
| Some s -> st := Some (Str s)
| None -> (
match payload with
| PStr
[
{
pstr_desc =
Pstr_eval
( {
pexp_desc = Pexp_constant (Pconst_json s);
pexp_loc;
_;
},
_ );
_;
};
] -> (
st := Some (Json s);
(* Check that it is a valid object literal. *)
match
Classify_function.classify
~check:
( pexp_loc,
Bs_flow_ast_utils.flow_deli_offset (Some "json") )
s
with
| Js_literal _ -> ()
| _ ->
Location.raise_errorf ~loc:pexp_loc
"an object literal expected")
| _ -> Bs_syntaxerr.err loc Expect_int_or_string_or_json_literal)))
let is_fixed_value_payload =
Ast_payload.is_single_int payload <> None
|| Ast_payload.semantic_string_of_payload payload <> None
||
match payload with
| PStr
[
{
pstr_desc =
Pstr_eval
( {
pexp_desc =
Pexp_tagged_template
{
tag =
{
pexp_desc =
Pexp_ident {txt = Lident "json"};
};
raw_sources = [_];
values = [];
};
_;
},
_ );
_;
};
] ->
true
| _ -> false
in
if not is_fixed_value_payload then
Bs_syntaxerr.err loc Expect_int_or_string_or_json_literal;
match Ast_payload.fixed_source_of_payload payload with
| Some source -> set_fixed source
| None -> Bs_syntaxerr.err loc Expect_int_or_string_or_json_literal)
else raise (Ast_untagged_variants.Error (loc, Duplicated_bs_as))
| _ -> ());
!st
Expand Down
2 changes: 1 addition & 1 deletion compiler/frontend/ast_attributes.mli
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ val has_unwrap_attr : t -> bool

val iter_process_bs_int_as : t -> int option

type as_const_payload = Int of int | Str of string | Json of string
type as_const_payload = Fixed of string
val iter_process_bs_string_or_int_as : t -> as_const_payload option

val process_derive_type : t -> derive_attr * t
Expand Down
1 change: 0 additions & 1 deletion compiler/frontend/ast_config.ml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ let process_directives str =
|> List.iter (fun (item : Parsetree.structure_item) ->
match item.pstr_desc with
| Pstr_attribute ({txt = "directive"}, payload) -> (
Ast_payload.reject_json_literal_payload payload;
match Ast_payload.semantic_string_of_payload payload with
| Some d -> Js_config.directives := !Js_config.directives @ [d]
| None -> Bs_syntaxerr.err item.pstr_loc Expect_string_literal)
Expand Down
24 changes: 12 additions & 12 deletions compiler/frontend/ast_derive_abstract.ml
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ let handle_tdcl light (tdcl : Parsetree.type_declaration) :
(if has_optional_field then
(* start with the implicit unit argument *)
[
({attrs = []; lbl = Nolabel; typ = Ast_literal.type_unit ()}
: Parsetree.arg);
Parsetree.Parg_type
{attrs = []; lbl = Nolabel; typ = Ast_literal.type_unit ()};
]
else []),
[] )
Expand All @@ -111,11 +111,11 @@ let handle_tdcl light (tdcl : Parsetree.type_declaration) :
(* build the argument representing this field *)
let field_arg =
if is_optional then
({attrs = []; lbl = Asttypes.Optional pld_name; typ = pld_type}
: Parsetree.arg)
Parsetree.Parg_type
{attrs = []; lbl = Asttypes.Optional pld_name; typ = pld_type}
else
({attrs = []; lbl = Asttypes.Labelled pld_name; typ = pld_type}
: Parsetree.arg)
Parsetree.Parg_type
{attrs = []; lbl = Asttypes.Labelled pld_name; typ = pld_type}
in

(* prepend to the maker argument list *)
Expand All @@ -126,11 +126,11 @@ let handle_tdcl light (tdcl : Parsetree.type_declaration) :
if is_optional then
let optional_type = Ast_core_type.lift_option_type pld_type in
Ast_helper.Typ.arrow ~loc
[{attrs = []; lbl = Nolabel; typ = core_type}]
[Parg_type {attrs = []; lbl = Nolabel; typ = core_type}]
optional_type
else
Ast_helper.Typ.arrow ~loc
[{attrs = []; lbl = Nolabel; typ = core_type}]
[Parg_type {attrs = []; lbl = Nolabel; typ = core_type}]
pld_type
in
let accessor_prim =
Expand Down Expand Up @@ -172,10 +172,10 @@ let handle_tdcl light (tdcl : Parsetree.type_declaration) :
let setter_type =
Ast_helper.Typ.arrow ~loc:pld_loc
[
({attrs = []; lbl = Nolabel; typ = core_type}
: Parsetree.arg);
({attrs = []; lbl = Nolabel; typ = pld_type}
: Parsetree.arg);
Parsetree.Parg_type
{attrs = []; lbl = Nolabel; typ = core_type};
Parsetree.Parg_type
{attrs = []; lbl = Nolabel; typ = pld_type};
]
(Ast_literal.type_unit ())
in
Expand Down
Loading
Loading