@@ -1718,6 +1718,7 @@ pub fn evaluate_expr(env: &JSObjectDataPtr, expr: &Expr) -> Result<Value, JSErro
17181718 Expr :: AddAssign ( target, value) => evaluate_add_assign ( env, target, value) ,
17191719 Expr :: SubAssign ( target, value) => evaluate_sub_assign ( env, target, value) ,
17201720 Expr :: MulAssign ( target, value) => evaluate_mul_assign ( env, target, value) ,
1721+ Expr :: PowAssign ( target, value) => evaluate_pow_assign ( env, target, value) ,
17211722 Expr :: DivAssign ( target, value) => evaluate_div_assign ( env, target, value) ,
17221723 Expr :: ModAssign ( target, value) => evaluate_mod_assign ( env, target, value) ,
17231724 Expr :: Increment ( expr) => evaluate_increment ( env, expr) ,
@@ -2035,6 +2036,67 @@ fn evaluate_mul_assign(env: &JSObjectDataPtr, target: &Expr, value: &Expr) -> Re
20352036 Ok ( result)
20362037}
20372038
2039+ fn evaluate_pow_assign ( env : & JSObjectDataPtr , target : & Expr , value : & Expr ) -> Result < Value , JSError > {
2040+ // a **= b is equivalent to a = a ** b
2041+ let left_val = evaluate_expr ( env, target) ?;
2042+ let right_val = evaluate_expr ( env, value) ?;
2043+ let result = match ( left_val, right_val) {
2044+ ( Value :: Number ( ln) , Value :: Number ( rn) ) => Value :: Number ( ln. powf ( rn) ) ,
2045+ ( Value :: BigInt ( la) , Value :: BigInt ( rb) ) => {
2046+ let a = BigInt :: parse_bytes ( la. as_bytes ( ) , 10 ) . ok_or ( JSError :: EvaluationError {
2047+ message : "invalid bigint" . to_string ( ) ,
2048+ } ) ?;
2049+ let b = BigInt :: parse_bytes ( rb. as_bytes ( ) , 10 ) . ok_or ( JSError :: EvaluationError {
2050+ message : "invalid bigint" . to_string ( ) ,
2051+ } ) ?;
2052+ if b < BigInt :: from ( 0 ) {
2053+ return Err ( JSError :: EvaluationError {
2054+ message : "negative exponent for bigint" . to_string ( ) ,
2055+ } ) ;
2056+ }
2057+ let exp = b. to_u32 ( ) . ok_or ( JSError :: EvaluationError {
2058+ message : "exponent too large" . to_string ( ) ,
2059+ } ) ?;
2060+ Value :: BigInt ( a. pow ( exp) . to_string ( ) )
2061+ }
2062+ ( Value :: BigInt ( la) , Value :: Number ( rn) ) => {
2063+ if rn < 0.0 || rn. fract ( ) != 0.0 {
2064+ return Err ( JSError :: EvaluationError {
2065+ message : "invalid exponent for bigint" . to_string ( ) ,
2066+ } ) ;
2067+ }
2068+ let exp_u = rn as u32 ;
2069+ let a = BigInt :: parse_bytes ( la. as_bytes ( ) , 10 ) . ok_or ( JSError :: EvaluationError {
2070+ message : "invalid bigint" . to_string ( ) ,
2071+ } ) ?;
2072+ Value :: BigInt ( a. pow ( exp_u) . to_string ( ) )
2073+ }
2074+ ( Value :: Number ( ln) , Value :: BigInt ( rb) ) => {
2075+ if let Some ( rv) = BigInt :: parse_bytes ( rb. as_bytes ( ) , 10 ) . and_then ( |bi| bi. to_f64 ( ) ) {
2076+ Value :: Number ( ln. powf ( rv) )
2077+ } else {
2078+ return Err ( JSError :: EvaluationError {
2079+ message : "invalid exponent" . to_string ( ) ,
2080+ } ) ;
2081+ }
2082+ }
2083+ _ => {
2084+ return Err ( JSError :: EvaluationError {
2085+ message : "Invalid operands for **=" . to_string ( ) ,
2086+ } ) ;
2087+ }
2088+ } ;
2089+
2090+ // update assignment target
2091+ let assignment_expr = match & result {
2092+ Value :: Number ( n) => Expr :: Number ( * n) ,
2093+ Value :: BigInt ( s) => Expr :: BigInt ( s. clone ( ) ) ,
2094+ _ => unreachable ! ( ) ,
2095+ } ;
2096+ evaluate_assignment_expr ( env, target, & assignment_expr) ?;
2097+ Ok ( result)
2098+ }
2099+
20382100fn evaluate_div_assign ( env : & JSObjectDataPtr , target : & Expr , value : & Expr ) -> Result < Value , JSError > {
20392101 // a /= b is equivalent to a = a / b
20402102 let left_val = evaluate_expr ( env, target) ?;
@@ -2565,6 +2627,52 @@ fn evaluate_binary(env: &JSObjectDataPtr, left: &Expr, op: &BinaryOp, right: &Ex
25652627 message : "error" . to_string ( ) ,
25662628 } ) ,
25672629 } ,
2630+ BinaryOp :: Pow => match ( l, r) {
2631+ ( Value :: Number ( ln) , Value :: Number ( rn) ) => Ok ( Value :: Number ( ln. powf ( rn) ) ) ,
2632+ ( Value :: BigInt ( la) , Value :: BigInt ( rb) ) => {
2633+ let a = BigInt :: parse_bytes ( la. as_bytes ( ) , 10 ) . ok_or ( JSError :: EvaluationError {
2634+ message : "invalid bigint" . to_string ( ) ,
2635+ } ) ?;
2636+ let b = BigInt :: parse_bytes ( rb. as_bytes ( ) , 10 ) . ok_or ( JSError :: EvaluationError {
2637+ message : "invalid bigint" . to_string ( ) ,
2638+ } ) ?;
2639+ // exponent must be non-negative and fit into u32 for pow
2640+ if b < BigInt :: from ( 0 ) {
2641+ return Err ( JSError :: EvaluationError {
2642+ message : "negative exponent for bigint" . to_string ( ) ,
2643+ } ) ;
2644+ }
2645+ let exp = b. to_u32 ( ) . ok_or ( JSError :: EvaluationError {
2646+ message : "exponent too large" . to_string ( ) ,
2647+ } ) ?;
2648+ Ok ( Value :: BigInt ( a. pow ( exp) . to_string ( ) ) )
2649+ }
2650+ ( Value :: BigInt ( la) , Value :: Number ( rn) ) => {
2651+ if rn < 0.0 || rn. fract ( ) != 0.0 {
2652+ return Err ( JSError :: EvaluationError {
2653+ message : "invalid exponent for bigint" . to_string ( ) ,
2654+ } ) ;
2655+ }
2656+ let exp_u = rn as u32 ;
2657+ let a = BigInt :: parse_bytes ( la. as_bytes ( ) , 10 ) . ok_or ( JSError :: EvaluationError {
2658+ message : "invalid bigint" . to_string ( ) ,
2659+ } ) ?;
2660+ Ok ( Value :: BigInt ( a. pow ( exp_u) . to_string ( ) ) )
2661+ }
2662+ // number ** bigint -> try converting bigint to number if possible
2663+ ( Value :: Number ( ln) , Value :: BigInt ( rb) ) => {
2664+ if let Some ( rv) = BigInt :: parse_bytes ( rb. as_bytes ( ) , 10 ) . and_then ( |bi| bi. to_f64 ( ) ) {
2665+ Ok ( Value :: Number ( ln. powf ( rv) ) )
2666+ } else {
2667+ Err ( JSError :: EvaluationError {
2668+ message : "invalid exponent" . to_string ( ) ,
2669+ } )
2670+ }
2671+ }
2672+ _ => Err ( JSError :: EvaluationError {
2673+ message : "error" . to_string ( ) ,
2674+ } ) ,
2675+ } ,
25682676 BinaryOp :: Div => match ( l, r) {
25692677 ( Value :: Number ( ln) , Value :: Number ( rn) ) => {
25702678 if rn == 0.0 {
0 commit comments