From bca424832dea17759a63c977d41da2de450617a3 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sat, 9 Nov 2024 09:17:05 +0900 Subject: [PATCH 1/9] Upgrade exponentiation to unified operator Also make its output to use ES7 exponentiation (`**`) operator. `**` is more concise, faster than `Math.pow()`, works well with all numeric types include bigint. We were already using it for bigint, now for int and float too. --- compiler/core/js_exp_make.ml | 7 +++++++ compiler/core/js_exp_make.mli | 4 ++++ compiler/core/js_op.ml | 3 ++- compiler/core/js_op_util.ml | 5 ++++- compiler/core/lam_analysis.ml | 9 +++++---- compiler/core/lam_compile_primitive.ml | 8 ++++++++ compiler/core/lam_convert.ml | 2 ++ compiler/core/lam_primitive.ml | 10 ++++++---- compiler/core/lam_primitive.mli | 2 ++ compiler/core/lam_print.ml | 2 ++ compiler/ext/ext_int.ml | 8 ++++++++ compiler/ext/ext_int.mli | 2 ++ compiler/ml/lambda.ml | 2 ++ compiler/ml/lambda.mli | 2 ++ compiler/ml/printlambda.ml | 2 ++ compiler/ml/unified_ops.ml | 13 +++++++++++++ compiler/syntax/src/res_parens.ml | 12 +++++++----- compiler/syntax/src/res_parsetree_viewer.mli | 1 + runtime/Pervasives.res | 4 +--- runtime/Pervasives_mini.res | 1 + tests/tests/src/b.mjs | 2 +- tests/tests/src/exponentiation_precedence_test.mjs | 10 +++++----- tests/tests/src/test_pervasive.mjs | 2 +- tests/tests/src/unified_ops_test.mjs | 9 +++++++++ tests/tests/src/unified_ops_test.res | 4 ++++ tests/tests/src/variantsMatching.mjs | 4 ++-- 26 files changed, 103 insertions(+), 27 deletions(-) diff --git a/compiler/core/js_exp_make.ml b/compiler/core/js_exp_make.ml index cc8d357043..c9238007c0 100644 --- a/compiler/core/js_exp_make.ml +++ b/compiler/core/js_exp_make.ml @@ -1533,6 +1533,7 @@ let unchecked_int32_minus ?comment e1 e2 : J.expression = float_minus ?comment e1 e2 let float_div ?comment e1 e2 = bin ?comment Div e1 e2 +let float_pow ?comment e1 e2 = bin ?comment Pow e1 e2 let float_notequal ?comment e1 e2 = bin ?comment NotEqEq e1 e2 let int32_asr ?comment e1 e2 : J.expression = @@ -1604,6 +1605,12 @@ let int32_mul ?comment (e1 : J.expression) (e2 : J.expression) : J.expression = let unchecked_int32_mul ?comment e1 e2 : J.expression = {comment; expression_desc = Bin (Mul, e1, e2)} +let int32_pow ?comment (e1 : t) (e2 : t) : J.expression = + match (e1.expression_desc, e2.expression_desc) with + | Number (Int {i = i1}), Number (Int {i = i2}) -> + int ?comment (Ext_int.int32_pow i1 i2) + | _ -> {comment; expression_desc = Bin (Pow, e1, e2)} + let rec int32_bxor ?comment (e1 : t) (e2 : t) : J.expression = match (e1.expression_desc, e2.expression_desc) with | Number (Int {i = i1}), Number (Int {i = i2}) -> diff --git a/compiler/core/js_exp_make.mli b/compiler/core/js_exp_make.mli index e890e4c6aa..e1fe0a5d3a 100644 --- a/compiler/core/js_exp_make.mli +++ b/compiler/core/js_exp_make.mli @@ -251,6 +251,8 @@ val int32_div : checked:bool -> ?comment:string -> t -> t -> t val int32_mod : checked:bool -> ?comment:string -> t -> t -> t +val int32_pow : ?comment:string -> t -> t -> t + val int32_lsl : ?comment:string -> t -> t -> t val int32_lsr : ?comment:string -> t -> t -> t @@ -275,6 +277,8 @@ val float_notequal : ?comment:string -> t -> t -> t val float_mod : ?comment:string -> t -> t -> t +val float_pow : ?comment:string -> t -> t -> t + val int_comp : Lam_compat.comparison -> ?comment:string -> t -> t -> t val bool_comp : Lam_compat.comparison -> ?comment:string -> t -> t -> t diff --git a/compiler/core/js_op.ml b/compiler/core/js_op.ml index 15f9944b27..0d7558e7ad 100644 --- a/compiler/core/js_op.ml +++ b/compiler/core/js_op.ml @@ -105,7 +105,8 @@ type int_op = | Div (* x / y | 0 *) | Mod -(* x % y *) + (* x % y *) + | Pow (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise_operators {[ diff --git a/compiler/core/js_op_util.ml b/compiler/core/js_op_util.ml index af6f3c5dcb..439c4463cf 100644 --- a/compiler/core/js_op_util.ml +++ b/compiler/core/js_op_util.ml @@ -40,7 +40,8 @@ let op_prec (op : Js_op.binop) = | Band -> (7, 7, 7) | Lsl | Lsr | Asr -> (10, 10, 11) | Plus | Minus -> (11, 11, 12) - | Mul | Div | Mod | Pow -> (12, 12, 13) + | Mul | Div | Mod -> (12, 12, 13) + | Pow -> (12, 14, 12) let op_int_prec (op : Js_op.int_op) = match op with @@ -50,6 +51,7 @@ let op_int_prec (op : Js_op.int_op) = | Lsl | Lsr | Asr -> (10, 10, 11) | Plus | Minus -> (11, 11, 12) | Mul | Div | Mod -> (12, 12, 13) + | Pow -> (12, 14, 12) let op_str (op : Js_op.binop) = match op with @@ -89,6 +91,7 @@ let op_int_str (op : Js_op.int_op) = | Mul -> "*" | Div -> "/" | Mod -> "%" + | Pow -> "**" let str_of_used_stats x = match (x : Js_op.used_stats) with diff --git a/compiler/core/lam_analysis.ml b/compiler/core/lam_analysis.ml index a95b382ca2..d99c83afe5 100644 --- a/compiler/core/lam_analysis.ml +++ b/compiler/core/lam_analysis.ml @@ -59,12 +59,13 @@ let rec no_side_effects (lam : Lam.t) : bool = (* bool primitives *) | Psequand | Psequor | Pnot | Pboolcomp _ | Pboolorder | Pboolmin | Pboolmax (* int primitives *) - | Pnegint | Paddint | Psubint | Pmulint | Pandint | Porint | Pxorint - | Plslint | Plsrint | Pasrint | Pintcomp _ | Pintorder | Pintmin | Pintmax + | Pnegint | Paddint | Psubint | Pmulint | Ppowint | Pandint | Porint + | Pxorint | Plslint | Plsrint | Pasrint | Pintcomp _ | Pintorder | Pintmin + | Pintmax (* float primitives *) | Pintoffloat | Pfloatofint | Pnegfloat | Paddfloat | Psubfloat | Pmulfloat - | Pdivfloat | Pmodfloat | Pfloatcomp _ | Pjscomp _ | Pfloatorder | Pfloatmin - | Pfloatmax + | Ppowfloat | Pdivfloat | Pmodfloat | Pfloatcomp _ | Pjscomp _ | Pfloatorder + | Pfloatmin | Pfloatmax (* bigint primitives *) | Pnegbigint | Paddbigint | Psubbigint | Pmulbigint | Ppowbigint | Pandbigint | Porbigint | Pxorbigint | Plslbigint | Pasrbigint diff --git a/compiler/core/lam_compile_primitive.ml b/compiler/core/lam_compile_primitive.ml index efea6c977b..58d488bb3b 100644 --- a/compiler/core/lam_compile_primitive.ml +++ b/compiler/core/lam_compile_primitive.ml @@ -250,6 +250,14 @@ let translate output_prefix loc (cxt : Lam_compile_context.t) match args with | [e1; e2] -> E.bigint_mod ~checked:!Js_config.check_div_by_zero e1 e2 | _ -> assert false) + | Ppowint -> ( + match args with + | [e1; e2] -> E.int32_pow e1 e2 + | _ -> assert false) + | Ppowfloat -> ( + match args with + | [e1; e2] -> E.float_pow e1 e2 + | _ -> assert false) | Ppowbigint -> ( match args with | [e1; e2] -> E.bigint_op Pow e1 e2 diff --git a/compiler/core/lam_convert.ml b/compiler/core/lam_convert.ml index 74131236ab..ad74ba176b 100644 --- a/compiler/core/lam_convert.ml +++ b/compiler/core/lam_convert.ml @@ -251,6 +251,7 @@ let lam_prim ~primitive:(p : Lambda.primitive) ~args loc : Lam.t = | Pmulint -> prim ~primitive:Pmulint ~args loc | Pdivint _is_safe (*FIXME*) -> prim ~primitive:Pdivint ~args loc | Pmodint _is_safe (*FIXME*) -> prim ~primitive:Pmodint ~args loc + | Ppowint -> prim ~primitive:Ppowint ~args loc | Pandint -> prim ~primitive:Pandint ~args loc | Porint -> prim ~primitive:Porint ~args loc | Pxorint -> prim ~primitive:Pxorint ~args loc @@ -283,6 +284,7 @@ let lam_prim ~primitive:(p : Lambda.primitive) ~args loc : Lam.t = | Pmulfloat -> prim ~primitive:Pmulfloat ~args loc | Pdivfloat -> prim ~primitive:Pdivfloat ~args loc | Pmodfloat -> prim ~primitive:Pmodfloat ~args loc + | Ppowfloat -> prim ~primitive:Ppowfloat ~args loc | Pfloatorder -> prim ~primitive:Pfloatorder ~args loc | Pfloatmin -> prim ~primitive:Pfloatmin ~args loc | Pfloatmax -> prim ~primitive:Pfloatmax ~args loc diff --git a/compiler/core/lam_primitive.ml b/compiler/core/lam_primitive.ml index 21cedb23e5..51ba970839 100644 --- a/compiler/core/lam_primitive.ml +++ b/compiler/core/lam_primitive.ml @@ -75,6 +75,7 @@ type t = | Pmulint | Pdivint | Pmodint + | Ppowint | Pandint | Porint | Pxorint @@ -96,6 +97,7 @@ type t = | Pmulfloat | Pdivfloat | Pmodfloat + | Ppowfloat | Pfloatcomp of Lam_compat.comparison | Pfloatorder | Pfloatmin @@ -199,12 +201,12 @@ let eq_primitive_approx (lhs : t) (rhs : t) = (* bool primitives *) | Psequand | Psequor | Pnot | Pboolcomp _ | Pboolorder | Pboolmin | Pboolmax (* int primitives *) - | Pisint | Pnegint | Paddint | Psubint | Pmulint | Pdivint | Pmodint | Pandint - | Porint | Pxorint | Plslint | Plsrint | Pasrint | Pintorder | Pintmin - | Pintmax + | Pisint | Pnegint | Paddint | Psubint | Pmulint | Pdivint | Pmodint | Ppowint + | Pandint | Porint | Pxorint | Plslint | Plsrint | Pasrint | Pintorder + | Pintmin | Pintmax (* float primitives *) | Pintoffloat | Pfloatofint | Pnegfloat | Paddfloat | Psubfloat | Pmulfloat - | Pdivfloat | Pmodfloat | Pfloatorder | Pfloatmin | Pfloatmax + | Pdivfloat | Pmodfloat | Ppowfloat | Pfloatorder | Pfloatmin | Pfloatmax (* bigint primitives *) | Pnegbigint | Paddbigint | Psubbigint | Pmulbigint | Pdivbigint | Pmodbigint | Ppowbigint | Pandbigint | Porbigint | Pxorbigint | Plslbigint | Pasrbigint diff --git a/compiler/core/lam_primitive.mli b/compiler/core/lam_primitive.mli index 4f358b525a..c7283ca927 100644 --- a/compiler/core/lam_primitive.mli +++ b/compiler/core/lam_primitive.mli @@ -69,6 +69,7 @@ type t = | Pmulint | Pdivint | Pmodint + | Ppowint | Pandint | Porint | Pxorint @@ -90,6 +91,7 @@ type t = | Pmulfloat | Pdivfloat | Pmodfloat + | Ppowfloat | Pfloatcomp of Lam_compat.comparison | Pfloatorder | Pfloatmin diff --git a/compiler/core/lam_print.ml b/compiler/core/lam_print.ml index 17c18d6108..8f3fdabd53 100644 --- a/compiler/core/lam_print.ml +++ b/compiler/core/lam_print.ml @@ -116,6 +116,7 @@ let primitive ppf (prim : Lam_primitive.t) = | Pmulint -> fprintf ppf "*" | Pdivint -> fprintf ppf "/" | Pmodint -> fprintf ppf "mod" + | Ppowint -> fprintf ppf "**" | Pandint -> fprintf ppf "and" | Porint -> fprintf ppf "or" | Pxorint -> fprintf ppf "xor" @@ -141,6 +142,7 @@ let primitive ppf (prim : Lam_primitive.t) = | Pmulfloat -> fprintf ppf "*." | Pdivfloat -> fprintf ppf "/." | Pmodfloat -> fprintf ppf "mod" + | Ppowfloat -> fprintf ppf "**" | Pfloatcomp Ceq -> fprintf ppf "==." | Pfloatcomp Cneq -> fprintf ppf "!=." | Pfloatcomp Clt -> fprintf ppf "<." diff --git a/compiler/ext/ext_int.ml b/compiler/ext/ext_int.ml index f31d4251de..92d292508f 100644 --- a/compiler/ext/ext_int.ml +++ b/compiler/ext/ext_int.ml @@ -34,3 +34,11 @@ let move = 0x1_0000_0000 let int32_unsigned_to_int (n : int32) : int = let i = Int32.to_int n in if i < 0 then i + move else i + +let rec int32_pow (a : int32) = function + | 0l -> 1l + | 1l -> a + | n -> + let b = int32_pow a (Int32.div n 2l) in + let b = Int32.mul b b in + Int32.mul b (if Int32.rem n 2l = 0l then 1l else a) diff --git a/compiler/ext/ext_int.mli b/compiler/ext/ext_int.mli index acfc7af2ed..0c61810009 100644 --- a/compiler/ext/ext_int.mli +++ b/compiler/ext/ext_int.mli @@ -33,3 +33,5 @@ val int32_unsigned_to_int : int32 -> int works on 64 bit platform only given input as an uint32 and convert it io int64 *) + +val int32_pow : int32 -> int32 -> int32 diff --git a/compiler/ml/lambda.ml b/compiler/ml/lambda.ml index fcd1dc86ca..db163360c2 100644 --- a/compiler/ml/lambda.ml +++ b/compiler/ml/lambda.ml @@ -220,6 +220,7 @@ type primitive = | Pmulint | Pdivint of is_safe | Pmodint of is_safe + | Ppowint | Pandint | Porint | Pxorint @@ -242,6 +243,7 @@ type primitive = | Psubfloat | Pmulfloat | Pdivfloat + | Ppowfloat | Pfloatcomp of comparison | Pfloatorder | Pfloatmin diff --git a/compiler/ml/lambda.mli b/compiler/ml/lambda.mli index 7f506ac62d..cb929d864a 100644 --- a/compiler/ml/lambda.mli +++ b/compiler/ml/lambda.mli @@ -183,6 +183,7 @@ type primitive = | Pmulint | Pdivint of is_safe | Pmodint of is_safe + | Ppowint | Pandint | Porint | Pxorint @@ -205,6 +206,7 @@ type primitive = | Psubfloat | Pmulfloat | Pdivfloat + | Ppowfloat | Pfloatcomp of comparison | Pfloatorder | Pfloatmin diff --git a/compiler/ml/printlambda.ml b/compiler/ml/printlambda.ml index 4512355c34..9018c0c889 100644 --- a/compiler/ml/printlambda.ml +++ b/compiler/ml/printlambda.ml @@ -156,6 +156,7 @@ let primitive ppf = function | Pdivint Unsafe -> fprintf ppf "/u" | Pmodint Safe -> fprintf ppf "mod" | Pmodint Unsafe -> fprintf ppf "mod_unsafe" + | Ppowint -> fprintf ppf "**" | Pandint -> fprintf ppf "and" | Porint -> fprintf ppf "or" | Pxorint -> fprintf ppf "xor" @@ -182,6 +183,7 @@ let primitive ppf = function | Pmulfloat -> fprintf ppf "*." | Pdivfloat -> fprintf ppf "/." | Pmodfloat -> fprintf ppf "mod" + | Ppowfloat -> fprintf ppf "**" | Pfloatcomp Ceq -> fprintf ppf "==." | Pfloatcomp Cneq -> fprintf ppf "!=." | Pfloatcomp Clt -> fprintf ppf "<." diff --git a/compiler/ml/unified_ops.ml b/compiler/ml/unified_ops.ml index c57c14bce0..5b3fea3ca1 100644 --- a/compiler/ml/unified_ops.ml +++ b/compiler/ml/unified_ops.ml @@ -161,6 +161,19 @@ let entries = string = None; }; }; + { + path = builtin "**"; + name = "%pow"; + form = Binary; + specialization = + { + int = Ppowint; + bool = None; + float = Some Ppowfloat; + bigint = Some Ppowbigint; + string = None; + }; + }; |] let index_by_path = diff --git a/compiler/syntax/src/res_parens.ml b/compiler/syntax/src/res_parens.ml index 336af9f77f..c0878e78f2 100644 --- a/compiler/syntax/src/res_parens.ml +++ b/compiler/syntax/src/res_parens.ml @@ -148,12 +148,14 @@ let binary_expr_operand ~is_lhs expr = else Nothing) let sub_binary_expr_operand parent_operator child_operator = - let prec_parent = ParsetreeViewer.operator_precedence parent_operator in - let prec_child = ParsetreeViewer.operator_precedence child_operator in + let open ParsetreeViewer in + let prec_parent = operator_precedence parent_operator in + let prec_child = operator_precedence child_operator in + Printf.eprintf "parent %s, %d; child %s, %d" parent_operator prec_parent + child_operator prec_child; prec_parent > prec_child - || prec_parent == prec_child - && not - (ParsetreeViewer.flattenable_operators parent_operator child_operator) + || is_equality_operator parent_operator + && is_equality_operator child_operator || (* a && b || c, add parens to (a && b) for readability, who knows the difference by heart… *) (parent_operator = "||" && child_operator = "&&") diff --git a/compiler/syntax/src/res_parsetree_viewer.mli b/compiler/syntax/src/res_parsetree_viewer.mli index 56e68a307b..610c78bb46 100644 --- a/compiler/syntax/src/res_parsetree_viewer.mli +++ b/compiler/syntax/src/res_parsetree_viewer.mli @@ -81,6 +81,7 @@ val is_unary_expression : Parsetree.expression -> bool val is_binary_operator : string -> bool val is_binary_expression : Parsetree.expression -> bool val is_rhs_binary_operator : string -> bool +val is_equality_operator : string -> bool val flattenable_operators : string -> string -> bool diff --git a/runtime/Pervasives.res b/runtime/Pervasives.res index a19348538d..168bde7ab2 100644 --- a/runtime/Pervasives.res +++ b/runtime/Pervasives.res @@ -51,6 +51,7 @@ external \"*": ('a, 'a) => 'a = "%mul" external \"/": ('a, 'a) => 'a = "%div" external \"%": ('a, 'a) => 'a = "%mod" external mod: ('a, 'a) => 'a = "%mod" +external \"**": ('a, 'a) => 'a = "%pow" /* Comparisons */ /* Note: Later comparisons will be converted to unified operations too */ @@ -114,9 +115,6 @@ external \"-.": (float, float) => float = "%subfloat" external \"*.": (float, float) => float = "%mulfloat" external \"/.": (float, float) => float = "%divfloat" -@deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") -external \"**": (float, float) => float = "pow" - @deprecated("Use Core instead. This will be removed in v13") @val @scope("Math") external exp: float => float = "exp" diff --git a/runtime/Pervasives_mini.res b/runtime/Pervasives_mini.res index 9cf3cd90e4..eedba6fe6e 100644 --- a/runtime/Pervasives_mini.res +++ b/runtime/Pervasives_mini.res @@ -30,6 +30,7 @@ external \"*": (int, int) => int = "%mulint" external \"/": (int, int) => int = "%divint" external \"%": (int, int) => int = "%modint" external mod: (int, int) => int = "%modint" +external \"**": (int, int) => int = "%powint" /* Comparisons */ /* Note: Later comparisons will be converted to unified operations too */ diff --git a/tests/tests/src/b.mjs b/tests/tests/src/b.mjs index 1738e2ec25..2d888ec7ee 100644 --- a/tests/tests/src/b.mjs +++ b/tests/tests/src/b.mjs @@ -4,7 +4,7 @@ function f(point) { let y = point.y; let x = point.x; - return Math.pow(x * x + y * y, 2); + return (x * x + y * y) ** 2; } export { diff --git a/tests/tests/src/exponentiation_precedence_test.mjs b/tests/tests/src/exponentiation_precedence_test.mjs index 1f84a4ec3c..4d88b12de0 100644 --- a/tests/tests/src/exponentiation_precedence_test.mjs +++ b/tests/tests/src/exponentiation_precedence_test.mjs @@ -1,13 +1,13 @@ // Generated by ReScript, PLEASE EDIT WITH CARE -let a = Math.pow(2, Math.pow(3, 2)); +let a = 2 ** 3 ** 2; -let b = Math.pow(2, Math.pow(-3, 2)); +let b = 2 ** (-3) ** 2; -let c = Math.pow(Math.pow(2, 3), 2); +let c = (2 ** 3) ** 2; -let d = Math.pow(-2, 2); +let d = (-2) ** 2; export { a, @@ -15,4 +15,4 @@ export { c, d, } -/* a Not a pure module */ +/* No side effect */ diff --git a/tests/tests/src/test_pervasive.mjs b/tests/tests/src/test_pervasive.mjs index 0653322903..df9af152dc 100644 --- a/tests/tests/src/test_pervasive.mjs +++ b/tests/tests/src/test_pervasive.mjs @@ -187,7 +187,7 @@ function a17(prim) { } function a18(prim0, prim1) { - return Math.pow(prim0, prim1); + return prim0 ** prim1; } let f = Pervasives.$at; diff --git a/tests/tests/src/unified_ops_test.mjs b/tests/tests/src/unified_ops_test.mjs index c9635201cc..bb6cdd7683 100644 --- a/tests/tests/src/unified_ops_test.mjs +++ b/tests/tests/src/unified_ops_test.mjs @@ -59,6 +59,12 @@ function odd(n) { return n % 2 === 1; } +let pow1 = 4; + +let pow2 = 2 ** 2; + +let pow3 = 2n ** 2n; + let int = 3; export { @@ -79,5 +85,8 @@ export { case2, even, odd, + pow1, + pow2, + pow3, } /* No side effect */ diff --git a/tests/tests/src/unified_ops_test.res b/tests/tests/src/unified_ops_test.res index c35588167f..434f8e0651 100644 --- a/tests/tests/src/unified_ops_test.res +++ b/tests/tests/src/unified_ops_test.res @@ -20,3 +20,7 @@ let case2 = (a, b) => a + "test" + b let even = n => n % 2 == 0 let odd = n => n % 2 == 1 + +let pow1 = 2 ** 2 +let pow2 = 2. ** 2. +let pow3 = 2n ** 2n diff --git a/tests/tests/src/variantsMatching.mjs b/tests/tests/src/variantsMatching.mjs index e4b281726f..dbf14100ae 100644 --- a/tests/tests/src/variantsMatching.mjs +++ b/tests/tests/src/variantsMatching.mjs @@ -333,9 +333,9 @@ let MyNullableExtended = { function area(shape) { switch (shape.kind) { case 1 : - return Math.PI * Math.pow(shape.radius, 2); + return Math.PI * (shape.radius ** 2); case "square" : - return Math.pow(shape.sideLength, 2); + return shape.sideLength ** 2; case "rectangle" : return shape.width * shape.height; } From 79a85270248cbc0387b1c3182a5dbb2b2a1781b5 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sat, 9 Nov 2024 09:37:52 +0900 Subject: [PATCH 2/9] remove debug log --- compiler/syntax/src/res_parens.ml | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/syntax/src/res_parens.ml b/compiler/syntax/src/res_parens.ml index c0878e78f2..e42a6a6c9f 100644 --- a/compiler/syntax/src/res_parens.ml +++ b/compiler/syntax/src/res_parens.ml @@ -151,8 +151,6 @@ let sub_binary_expr_operand parent_operator child_operator = let open ParsetreeViewer in let prec_parent = operator_precedence parent_operator in let prec_child = operator_precedence child_operator in - Printf.eprintf "parent %s, %d; child %s, %d" parent_operator prec_parent - child_operator prec_child; prec_parent > prec_child || is_equality_operator parent_operator && is_equality_operator child_operator From 54c750bbf25c0bb9b20166ef8c74fad080e8837f Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sat, 9 Nov 2024 09:48:15 +0900 Subject: [PATCH 3/9] adjust parens --- compiler/core/js_op_util.ml | 4 ++-- tests/tests/src/variantsMatching.mjs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/core/js_op_util.ml b/compiler/core/js_op_util.ml index 439c4463cf..373657adfb 100644 --- a/compiler/core/js_op_util.ml +++ b/compiler/core/js_op_util.ml @@ -41,7 +41,7 @@ let op_prec (op : Js_op.binop) = | Lsl | Lsr | Asr -> (10, 10, 11) | Plus | Minus -> (11, 11, 12) | Mul | Div | Mod -> (12, 12, 13) - | Pow -> (12, 14, 12) + | Pow -> (13, 14, 12) let op_int_prec (op : Js_op.int_op) = match op with @@ -51,7 +51,7 @@ let op_int_prec (op : Js_op.int_op) = | Lsl | Lsr | Asr -> (10, 10, 11) | Plus | Minus -> (11, 11, 12) | Mul | Div | Mod -> (12, 12, 13) - | Pow -> (12, 14, 12) + | Pow -> (13, 14, 12) let op_str (op : Js_op.binop) = match op with diff --git a/tests/tests/src/variantsMatching.mjs b/tests/tests/src/variantsMatching.mjs index dbf14100ae..0485b35dc4 100644 --- a/tests/tests/src/variantsMatching.mjs +++ b/tests/tests/src/variantsMatching.mjs @@ -333,7 +333,7 @@ let MyNullableExtended = { function area(shape) { switch (shape.kind) { case 1 : - return Math.PI * (shape.radius ** 2); + return Math.PI * shape.radius ** 2; case "square" : return shape.sideLength ** 2; case "rectangle" : From a64a2c0a195187b68efc7df8f1123b2ca5433428 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sun, 10 Nov 2024 03:43:47 +0900 Subject: [PATCH 4/9] result into int32 --- compiler/core/js_exp_make.ml | 2 +- compiler/core/js_op.ml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/core/js_exp_make.ml b/compiler/core/js_exp_make.ml index c9238007c0..0849460290 100644 --- a/compiler/core/js_exp_make.ml +++ b/compiler/core/js_exp_make.ml @@ -1608,7 +1608,7 @@ let unchecked_int32_mul ?comment e1 e2 : J.expression = let int32_pow ?comment (e1 : t) (e2 : t) : J.expression = match (e1.expression_desc, e2.expression_desc) with | Number (Int {i = i1}), Number (Int {i = i2}) -> - int ?comment (Ext_int.int32_pow i1 i2) + to_int32 (int ?comment (Ext_int.int32_pow i1 i2)) | _ -> {comment; expression_desc = Bin (Pow, e1, e2)} let rec int32_bxor ?comment (e1 : t) (e2 : t) : J.expression = diff --git a/compiler/core/js_op.ml b/compiler/core/js_op.ml index 0d7558e7ad..9bbe3b50a2 100644 --- a/compiler/core/js_op.ml +++ b/compiler/core/js_op.ml @@ -106,7 +106,7 @@ type int_op = (* x / y | 0 *) | Mod (* x % y *) - | Pow + | Pow (* x ** y | 0 *) (* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Bitwise_operators {[ From 9b90cc15dcf0ffe2b705ed2b9af852ad01bcb010 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sun, 10 Nov 2024 03:45:03 +0900 Subject: [PATCH 5/9] more exponentiation tests --- .../src/exponentiation_precedence_test.mjs | 18 -------- .../src/exponentiation_precedence_test.res | 4 -- tests/tests/src/exponentiation_test.mjs | 45 +++++++++++++++++++ tests/tests/src/exponentiation_test.res | 22 +++++++++ 4 files changed, 67 insertions(+), 22 deletions(-) delete mode 100644 tests/tests/src/exponentiation_precedence_test.mjs delete mode 100644 tests/tests/src/exponentiation_precedence_test.res create mode 100644 tests/tests/src/exponentiation_test.mjs create mode 100644 tests/tests/src/exponentiation_test.res diff --git a/tests/tests/src/exponentiation_precedence_test.mjs b/tests/tests/src/exponentiation_precedence_test.mjs deleted file mode 100644 index 4d88b12de0..0000000000 --- a/tests/tests/src/exponentiation_precedence_test.mjs +++ /dev/null @@ -1,18 +0,0 @@ -// Generated by ReScript, PLEASE EDIT WITH CARE - - -let a = 2 ** 3 ** 2; - -let b = 2 ** (-3) ** 2; - -let c = (2 ** 3) ** 2; - -let d = (-2) ** 2; - -export { - a, - b, - c, - d, -} -/* No side effect */ diff --git a/tests/tests/src/exponentiation_precedence_test.res b/tests/tests/src/exponentiation_precedence_test.res deleted file mode 100644 index 97c300005a..0000000000 --- a/tests/tests/src/exponentiation_precedence_test.res +++ /dev/null @@ -1,4 +0,0 @@ -let a = 2. ** 3. ** 2. -let b = 2. ** -3. ** 2. -let c = (2. ** 3.) ** 2. -let d = -2. ** 2. diff --git a/tests/tests/src/exponentiation_test.mjs b/tests/tests/src/exponentiation_test.mjs new file mode 100644 index 0000000000..a3c9bb71de --- /dev/null +++ b/tests/tests/src/exponentiation_test.mjs @@ -0,0 +1,45 @@ +// Generated by ReScript, PLEASE EDIT WITH CARE + +import * as Mt from "./mt.mjs"; + +let suites = { + contents: /* [] */0 +}; + +let test_id = { + contents: 0 +}; + +function eq(loc, x, y) { + Mt.eq_suites(test_id, suites, loc, x, y); +} + +let intPow = ((a, b) => Math.pow(a, b) | 0); + +eq("File \"exponentiation_test.res\", line 10, characters 5-12", 2 ** 3 ** 2, Math.pow(2, Math.pow(3, 2))); + +eq("File \"exponentiation_test.res\", line 11, characters 5-12", 2 ** (-3) ** 2, Math.pow(2, Math.pow(-3, 2))); + +eq("File \"exponentiation_test.res\", line 12, characters 5-12", (2 ** 3) ** 2, Math.pow(Math.pow(2, 3), 2)); + +eq("File \"exponentiation_test.res\", line 13, characters 5-12", (-2) ** 2, Math.pow(-2, 2)); + +eq("File \"exponentiation_test.res\", line 15, characters 5-12", 512, intPow(2, intPow(3, 2))); + +eq("File \"exponentiation_test.res\", line 16, characters 5-12", 512, intPow(2, intPow(-3, 2))); + +eq("File \"exponentiation_test.res\", line 17, characters 5-12", 64, intPow(intPow(2, 3), 2)); + +eq("File \"exponentiation_test.res\", line 18, characters 5-12", -2147483648, intPow(-2, 31)); + +eq("File \"exponentiation_test.res\", line 19, characters 5-12", 0, intPow(2, 32)); + +Mt.from_pair_suites("Exponentiation_test", suites.contents); + +export { + suites, + test_id, + eq, + intPow, +} +/* Not a pure module */ diff --git a/tests/tests/src/exponentiation_test.res b/tests/tests/src/exponentiation_test.res new file mode 100644 index 0000000000..cb4a54aef2 --- /dev/null +++ b/tests/tests/src/exponentiation_test.res @@ -0,0 +1,22 @@ +let suites: ref = ref(list{}) +let test_id = ref(0) +let eq = (loc, x, y) => Mt.eq_suites(~test_id, ~suites, loc, x, y) + +external jsPow: (float, float) => float = "Math.pow" + +let intPow: (int, int) => int = %raw(`(a, b) => Math.pow(a, b) | 0`) + +let () = { + eq(__LOC__, 2. ** 3. ** 2., jsPow(2., jsPow(3., 2.))) + eq(__LOC__, 2. ** -3. ** 2., jsPow(2., jsPow(-3., 2.))) + eq(__LOC__, (2. ** 3.) ** 2., jsPow(jsPow(2., 3.), 2.)) + eq(__LOC__, -2. ** 2., jsPow(-2., 2.)) + + eq(__LOC__, 2 ** 3 ** 2, intPow(2, intPow(3, 2))) + eq(__LOC__, 2 ** -3 ** 2, intPow(2, intPow(-3, 2))) + eq(__LOC__, (2 ** 3) ** 2, intPow(intPow(2, 3), 2)) + eq(__LOC__, -2 ** 31, intPow(-2, 31)) + eq(__LOC__, 2 ** 32, intPow(2, 32)) +} + +let () = Mt.from_pair_suites(__MODULE__, suites.contents) From 0add4e356e6c9d45d37cf0ce5e68a00cc196431b Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sun, 10 Nov 2024 04:03:33 +0900 Subject: [PATCH 6/9] make sure it is int32 --- compiler/core/js_exp_make.ml | 2 +- tests/tests/src/test_pervasive.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/core/js_exp_make.ml b/compiler/core/js_exp_make.ml index 0849460290..c43bd4d244 100644 --- a/compiler/core/js_exp_make.ml +++ b/compiler/core/js_exp_make.ml @@ -1609,7 +1609,7 @@ let int32_pow ?comment (e1 : t) (e2 : t) : J.expression = match (e1.expression_desc, e2.expression_desc) with | Number (Int {i = i1}), Number (Int {i = i2}) -> to_int32 (int ?comment (Ext_int.int32_pow i1 i2)) - | _ -> {comment; expression_desc = Bin (Pow, e1, e2)} + | _ -> to_int32 (float_pow ?comment e1 e2) let rec int32_bxor ?comment (e1 : t) (e2 : t) : J.expression = match (e1.expression_desc, e2.expression_desc) with diff --git a/tests/tests/src/test_pervasive.mjs b/tests/tests/src/test_pervasive.mjs index df9af152dc..0771c48e88 100644 --- a/tests/tests/src/test_pervasive.mjs +++ b/tests/tests/src/test_pervasive.mjs @@ -187,7 +187,7 @@ function a17(prim) { } function a18(prim0, prim1) { - return prim0 ** prim1; + return prim0 ** prim1 | 0; } let f = Pervasives.$at; From c3dc1a068445b368552dc5fc300e2b5908051600 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sun, 10 Nov 2024 04:05:33 +0900 Subject: [PATCH 7/9] remove unnecessary guard for constants --- compiler/core/js_exp_make.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/core/js_exp_make.ml b/compiler/core/js_exp_make.ml index c43bd4d244..c0ec1eecb1 100644 --- a/compiler/core/js_exp_make.ml +++ b/compiler/core/js_exp_make.ml @@ -1608,7 +1608,7 @@ let unchecked_int32_mul ?comment e1 e2 : J.expression = let int32_pow ?comment (e1 : t) (e2 : t) : J.expression = match (e1.expression_desc, e2.expression_desc) with | Number (Int {i = i1}), Number (Int {i = i2}) -> - to_int32 (int ?comment (Ext_int.int32_pow i1 i2)) + int ?comment (Ext_int.int32_pow i1 i2) | _ -> to_int32 (float_pow ?comment e1 e2) let rec int32_bxor ?comment (e1 : t) (e2 : t) : J.expression = From 73dedfb14093097ab1916f462be9e1e2686dff0f Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sun, 10 Nov 2024 09:53:15 +0900 Subject: [PATCH 8/9] add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dde3c2e946..4ae435e261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - Introduce "Unified operators" for arithmetic operators (`+`, `-`, `*`, `/`, `mod`). https://github.com/rescript-lang/rescript-compiler/pull/7057 - Add remainder (`%`, aka modulus) operator. https://github.com/rescript-lang/rescript-compiler/pull/7152 +- Allow exponentiation (`**`) operator for `int` and `float`, using ES7 `**`. https://github.com/rescript-lang/rescript-compiler/pull/7153 # 12.0.0-alpha.4 From 6a077e283599b6fff187c768aa697c8aa125e8c5 Mon Sep 17 00:00:00 2001 From: Hyeseong Kim Date: Sun, 10 Nov 2024 09:58:42 +0900 Subject: [PATCH 9/9] add a test --- tests/tests/src/exponentiation_test.mjs | 23 ++++++++++++++--------- tests/tests/src/exponentiation_test.res | 3 +++ 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/tests/tests/src/exponentiation_test.mjs b/tests/tests/src/exponentiation_test.mjs index a3c9bb71de..cd1b851151 100644 --- a/tests/tests/src/exponentiation_test.mjs +++ b/tests/tests/src/exponentiation_test.mjs @@ -16,23 +16,27 @@ function eq(loc, x, y) { let intPow = ((a, b) => Math.pow(a, b) | 0); -eq("File \"exponentiation_test.res\", line 10, characters 5-12", 2 ** 3 ** 2, Math.pow(2, Math.pow(3, 2))); +let four = 4; -eq("File \"exponentiation_test.res\", line 11, characters 5-12", 2 ** (-3) ** 2, Math.pow(2, Math.pow(-3, 2))); +eq("File \"exponentiation_test.res\", line 11, characters 5-12", 2 ** 3 ** 2, Math.pow(2, Math.pow(3, 2))); -eq("File \"exponentiation_test.res\", line 12, characters 5-12", (2 ** 3) ** 2, Math.pow(Math.pow(2, 3), 2)); +eq("File \"exponentiation_test.res\", line 12, characters 5-12", 2 ** (-3) ** 2, Math.pow(2, Math.pow(-3, 2))); -eq("File \"exponentiation_test.res\", line 13, characters 5-12", (-2) ** 2, Math.pow(-2, 2)); +eq("File \"exponentiation_test.res\", line 13, characters 5-12", (2 ** 3) ** 2, Math.pow(Math.pow(2, 3), 2)); -eq("File \"exponentiation_test.res\", line 15, characters 5-12", 512, intPow(2, intPow(3, 2))); +eq("File \"exponentiation_test.res\", line 14, characters 5-12", (-2) ** 2, Math.pow(-2, 2)); -eq("File \"exponentiation_test.res\", line 16, characters 5-12", 512, intPow(2, intPow(-3, 2))); +eq("File \"exponentiation_test.res\", line 16, characters 5-12", 512, intPow(2, intPow(3, 2))); -eq("File \"exponentiation_test.res\", line 17, characters 5-12", 64, intPow(intPow(2, 3), 2)); +eq("File \"exponentiation_test.res\", line 17, characters 5-12", 512, intPow(2, intPow(-3, 2))); -eq("File \"exponentiation_test.res\", line 18, characters 5-12", -2147483648, intPow(-2, 31)); +eq("File \"exponentiation_test.res\", line 18, characters 5-12", 64, intPow(intPow(2, 3), 2)); -eq("File \"exponentiation_test.res\", line 19, characters 5-12", 0, intPow(2, 32)); +eq("File \"exponentiation_test.res\", line 19, characters 5-12", -2147483648, intPow(-2, 31)); + +eq("File \"exponentiation_test.res\", line 20, characters 5-12", 0, intPow(2, 32)); + +eq("File \"exponentiation_test.res\", line 22, characters 5-12", 256, four ** four | 0); Mt.from_pair_suites("Exponentiation_test", suites.contents); @@ -41,5 +45,6 @@ export { test_id, eq, intPow, + four, } /* Not a pure module */ diff --git a/tests/tests/src/exponentiation_test.res b/tests/tests/src/exponentiation_test.res index cb4a54aef2..0d0caa7b21 100644 --- a/tests/tests/src/exponentiation_test.res +++ b/tests/tests/src/exponentiation_test.res @@ -5,6 +5,7 @@ let eq = (loc, x, y) => Mt.eq_suites(~test_id, ~suites, loc, x, y) external jsPow: (float, float) => float = "Math.pow" let intPow: (int, int) => int = %raw(`(a, b) => Math.pow(a, b) | 0`) +let four: int = %raw(`4`) let () = { eq(__LOC__, 2. ** 3. ** 2., jsPow(2., jsPow(3., 2.))) @@ -17,6 +18,8 @@ let () = { eq(__LOC__, (2 ** 3) ** 2, intPow(intPow(2, 3), 2)) eq(__LOC__, -2 ** 31, intPow(-2, 31)) eq(__LOC__, 2 ** 32, intPow(2, 32)) + + eq(__LOC__, 4 ** 4, four ** four) } let () = Mt.from_pair_suites(__MODULE__, suites.contents)