@@ -186,6 +186,30 @@ static bool writeback_ptr_range(Interpreter* interp, Expr** arg_nodes, Env* env,
186186 return true;
187187}
188188
189+ // Checked FLT -> INT coercion helper.
190+ // Returns true and sets *out on success. On failure, sets interp->error
191+ // and returns false (caller should return value_null()).
192+ static bool coerce_flt_to_int_checked (Interpreter * interp , double f , int64_t * out , const char * opname , int line , int col ) {
193+ if (isnan (f ) || isinf (f )) {
194+ char buf [128 ];
195+ snprintf (buf , sizeof (buf ), "%s cannot coerce FLT to INT" , opname );
196+ interp -> error = strdup (buf );
197+ interp -> error_line = line ;
198+ interp -> error_col = col ;
199+ return false;
200+ }
201+ if (f > (double )INT64_MAX || f < (double )INT64_MIN ) {
202+ char buf [128 ];
203+ snprintf (buf , sizeof (buf ), "%s cannot coerce FLT to INT (out of range)" , opname );
204+ interp -> error = strdup (buf );
205+ interp -> error_line = line ;
206+ interp -> error_col = col ;
207+ return false;
208+ }
209+ * out = (int64_t )f ;
210+ return true;
211+ }
212+
189213// --- Encoding helpers ---
190214static char * dec_latin1_to_utf8 (const unsigned char * buf , size_t sz ) {
191215 size_t outcap = sz * 2 + 1 ;
@@ -3492,8 +3516,18 @@ static Value builtin_iadd(Interpreter* interp, Value* args, int argc, Expr** arg
34923516 EXPECT_NUM (args [0 ], "IADD" , interp , line , col );
34933517 EXPECT_NUM (args [1 ], "IADD" , interp , line , col );
34943518
3495- int64_t a = args [0 ].type == VAL_INT ? args [0 ].as .i : (int64_t )args [0 ].as .f ;
3496- int64_t b = args [1 ].type == VAL_INT ? args [1 ].as .i : (int64_t )args [1 ].as .f ;
3519+ int64_t a ;
3520+ if (args [0 ].type == VAL_INT ) {
3521+ a = args [0 ].as .i ;
3522+ } else {
3523+ if (!coerce_flt_to_int_checked (interp , args [0 ].as .f , & a , "IADD" , line , col )) return value_null ();
3524+ }
3525+ int64_t b ;
3526+ if (args [1 ].type == VAL_INT ) {
3527+ b = args [1 ].as .i ;
3528+ } else {
3529+ if (!coerce_flt_to_int_checked (interp , args [1 ].as .f , & b , "IADD" , line , col )) return value_null ();
3530+ }
34973531 Value result = value_int_base (a + b , result_base_from_values (args [0 ], args [1 ]));
34983532 if (!writeback_ptr_range (interp , arg_nodes , env , 0 , 2 , result , "IADD" , line , col )) {
34993533 value_free (result );
@@ -3507,8 +3541,18 @@ static Value builtin_isub(Interpreter* interp, Value* args, int argc, Expr** arg
35073541 EXPECT_NUM (args [0 ], "ISUB" , interp , line , col );
35083542 EXPECT_NUM (args [1 ], "ISUB" , interp , line , col );
35093543
3510- int64_t a = args [0 ].type == VAL_INT ? args [0 ].as .i : (int64_t )args [0 ].as .f ;
3511- int64_t b = args [1 ].type == VAL_INT ? args [1 ].as .i : (int64_t )args [1 ].as .f ;
3544+ int64_t a ;
3545+ if (args [0 ].type == VAL_INT ) {
3546+ a = args [0 ].as .i ;
3547+ } else {
3548+ if (!coerce_flt_to_int_checked (interp , args [0 ].as .f , & a , "ISUB" , line , col )) return value_null ();
3549+ }
3550+ int64_t b ;
3551+ if (args [1 ].type == VAL_INT ) {
3552+ b = args [1 ].as .i ;
3553+ } else {
3554+ if (!coerce_flt_to_int_checked (interp , args [1 ].as .f , & b , "ISUB" , line , col )) return value_null ();
3555+ }
35123556 Value result = value_int_base (a - b , result_base_from_values (args [0 ], args [1 ]));
35133557 if (!writeback_ptr_range (interp , arg_nodes , env , 0 , 2 , result , "ISUB" , line , col )) {
35143558 value_free (result );
@@ -3522,8 +3566,18 @@ static Value builtin_imul(Interpreter* interp, Value* args, int argc, Expr** arg
35223566 EXPECT_NUM (args [0 ], "IMUL" , interp , line , col );
35233567 EXPECT_NUM (args [1 ], "IMUL" , interp , line , col );
35243568
3525- int64_t a = args [0 ].type == VAL_INT ? args [0 ].as .i : (int64_t )args [0 ].as .f ;
3526- int64_t b = args [1 ].type == VAL_INT ? args [1 ].as .i : (int64_t )args [1 ].as .f ;
3569+ int64_t a ;
3570+ if (args [0 ].type == VAL_INT ) {
3571+ a = args [0 ].as .i ;
3572+ } else {
3573+ if (!coerce_flt_to_int_checked (interp , args [0 ].as .f , & a , "IMUL" , line , col )) return value_null ();
3574+ }
3575+ int64_t b ;
3576+ if (args [1 ].type == VAL_INT ) {
3577+ b = args [1 ].as .i ;
3578+ } else {
3579+ if (!coerce_flt_to_int_checked (interp , args [1 ].as .f , & b , "IMUL" , line , col )) return value_null ();
3580+ }
35273581 Value result = value_int_base (a * b , result_base_from_values (args [0 ], args [1 ]));
35283582 if (!writeback_ptr_range (interp , arg_nodes , env , 0 , 2 , result , "IMUL" , line , col )) {
35293583 value_free (result );
@@ -3537,8 +3591,18 @@ static Value builtin_idiv(Interpreter* interp, Value* args, int argc, Expr** arg
35373591 EXPECT_NUM (args [0 ], "IDIV" , interp , line , col );
35383592 EXPECT_NUM (args [1 ], "IDIV" , interp , line , col );
35393593
3540- int64_t a = args [0 ].type == VAL_INT ? args [0 ].as .i : (int64_t )args [0 ].as .f ;
3541- int64_t b = args [1 ].type == VAL_INT ? args [1 ].as .i : (int64_t )args [1 ].as .f ;
3594+ int64_t a ;
3595+ if (args [0 ].type == VAL_INT ) {
3596+ a = args [0 ].as .i ;
3597+ } else {
3598+ if (!coerce_flt_to_int_checked (interp , args [0 ].as .f , & a , "IDIV" , line , col )) return value_null ();
3599+ }
3600+ int64_t b ;
3601+ if (args [1 ].type == VAL_INT ) {
3602+ b = args [1 ].as .i ;
3603+ } else {
3604+ if (!coerce_flt_to_int_checked (interp , args [1 ].as .f , & b , "IDIV" , line , col )) return value_null ();
3605+ }
35423606 if (b == 0 ) {
35433607 RUNTIME_ERROR (interp , "Division by zero" , line , col );
35443608 }
@@ -3618,8 +3682,18 @@ static Value builtin_ipow(Interpreter* interp, Value* args, int argc, Expr** arg
36183682 EXPECT_NUM (args [0 ], "IPOW" , interp , line , col );
36193683 EXPECT_NUM (args [1 ], "IPOW" , interp , line , col );
36203684
3621- int64_t base = args [0 ].type == VAL_INT ? args [0 ].as .i : (int64_t )args [0 ].as .f ;
3622- int64_t exp = args [1 ].type == VAL_INT ? args [1 ].as .i : (int64_t )args [1 ].as .f ;
3685+ int64_t base ;
3686+ if (args [0 ].type == VAL_INT ) {
3687+ base = args [0 ].as .i ;
3688+ } else {
3689+ if (!coerce_flt_to_int_checked (interp , args [0 ].as .f , & base , "IPOW" , line , col )) return value_null ();
3690+ }
3691+ int64_t exp ;
3692+ if (args [1 ].type == VAL_INT ) {
3693+ exp = args [1 ].as .i ;
3694+ } else {
3695+ if (!coerce_flt_to_int_checked (interp , args [1 ].as .f , & exp , "IPOW" , line , col )) return value_null ();
3696+ }
36233697 if (exp < 0 ) {
36243698 RUNTIME_ERROR (interp , "Negative exponent not supported" , line , col );
36253699 }
@@ -3948,8 +4022,11 @@ static Value builtin_conv(Interpreter* interp, Value* args, int argc, Expr** arg
39484022 if (bias_present && bias_t -> length > 0 ) {
39494023 Value bv = bias_t -> data [oc ];
39504024 if (bv .type == VAL_INT ) acc += bv .as .i ;
3951- else if (bv .type == VAL_FLT ) acc += (int64_t )bv .as .f ;
3952- else { value_free (out ); RUNTIME_ERROR (interp , "CONV bias must be numeric" , line , col ); }
4025+ else if (bv .type == VAL_FLT ) {
4026+ int64_t tmp ;
4027+ if (!coerce_flt_to_int_checked (interp , bv .as .f , & tmp , "CONV" , line , col )) { value_free (out ); return value_null (); }
4028+ acc += tmp ;
4029+ } else { value_free (out ); RUNTIME_ERROR (interp , "CONV bias must be numeric" , line , col ); }
39534030 }
39544031 ot -> data [ow * ot -> strides [0 ] + oh * ot -> strides [1 ] + oc * ot -> strides [2 ]] = value_int (acc );
39554032 } else {
@@ -5009,7 +5086,9 @@ static Value builtin_int(Interpreter* interp, Value* args, int argc, Expr** arg_
50095086 if (args [0 ].type == VAL_FLT ) {
50105087 int b = numeric_base_of (args [0 ]);
50115088 if (b <= 0 ) b = 2 ;
5012- return value_int_base ((int64_t )args [0 ].as .f , b );
5089+ int64_t tmp ;
5090+ if (!coerce_flt_to_int_checked (interp , args [0 ].as .f , & tmp , "INT" , line , col )) return value_null ();
5091+ return value_int_base (tmp , b );
50135092 }
50145093 if (args [0 ].type == VAL_STR ) {
50155094 int64_t val = 0 ;
@@ -7148,7 +7227,13 @@ static Value builtin_isum(Interpreter* interp, Value* args, int argc, Expr** arg
71487227 int64_t sum = 0 ;
71497228 for (int i = 0 ; i < argc ; i ++ ) {
71507229 EXPECT_NUM (args [i ], "ISUM" , interp , line , col );
7151- sum += args [i ].type == VAL_INT ? args [i ].as .i : (int64_t )args [i ].as .f ;
7230+ if (args [i ].type == VAL_INT ) {
7231+ sum += args [i ].as .i ;
7232+ } else {
7233+ int64_t tmp ;
7234+ if (!coerce_flt_to_int_checked (interp , args [i ].as .f , & tmp , "ISUM" , line , col )) return value_null ();
7235+ sum += tmp ;
7236+ }
71527237 }
71537238 return value_int (sum );
71547239}
@@ -7178,7 +7263,13 @@ static Value builtin_iprod(Interpreter* interp, Value* args, int argc, Expr** ar
71787263 int64_t prod = 1 ;
71797264 for (int i = 0 ; i < argc ; i ++ ) {
71807265 EXPECT_NUM (args [i ], "IPROD" , interp , line , col );
7181- prod *= args [i ].type == VAL_INT ? args [i ].as .i : (int64_t )args [i ].as .f ;
7266+ if (args [i ].type == VAL_INT ) {
7267+ prod *= args [i ].as .i ;
7268+ } else {
7269+ int64_t tmp ;
7270+ if (!coerce_flt_to_int_checked (interp , args [i ].as .f , & tmp , "IPROD" , line , col )) return value_null ();
7271+ prod *= tmp ;
7272+ }
71827273 }
71837274 return value_int (prod );
71847275}
0 commit comments