Skip to content

Commit 220b3d0

Browse files
gwansikkcometkim
andauthored
Add shift operators (<<, >>, >>>) (#7183)
Resolved #7171 --------- Co-authored-by: Hyeseong Kim <[email protected]>
1 parent 99c173d commit 220b3d0

File tree

15 files changed

+119
-15
lines changed

15 files changed

+119
-15
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
1313
# 12.0.0-alpha.13 (Unreleased)
1414

15+
#### :rocket: New Feature
16+
17+
- Add shift (`<<`, `>>`, `>>>`) operators for `int` and `bigint`. https://github.com/rescript-lang/rescript/pull/7183
18+
1519
# 12.0.0-alpha.12
1620

1721
#### :bug: Bug fix

compiler/ml/unified_ops.ml

+33
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,39 @@ let entries =
148148
string = None;
149149
};
150150
};
151+
{
152+
path = builtin "<<";
153+
name = "%lsl";
154+
form = Binary;
155+
specialization =
156+
{
157+
int = Plslint;
158+
bool = None;
159+
float = None;
160+
bigint = Some Plslbigint;
161+
string = None;
162+
};
163+
};
164+
{
165+
path = builtin ">>";
166+
name = "%asr";
167+
form = Binary;
168+
specialization =
169+
{
170+
int = Pasrint;
171+
bool = None;
172+
float = None;
173+
bigint = Some Pasrbigint;
174+
string = None;
175+
};
176+
};
177+
{
178+
path = builtin ">>>";
179+
name = "%lsr";
180+
form = Binary;
181+
specialization =
182+
{int = Plsrint; bool = None; float = None; bigint = None; string = None};
183+
};
151184
{
152185
path = builtin "mod";
153186
name = "%mod";

compiler/syntax/src/res_parsetree_viewer.ml

+6-5
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,11 @@ let operator_precedence operator =
274274
| "&&" -> 3
275275
| "^" -> 4
276276
| "==" | "===" | "<" | ">" | "!=" | "<>" | "!==" | "<=" | ">=" | "|>" -> 5
277-
| "+" | "+." | "-" | "-." | "++" -> 6
278-
| "*" | "*." | "/" | "/." | "%" -> 7
279-
| "**" -> 8
280-
| "#" | "##" | "->" -> 9
277+
| "<<" | ">>" | ">>>" -> 6
278+
| "+" | "+." | "-" | "-." | "++" -> 7
279+
| "*" | "*." | "/" | "/." | "%" -> 8
280+
| "**" -> 9
281+
| "#" | "##" | "->" -> 10
281282
| _ -> 0
282283

283284
let is_unary_operator operator =
@@ -300,7 +301,7 @@ let is_binary_operator operator =
300301
match operator with
301302
| ":=" | "||" | "&&" | "==" | "===" | "<" | ">" | "!=" | "!==" | "<=" | ">="
302303
| "|>" | "+" | "+." | "-" | "-." | "++" | "*" | "*." | "/" | "/." | "**"
303-
| "->" | "<>" | "%" | "^" ->
304+
| "->" | "<>" | "%" | "^" | "<<" | ">>" | ">>>" ->
304305
true
305306
| _ -> false
306307

compiler/syntax/src/res_scanner.ml

+16-2
Original file line numberDiff line numberDiff line change
@@ -886,16 +886,30 @@ let rec scan scanner =
886886
| _ ->
887887
next scanner;
888888
Token.Plus)
889-
| '>' -> (
889+
| '>' when not (in_diamond_mode scanner) -> (
890890
match peek scanner with
891-
| '=' when not (in_diamond_mode scanner) ->
891+
| '=' ->
892892
next2 scanner;
893893
Token.GreaterEqual
894+
| '>' -> (
895+
match peek2 scanner with
896+
| '>' ->
897+
next3 scanner;
898+
Token.RightShiftUnsigned
899+
| _ ->
900+
next2 scanner;
901+
Token.RightShift)
894902
| _ ->
895903
next scanner;
896904
Token.GreaterThan)
905+
| '>' ->
906+
next scanner;
907+
Token.GreaterThan
897908
| '<' when not (in_jsx_mode scanner) -> (
898909
match peek scanner with
910+
| '<' when not (in_diamond_mode scanner) ->
911+
next2 scanner;
912+
Token.LeftShift
899913
| '=' ->
900914
next2 scanner;
901915
Token.LessEqual

compiler/syntax/src/res_token.ml

+12-5
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ type t =
9898
| Try
9999
| DocComment of Location.t * string
100100
| ModuleComment of Location.t * string
101+
| LeftShift
102+
| RightShift
103+
| RightShiftUnsigned
101104

102105
let precedence = function
103106
| HashEqual | ColonEqual -> 1
@@ -107,11 +110,12 @@ let precedence = function
107110
| Equal | EqualEqual | EqualEqualEqual | LessThan | GreaterThan | BangEqual
108111
| BangEqualEqual | LessEqual | GreaterEqual | BarGreater ->
109112
5
110-
| Plus | PlusDot | Minus | MinusDot | PlusPlus -> 6
111-
| Asterisk | AsteriskDot | Forwardslash | ForwardslashDot | Percent -> 7
112-
| Exponentiation -> 8
113-
| MinusGreater -> 9
114-
| Dot -> 10
113+
| LeftShift | RightShift | RightShiftUnsigned -> 6
114+
| Plus | PlusDot | Minus | MinusDot | PlusPlus -> 7
115+
| Asterisk | AsteriskDot | Forwardslash | ForwardslashDot | Percent -> 8
116+
| Exponentiation -> 9
117+
| MinusGreater -> 10
118+
| Dot -> 11
115119
| _ -> 0
116120

117121
let to_string = function
@@ -212,6 +216,9 @@ let to_string = function
212216
| Try -> "try"
213217
| DocComment (_loc, s) -> "DocComment " ^ s
214218
| ModuleComment (_loc, s) -> "ModuleComment " ^ s
219+
| LeftShift -> "<<"
220+
| RightShift -> ">>"
221+
| RightShiftUnsigned -> ">>>"
215222

216223
let keyword_table = function
217224
| "and" -> And

runtime/Pervasives.res

+3
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,12 @@ external \"-": ('a, 'a) => 'a = "%sub"
6565
external \"*": ('a, 'a) => 'a = "%mul"
6666
external \"/": ('a, 'a) => 'a = "%div"
6767
external \"%": ('a, 'a) => 'a = "%mod"
68+
external \"<<": ('a, 'a) => 'a = "%lsl"
6869
external mod: ('a, 'a) => 'a = "%mod"
6970
external \"**": ('a, 'a) => 'a = "%pow"
7071
external \"^": ('a, 'a) => 'a = "%bitxor"
72+
external \">>": ('a, 'a) => 'a = "%asr"
73+
external \">>>": ('a, 'a) => 'a = "%lsr"
7174

7275
/* Comparisons */
7376
/* Note: Later comparisons will be converted to unified operations too */

tests/syntax_tests/data/parsing/errors/typexpr/expected/typeConstructorArgs.res.txt

+5-3
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,20 @@
3838

3939

4040
Syntax error!
41-
syntax_tests/data/parsing/errors/typexpr/typeConstructorArgs.res:9:28
41+
syntax_tests/data/parsing/errors/typexpr/typeConstructorArgs.res:8:16-17
4242

43+
6 │ type t<'a> = private Belt.Map.t('a)
4344
7 │
4445
8 │ type t = option<<node<int>>
4546
9 │ type t = option(<node<int>>)
4647
10 │
4748

48-
I'm not sure what to parse here when looking at ")".
49+
I'm not sure what to parse here when looking at "<<".
4950

5051
type nonrec 'a node = {
5152
_value: 'a Js.Nullable.value }
5253
type nonrec 'a t = 'a Belt.Map.t
5354
type nonrec 'a t = private 'a Belt.Map.t
54-
type nonrec t = int node option
55+
type nonrec t = option
56+
;;node < (int >> ([%rescript.exprhole ]))
5557
type nonrec t = int node option

tests/syntax_tests/data/parsing/grammar/expressions/binary.res

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ let x = a + -1 + -2
2929
let x = a + @attr -1 + @attr -2
3030
let x = a % a == 0
3131
let x = a ^ a == 0
32+
let x = a << a == 0
33+
let x = a >> a == 0
34+
let x = a >>> a == 0
3235

3336
// should be interpreted as binary expression not prefix op
3437
let x = a -b

tests/syntax_tests/data/parsing/grammar/expressions/expected/binary.res.txt

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ let x = (a + (-1)) + (-2)
1515
let x = (a + (((-1))[@attr ])) + (((-2))[@attr ])
1616
let x = (a % a) == 0
1717
let x = a ^ (a == 0)
18+
let x = (a << a) == 0
19+
let x = (a >> a) == 0
20+
let x = (a >>> a) == 0
1821
let x = a - b
1922
let x = a -. b
2023
;;Constructor (a, b)

tests/syntax_tests/data/printer/expr/binary.res

+3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ x + y / z
5555
x / y + z
5656
x % y * z
5757
x ^ y + z
58+
x << y + z
59+
x >> y + z
60+
x >>> y + z
5861
100 * x / total
5962
2 / 3 * 10 / 2 + 2
6063
let rotateX = ((range / rect.height) * refY - range / 2) * getXMultiplication(rect.width)

tests/syntax_tests/data/printer/expr/expected/binary.res.txt

+3
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ x + y / z
8686
x / y + z
8787
x % y * z
8888
x ^ y + z
89+
x << y + z
90+
x >> y + z
91+
x >>> y + z
8992
100 * x / total
9093
2 / 3 * 10 / 2 + 2
9194
let rotateX = (range / rect.height * refY - range / 2) * getXMultiplication(rect.width)

tests/tests/src/belt_int_test.mjs

+3
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ Mocha.describe("Belt_int_test", () => {
3737
Test_utils.eq("File \"belt_int_test.res\", line 42, characters 7-14", 0, 0);
3838
Test_utils.eq("File \"belt_int_test.res\", line 43, characters 7-14", 0, 0);
3939
Test_utils.eq("File \"belt_int_test.res\", line 44, characters 7-14", 1, 1);
40+
Test_utils.eq("File \"belt_int_test.res\", line 45, characters 7-14", 16, 16);
41+
Test_utils.eq("File \"belt_int_test.res\", line 46, characters 7-14", 2, 2);
42+
Test_utils.eq("File \"belt_int_test.res\", line 47, characters 7-14", 2, 2);
4043
});
4144
});
4245

