Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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 @@ -23,6 +23,7 @@
- Experimental: Support nested/inline record types - records defined inside of other records, without needing explicit separate type definitions. https://github.com/rescript-lang/rescript/pull/7241
- Add unified exponentiation (`**`) operator for numeric types using ES7 `**`. https://github.com/rescript-lang/rescript-compiler/pull/7153
- Rename `raise` to `throw` to align with JavaScript vocabulary. `raise` has been deprecated. https://github.com/rescript-lang/rescript/pull/7346
- Add unified bitwise (`^`) operator `**`. https://github.com/rescript-lang/rescript/pull/7216

#### :boom: Breaking Change

Expand Down
13 changes: 13 additions & 0 deletions compiler/ml/unified_ops.ml
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,19 @@ let entries =
string = None;
};
};
{
path = builtin "^";
name = "%bitxor";
form = Binary;
specialization =
{
int = Pxorint;
bool = None;
float = None;
bigint = Some Pxorbigint;
string = None;
};
};
|]

let index_by_path =
Expand Down
10 changes: 2 additions & 8 deletions compiler/syntax/src/res_diagnostics.ml
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,8 @@ let explain t =
| UnclosedTemplate ->
"Did you forget to close this template expression with a backtick?"
| UnclosedComment -> "This comment seems to be missing a closing `*/`"
| UnknownUchar uchar -> (
match uchar with
| '^' ->
"Not sure what to do with this character.\n"
^ " If you're trying to dereference a mutable value, use \
`myValue.contents` instead.\n"
^ " To concatenate strings, use `\"a\" ++ \"b\"` instead."
| _ -> "Not sure what to do with this character.")
| UnknownUchar uchar ->
"Not sure what to do with this character: \"" ^ Char.escaped uchar ^ "\"."
| Expected {context; token = t} ->
let hint =
match context with
Expand Down
6 changes: 2 additions & 4 deletions compiler/syntax/src/res_parens.ml
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ let rhs_binary_expr_operand parent_operator rhs =
};
args = [(_, _left); (_, _right)];
}
when ParsetreeViewer.is_binary_operator operator
&& not (operator_loc.loc_ghost && operator = "++") ->
when ParsetreeViewer.not_ghost_operator operator operator_loc ->
let prec_parent = ParsetreeViewer.operator_precedence parent_operator in
let prec_child = ParsetreeViewer.operator_precedence operator in
prec_parent == prec_child
Expand All @@ -180,8 +179,7 @@ let flatten_operand_rhs parent_operator rhs =
};
args = [(_, _left); (_, _right)];
}
when ParsetreeViewer.is_binary_operator operator
&& not (operator_loc.loc_ghost && operator = "++") ->
when ParsetreeViewer.not_ghost_operator operator operator_loc ->
let prec_parent = ParsetreeViewer.operator_precedence parent_operator in
let prec_child = ParsetreeViewer.operator_precedence operator in
prec_parent >= prec_child || rhs.pexp_attributes <> []
Expand Down
21 changes: 11 additions & 10 deletions compiler/syntax/src/res_parsetree_viewer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,12 @@ let operator_precedence operator =
| ":=" -> 1
| "||" -> 2
| "&&" -> 3
| "==" | "===" | "<" | ">" | "!=" | "<>" | "!==" | "<=" | ">=" | "|>" -> 4
| "+" | "+." | "-" | "-." | "++" -> 5
| "*" | "*." | "/" | "/." | "%" -> 6
| "**" -> 7
| "#" | "##" | "->" -> 8
| "^" -> 4
| "==" | "===" | "<" | ">" | "!=" | "<>" | "!==" | "<=" | ">=" | "|>" -> 5
| "+" | "+." | "-" | "-." | "++" -> 6
| "*" | "*." | "/" | "/." | "%" -> 7
| "**" -> 8
| "#" | "##" | "->" -> 9
| _ -> 0

let is_unary_operator operator =
Expand All @@ -295,15 +296,17 @@ let is_unary_expression expr =
true
| _ -> false

