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)?;
+8 -8
View File
@@ -52,13 +52,13 @@ pub use objects::{
RootTypes, TypeConstructor, TypedMethodRequirement,
};
pub use objects::{
CallArity, CallEffect, CallSignature, CallType, ChangeBatch, ChangeKey, CodeLayout, CompareOp,
ContextNativeFunction, DecodedInstruction, EndorBaseExceptionObject, EndorCellObject,
EndorCode, EndorCodeObject, EndorDecimal, EndorDictObject, EndorFunctionObject, EndorInteger,
EndorNativeCall, EndorNativeFunctionObject, EndorNumber, EndorNumberObject, EndorObject,
EndorRational, EndorReal, EndorStringObject, EndorTracebackEntry, Instruction, NativeCall,
NativeCallable, NativeContext, NativeFunction, NativeResult, ObjectChange, ObjectHeader,
ObjectPayload, ObjectRef, Opcode, ReadAccess, ReadDependency, ReadSet, Record, SourceSignature,
TrackedReads, Value, VmError, WeakObjectRef,
ArithmeticOp, CallArity, CallEffect, CallSignature, CallType, ChangeBatch, ChangeKey,
CodeLayout, CompareOp, ContextNativeFunction, DecodedInstruction, EndorBaseExceptionObject,
EndorCellObject, EndorCode, EndorCodeObject, EndorDecimal, EndorDictObject,
EndorFunctionObject, EndorInteger, EndorNativeCall, EndorNativeFunctionObject, EndorNumber,
EndorNumberObject, EndorObject, EndorRational, EndorReal, EndorStringObject,
EndorTracebackEntry, Instruction, NativeCall, NativeCallable, NativeContext, NativeFunction,
NativeResult, ObjectChange, ObjectHeader, ObjectPayload, ObjectRef, Opcode, ReadAccess,
ReadDependency, ReadSet, Record, SourceSignature, TrackedReads, Value, VmError, WeakObjectRef,
};
pub use vm::Vm;