Skip to content

Commit d8d9d5a

Browse files
committed
Add support for in operator
1 parent 1d8560f commit d8d9d5a

25 files changed

+83
-21
lines changed

compiler/core/j.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ and expression_desc =
8686
[typeof] is an operator
8787
*)
8888
| Typeof of expression
89+
| In of expression * expression (* prop in obj *)
8990
| Js_not of expression (* !v *)
9091
(* TODO: Add some primitives so that [js inliner] can do a better job *)
9192
| Seq of expression * expression

compiler/core/js_analyzer.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ let rec no_side_effect_expression_desc (x : J.expression_desc) =
111111
&& Ext_list.for_all strings no_side_effect
112112
&& Ext_list.for_all values no_side_effect
113113
| Js_not e -> no_side_effect e
114+
| In (prop, obj) -> no_side_effect prop && no_side_effect obj
114115
| Cond (a, b, c) -> no_side_effect a && no_side_effect b && no_side_effect c
115116
| Call ({expression_desc = Str {txt = "Array.isArray"}}, [e], _) ->
116117
no_side_effect e
@@ -227,7 +228,7 @@ let rec eq_expression ({expression_desc = x0} : J.expression)
227228
eq_expression_list ls0 ls1 && flag0 = flag1 && eq_expression tag0 tag1
228229
| _ -> false)
229230
| Length _ | Is_null_or_undefined _ | String_append _ | Typeof _ | Js_not _
230-
| Cond _ | FlatCall _ | New _ | Fun _ | Raw_js_code _ | Array _
231+
| In _ | Cond _ | FlatCall _ | New _ | Fun _ | Raw_js_code _ | Array _
231232
| Caml_block_tag _ | Object _ | Tagged_template _ | Await _ ->
232233
false
233234
| Spread _ -> false

compiler/core/js_dump.ml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ let rec exp_need_paren ?(arrow = false) (e : J.expression) =
166166
| Length _ | Call _ | Caml_block_tag _ | Seq _ | Static_index _ | Cond _
167167
| Bin _ | Is_null_or_undefined _ | String_index _ | Array_index _
168168
| String_append _ | Var _ | Undefined _ | Null | Str _ | Array _
169-
| Caml_block _ | FlatCall _ | Typeof _ | Number _ | Js_not _ | Bool _ | New _
170-
->
169+
| Caml_block _ | FlatCall _ | Typeof _ | Number _ | Js_not _ | In _ | Bool _
170+
| New _ ->
171171
false
172172
| Await _ -> false
173173
| Spread _ -> false
@@ -677,6 +677,11 @@ and expression_desc cxt ~(level : int) f x : cxt =
677677
P.cond_paren_group f (level > 13) (fun _ ->
678678
P.string f "!";
679679
expression ~level:13 cxt f e)
680+
| In (prop, obj) ->
681+
P.cond_paren_group f (level > 12) (fun _ ->
682+
let cxt = expression ~level:0 cxt f prop in
683+
P.string f " in ";
684+
expression ~level:0 cxt f obj)
680685
| Typeof e ->
681686
P.string f "typeof";
682687
P.space f;

compiler/core/js_exp_make.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1128,6 +1128,9 @@ let or_ ?comment (e1 : t) (e2 : t) =
11281128
| Some e -> e
11291129
| None -> {expression_desc = Bin (Or, e1, e2); comment})
11301130

1131+
let in_ (prop : t) (obj : t) : t =
1132+
{expression_desc = In (prop, obj); comment = None}
1133+
11311134
let not (e : t) : t =
11321135
match e.expression_desc with
11331136
| Number (Int {i; _}) -> bool (i = 0l)

compiler/core/js_exp_make.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ val and_ : ?comment:string -> t -> t -> t
352352

353353
val or_ : ?comment:string -> t -> t -> t
354354

355+
val in_ : t -> t -> t
356+
355357
(** we don't expose a general interface, since a general interface is generally not safe *)
356358

357359
val dummy_obj : ?comment:string -> Lam_tag_info.t -> t

compiler/core/js_fold.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ class fold =
103103
| Js_not _x0 ->
104104
let _self = _self#expression _x0 in
105105
_self
106+
| In (_x0, _x1) ->
107+
let _self = _self#expression _x0 in
108+
let _self = _self#expression _x1 in
109+
_self
106110
| Seq (_x0, _x1) ->
107111
let _self = _self#expression _x0 in
108112
let _self = _self#expression _x1 in

compiler/core/js_record_fold.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ let expression_desc : 'a. ('a, expression_desc) fn =
109109
| Js_not _x0 ->
110110
let st = _self.expression _self st _x0 in
111111
st
112+
| In (_x0, _x1) ->
113+
let st = _self.expression _self st _x0 in
114+
let st = _self.expression _self st _x1 in
115+
st
112116
| Seq (_x0, _x1) ->
113117
let st = _self.expression _self st _x0 in
114118
let st = _self.expression _self st _x1 in