(* TODO: tweak this to check for ghost ^ as template literal *)
let is_binary_operator operator =
match operator with
| ":=" | "||" | "&&" | "==" | "===" | "<" | ">" | "!=" | "!==" | "<=" | ">="
| "|>" | "+" | "+." | "-" | "-." | "++" | "*" | "*." | "/" | "/." | "**"
| "->" | "<>" | "%" ->
| "->" | "<>" | "%" | "^" ->
true
| _ -> false

let not_ghost_operator operator (loc : Location.t) =
is_binary_operator operator && not (loc.loc_ghost && operator = "++")

let is_binary_expression expr =
match expr.pexp_desc with
| Pexp_apply
Expand All @@ -315,9 +318,7 @@ let is_binary_expression expr =
};
args = [(Nolabel, _operand1); (Nolabel, _operand2)];
}
when is_binary_operator operator
&& not (operator_loc.loc_ghost && operator = "++")
(* template literal *) ->
when not_ghost_operator operator operator_loc ->
true
| _ -> false

Expand Down
1 change: 1 addition & 0 deletions compiler/syntax/src/res_parsetree_viewer.mli
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ val is_huggable_rhs : Parsetree.expression -> bool

val operator_precedence : string -> int

val not_ghost_operator : string -> Location.t -> bool
val is_unary_expression : Parsetree.expression -> bool
val is_binary_operator : string -> bool
val is_binary_expression : Parsetree.expression -> bool
Expand Down
3 changes: 3 additions & 0 deletions compiler/syntax/src/res_scanner.ml
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,9 @@ let rec scan scanner =
| _ ->
next scanner;
Token.Band)
| '^' ->
next scanner;
Token.Caret
| ':' -> (
match peek scanner with
| '=' ->
Expand Down
15 changes: 9 additions & 6 deletions compiler/syntax/src/res_token.ml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ type t =
| Land
| Lor
| Band (* Bitwise and: & *)
| Caret
| BangEqual
| BangEqualEqual
| LessEqual
Expand All @@ -102,14 +103,15 @@ let precedence = function
| HashEqual | ColonEqual -> 1
| Lor -> 2
| Land -> 3
| Caret -> 4
| Equal | EqualEqual | EqualEqualEqual | LessThan | GreaterThan | BangEqual
| BangEqualEqual | LessEqual | GreaterEqual | BarGreater ->
4
| Plus | PlusDot | Minus | MinusDot | PlusPlus -> 5
| Asterisk | AsteriskDot | Forwardslash | ForwardslashDot | Percent -> 6
| Exponentiation -> 7
| MinusGreater -> 8
| Dot -> 9
5
| Plus | PlusDot | Minus | MinusDot | PlusPlus -> 6
| Asterisk | AsteriskDot | Forwardslash | ForwardslashDot | Percent -> 7
| Exponentiation -> 8
| MinusGreater -> 9
| Dot -> 10
| _ -> 0

let to_string = function
Expand Down Expand Up @@ -189,6 +191,7 @@ let to_string = function
| Of -> "of"
| Lor -> "||"
| Band -> "&"
| Caret -> "^"
| Land -> "&&"
| BangEqual -> "!="
| BangEqualEqual -> "!=="
Expand Down
1 change: 1 addition & 0 deletions runtime/Pervasives.res
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ external \"/": ('a, 'a) => 'a = "%div"
external \"%": ('a, 'a) => 'a = "%mod"
external mod: ('a, 'a) => 'a = "%mod"
external \"**": ('a, 'a) => 'a = "%pow"
external \"^": ('a, 'a) => 'a = "%bitxor"

/* Comparisons */
/* Note: Later comparisons will be converted to unified operations too */
Expand Down
1 change: 1 addition & 0 deletions runtime/Pervasives_mini.res
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ external \"/": (int, int) => int = "%divint"
external \"%": (int, int) => int = "%modint"
external mod: (int, int) => int = "%modint"
external \"**": (int, int) => int = "%powint"
external \"^": (int, int) => int = "%bitxorint"

/* Comparisons */
/* Note: Later comparisons will be converted to unified operations too */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
6 │ | _ => ()
7 │ }

Not sure what to do with this character.
Not sure what to do with this character: "$".


Syntax error!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

1 │ let $ = 1

Not sure what to do with this character.
Not sure what to do with this character: "$".


Syntax error!
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@

Syntax error!
syntax_tests/data/parsing/errors/scanner/oldDerefOp.res:1:50
syntax_tests/data/parsing/errors/scanner/oldDerefOp.res:1:51

