Skip to content

Commit 273c4f4

Browse files
committed
Add support for @tag(...) to customize the property used for the tag.
1 parent 4b9d87e commit 273c4f4

39 files changed

+3808
-4467
lines changed

jscomp/core/j.ml

+1-10
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,7 @@ and expression_desc =
151151
(* | Caml_uninitialized_obj of expression * expression *)
152152
(* [tag] and [size] tailed for [Obj.new_block] *)
153153

154-
(* For setter, it still return the value of expression,
155-
we can not use
156-
{[
157-
type 'a access = Get | Set of 'a
158-
]}
159-
in another module, since it will break our code generator
160-
[Caml_block_tag] can return [undefined],
161-
you have to use [E.tag] in a safe way
162-
*)
163-
| Caml_block_tag of expression
154+
| Caml_block_tag of expression * string (* e.tag *)
164155
(* | Caml_block_set_length of expression * expression *)
165156
(* It will just fetch tag, to make it safe, when creating it,
166157
we need apply "|0", we don't do it in the

jscomp/core/js_analyzer.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) =
101101
| Optional_block (x, _) -> no_side_effect x
102102
| Object kvs -> Ext_list.for_all_snd kvs no_side_effect
103103
| String_append (a, b) | Seq (a, b) -> no_side_effect a && no_side_effect b
104-
| Length (e, _) | Caml_block_tag e | Typeof e -> no_side_effect e
104+
| Length (e, _) | Caml_block_tag (e, _) | Typeof e -> no_side_effect e
105105
| Bin (op, a, b) -> op <> Eq && no_side_effect a && no_side_effect b
106106
| Js_not _ | Cond _ | FlatCall _ | Call _ | New _ | Raw_js_code _
107107
(* actually true? *) ->

jscomp/core/js_dump.ml

