Skip to content

Commit f2e2d1e

Browse files
fix(vm): Correct float floor-div/mod and unpack error messages; 2x vm test suite.
1 parent 85f464c commit f2e2d1e

3 files changed

Lines changed: 662 additions & 11 deletions

File tree

compiler/src/modules/vm/handlers/arith.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ impl<'a> VM<'a> {
5454
let af = self.to_f64_coerce(a).map_err(|_| cold_type("% requires numeric operands"))?;
5555
let bf = self.to_f64_coerce(b).map_err(|_| cold_type("% requires numeric operands"))?;
5656
if bf == 0.0 { return Err(VmErr::ZeroDiv); }
57-
let q = (af / bf) as i64 as f64;
58-
let q_floor = q - if af / bf < 0.0 && q != af / bf { 1.0 } else { 0.0 };
59-
return Ok(Val::float(af - q_floor * bf));
57+
// Use floor division semantics: result has the same sign as the divisor.
58+
let r = af - (af / bf).floor() * bf;
59+
return Ok(Val::float(r));
6060
}
6161
let (Some(ba), Some(bb)) = (self.to_bigint(a), self.to_bigint(b))
6262
else { return Err(cold_type("% requires numeric operands")); };
@@ -69,10 +69,8 @@ impl<'a> VM<'a> {
6969
let af = self.to_f64_coerce(a).map_err(|_| cold_type("// requires numeric operands"))?;
7070
let bf = self.to_f64_coerce(b).map_err(|_| cold_type("// requires numeric operands"))?;
7171
if bf == 0.0 { return Err(VmErr::ZeroDiv); }
72-
let q = af / bf;
73-
let t = q as i64 as f64;
74-
let floored = t - if q < 0.0 && t != q { 1.0 } else { 0.0 };
75-
return Ok(Val::float(floored));
72+
// floor() is correct for all magnitudes, including large floats where as-i64 would overflow.
73+
return Ok(Val::float((af / bf).floor()));
7674
}
7775
let (Some(ba), Some(bb)) = (self.to_bigint(a), self.to_bigint(b))
7876
else { return Err(cold_type("// requires numeric operands")); };

compiler/src/modules/vm/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,18 @@ impl<'a> VM<'a> {
190190
HeapObj::Str(s) => {
191191
let s = s.clone();
192192
let out = self.str_to_char_vals(&s)?;
193-
if out.len() != expected {
193+
if out.len() > expected {
194+
return Err(cold_value("too many values to unpack"));
195+
} else if out.len() < expected {
194196
return Err(cold_value("not enough values to unpack"));
195197
}
196198
out
197199
},
198200
_ => return Err(cold_type("cannot unpack non-sequence")),
199201
};
200-
if items.len() != expected {
202+
if items.len() > expected {
203+
return Err(cold_value("too many values to unpack"));
204+
} else if items.len() < expected {
201205
return Err(cold_value("not enough values to unpack"));
202206
}
203207
for item in items.into_iter().rev() { self.push(item); }

0 commit comments

Comments
 (0)