1 │ let newVelocity = velocity +. a *. secondPerFrame^;
2 │ let newX = x +. newVelocity *. secondPerFrame^;
3 │

Not sure what to do with this character.
If you're trying to dereference a mutable value, use `myValue.contents` instead.
To concatenate strings, use `"a" ++ "b"` instead.
Did you forget to write an expression here?


Syntax error!
syntax_tests/data/parsing/errors/scanner/oldDerefOp.res:2:46
syntax_tests/data/parsing/errors/scanner/oldDerefOp.res:2:47

1 │ let newVelocity = velocity +. a *. secondPerFrame^;
2 │ let newX = x +. newVelocity *. secondPerFrame^;
3 │

Not sure what to do with this character.
If you're trying to dereference a mutable value, use `myValue.contents` instead.
To concatenate strings, use `"a" ++ "b"` instead.
Did you forget to write an expression here?

let newVelocity = velocity +. (a *. secondPerFrame)
let newX = x +. (newVelocity *. secondPerFrame)
let newVelocity =
(velocity +. (a *. secondPerFrame)) ^ ([%rescript.exprhole ])
let newX = (x +. (newVelocity *. secondPerFrame)) ^ ([%rescript.exprhole ])
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ let x = z |> @attr while condition { () }
let x = a + -1 + -2
let x = a + @attr -1 + @attr -2
let x = a % a == 0
let x = a ^ a == 0

// should be interpreted as binary expression not prefix op
let x = a -b
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ let x = ((while condition do () done)[@attr ]) z
let x = (a + (-1)) + (-2)
let x = (a + (((-1))[@attr ])) + (((-2))[@attr ])
let x = (a % a) == 0
let x = a ^ (a == 0)
let x = a - b
let x = a -. b
;;Constructor (a, b)
Expand Down
1 change: 1 addition & 0 deletions tests/syntax_tests/data/printer/expr/binary.res
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ let () = (x: int) |> (print_int: int => unit)
x + y / z
x / y + z
x % y * z
x ^ y + z
100 * x / total
2 / 3 * 10 / 2 + 2
let rotateX = ((range / rect.height) * refY - range / 2) * getXMultiplication(rect.width)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ let () = (print_int: int => unit)((x: int))
x + y / z
x / y + z
x % y * z
x ^ y + z
100 * x / total
2 / 3 * 10 / 2 + 2
let rotateX = (range / rect.height * refY - range / 2) * getXMultiplication(rect.width)
Expand Down
1 change: 1 addition & 0 deletions tests/tests/src/belt_int_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Mocha.describe("Belt_int_test", () => {
Test_utils.eq("File \"belt_int_test.res\", line 41, characters 7-14", 6, 6);
Test_utils.eq("File \"belt_int_test.res\", line 42, characters 7-14", 0, 0);
Test_utils.eq("File \"belt_int_test.res\", line 43, characters 7-14", 0, 0);
Test_utils.eq("File \"belt_int_test.res\", line 44, characters 7-14", 1, 1);
});
});

Expand Down
1 change: 1 addition & 0 deletions tests/tests/src/belt_int_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ describe(__MODULE__, () => {
eq(__LOC__, 2 * 3, 6)
eq(__LOC__, 2 / 3, 0)
eq(__LOC__, 2 % 2, 0)
eq(__LOC__, 2 ^ 3, 1)
})
})
10 changes: 10 additions & 0 deletions tests/tests/src/unified_ops_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ let pow3 = 2n ** 2n;

let pow_overflow = 0;

function bxor_int(a, b) {
return a ^ b;
}

function bxor_bigint(a, b) {
return a ^ b;
}

let int = 3;

export {
Expand All @@ -91,5 +99,7 @@ export {
pow2,
pow3,
pow_overflow,
bxor_int,
bxor_bigint,
}
/* No side effect */
3 changes: 3 additions & 0 deletions tests/tests/src/unified_ops_test.res
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,6 @@ let pow2 = 2. ** 2.
let pow3 = 2n ** 2n

let pow_overflow = 2147483647 ** 2

let bxor_int = (a, b) => a ^ b
let bxor_bigint = (a: bigint, b) => a ^ b