284 lines
8.7 KiB
Rust
284 lines
8.7 KiB
Rust
use objects::ObjectStore;
|
|
|
|
use crate::{
|
|
CompareOp, EndorCode, EndorNumber, EndorObject, ExecutionLocation, ObjectPayload, ObjectRef,
|
|
Value, VmError,
|
|
};
|
|
|
|
/// Owns the object store and execution state. Object representation, allocation,
|
|
/// reference accounting and builtin operations live in the objects crate.
|
|
#[derive(Debug)]
|
|
pub struct Vm {
|
|
pub(crate) objects: ObjectStore,
|
|
pub(crate) last_traceback: Vec<ExecutionLocation>,
|
|
}
|
|
|
|
impl Vm {
|
|
pub fn define_method(
|
|
&mut self,
|
|
type_object: ObjectRef,
|
|
name: impl Into<String>,
|
|
function: ObjectRef,
|
|
) -> Result<(), VmError> {
|
|
self.objects.define_method(type_object, name, function)
|
|
}
|
|
|
|
/// Owned result; release_value when finished. Unlike get_attr, methods bind
|
|
/// their receiver and retain it until the bound method itself is released.
|
|
pub fn bind_attr(&mut self, object: ObjectRef, name: &str) -> Result<Value, VmError> {
|
|
self.objects.bind_attr(object, name)
|
|
}
|
|
|
|
pub fn bootstrap_types(&mut self) -> Result<crate::RootTypes, VmError> {
|
|
self.objects.bootstrap_types()
|
|
}
|
|
|
|
/// Host registration uses the same validated class builder as source code.
|
|
pub fn new_class(
|
|
&mut self,
|
|
name: impl Into<String>,
|
|
base: ObjectRef,
|
|
fields: Vec<crate::ClassField>,
|
|
methods: std::collections::BTreeMap<String, ObjectRef>,
|
|
) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_class(name, base, fields, methods)
|
|
}
|
|
|
|
pub fn new_type(
|
|
&mut self,
|
|
name: impl Into<String>,
|
|
base: ObjectRef,
|
|
constructor: crate::TypeConstructor,
|
|
) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_type(name, base, constructor)
|
|
}
|
|
|
|
pub fn attach_type(
|
|
&mut self,
|
|
object: ObjectRef,
|
|
type_object: ObjectRef,
|
|
) -> Result<(), VmError> {
|
|
self.objects.attach_type(object, type_object)
|
|
}
|
|
|
|
pub fn type_of(&self, object: ObjectRef) -> Result<Option<ObjectRef>, VmError> {
|
|
self.objects.type_of(object)
|
|
}
|
|
|
|
pub fn is_subtype(&self, candidate: ObjectRef, expected: ObjectRef) -> Result<bool, VmError> {
|
|
self.objects.is_subtype(candidate, expected)
|
|
}
|
|
|
|
pub fn is_instance(&self, object: ObjectRef, expected: ObjectRef) -> Result<bool, VmError> {
|
|
self.objects.is_instance(object, expected)
|
|
}
|
|
|
|
/// Read-only access for embedding protocols sharing the same object graph.
|
|
pub fn object_store(&self) -> &ObjectStore {
|
|
&self.objects
|
|
}
|
|
|
|
pub fn downgrade(&self, reference: ObjectRef) -> Result<crate::WeakObjectRef, VmError> {
|
|
self.objects.downgrade(reference)
|
|
}
|
|
|
|
pub fn upgrade(
|
|
&mut self,
|
|
reference: crate::WeakObjectRef,
|
|
) -> Result<Option<ObjectRef>, VmError> {
|
|
self.objects.upgrade(reference)
|
|
}
|
|
|
|
pub fn take_changes(&mut self) -> crate::ChangeBatch {
|
|
self.objects.take_changes()
|
|
}
|
|
|
|
pub fn change_version(&self, reference: ObjectRef) -> Result<u64, VmError> {
|
|
self.objects.change_version(reference)
|
|
}
|
|
|
|
pub fn replace_payload(
|
|
&mut self,
|
|
reference: ObjectRef,
|
|
payload: impl ObjectPayload,
|
|
) -> Result<(), VmError> {
|
|
self.objects.replace_payload(reference, payload)
|
|
}
|
|
|
|
pub fn new() -> Result<Self, VmError> {
|
|
Ok(Self {
|
|
objects: ObjectStore::new()?,
|
|
last_traceback: Vec::new(),
|
|
})
|
|
}
|
|
|
|
pub fn object_count(&self) -> usize {
|
|
self.objects.object_count()
|
|
}
|
|
|
|
/// Returns one external strong reference. Copies of the returned handle
|
|
/// are borrowed; use retain/release to manage additional owned references.
|
|
pub fn allocate(&mut self, payload: impl ObjectPayload) -> Result<ObjectRef, VmError> {
|
|
self.objects.allocate(payload)
|
|
}
|
|
|
|
pub fn new_object(&mut self) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_object()
|
|
}
|
|
|
|
pub fn object(&self, reference: ObjectRef) -> Result<&EndorObject, VmError> {
|
|
self.objects.object(reference)
|
|
}
|
|
|
|
pub fn retain(&mut self, reference: ObjectRef) -> Result<(), VmError> {
|
|
self.objects.retain(reference)
|
|
}
|
|
|
|
pub fn release(&mut self, reference: ObjectRef) -> Result<(), VmError> {
|
|
self.objects.release(reference)
|
|
}
|
|
|
|
pub fn ref_count(&self, reference: ObjectRef) -> Result<usize, VmError> {
|
|
self.objects.ref_count(reference)
|
|
}
|
|
|
|
pub fn is_same(&self, left: ObjectRef, right: ObjectRef) -> Result<bool, VmError> {
|
|
self.objects.is_same(left, right)
|
|
}
|
|
|
|
pub fn repr(&self, reference: ObjectRef) -> Result<String, VmError> {
|
|
self.objects.repr(reference)
|
|
}
|
|
|
|
pub fn str(&self, reference: ObjectRef) -> Result<String, VmError> {
|
|
self.objects.str(reference)
|
|
}
|
|
|
|
pub fn is_true(&self, reference: ObjectRef) -> Result<bool, VmError> {
|
|
self.objects.is_true(reference)
|
|
}
|
|
|
|
pub fn hash(&self, reference: ObjectRef) -> Result<u64, VmError> {
|
|
self.objects.hash(reference)
|
|
}
|
|
|
|
pub fn compare(
|
|
&self,
|
|
left: ObjectRef,
|
|
right: ObjectRef,
|
|
operation: CompareOp,
|
|
) -> Result<bool, VmError> {
|
|
self.objects.compare(left, right, operation)
|
|
}
|
|
|
|
/// Reads a borrowed value. An Object result needs retain() if the host
|
|
/// wants it to survive removal of the attribute that currently owns it.
|
|
pub fn get_attr(&self, reference: ObjectRef, name: &str) -> Result<Value, VmError> {
|
|
self.objects.get_attr(reference, name)
|
|
}
|
|
|
|
/// Object-valued attributes own internal strong references independently
|
|
/// of the caller's external references. Failure leaves the field unchanged.
|
|
pub fn set_attr(
|
|
&mut self,
|
|
reference: ObjectRef,
|
|
name: impl Into<String>,
|
|
value: Value,
|
|
) -> Result<(), VmError> {
|
|
self.objects.set_attr(reference, name, value)
|
|
}
|
|
|
|
pub fn del_attr(&mut self, reference: ObjectRef, name: &str) -> Result<(), VmError> {
|
|
self.objects.del_attr(reference, name)
|
|
}
|
|
|
|
pub(crate) fn validate_value(&self, value: &Value) -> Result<(), VmError> {
|
|
self.objects.validate_value(value)
|
|
}
|
|
|
|
/// Explicit full collection. Execution slots use owned roots, so values
|
|
/// on live execution stacks participate in the same root accounting.
|
|
pub fn collect_cycles(&mut self) -> usize {
|
|
self.objects.collect_cycles()
|
|
}
|
|
|
|
pub fn payload<T: ObjectPayload>(
|
|
&self,
|
|
reference: ObjectRef,
|
|
expected: &'static str,
|
|
) -> Result<&T, VmError> {
|
|
self.objects.payload::<T>(reference, expected)
|
|
}
|
|
|
|
pub fn new_string(&mut self, text: impl Into<String>) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_string(text)
|
|
}
|
|
|
|
pub fn new_code(&mut self, code: EndorCode) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_code(code)
|
|
}
|
|
|
|
pub fn new_function(
|
|
&mut self,
|
|
name: impl Into<String>,
|
|
code: ObjectRef,
|
|
globals: ObjectRef,
|
|
defaults: Vec<Value>,
|
|
closure: Vec<ObjectRef>,
|
|
) -> Result<ObjectRef, VmError> {
|
|
self.objects
|
|
.new_function(name, code, globals, defaults, closure)
|
|
}
|
|
|
|
pub fn new_number(&mut self, number: EndorNumber) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_number(number)
|
|
}
|
|
|
|
pub fn new_dict(&mut self) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_dict()
|
|
}
|
|
|
|
/// Returns borrowed keys and values in insertion order.
|
|
pub fn dict_items(&self, dictionary: ObjectRef) -> Result<&[(Value, Value)], VmError> {
|
|
self.objects.dict_items(dictionary)
|
|
}
|
|
|
|
pub fn dict_get(&self, dictionary: ObjectRef, key: &Value) -> Result<Option<Value>, VmError> {
|
|
self.objects.dict_get(dictionary, key)
|
|
}
|
|
|
|
pub fn dict_set(
|
|
&mut self,
|
|
dictionary: ObjectRef,
|
|
key: Value,
|
|
value: Value,
|
|
) -> Result<(), VmError> {
|
|
self.objects.dict_set(dictionary, key, value)
|
|
}
|
|
|
|
pub fn dict_delete(&mut self, dictionary: ObjectRef, key: &Value) -> Result<bool, VmError> {
|
|
self.objects.dict_delete(dictionary, key)
|
|
}
|
|
|
|
pub fn dict_clear(&mut self, dictionary: ObjectRef) -> Result<(), VmError> {
|
|
self.objects.dict_clear(dictionary)
|
|
}
|
|
|
|
pub fn new_cell(&mut self, value: Option<Value>) -> Result<ObjectRef, VmError> {
|
|
self.objects.new_cell(value)
|
|
}
|
|
|
|
/// Reads a borrowed value; an empty cell is not Value::Nil.
|
|
pub fn cell_get(&self, cell: ObjectRef) -> Result<Value, VmError> {
|
|
self.objects.cell_get(cell)
|
|
}
|
|
|
|
pub fn cell_set(&mut self, cell: ObjectRef, value: Value) -> Result<(), VmError> {
|
|
self.objects.cell_set(cell, value)
|
|
}
|
|
|
|
pub fn cell_clear(&mut self, cell: ObjectRef) -> Result<(), VmError> {
|
|
self.objects.cell_clear(cell)
|
|
}
|
|
}
|