+10-4
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,9 @@ and expression_desc cxt ~(level : int) f x : cxt =
762762
| Lit n -> Ext_list.mem_string p.optional_labels n
763763
| Symbol_name -> false
764764
in
765+
let tag_name = match Ast_attributes.process_tag_name p.attrs with
766+
| None -> L.tag
767+
| Some s -> s in
765768
let tails =
766769
match p.optional_labels with
767770
| [] -> tails
@@ -771,7 +774,7 @@ and expression_desc cxt ~(level : int) f x : cxt =
771774
| Undefined when is_optional f -> None
772775
| _ -> Some (f, x))
773776
in
774-
( Js_op.Lit L.tag,
777+
( Js_op.Lit tag_name, (* TAG:xx for inline records *)
775778
match Ast_attributes.process_as_value p.attrs with
776779
| None -> E.str p.name
777780
| Some as_value -> E.as_value as_value )
@@ -781,6 +784,9 @@ and expression_desc cxt ~(level : int) f x : cxt =
781784
| Caml_block (el, _, tag, Blk_constructor p) ->
782785
let not_is_cons = p.name <> Literals.cons in
783786
let as_value = Ast_attributes.process_as_value p.attrs in
787+
let tag_name = match Ast_attributes.process_tag_name p.attrs with
788+
| None -> L.tag
789+
| Some s -> s in
784790
let objs =
785791
let tails =
786792
Ext_list.mapi_append el
@@ -796,7 +802,7 @@ and expression_desc cxt ~(level : int) f x : cxt =
796802
in
797803
if (as_value = Some AsUnboxed || not_is_cons = false) && p.num_nonconst = 1 then tails
798804
else
799-
( Js_op.Lit L.tag,
805+
( Js_op.Lit tag_name, (* TAG:xx *)
800806
match as_value with
801807
| None -> E.str p.name
802808
| Some as_value -> E.as_value as_value )
@@ -816,11 +822,11 @@ and expression_desc cxt ~(level : int) f x : cxt =
816822
assert false
817823
| Caml_block (el, mutable_flag, _tag, Blk_tuple) ->
818824
expression_desc cxt ~level f (Array (el, mutable_flag))
819-
| Caml_block_tag e ->
825+
| Caml_block_tag (e, tag) ->
820826
P.group f 1 (fun _ ->
821827
let cxt = expression ~level:15 cxt f e in
822828
P.string f L.dot;
823-
P.string f L.tag;
829+
P.string f tag;
824830
cxt)
825831
| Array_index (e, p) ->
826832
P.cond_paren_group f (level > 15) 1 (fun _ ->

jscomp/core/js_exp_make.ml

+2-2
Original file line numberDiff line numberDiff line change
@@ -800,8 +800,8 @@ let is_type_object (e : t) : t = string_equal (typeof e) (str "object")
800800
call plain [dot]
801801
*)
802802

803-
let tag ?comment e : t =
804-
{ expression_desc = Caml_block_tag e; comment }
803+
let tag ?comment ?(name=Js_dump_lit.tag) e : t =
804+
{ expression_desc = Caml_block_tag (e, name); comment }
805805

806806
(* according to the compiler, [Btype.hash_variant],
807807
it's reduced to 31 bits for hash

jscomp/core/js_exp_make.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ val unit : t
307307

308308
val undefined : t
309309

310-
val tag : ?comment:string -> J.expression -> t
310+
val tag : ?comment:string -> ?name:string -> J.expression -> t
311311

312312
(** Note that this is coupled with how we encode block, if we use the
313313
`Object.defineProperty(..)` since the array already hold the length,

jscomp/core/js_fold.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class fold =
162162
let _self = list (fun _self -> _self#expression) _self _x0 in
163163
let _self = _self#expression _x2 in
164164
_self
165-
| Caml_block_tag _x0 ->
165+
| Caml_block_tag (_x0, _tag) ->
166166
let _self = _self#expression _x0 in
167167
_self
168168
| Number _ -> _self

jscomp/core/js_record_fold.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ let expression_desc : 'a. ('a, expression_desc) fn =
168168
let st = list _self.expression _self st _x0 in
169169
let st = _self.expression _self st _x2 in
170170
st
171-
| Caml_block_tag _x0 ->
171+
| Caml_block_tag (_x0, _tag) ->
172172
let st = _self.expression _self st _x0 in
173173
st
174174
| Number _ -> st

jscomp/core/js_record_iter.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ let expression_desc : expression_desc fn =
128128
| Caml_block (_x0, _x1, _x2, _x3) ->
129129
list _self.expression _self _x0;
130130
_self.expression _self _x2
131-
| Caml_block_tag _x0 -> _self.expression _self _x0
131+
| Caml_block_tag (_x0, _tag) -> _self.expression _self _x0
132132
| Number _ -> ()
133133
| Object _x0 -> property_map _self _x0
134134
| Undefined -> ()

jscomp/core/js_record_map.ml

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,9 @@ let expression_desc : expression_desc fn =
166166
let _x0 = list _self.expression _self _x0 in
167167
let _x2 = _self.expression _self _x2 in
168168
Caml_block (_x0, _x1, _x2, _x3)
169-
| Caml_block_tag _x0 ->
169+
| Caml_block_tag (_x0, tag) ->
170170
let _x0 = _self.expression _self _x0 in
171-
Caml_block_tag _x0
171+
Caml_block_tag (_x0, tag)
172172
| Number _ as v -> v
173173
| Object _x0 ->
174174
let _x0 = property_map _self _x0 in

jscomp/core/lam_compile.ml

+16-4
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,17 @@ let default_action ~saturated failaction =
141141
let get_const_name i (sw_names : Lambda.switch_names option) =
142142
match sw_names with None -> None | Some { consts } -> Some consts.(i)
143143

144-
let get_block_name i (sw_names : Lambda.switch_names option) =
144+
let get_block i (sw_names : Lambda.switch_names option) =
145145
match sw_names with None -> None | Some { blocks } -> Some blocks.(i)
146146

147+
let get_tag_name (sw_names : Lambda.switch_names option) =
148+
match sw_names with
149+
| None -> Js_dump_lit.tag
150+
| Some { blocks } ->
151+
(match Array.find_opt (fun {Lambda.tag_name} -> tag_name <> None) blocks with
152+
| Some {tag_name = Some s} -> s
153+
| _ -> Js_dump_lit.tag
154+
)
147155

148156
let has_null_undefined_other (sw_names : Lambda.switch_names option) =
149157
let (null, undefined, other) = (ref false, ref false, ref false) in
@@ -628,7 +636,11 @@ and compile_switch (switch_arg : Lam.t) (sw : Lam.lambda_switch)
628636
default_action ~saturated:sw_blocks_full sw_failaction
629637
in
630638
let get_const_name i = get_const_name i sw_names in
631-
let get_block_name i = get_block_name i sw_names in
639+
let get_block i = get_block i sw_names in
640+
let get_block_name i = match get_block i with
641+
| None -> None
642+
| Some {cstr_name} -> Some cstr_name in
643+
let tag_name = get_tag_name sw_names in
632644
let compile_whole (cxt : Lam_compile_context.t) =
633645
match
634646
compile_lambda { cxt with continuation = NeedValue Not_tail } switch_arg
@@ -638,7 +650,7 @@ and compile_switch (switch_arg : Lam.t) (sw : Lam.lambda_switch)
638650
block
639651
@
640652
if sw_consts_full && sw_consts = [] then
641-
compile_cases cxt (E.tag e) sw_blocks sw_blocks_default get_block_name
653+
compile_cases cxt (E.tag ~name:tag_name e) sw_blocks sw_blocks_default get_block_name
642654
else if sw_blocks_full && sw_blocks = [] then
643655
compile_cases cxt e sw_consts sw_num_default get_const_name
644656
else
@@ -648,7 +660,7 @@ and compile_switch (switch_arg : Lam.t) (sw : Lam.lambda_switch)
648660
(compile_cases cxt e sw_consts sw_num_default get_const_name)
649661
(* default still needed, could simplified*)
650662
~else_:
651-
(compile_cases cxt (E.tag e) sw_blocks sw_blocks_default
663+
(compile_cases cxt (E.tag ~name:tag_name e) sw_blocks sw_blocks_default
652664
get_block_name)
653665
in
654666
match e.expression_desc with

jscomp/core/lam_print.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ let lambda ppf v =
320320
(fun (n, l) ->
321321
if !spc then fprintf ppf "@ " else spc := true;
322322
fprintf ppf "@[<hv 1>case tag %i %S:@ %a@]" n
323-
(match sw.sw_names with None -> "" | Some x -> x.blocks.(n).name)
323+
(match sw.sw_names with None -> "" | Some x -> x.blocks.(n).cstr_name.name)
324324
lam l)
325325
sw.sw_blocks;
326326
match sw.sw_failaction with

jscomp/core/matching_polyfill.ml

+5-2
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,15 @@ let names_from_construct_pattern (pat : Typedtree.pattern) =
3030
let get_cstr_name (cstr: Types.constructor_declaration) =
3131
{ Lambda.name = Ident.name cstr.cd_id;
3232
as_value = Ast_attributes.process_as_value cstr.cd_attributes } in
33+
let get_tag_name (cstr: Types.constructor_declaration) =
34+
Ast_attributes.process_tag_name cstr.cd_attributes in
35+
let get_block cstr : Lambda.block =
36+
{cstr_name = get_cstr_name cstr; tag_name = get_tag_name cstr} in
3337
let consts, blocks =
3438
Ext_list.fold_left cstrs ([], []) (fun (consts, blocks) cstr ->
3539
if is_nullary_variant cstr.cd_args then
3640
(get_cstr_name cstr :: consts, blocks)
37-
else (consts, get_cstr_name cstr :: blocks))
41+
else (consts, get_block cstr :: blocks))
3842
in
3943
Some
4044
{
@@ -48,7 +52,6 @@ let names_from_construct_pattern (pat : Typedtree.pattern) =
4852
| { type_kind = Type_abstract; type_manifest = Some t; _ } -> (
4953
match (Ctype.unalias t).desc with
5054
| Tconstr (pathn, _, _) ->
51-
(* Format.eprintf "XXX path%d:%s path%d:%s@." n (Path.name path) (n+1) (Path.name pathn); *)
5255
resolve_path (n + 1) pathn
5356
| _ -> None)
5457
| { type_kind = Type_abstract; type_manifest = None; _ } -> None

jscomp/frontend/ast_attributes.ml

+17
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,23 @@ let process_as_value (attrs : t) =
368368
| _ -> ());
369369
!st
370370

371+
let process_tag_name (attrs : t) =
372+
let st = ref None in
373+
Ext_list.iter attrs (fun (({ txt; loc }, payload) as attr) ->
374+
match txt with
375+
| "tag" ->
376+
if !st = None then (
377+
(match Ast_payload.is_single_string payload with
378+
| None -> ()
379+
| Some (s, _dec) ->
380+
Bs_ast_invariant.mark_used_bs_attribute attr;
381+
st := Some s);
382+
if !st = None then Bs_syntaxerr.err loc InvalidVariantTagAnnotation
383+
)
384+
else Bs_syntaxerr.err loc Duplicated_bs_as
385+
| _ -> ());
386+
!st
387+
371388
let locg = Location.none
372389
(* let bs : attr
373390
= {txt = "bs" ; loc = locg}, Ast_payload.empty *)

jscomp/frontend/ast_attributes.mli

+3-1
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,6 @@ val rs_externals : t -> string list -> bool
9292

9393
val process_send_pipe : t -> (Parsetree.core_type * t) option
9494

95-
val process_as_value : t -> Lambda.as_value option
95+
val process_as_value : t -> Lambda.as_value option
96+
97+
val process_tag_name : t -> string option

jscomp/frontend/bs_syntaxerr.ml

+3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type error =
5252
| Bs_this_simple_pattern
5353
| Bs_uncurried_arity_too_large
5454
| InvalidVariantAsAnnotation
55+
| InvalidVariantTagAnnotation
5556

5657
let pp_error fmt err =
5758
Format.pp_print_string fmt
@@ -100,6 +101,8 @@ let pp_error fmt err =
100101
"%@this expect its pattern variable to be simple form"
101102
| InvalidVariantAsAnnotation ->
102103
"A variant case annotation @as(...) must be a string or integer or null"
104+
| InvalidVariantTagAnnotation ->
105+
"A variant tag annotation @tag(...) must be a string"
103106
)
104107

105108
type exn += Error of Location.t * error

jscomp/frontend/bs_syntaxerr.mli

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type error =
5252
| Bs_this_simple_pattern
5353
| Bs_uncurried_arity_too_large
5454
| InvalidVariantAsAnnotation
55+
| InvalidVariantTagAnnotation
5556

5657
val err : Location.t -> error -> 'a
5758

jscomp/ml/datarepr.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ let constructor_descrs ty_path decl cstrs =
142142
let representation =
143143
if decl.type_unboxed.unboxed
144144
then Record_unboxed true
145-
else Record_inlined {tag = idx_nonconst; name = cstr_name; num_nonconsts = !num_nonconsts; optional_labels}
145+
else Record_inlined {tag = idx_nonconst; name = cstr_name; num_nonconsts = !num_nonconsts; optional_labels; attrs = cd_attributes}
146146
in
147147
constructor_args decl.type_private cd_args cd_res
148148
(Path.Pdot (ty_path, cstr_name, Path.nopos)) representation

jscomp/ml/lambda.ml

+4-3
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,9 @@ let blk_record_ext = ref (fun fields mutable_flag ->
9999
Blk_record_ext {fields = all_labels_info; mutable_flag }
100100
)
101101

102-
let blk_record_inlined = ref (fun fields name num_nonconst optional_labels ~tag mutable_flag ->
102+
let blk_record_inlined = ref (fun fields name num_nonconst optional_labels ~tag ~attrs mutable_flag ->
103103
let fields = fields |> Array.map (fun (x,_) -> x.Types.lbl_name) in
104-
Blk_record_inlined {fields; name; num_nonconst; tag; mutable_flag; optional_labels; attrs = []}
104+
Blk_record_inlined {fields; name; num_nonconst; tag; mutable_flag; optional_labels; attrs }
105105
)
106106

107107
let ref_tag_info : tag_info =
@@ -273,7 +273,8 @@ type function_attribute = {
273273
return_unit : bool;
274274
async : bool;
275275
}
276-
type switch_names = {consts: cstr_name array; blocks: cstr_name array}
276+
type block = {cstr_name: cstr_name; tag_name: string option}
277+
type switch_names = {consts: cstr_name array; blocks: block array}
277278

278279
type lambda =
279280
Lvar of Ident.t

jscomp/ml/lambda.mli

+3-1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ val blk_record_inlined :
9090
int ->
9191
string list ->
9292
tag:int ->
93+
attrs:Parsetree.attributes ->
9394
mutable_flag ->
9495
tag_info
9596
) ref
@@ -275,7 +276,8 @@ type function_attribute = {
275276
async : bool;
276277
}
277278

278-
type switch_names = {consts: cstr_name array; blocks: cstr_name array}
279+
type block = {cstr_name: cstr_name; tag_name: string option}
280+
type switch_names = {consts: cstr_name array; blocks: block array}
279281

280282
type lambda =
281283
Lvar of Ident.t

jscomp/ml/translcore.ml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1157,10 +1157,10 @@ and transl_record loc env fields repres opt_init_expr =
11571157
| Record_optional_labels _ ->
11581158
Lconst
11591159
(Const_block (!Lambda.blk_record fields mut Record_optional, cl))
1160-
| Record_inlined { tag; name; num_nonconsts; optional_labels } ->
1160+
| Record_inlined { tag; name; num_nonconsts; optional_labels; attrs } ->
11611161
Lconst
11621162
(Const_block
1163-
( !Lambda.blk_record_inlined fields name num_nonconsts optional_labels ~tag
1163+
( !Lambda.blk_record_inlined fields name num_nonconsts optional_labels ~tag ~attrs
11641164
mut,
11651165
cl ))
11661166
| Record_unboxed _ ->
@@ -1179,10 +1179,10 @@ and transl_record loc env fields repres opt_init_expr =
11791179
ll,
11801180
loc )
11811181
| Record_float_unused -> assert false
1182-
| Record_inlined { tag; name; num_nonconsts; optional_labels } ->
1182+
| Record_inlined { tag; name; num_nonconsts; optional_labels; attrs } ->
11831183
Lprim
11841184
( Pmakeblock
1185-
(!Lambda.blk_record_inlined fields name num_nonconsts optional_labels ~tag
1185+
(!Lambda.blk_record_inlined fields name num_nonconsts optional_labels ~tag ~attrs
11861186
mut),
11871187
ll,
11881188
loc )

jscomp/ml/typedecl.ml

+5-2
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,9 @@ let transl_declaration env sdecl id =
379379
raise(Error(sdecl.ptype_loc, Duplicate_constructor name));
380380
all_constrs := StringSet.add name !all_constrs)
381381
scstrs;
382+
let copy_tag_attr_from_decl attr =
383+
let tag_attr = Ext_list.filter sdecl.ptype_attributes (fun ({txt}, _) -> txt = "tag") in
384+
if tag_attr = [] then attr else tag_attr @ attr in
382385
let make_cstr scstr =
383386
let name = Ident.create scstr.pcd_name.txt in
384387
let targs, tret_type, args, ret_type, _cstr_params =
@@ -391,14 +394,14 @@ let transl_declaration env sdecl id =
391394
cd_args = targs;
392395
cd_res = tret_type;
393396
cd_loc = scstr.pcd_loc;
394-
cd_attributes = scstr.pcd_attributes }
397+
cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl }
395398
in
396399
let cstr =
397400
{ Types.cd_id = name;
398401
cd_args = args;
399402
cd_res = ret_type;
400403
cd_loc = scstr.pcd_loc;
401-
cd_attributes = scstr.pcd_attributes }
404+
cd_attributes = scstr.pcd_attributes |> copy_tag_attr_from_decl }
402405
in
403406
tcstr, cstr
404407
in

jscomp/ml/types.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ and record_representation =
154154
| Record_float_unused (* Was: all fields are floats. Now: unused *)
155155
| Record_unboxed of bool (* Unboxed single-field record, inlined or not *)
156156
| Record_inlined of (* Inlined record *)
157-
{ tag : int ; name : string; num_nonconsts : int; optional_labels : string list}
157+
{ tag : int ; name : string; num_nonconsts : int; optional_labels : string list; attrs: Parsetree.attributes}
158158
| Record_extension (* Inlined record under extension *)
159159
| Record_optional_labels of string list (* List of optional labels *)
160160

0 commit comments

Comments
 (0)