compiler/core/js_record_iter.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ let expression_desc : expression_desc fn =
9191
| Bool _ -> ()
9292
| Typeof _x0 -> _self.expression _self _x0
9393
| Js_not _x0 -> _self.expression _self _x0
94+
| In (_x0, _x1) ->
95+
_self.expression _self _x0;
96+
_self.expression _self _x1
9497
| Seq (_x0, _x1) ->
9598
_self.expression _self _x0;
9699
_self.expression _self _x1

compiler/core/js_record_map.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ let expression_desc : expression_desc fn =
109109
| Js_not _x0 ->
110110
let _x0 = _self.expression _self _x0 in
111111
Js_not _x0
112+
| In (_x0, _x1) ->
113+
let _x0 = _self.expression _self _x0 in
114+
let _x1 = _self.expression _self _x1 in
115+
In (_x0, _x1)
112116
| Seq (_x0, _x1) ->
113117
let _x0 = _self.expression _self _x0 in
114118
let _x1 = _self.expression _self _x1 in

compiler/core/lam_analysis.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ let rec no_side_effects (lam : Lam.t) : bool =
7777
(* list primitives *)
7878
| Pmakelist
7979
(* dict primitives *)
80-
| Pmakedict
80+
| Pmakedict | Phasin
8181
(* Test if the argument is a block or an immediate integer *)
8282
| Pisint | Pis_poly_var_block
8383
(* Test if the (integer) argument is outside an interval *)