tests/tests/src/belt_int_test.res

+3
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,8 @@ describe(__MODULE__, () => {
4242
eq(__LOC__, 2 / 3, 0)
4343
eq(__LOC__, 2 % 2, 0)
4444
eq(__LOC__, 2 ^ 3, 1)
45+
eq(__LOC__, 2 << 3, 16)
46+
eq(__LOC__, 16 >> 3, 2)
47+
eq(__LOC__, 16 >>> 3, 2)
4548
})
4649
})

tests/tests/src/unified_ops_test.mjs

+15
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,18 @@ function bxor_bigint(a, b) {
7575
return a ^ b;
7676
}
7777

78+
let bigintShiftLeft = (1n << 2n);
79+
80+
let bigintShiftRight = (8n >> 2n);
81+
7882
let int = 3;
7983

84+
let intShiftLeft = 4;
85+
86+
let intShiftRight = 2;
87+
88+
let intShiftRightUnsigned = 2147483647;
89+
8090
export {
8191
int,
8292
float,
@@ -101,5 +111,10 @@ export {
101111
pow_overflow,
102112
bxor_int,
103113
bxor_bigint,
114+
intShiftLeft,
115+
intShiftRight,
116+
intShiftRightUnsigned,
117+
bigintShiftLeft,
118+
bigintShiftRight,
104119
}
105120
/* No side effect */

tests/tests/src/unified_ops_test.res

+7
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,10 @@ let pow_overflow = 2147483647 ** 2
2929

3030
let bxor_int = (a, b) => a ^ b
3131
let bxor_bigint = (a: bigint, b) => a ^ b
32+
33+
let intShiftLeft = 1 << 2
34+
let intShiftRight = 8 >> 2
35+
let intShiftRightUnsigned = -2 >>> 1
36+
37+
let bigintShiftLeft = 1n << 2n
38+
let bigintShiftRight = 8n >> 2n

0 commit comments

Comments
 (0)