Skip to content

Make exponentiation operator right-associative #5959

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
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 @@ -37,6 +37,7 @@ subset of the arguments, and return a curried type with the remaining ones https
- Curried after uncurried is not fused anymore: `(. x) => y => 3` is not equivalent to `(. x, y) => 3` anymore. It's instead equivalent to `(. x) => { y => 3 }`.
Also, `(. int) => string => bool` is not equivalen to `(. int, string) => bool` anymore.
These are only breaking changes for unformatted code.
- Exponentiation operator `**` is now right-associative. `2. ** 3. ** 2.` now compile to `Math.pow(2, Math.pow(3, 2))` and not anymore `Math.pow(Math.pow(2, 3), 2)`. Parentheses can be used to change precedence.

#### :bug: Bug Fix

Expand Down
3 changes: 2 additions & 1 deletion jscomp/test/build.ninja

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions jscomp/test/exponentiation_precedence_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';


var a = Math.pow(2, Math.pow(3, 2));

var b = Math.pow(2, Math.pow(-3, 2));

var c = Math.pow(Math.pow(2, 3), 2);

var d = Math.pow(-2, 2);

exports.a = a;
exports.b = b;
exports.c = c;
exports.d = d;
/* a Not a pure module */
4 changes: 4 additions & 0 deletions jscomp/test/exponentiation_precedence_test.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let a = 2. ** 3. ** 2.
let b = 2. ** -3. ** 2.
let c = (2. ** 3.) ** 2.
let d = (-2.) ** 2.
6 changes: 5 additions & 1 deletion res_syntax/src/res_core.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2200,7 +2200,11 @@ and parseBinaryExpr ?(context = OrdinaryExpr) ?a p prec =
let startPos = p.startPos in
Parser.next p;
let endPos = p.prevEndPos in
let b = parseBinaryExpr ~context p (tokenPrec + 1) in
let tokenPrec =
(* exponentiation operator is right-associative *)
if token = Exponentiation then tokenPrec else tokenPrec + 1
in
let b = parseBinaryExpr ~context p tokenPrec in
let loc = mkLoc a.Parsetree.pexp_loc.loc_start b.pexp_loc.loc_end in
let expr =
Ast_helper.Exp.apply ~loc
Expand Down
5 changes: 5 additions & 0 deletions res_syntax/src/res_parsetree_viewer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ let isEqualityOperator operator =
| "=" | "==" | "<>" | "!=" -> true
| _ -> false

let isRhsBinaryOperator operator =
match operator with
| "**" -> true
| _ -> false

let flattenableOperators parentOperator childOperator =
let precParent = operatorPrecedence parentOperator in
let precChild = operatorPrecedence childOperator in
Expand Down
1 change: 1 addition & 0 deletions res_syntax/src/res_parsetree_viewer.mli
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ val operatorPrecedence : string -> int
val isUnaryExpression : Parsetree.expression -> bool
val isBinaryOperator : string -> bool
val isBinaryExpression : Parsetree.expression -> bool
val isRhsBinaryOperator : string -> bool

val flattenableOperators : string -> string -> bool

Expand Down
15 changes: 13 additions & 2 deletions res_syntax/src/res_printer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3672,7 +3672,11 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl =
[(Nolabel, lhs); (Nolabel, rhs)] ) ->
let right =
let operatorWithRhs =
let rhsDoc = printOperand ~isLhs:false rhs operator in
let rhsDoc =
printOperand
~isLhs:(ParsetreeViewer.isRhsBinaryOperator operator)
rhs operator
in
Doc.concat
[
printBinaryOperator
Expand All @@ -3686,7 +3690,14 @@ and printBinaryExpression ~state (expr : Parsetree.expression) cmtTbl =
else operatorWithRhs
in
let doc =
Doc.group (Doc.concat [printOperand ~isLhs:true lhs operator; right])
Doc.group
(Doc.concat
[
printOperand
~isLhs:(not @@ ParsetreeViewer.isRhsBinaryOperator operator)
lhs operator;
right;
])
in
Doc.group
(Doc.concat
Expand Down
5 changes: 5 additions & 0 deletions res_syntax/tests/printer/expr/binary.res
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ let x = longIdentifier + longIdentifier * longIdentifier * longIdentifier / long
let x = longIdentifier && longIdentifier && longIdentifier && longIdentifier && longIdentifier && longIdentifier;
let x = longIdentifier && longIdentifier || longIdentifier && longIdentifier || longIdentifier && longIdentifier;

// exponentiation is right associative
let x = 2. ** 3. ** 2.
let x = (2. ** 3.) ** 2.
let x = 2. ** (3. ** 2.)

if (
successorParent.color === Black &&
(sibling === None ||
Expand Down
5 changes: 5 additions & 0 deletions res_syntax/tests/printer/expr/expected/binary.res.txt
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ let x =
longIdentifier && longIdentifier ||
(longIdentifier && longIdentifier)

// exponentiation is right associative
let x = 2. ** 3. ** 2.
let x = (2. ** 3.) ** 2.
let x = 2. ** 3. ** 2.

if (
successorParent.color === Black &&
(sibling === None ||
Expand Down