compiler/core/lam_compile_primitive.ml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,13 @@ let translate output_prefix loc (cxt : Lam_compile_context.t)
566566
Some (Js_op.Lit txt, expr)
567567
| _ -> None))
568568
| _ -> assert false)
569+
| Phasin -> (
570+
match args with
571+
| [obj; prop] -> E.in_ prop obj
572+
| _ ->
573+
Location.raise_errorf ~loc
574+
"Invalid external \"%%has_in\" type signature. Expected to have two \
575+
arguments.")
569576
| Parraysetu -> (
570577
match args with
571578
(* wrong*)

compiler/core/lam_convert.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ let lam_prim ~primitive:(p : Lambda.primitive) ~args loc : Lam.t =
312312
| Parraysets -> prim ~primitive:Parraysets ~args loc
313313
| Pmakelist _mutable_flag (*FIXME*) -> prim ~primitive:Pmakelist ~args loc
314314
| Pmakedict -> prim ~primitive:Pmakedict ~args loc
315+
| Phasin -> prim ~primitive:Phasin ~args loc
315316
| Pawait -> prim ~primitive:Pawait ~args loc
316317
| Pimport -> prim ~primitive:Pimport ~args loc
317318
| Pinit_mod -> (

compiler/core/lam_primitive.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ type t =
135135
| Pmakelist
136136
(* dict primitives *)
137137
| Pmakedict
138+
| Phasin
138139
(* promise *)
139140
| Pawait
140141
(* etc or deprecated *)
@@ -213,7 +214,7 @@ let eq_primitive_approx (lhs : t) (rhs : t) =
213214
(* List primitives *)
214215
| Pmakelist
215216
(* dict primitives *)
216-
| Pmakedict
217+
| Pmakedict | Phasin
217218
(* promise *)
218219
| Pawait
219220
(* etc *)

compiler/core/lam_primitive.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ type t =
130130
| Pmakelist
131131
(* dict primitives *)
132132
| Pmakedict
133+
| Phasin
133134
(* promise *)
134135
| Pawait
135136
(* etc or deprecated *)

compiler/core/lam_print.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ let primitive ppf (prim : Lam_primitive.t) =
192192
| Pmakearray -> fprintf ppf "makearray"
193193
| Pmakelist -> fprintf ppf "makelist"
194194
| Pmakedict -> fprintf ppf "makedict"
195+
| Phasin -> fprintf ppf "has_in"
195196
| Parrayrefu -> fprintf ppf "array.unsafe_get"
196197
| Parraysetu -> fprintf ppf "array.unsafe_set"
197198
| Parrayrefs -> fprintf ppf "array.get"

compiler/ml/lambda.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ type primitive =
269269
| Pmakelist of Asttypes.mutable_flag
270270
(* dict primitives *)
271271
| Pmakedict
272+
| Phasin
272273
(* promise *)
273274
| Pawait
274275
(* module *)

compiler/ml/lambda.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ type primitive =
236236
| Pmakelist of Asttypes.mutable_flag
237237
(* dict primitives *)
238238
| Pmakedict
239+
| Phasin
239240
(* promise *)
240241
| Pawait
241242
(* modules *)

compiler/ml/printlambda.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ let primitive ppf = function
227227
| Pmakelist Mutable -> fprintf ppf "makelist"
228228
| Pmakelist Immutable -> fprintf ppf "makelist_imm"
229229
| Pmakedict -> fprintf ppf "makedict"
230+
| Phasin -> fprintf ppf "has_in"
230231
| Pisint -> fprintf ppf "isint"
231232
| Pisout -> fprintf ppf "isout"
232233
| Pisnullable -> fprintf ppf "isnullable"

compiler/ml/translcore.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ let primitives_table =
346346
("%array_unsafe_set", Parraysetu);
347347
(* dict primitives *)
348348
("%makedict", Pmakedict);
349+
("%has_in", Phasin);
349350
(* promise *)
350351
("%await", Pawait);
351352
(* module *)

lib/es6/Stdlib_Dict.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,10 @@ function mapValues(dict, f) {
2222
return target;
2323
}
2424

25-
let has = ((dict, key) => key in dict);
26-
2725
export {
2826
$$delete$1 as $$delete,
2927
forEach,
3028
forEachWithKey,
3129
mapValues,
32-
has,
3330
}
3431
/* No side effect */

lib/js/Stdlib_Dict.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,8 @@ function mapValues(dict, f) {
2222
return target;
2323
}
2424

25-
let has = ((dict, key) => key in dict);
26-
2725
exports.$$delete = $$delete$1;
2826
exports.forEach = forEach;
2927
exports.forEachWithKey = forEachWithKey;
3028
exports.mapValues = mapValues;
31-
exports.has = has;
3229
/* No side effect */

runtime/Stdlib_Dict.res

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,4 @@ let mapValues = (dict, f) => {
4141
target
4242
}
4343

44-
let has: (dict<'a>, string) => bool = %raw(`(dict, key) => key in dict`)
44+
external has: (dict<'a>, string) => bool = "%has_in"

runtime/Stdlib_Dict.resi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ let dict = dict{"key1": Some(1), "key2": None}
254254
dict->Dict.has("key1") // true
255255
dict->Dict.has("key2") // true
256256
dict->Dict.has("key3") // false
257+
dict->Dict.has("__proto__") // true, since it uses in operator under the hood
257258
```
258259
*/
259-
let has: (dict<'a>, string) => bool
260+
external has: (dict<'a>, string) => bool = "%has_in"

tests/tests/src/DictTests.mjs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Generated by ReScript, PLEASE EDIT WITH CARE
22

3-
import * as Stdlib_Dict from "rescript/lib/es6/Stdlib_Dict.js";
43

54
let someString = "hello";
65

@@ -43,11 +42,11 @@ let PatternMatching = {
4342
};
4443

4544
let dict = {
46-
key1: 1,
45+
key1: false,
4746
key2: undefined
4847
};
4948

50-
if (Stdlib_Dict.has(dict, "key1") !== true) {
49+
if (!("key1" in dict)) {
5150
throw {
5251
RE_EXN_ID: "Assert_failure",
5352
_1: [
@@ -59,7 +58,7 @@ if (Stdlib_Dict.has(dict, "key1") !== true) {
5958
};
6059
}
6160

62-
if (Stdlib_Dict.has(dict, "key2") !== true) {
61+
if (!("key2" in dict)) {
6362
throw {
6463
RE_EXN_ID: "Assert_failure",
6564
_1: [
@@ -71,7 +70,7 @@ if (Stdlib_Dict.has(dict, "key2") !== true) {
7170
};
7271
}
7372

74-
if (Stdlib_Dict.has(dict, "key3") !== false) {
73+
if ("key3" in dict !== false) {
7574
throw {
7675
RE_EXN_ID: "Assert_failure",
7776
_1: [
@@ -83,6 +82,30 @@ if (Stdlib_Dict.has(dict, "key3") !== false) {
8382
};
8483
}
8584

85+
if (!("__proto__" in dict)) {
86+
throw {
87+
RE_EXN_ID: "Assert_failure",
88+
_1: [
89+
"DictTests.res",
90+
46,
91+
2
92+
],
93+
Error: new Error()
94+
};
95+
}
96+
97+
if (typeof ("key1" in dict) !== "boolean") {
98+
throw {
99+
RE_EXN_ID: "Assert_failure",
100+
_1: [
101+
"DictTests.res",
102+
47,
103+
2
104+
],
105+
Error: new Error()
106+
};
107+
}
108+
86109
let DictHas = {
87110
dict: dict
88111
};

tests/tests/src/DictTests.res

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,13 @@ module PatternMatching = {
3636

3737
module DictHas = {
3838
let dict = dict{
39-
"key1": Some(1),
39+
"key1": Some(false),
4040
"key2": None,
4141
}
4242

43-
assert(dict->Dict.has("key1") === true)
44-
assert(dict->Dict.has("key2") === true)
43+
assert(dict->Dict.has("key1"))
44+
assert(dict->Dict.has("key2"))
4545
assert(dict->Dict.has("key3") === false)
46+
assert(dict->Dict.has("__proto__"))
47+
assert(typeof(dict->Dict.has("key1")) === #boolean)
4648
}

0 commit comments

Comments
 (0)