feat: execute source control flow and exact real arithmetic

This commit is contained in:
2026-11-12 10:48:27 +08:00
parent f3e1670c58
commit 5ff1c68f5f
28 changed files with 1045 additions and 117 deletions
+65 -2
View File
@@ -901,14 +901,38 @@ impl Vm {
})
}
fn number_value<'a>(
&'a self,
value: &'a Value,
) -> Result<Option<&'a crate::EndorNumber>, VmError> {
Ok(match value {
Value::Number(n) => Some(n),
Value::Object(o) => self
.object(*o)?
.payload()
.as_any()
.downcast_ref::<crate::EndorNumberObject>()
.map(|n| n.value()),
_ => None,
})
}
fn compare_values(
&self,
left: &Value,
right: &Value,
operation: CompareOp,
) -> Result<bool, VmError> {
if matches!(left, Value::Number(_)) || matches!(right, Value::Number(_)) {
return Err(VmError::UnsupportedOperation("numeric comparison"));
let (left_number, right_number) = (self.number_value(left)?, self.number_value(right)?);
if let (Some(left), Some(right)) = (left_number, right_number) {
return left.numeric_compare(right, operation);
}
if left_number.is_some() || right_number.is_some() {
return match operation {
CompareOp::Eq => Ok(false),
CompareOp::Ne => Ok(true),
_ => Err(VmError::UnsupportedOperation("mixed numeric ordering")),
};
}
if let (Some(left), Some(right)) = (self.text_value(left)?, self.text_value(right)?) {
return Ok(match operation {
@@ -1242,6 +1266,45 @@ impl Vm {
},
)));
}
Opcode::BinaryArithmetic => {
if decoded.instruction.argument == 0 {
let left = Self::stack_value(frame, frame.stack.len() - 2)?;
let right = Self::top_value(frame)?;
if let (Value::Text(a), Value::Text(b)) = (left, right) {
if a.len().saturating_add(b.len()) > 1_048_576 {
return Err(VmError::InvalidArgument(
"text concatenation exceeds operation budget",
));
}
self.discard(frame, 2);
frame.stack.push(StackEntry::Value(Value::Text(a + &b)));
continue;
}
}
let left = Self::stack_value(frame, frame.stack.len() - 2)?;
let right = Self::top_value(frame)?;
let left = self
.number_value(&left)?
.ok_or(VmError::ObjectKindMismatch("Number"))?;
let right = self
.number_value(&right)?
.ok_or(VmError::ObjectKindMismatch("Number"))?;
let result = left.arithmetic(
right,
crate::ArithmeticOp::from_argument(decoded.instruction.argument).unwrap(),
)?;
self.discard(frame, 2);
frame.stack.push(StackEntry::Value(Value::Number(result)));
}
Opcode::UnaryNegate => {
let value = Self::top_value(frame)?;
let value = self
.number_value(&value)?
.ok_or(VmError::ObjectKindMismatch("Number"))?;
let result = value.negated()?;
self.discard(frame, 1);
frame.stack.push(StackEntry::Value(Value::Number(result)));
}
Opcode::CompareOp => {
let left = Self::stack_value(frame, frame.stack.len() - 2)?;
let right = Self::top_value(frame)?;