#![allow(missing_docs)]
use crate::ast::{CaseLambdaClause, Expr, Formals, Literal};
use crate::diagnostics::{Span, Spanned};
use crate::effects::Effect;
use crate::utils::SymbolId;
use std::collections::HashMap;
use std::fmt;
use std::sync::{Arc, RwLock};
use std::rc::Rc;
pub type Generation = u64;
#[derive(Debug, Clone)]
pub enum Value {
Literal(Literal),
Symbol(SymbolId),
Keyword(String),
Nil,
Unspecified,
Pair(Arc<Value>, Arc<Value>),
MutablePair(Arc<RwLock<Value>>, Arc<RwLock<Value>>),
Vector(Arc<RwLock<Vec<Value>>>),
Hashtable(Arc<RwLock<HashMap<Value, Value>>>),
MutableString(Arc<RwLock<Vec<char>>>),
AdvancedHashTable(Arc<crate::containers::ThreadSafeHashTable>),
Ideque(Arc<crate::containers::PersistentIdeque>),
PriorityQueue(Arc<crate::containers::ThreadSafePriorityQueue>),
OrderedSet(Arc<crate::containers::ThreadSafeOrderedSet>),
ListQueue(Arc<crate::containers::ThreadSafeListQueue>),
RandomAccessList(Arc<crate::containers::ThreadSafeRandomAccessList>),
Set(Arc<crate::containers::ThreadSafeSet>),
Bag(Arc<crate::containers::ThreadSafeBag>),
Generator(Arc<crate::containers::ThreadSafeGenerator>),
Procedure(Arc<Procedure>),
CaseLambda(Arc<CaseLambdaProcedure>),
Primitive(Arc<PrimitiveProcedure>),
Continuation(Arc<Continuation>),
Syntax(Arc<SyntaxTransformer>),
Port(Arc<Port>),
Promise(Arc<RwLock<Promise>>),
Type(Arc<TypeValue>),
Foreign(Arc<ForeignObject>),
ErrorObject(Arc<crate::stdlib::exceptions::ErrorObject>),
CharSet(Arc<crate::stdlib::charset::CharSet>),
Parameter(Arc<Parameter>),
Record(Arc<Record>),
#[cfg(feature = "async-runtime")]
Future(Arc<crate::concurrency::futures::Future>),
#[cfg(feature = "async-runtime")]
Channel(Arc<crate::concurrency::channels::Channel>),
#[cfg(feature = "async-runtime")]
Mutex(Arc<crate::concurrency::Mutex>),
#[cfg(feature = "async-runtime")]
Semaphore(Arc<crate::concurrency::SemaphoreSync>),
#[cfg(feature = "async-runtime")]
AtomicCounter(Arc<crate::concurrency::AtomicCounter>),
#[cfg(feature = "async-runtime")]
DistributedNode(Arc<crate::concurrency::distributed::DistributedNode>),
Opaque(Arc<dyn std::any::Any + Send + Sync>),
}
#[derive(Debug, Clone)]
pub struct Procedure {
pub formals: Formals,
pub body: Vec<Spanned<Expr>>,
pub environment: Arc<ThreadSafeEnvironment>,
pub name: Option<String>,
pub metadata: HashMap<String, Value>,
pub source: Option<Span>,
}
#[derive(Debug, Clone)]
pub struct CaseLambdaProcedure {
pub clauses: Vec<CaseLambdaClause>,
pub environment: Arc<ThreadSafeEnvironment>,
pub name: Option<String>,
pub metadata: HashMap<String, Value>,
pub source: Option<Span>,
}
#[derive(Debug, Clone)]
pub struct PrimitiveProcedure {
pub name: String,
pub arity_min: usize,
pub arity_max: Option<usize>,
pub implementation: PrimitiveImpl,
pub effects: Vec<Effect>,
}
#[derive(Debug, Clone)]
pub enum PrimitiveImpl {
RustFn(fn(&[Value]) -> crate::diagnostics::Result<Value>),
Native(fn(&[Value]) -> crate::diagnostics::Result<Value>),
EvaluatorIntegrated(fn(&mut crate::eval::evaluator::Evaluator, &[Value]) -> crate::diagnostics::Result<Value>),
ForeignFn {
library: String,
symbol: String,
},
}
#[derive(Debug, Clone)]
pub struct Continuation {
pub stack: Vec<Frame>,
pub environment: Arc<ThreadSafeEnvironment>,
pub id: u64,
pub current_expr: Option<Spanned<Expr>>,
pub invoked: Arc<std::sync::atomic::AtomicBool>,
}
#[derive(Debug, Clone)]
pub enum Frame {
Application {
operator: Value,
evaluated_args: Vec<Value>,
remaining_args: Vec<Spanned<Expr>>,
environment: Arc<ThreadSafeEnvironment>,
source: Span,
},
If {
consequent: Spanned<Expr>,
alternative: Box<Option<Spanned<Expr>>>,
environment: Arc<ThreadSafeEnvironment>,
source: Span,
},
Set {
name: String,
environment: Arc<ThreadSafeEnvironment>,
source: Span,
},
Begin {
remaining_exprs: Vec<Spanned<Expr>>,
environment: Arc<ThreadSafeEnvironment>,
source: Span,
},
Let {
remaining_bindings: Vec<crate::ast::Binding>,
evaluated_bindings: Vec<(String, Value)>,
body: Vec<Spanned<Expr>>,
environment: Arc<ThreadSafeEnvironment>,
source: Span,
},
ProcedureCall {
procedure_name: Option<String>,
remaining_body: Vec<Spanned<Expr>>,
environment: Arc<ThreadSafeEnvironment>,
source: Span,
},
CallCC {
environment: Arc<ThreadSafeEnvironment>,
source: Span,
},
}
#[derive(Debug, Clone)]
pub struct SyntaxTransformer {
pub name: String,
pub transformer: Value,
pub environment: Arc<ThreadSafeEnvironment>,
}
#[derive(Debug, Clone)]
pub struct Port {
pub implementation: PortImpl,
pub is_open: Arc<RwLock<bool>>,
pub mode: PortMode,
pub direction: PortDirection,
pub buffer: Arc<RwLock<Vec<u8>>>,
pub position: Arc<RwLock<usize>>,
pub metadata: HashMap<String, Value>,
}
#[derive(Debug, Clone)]
pub enum PortImpl {
String {
content: Arc<RwLock<String>>,
position: Arc<RwLock<usize>>,
},
Bytevector {
content: Arc<RwLock<Vec<u8>>>,
position: Arc<RwLock<usize>>,
},
File {
path: String,
handle: Arc<RwLock<Option<PortFileHandle>>>,
},
Standard(StandardPort),
}
#[derive(Debug, Clone)]
pub enum StandardPort {
Stdin,
Stdout,
Stderr,
}
#[derive(Debug)]
pub enum PortFileHandle {
TextReader(std::io::BufReader<std::fs::File>),
TextWriter(std::io::BufWriter<std::fs::File>),
BinaryReader(std::io::BufReader<std::fs::File>),
BinaryWriter(std::io::BufWriter<std::fs::File>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum PortMode {
Textual,
Binary,
}
#[derive(Debug, Clone, PartialEq)]
pub enum PortDirection {
Input,
Output,
InputOutput,
}
impl Port {
pub fn new_string_input(content: String) -> Self {
Port {
implementation: PortImpl::String {
content: Arc::new(RwLock::new(content)),
position: Arc::new(RwLock::new(0)),
},
is_open: Arc::new(RwLock::new(true)),
mode: PortMode::Textual,
direction: PortDirection::Input,
buffer: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
metadata: HashMap::new(),
}
}
pub fn new_string_output() -> Self {
Port {
implementation: PortImpl::String {
content: Arc::new(RwLock::new(String::new())),
position: Arc::new(RwLock::new(0)),
},
is_open: Arc::new(RwLock::new(true)),
mode: PortMode::Textual,
direction: PortDirection::Output,
buffer: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
metadata: HashMap::new(),
}
}
pub fn new_bytevector_input(content: Vec<u8>) -> Self {
Port {
implementation: PortImpl::Bytevector {
content: Arc::new(RwLock::new(content)),
position: Arc::new(RwLock::new(0)),
},
is_open: Arc::new(RwLock::new(true)),
mode: PortMode::Binary,
direction: PortDirection::Input,
buffer: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
metadata: HashMap::new(),
}
}
pub fn new_bytevector_output() -> Self {
Port {
implementation: PortImpl::Bytevector {
content: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
},
is_open: Arc::new(RwLock::new(true)),
mode: PortMode::Binary,
direction: PortDirection::Output,
buffer: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
metadata: HashMap::new(),
}
}
pub fn new_file_input(path: String, binary: bool) -> Self {
Port {
implementation: PortImpl::File {
path,
handle: Arc::new(RwLock::new(None)),
},
is_open: Arc::new(RwLock::new(true)),
mode: if binary { PortMode::Binary } else { PortMode::Textual },
direction: PortDirection::Input,
buffer: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
metadata: HashMap::new(),
}
}
pub fn new_file_output(path: String, binary: bool) -> Self {
Port {
implementation: PortImpl::File {
path,
handle: Arc::new(RwLock::new(None)),
},
is_open: Arc::new(RwLock::new(true)),
mode: if binary { PortMode::Binary } else { PortMode::Textual },
direction: PortDirection::Output,
buffer: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
metadata: HashMap::new(),
}
}
pub fn new_standard(port_type: StandardPort) -> Self {
let direction = match port_type {
StandardPort::Stdin => PortDirection::Input,
StandardPort::Stdout | StandardPort::Stderr => PortDirection::Output,
};
Port {
implementation: PortImpl::Standard(port_type),
is_open: Arc::new(RwLock::new(true)),
mode: PortMode::Textual,
direction,
buffer: Arc::new(RwLock::new(Vec::new())),
position: Arc::new(RwLock::new(0)),
metadata: HashMap::new(),
}
}
pub fn is_open(&self) -> bool {
*self.is_open.read().unwrap()
}
pub fn close(&self) {
*self.is_open.write().unwrap() = false;
}
pub fn is_textual(&self) -> bool {
self.mode == PortMode::Textual
}
pub fn is_binary(&self) -> bool {
self.mode == PortMode::Binary
}
pub fn is_input(&self) -> bool {
matches!(self.direction, PortDirection::Input | PortDirection::InputOutput)
}
pub fn is_output(&self) -> bool {
matches!(self.direction, PortDirection::Output | PortDirection::InputOutput)
}
}
#[derive(Debug, Clone)]
pub enum Promise {
Delayed {
thunk: Value,
},
Forced(Value),
TailRecursive {
thunk: Value,
},
Expression {
expression: Spanned<Expr>,
environment: Arc<ThreadSafeEnvironment>,
},
}
#[derive(Debug, Clone)]
pub enum PromiseTrampoline {
Continue(Arc<RwLock<Promise>>),
Done(Value),
ComputeThunk {
thunk: Value,
promise_ref: Arc<RwLock<Promise>>,
},
}
#[derive(Debug, Clone)]
pub enum TypeValue {
Base(String),
Function {
parameter_types: Vec<TypeValue>,
return_type: Box<TypeValue>,
},
Union(Vec<TypeValue>),
Intersection(Vec<TypeValue>),
Variable(String),
}
#[derive(Debug, Clone)]
pub struct ForeignObject {
pub type_name: String,
pub data: *mut std::ffi::c_void,
pub destructor: Option<fn(*mut std::ffi::c_void)>,
}
#[derive(Debug, Clone)]
pub struct Parameter {
pub id: u64,
pub converter: Option<Arc<Value>>,
pub global_default: Arc<RwLock<Value>>,
pub name: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct RecordType {
pub id: u64,
pub name: String,
pub field_names: Vec<String>,
pub constructor_name: Option<String>,
pub predicate_name: Option<String>,
pub field_info: Vec<FieldInfo>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FieldInfo {
pub name: String,
pub accessor: String,
pub mutator: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Record {
pub type_id: u64,
pub fields: Arc<RwLock<Vec<Value>>>,
}
#[derive(Debug, Clone)]
pub struct ThreadSafeEnvironment {
bindings: std::sync::Arc<std::sync::RwLock<HashMap<String, Value>>>,
parent: Option<Arc<ThreadSafeEnvironment>>,
generation: Generation,
name: Option<String>,
}
#[derive(Debug, Clone)]
pub struct Environment {
pub bindings: Rc<std::cell::RefCell<HashMap<String, Value>>>,
pub parent: Option<Rc<Environment>>,
pub generation: Generation,
pub name: Option<String>,
}
impl Value {
pub fn is_truthy(&self) -> bool {
!matches!(self, Value::Literal(Literal::Boolean(false)))
}
pub fn is_falsy(&self) -> bool {
matches!(self, Value::Literal(Literal::Boolean(false)))
}
pub fn is_number(&self) -> bool {
matches!(self, Value::Literal(lit) if lit.is_number())
}
pub fn display_string(&self) -> String {
match self {
Value::Literal(Literal::String(s)) => s.clone(),
Value::Literal(Literal::Character(c)) => c.to_string(),
_ => format!("{self}"),
}
}
pub fn is_string(&self) -> bool {
matches!(self, Value::Literal(Literal::String(_)) | Value::MutableString(_))
}
pub fn is_immutable_string(&self) -> bool {
matches!(self, Value::Literal(Literal::String(_)))
}
pub fn is_mutable_string(&self) -> bool {
matches!(self, Value::MutableString(_))
}
pub fn is_symbol(&self) -> bool {
matches!(self, Value::Symbol(_))
}
pub fn is_pair(&self) -> bool {
matches!(self, Value::Pair(_, _) | Value::MutablePair(_, _))
}
pub fn is_nil(&self) -> bool {
matches!(self, Value::Nil)
}
pub fn is_list(&self) -> bool {
self.is_nil() || self.is_pair()
}
pub fn is_procedure(&self) -> bool {
matches!(
self,
Value::Procedure(_) | Value::CaseLambda(_) | Value::Primitive(_) | Value::Continuation(_) | Value::Parameter(_)
)
}
pub fn is_vector(&self) -> bool {
matches!(self, Value::Vector(_))
}
pub fn is_port(&self) -> bool {
matches!(self, Value::Port(_))
}
pub fn is_charset(&self) -> bool {
matches!(self, Value::CharSet(_))
}
pub fn is_parameter(&self) -> bool {
matches!(self, Value::Parameter(_))
}
pub fn is_record(&self) -> bool {
matches!(self, Value::Record(_))
}
pub fn as_number(&self) -> Option<f64> {
match self {
Value::Literal(lit) => lit.to_f64(),
_ => None,
}
}
pub fn as_integer(&self) -> Option<i64> {
match self {
Value::Literal(lit) => lit.to_i64(),
_ => None,
}
}
pub fn as_string(&self) -> Option<&str> {
match self {
Value::Literal(Literal::String(s)) => Some(s),
_ => None,
}
}
pub fn as_string_owned(&self) -> Option<String> {
match self {
Value::Literal(Literal::String(s)) => Some(s.clone()),
Value::MutableString(chars) => {
chars.read().ok().map(|guard| guard.iter().collect())
}
_ => None,
}
}
pub fn string_length(&self) -> Option<usize> {
match self {
Value::Literal(Literal::String(s)) => Some(s.chars().count()),
Value::MutableString(chars) => {
chars.read().ok().map(|guard| guard.len())
}
_ => None,
}
}
pub fn as_symbol(&self) -> Option<SymbolId> {
match self {
Value::Symbol(id) => Some(*id),
_ => None,
}
}
pub fn as_list(&self) -> Option<Vec<Value>> {
let mut result = Vec::new();
let mut current = self;
loop {
match current {
Value::Nil => return Some(result),
Value::Pair(car, cdr) => {
result.push((**car).clone());
current = cdr;
}
Value::MutablePair(car_ref, cdr_ref) => {
if let (Ok(car), Ok(cdr)) = (car_ref.read(), cdr_ref.read()) {
result.push(car.clone());
let cdr_clone = cdr.clone();
drop(cdr); if let Some(mut rest) = cdr_clone.as_list() {
result.append(&mut rest);
return Some(result);
} else {
return None; }
} else {
return None; }
}
_ => return None, }
}
}
pub fn number(n: f64) -> Self {
Value::Literal(Literal::from_f64(n))
}
pub fn integer(n: i64) -> Self {
Value::Literal(Literal::integer(n))
}
pub fn string(s: impl Into<String>) -> Self {
Value::Literal(Literal::String(s.into()))
}
pub fn mutable_string(s: impl Into<String>) -> Self {
let chars: Vec<char> = s.into().chars().collect();
Value::MutableString(Arc::new(RwLock::new(chars)))
}
pub fn mutable_string_filled(length: usize, ch: char) -> Self {
let chars = vec![ch; length];
Value::MutableString(Arc::new(RwLock::new(chars)))
}
pub fn boolean(b: bool) -> Self {
Value::Literal(Literal::Boolean(b))
}
pub fn symbol(id: SymbolId) -> Self {
Value::Symbol(id)
}
pub fn symbol_from_str(name: impl Into<String>) -> Self {
let name_str = name.into();
let id = SymbolId::new(name_str.chars()
.fold(0, |acc, c| acc.wrapping_mul(31).wrapping_add(c as usize)));
Value::Symbol(id)
}
pub fn pair(car: Value, cdr: Value) -> Self {
Value::Pair(Arc::new(car), Arc::new(cdr))
}
pub fn mutable_pair(car: Value, cdr: Value) -> Self {
Value::MutablePair(Arc::new(RwLock::new(car)), Arc::new(RwLock::new(cdr)))
}
pub fn list(values: Vec<Value>) -> Self {
values.into_iter().rev().fold(Value::Nil, |acc, val| {
Value::pair(val, acc)
})
}
pub fn vector(values: Vec<Value>) -> Self {
Value::Vector(Arc::new(RwLock::new(values)))
}
pub fn from_vec(values: Vec<Value>) -> Self {
Self::vector(values)
}
pub fn bytevector(bytes: Vec<u8>) -> Self {
Value::Literal(Literal::Bytevector(bytes))
}
pub fn charset(charset: crate::stdlib::charset::CharSet) -> Self {
Value::CharSet(Arc::new(charset))
}
pub fn parameter(parameter: Parameter) -> Self {
Value::Parameter(Arc::new(parameter))
}
pub fn case_lambda(case_lambda: CaseLambdaProcedure) -> Self {
Value::CaseLambda(Arc::new(case_lambda))
}
pub fn opaque<T: std::any::Any + Send + Sync>(value: T) -> Self {
Value::Opaque(Arc::new(value))
}
pub fn record(record: Record) -> Self {
Value::Record(Arc::new(record))
}
pub fn from_literal(lit: Literal) -> Self {
Value::Literal(lit)
}
pub fn procedure(proc: Procedure) -> Self {
Value::Procedure(Arc::new(proc))
}
pub fn t() -> Self {
Value::boolean(true)
}
pub fn f() -> Self {
Value::boolean(false)
}
pub fn error_object(error: crate::stdlib::exceptions::ErrorObject) -> Self {
Value::ErrorObject(Arc::new(error))
}
pub fn exception_object(exception: crate::stdlib::exceptions::ExceptionObject) -> Self {
exception.value
}
pub fn advanced_hash_table() -> Self {
Value::AdvancedHashTable(Arc::new(crate::containers::ThreadSafeHashTable::new()))
}
pub fn advanced_hash_table_with_comparator(comparator: crate::containers::HashComparator) -> Self {
Value::AdvancedHashTable(Arc::new(crate::containers::ThreadSafeHashTable::with_comparator(comparator)))
}
pub fn ideque() -> Self {
Value::Ideque(Arc::new(crate::containers::PersistentIdeque::new()))
}
pub fn ideque_from_vec(values: Vec<Value>) -> Self {
Value::Ideque(Arc::new(crate::containers::PersistentIdeque::from_vec(values)))
}
pub fn priority_queue() -> Self {
Value::PriorityQueue(Arc::new(crate::containers::ThreadSafePriorityQueue::new()))
}
pub fn min_priority_queue() -> Self {
Value::PriorityQueue(Arc::new(crate::containers::ThreadSafePriorityQueue::new_min_heap()))
}
pub fn priority_queue_with_comparator(comparator: crate::containers::Comparator) -> Self {
Value::PriorityQueue(Arc::new(crate::containers::ThreadSafePriorityQueue::with_comparator(comparator)))
}
pub fn ordered_set() -> Self {
Value::OrderedSet(Arc::new(crate::containers::ThreadSafeOrderedSet::new()))
}
pub fn ordered_set_with_comparator(comparator: crate::containers::Comparator) -> Self {
Value::OrderedSet(Arc::new(crate::containers::ThreadSafeOrderedSet::with_comparator(comparator)))
}
pub fn list_queue() -> Self {
Value::ListQueue(Arc::new(crate::containers::ThreadSafeListQueue::new()))
}
pub fn list_queue_from_vec(values: Vec<Value>) -> Self {
Value::ListQueue(Arc::new(crate::containers::ThreadSafeListQueue::from_vec(values)))
}
pub fn random_access_list() -> Self {
Value::RandomAccessList(Arc::new(crate::containers::ThreadSafeRandomAccessList::new()))
}
pub fn random_access_list_from_vec(values: Vec<Value>) -> Self {
Value::RandomAccessList(Arc::new(crate::containers::ThreadSafeRandomAccessList::from_vec(values)))
}
pub fn set() -> Self {
Value::Set(Arc::new(crate::containers::ThreadSafeSet::new()))
}
pub fn set_with_comparator(comparator: crate::containers::HashComparator) -> Self {
Value::Set(Arc::new(crate::containers::ThreadSafeSet::with_comparator(comparator)))
}
pub fn set_from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = Value>,
{
Value::Set(Arc::new(crate::containers::ThreadSafeSet::from_iter(iter)))
}
pub fn set_from_iter_with_comparator<I>(iter: I, comparator: crate::containers::HashComparator) -> Self
where
I: IntoIterator<Item = Value>,
{
Value::Set(Arc::new(crate::containers::ThreadSafeSet::from_iter_with_comparator(iter, comparator)))
}
pub fn as_set(&self) -> Option<&Arc<crate::containers::ThreadSafeSet>> {
match self {
Value::Set(set) => Some(set),
_ => None,
}
}
pub fn to_set(&self) -> Option<Arc<crate::containers::ThreadSafeSet>> {
match self {
Value::Set(set) => Some(set.clone()),
_ => None,
}
}
pub fn bag() -> Self {
Value::Bag(Arc::new(crate::containers::ThreadSafeBag::new()))
}
pub fn bag_with_comparator(comparator: crate::containers::HashComparator) -> Self {
Value::Bag(Arc::new(crate::containers::ThreadSafeBag::with_comparator(comparator)))
}
pub fn bag_from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = Value>,
{
Value::Bag(Arc::new(crate::containers::ThreadSafeBag::from_iter(iter)))
}
pub fn generator_from_procedure(thunk: Value, environment: Arc<ThreadSafeEnvironment>) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::from_procedure(thunk, environment)))
}
pub fn generator_from_procedure_with_evaluator(
thunk: Value,
environment: Arc<ThreadSafeEnvironment>,
evaluator: Arc<crate::containers::generator::ProcedureEvaluator>
) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::from_procedure_with_evaluator(thunk, environment, evaluator)))
}
pub fn generator_from_values(values: Vec<Value>) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::from_values(values)))
}
pub fn generator_range(start: f64, end: Option<f64>, step: f64) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::range(start, end, step)))
}
pub fn generator_iota(count: Option<usize>, start: i64, step: i64) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::iota(count, start, step)))
}
pub fn generator_from_list(list: Value) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::from_list(list)))
}
pub fn generator_from_vector(vector: Arc<RwLock<Vec<Value>>>) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::from_vector(vector)))
}
pub fn generator_from_string(string: String) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::from_string(string)))
}
pub fn generator_exhausted() -> Self {
Value::Generator(Arc::new(crate::containers::Generator::exhausted()))
}
pub fn generator_unfold(
stop_predicate: Value,
mapper: Value,
successor: Value,
seed: Value,
) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::unfold(stop_predicate, mapper, successor, seed)))
}
pub fn generator_unfold_with_evaluator(
stop_predicate: Value,
mapper: Value,
successor: Value,
seed: Value,
evaluator: Arc<crate::containers::generator::ProcedureEvaluator>,
) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::unfold_with_evaluator(stop_predicate, mapper, successor, seed, evaluator)))
}
pub fn generator_tabulate(func: Value, max_count: Option<usize>) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::tabulate(func, max_count)))
}
pub fn generator_tabulate_with_evaluator(
func: Value,
max_count: Option<usize>,
evaluator: Arc<crate::containers::generator::ProcedureEvaluator>,
) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::tabulate_with_evaluator(func, max_count, evaluator)))
}
pub fn generator_map(source: Arc<crate::containers::Generator>, mapper: Value) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::map(source, mapper)))
}
pub fn generator_map_with_evaluator(
source: Arc<crate::containers::Generator>,
mapper: Value,
evaluator: Arc<crate::containers::generator::ProcedureEvaluator>,
) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::map_with_evaluator(source, mapper, evaluator)))
}
pub fn generator_filter(source: Arc<crate::containers::Generator>, predicate: Value) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::filter(source, predicate)))
}
pub fn generator_filter_with_evaluator(
source: Arc<crate::containers::Generator>,
predicate: Value,
evaluator: Arc<crate::containers::generator::ProcedureEvaluator>,
) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::filter_with_evaluator(source, predicate, evaluator)))
}
pub fn generator_take(source: Arc<crate::containers::Generator>, count: usize) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::take(source, count)))
}
pub fn generator_drop(source: Arc<crate::containers::Generator>, count: usize) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::drop(source, count)))
}
pub fn generator_append(first: Arc<crate::containers::Generator>, second: Arc<crate::containers::Generator>) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::append(first, second)))
}
pub fn generator_concatenate(generators: Vec<Arc<crate::containers::Generator>>) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::concatenate(generators)))
}
pub fn generator_zip(sources: Vec<Arc<crate::containers::Generator>>) -> Self {
Value::Generator(Arc::new(crate::containers::Generator::zip(sources)))
}
pub fn is_advanced_hash_table(&self) -> bool {
matches!(self, Value::AdvancedHashTable(_))
}
pub fn is_ideque(&self) -> bool {
matches!(self, Value::Ideque(_))
}
pub fn is_priority_queue(&self) -> bool {
matches!(self, Value::PriorityQueue(_))
}
pub fn is_ordered_set(&self) -> bool {
matches!(self, Value::OrderedSet(_))
}
pub fn is_list_queue(&self) -> bool {
matches!(self, Value::ListQueue(_))
}
pub fn is_random_access_list(&self) -> bool {
matches!(self, Value::RandomAccessList(_))
}
pub fn is_set(&self) -> bool {
matches!(self, Value::Set(_))
}
pub fn is_bag(&self) -> bool {
matches!(self, Value::Bag(_))
}
pub fn is_generator(&self) -> bool {
matches!(self, Value::Generator(_))
}
#[cfg(feature = "async-runtime")]
pub fn is_future(&self) -> bool {
matches!(self, Value::Future(_))
}
#[cfg(not(feature = "async-runtime"))]
pub fn is_future(&self) -> bool {
false
}
#[cfg(feature = "async-runtime")]
pub fn is_channel(&self) -> bool {
matches!(self, Value::Channel(_))
}
#[cfg(not(feature = "async-runtime"))]
pub fn is_channel(&self) -> bool {
false
}
#[cfg(feature = "async-runtime")]
pub fn is_mutex(&self) -> bool {
matches!(self, Value::Mutex(_))
}
#[cfg(not(feature = "async-runtime"))]
pub fn is_mutex(&self) -> bool {
false
}
#[cfg(feature = "async-runtime")]
pub fn is_semaphore(&self) -> bool {
matches!(self, Value::Semaphore(_))
}
#[cfg(not(feature = "async-runtime"))]
pub fn is_semaphore(&self) -> bool {
false
}
#[cfg(feature = "async-runtime")]
pub fn is_atomic_counter(&self) -> bool {
matches!(self, Value::AtomicCounter(_))
}
#[cfg(not(feature = "async-runtime"))]
pub fn is_atomic_counter(&self) -> bool {
false
}
#[cfg(feature = "async-runtime")]
pub fn is_distributed_node(&self) -> bool {
matches!(self, Value::DistributedNode(_))
}
#[cfg(not(feature = "async-runtime"))]
pub fn is_distributed_node(&self) -> bool {
false
}
pub fn is_opaque(&self) -> bool {
matches!(self, Value::Opaque(_))
}
pub fn car(&self) -> Option<&Value> {
match self {
Value::Pair(car, _) => Some(car.as_ref()),
_ => None,
}
}
pub fn cdr(&self) -> Option<&Value> {
match self {
Value::Pair(_, cdr) => Some(cdr.as_ref()),
_ => None,
}
}
pub fn is_exact_number(&self) -> bool {
match self {
Value::Literal(lit) => lit.is_exact(),
_ => false,
}
}
pub fn is_inexact_number(&self) -> bool {
match self {
Value::Literal(lit) => lit.is_inexact(),
_ => false,
}
}
pub fn is_finite_number(&self) -> bool {
match self {
Value::Literal(Literal::ExactInteger(_)) => true,
Value::Literal(Literal::InexactReal(f)) => f.is_finite(),
Value::Literal(Literal::Rational { .. }) => true,
Value::Literal(Literal::Complex { real, imaginary }) => {
real.is_finite() && imaginary.is_finite()
}
_ => false,
}
}
pub fn is_infinite_number(&self) -> bool {
match self {
Value::Literal(Literal::InexactReal(f)) => f.is_infinite(),
Value::Literal(Literal::Complex { real, imaginary }) => {
real.is_infinite() || imaginary.is_infinite()
}
_ => false,
}
}
pub fn is_nan_number(&self) -> bool {
match self {
Value::Literal(Literal::InexactReal(f)) => f.is_nan(),
Value::Literal(Literal::Complex { real, imaginary }) => {
real.is_nan() || imaginary.is_nan()
}
_ => false,
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Literal(a), Value::Literal(b)) => a == b,
(Value::Symbol(a), Value::Symbol(b)) => a == b,
(Value::Keyword(a), Value::Keyword(b)) => a == b,
(Value::Nil, Value::Nil) => true,
(Value::Unspecified, Value::Unspecified) => true,
(Value::Pair(a1, b1), Value::Pair(a2, b2)) => a1 == a2 && b1 == b2,
(Value::Vector(a), Value::Vector(b)) => Arc::ptr_eq(a, b),
(Value::Hashtable(a), Value::Hashtable(b)) => Arc::ptr_eq(a, b),
(Value::Procedure(a), Value::Procedure(b)) => Arc::ptr_eq(a, b),
(Value::CaseLambda(a), Value::CaseLambda(b)) => Arc::ptr_eq(a, b),
(Value::Primitive(a), Value::Primitive(b)) => a.name == b.name,
(Value::Continuation(a), Value::Continuation(b)) => a.id == b.id,
(Value::ErrorObject(a), Value::ErrorObject(b)) => Arc::ptr_eq(a, b),
(Value::CharSet(a), Value::CharSet(b)) => a == b,
(Value::Parameter(a), Value::Parameter(b)) => a.id == b.id,
(Value::Record(a), Value::Record(b)) => {
if a.type_id != b.type_id {
false
} else {
if let (Ok(a_fields), Ok(b_fields)) = (a.fields.read(), b.fields.read()) {
*a_fields == *b_fields
} else {
false }
}
}
(Value::AdvancedHashTable(a), Value::AdvancedHashTable(b)) => Arc::ptr_eq(a, b),
(Value::Ideque(a), Value::Ideque(b)) => Arc::ptr_eq(a, b),
(Value::PriorityQueue(a), Value::PriorityQueue(b)) => Arc::ptr_eq(a, b),
(Value::OrderedSet(a), Value::OrderedSet(b)) => Arc::ptr_eq(a, b),
(Value::ListQueue(a), Value::ListQueue(b)) => Arc::ptr_eq(a, b),
(Value::RandomAccessList(a), Value::RandomAccessList(b)) => Arc::ptr_eq(a, b),
(Value::Set(a), Value::Set(b)) => Arc::ptr_eq(a, b),
(Value::Bag(a), Value::Bag(b)) => Arc::ptr_eq(a, b),
(Value::Generator(a), Value::Generator(b)) => Arc::ptr_eq(a, b),
#[cfg(feature = "async-runtime")]
(Value::Future(a), Value::Future(b)) => Arc::ptr_eq(a, b),
#[cfg(feature = "async-runtime")]
(Value::Channel(a), Value::Channel(b)) => Arc::ptr_eq(a, b),
#[cfg(feature = "async-runtime")]
(Value::Mutex(a), Value::Mutex(b)) => Arc::ptr_eq(a, b),
#[cfg(feature = "async-runtime")]
(Value::Semaphore(a), Value::Semaphore(b)) => Arc::ptr_eq(a, b),
#[cfg(feature = "async-runtime")]
(Value::AtomicCounter(a), Value::AtomicCounter(b)) => Arc::ptr_eq(a, b),
#[cfg(feature = "async-runtime")]
(Value::DistributedNode(a), Value::DistributedNode(b)) => Arc::ptr_eq(a, b),
(Value::Opaque(a), Value::Opaque(b)) => Arc::ptr_eq(a, b),
_ => false,
}
}
}
impl Eq for Value {}
impl std::hash::Hash for Value {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Value::Literal(lit) => {
0u8.hash(state);
lit.hash(state);
}
Value::Symbol(id) => {
1u8.hash(state);
id.hash(state);
}
Value::Keyword(k) => {
2u8.hash(state);
k.hash(state);
}
Value::Nil => 3u8.hash(state),
Value::Unspecified => 4u8.hash(state),
_ => std::mem::discriminant(self).hash(state),
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Value::Literal(lit) => write!(f, "{lit}"),
Value::Symbol(id) => {
if let Some(name) = crate::utils::symbol_name(*id) {
write!(f, "{name}")
} else {
write!(f, "#<symbol:{}>", id.id())
}
}
Value::Keyword(k) => write!(f, "#{k}"),
Value::Nil => write!(f, "()"),
Value::Unspecified => write!(f, "#<unspecified>"),
Value::Pair(_car, _cdr) => {
write!(f, "(")?;
self.write_list_contents(f, true)?;
write!(f, ")")
}
Value::MutablePair(_car, _cdr) => {
write!(f, "(")?;
self.write_mutable_list_contents(f, true)?;
write!(f, ")")
}
Value::Vector(vec) => {
write!(f, "#(")?;
if let Ok(vec_ref) = vec.read() {
for (i, value) in vec_ref.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
write!(f, "{value}")?;
}
} else {
write!(f, "...")?; }
write!(f, ")")
}
Value::Hashtable(_) => write!(f, "#<hashtable>"),
Value::Procedure(proc) => {
if let Some(name) = &proc.name {
write!(f, "#<procedure:{name}>")
} else {
write!(f, "#<procedure>")
}
}
Value::CaseLambda(case_lambda) => {
if let Some(name) = &case_lambda.name {
write!(f, "#<case-lambda:{name}>")
} else {
write!(f, "#<case-lambda>")
}
}
Value::Primitive(prim) => write!(f, "#<primitive:{}>", prim.name),
Value::Continuation(cont) => write!(f, "#<continuation:{}>", cont.id),
Value::Syntax(syn) => write!(f, "#<syntax:{}>", syn.name),
Value::Port(_) => write!(f, "#<port>"),
Value::Promise(_) => write!(f, "#<promise>"),
Value::Type(_) => write!(f, "#<type>"),
Value::Foreign(obj) => write!(f, "#<foreign:{}>", obj.type_name),
Value::ErrorObject(err) => write!(f, "#<error:{}>", err.message),
Value::CharSet(charset) => write!(f, "{charset}"),
Value::Parameter(param) => {
if let Some(name) = ¶m.name {
write!(f, "#<parameter:{name}>")
} else {
write!(f, "#<parameter:{}>", param.id)
}
}
Value::Record(record) => {
write!(f, "#<record:{}>", record.type_id)
}
Value::AdvancedHashTable(_) => write!(f, "#<advanced-hash-table>"),
Value::Ideque(_) => write!(f, "#<ideque>"),
Value::PriorityQueue(_) => write!(f, "#<priority-queue>"),
Value::OrderedSet(_) => write!(f, "#<ordered-set>"),
Value::ListQueue(_) => write!(f, "#<list-queue>"),
Value::RandomAccessList(_) => write!(f, "#<random-access-list>"),
#[cfg(feature = "async-runtime")]
Value::Future(_) => write!(f, "#<future>"),
#[cfg(feature = "async-runtime")]
Value::Channel(_) => write!(f, "#<channel>"),
#[cfg(feature = "async-runtime")]
Value::Mutex(_) => write!(f, "#<mutex>"),
#[cfg(feature = "async-runtime")]
Value::Semaphore(_) => write!(f, "#<semaphore>"),
#[cfg(feature = "async-runtime")]
Value::AtomicCounter(counter) => write!(f, "#<atomic-counter:{}>", counter.get()),
#[cfg(feature = "async-runtime")]
Value::DistributedNode(_) => write!(f, "#<distributed-node>"),
Value::MutableString(s) => {
match s.read() {
Ok(chars) => {
write!(f, "\"")?;
for ch in chars.iter() {
match ch {
'"' => write!(f, "\\\"")?,
'\\' => write!(f, "\\\\")?,
'\n' => write!(f, "\\n")?,
'\t' => write!(f, "\\t")?,
'\r' => write!(f, "\\r")?,
c if c.is_control() => write!(f, "\\x{:02x}", *c as u8)?,
c => write!(f, "{c}")?,
}
}
write!(f, "\"")
}
Err(_) => write!(f, "#<locked-string>"),
}
}
Value::Set(set) => {
match set.size() {
Ok(size) => write!(f, "#<set:{size}>"),
Err(_) => write!(f, "#<set:locked>"),
}
}
Value::Bag(bag) => {
match bag.total_size() {
Ok(size) => write!(f, "#<bag:{size}>"),
Err(_) => write!(f, "#<bag:locked>"),
}
}
Value::Generator(generator) => {
write!(f, "{generator}")
}
Value::Opaque(_) => write!(f, "#<opaque>"),
}
}
}
impl Value {
fn write_list_contents(&self, f: &mut fmt::Formatter<'_>, first: bool) -> fmt::Result {
match self {
Value::Nil => Ok(()),
Value::Pair(car, cdr) => {
if !first {
write!(f, " ")?;
}
write!(f, "{car}")?;
match &**cdr {
Value::Nil => Ok(()),
Value::Pair(_, _) => cdr.write_list_contents(f, false),
_ => write!(f, " . {cdr}"),
}
}
_ => write!(f, " . {self}"),
}
}
fn write_mutable_list_contents(&self, f: &mut fmt::Formatter<'_>, first: bool) -> fmt::Result {
match self {
Value::Nil => Ok(()),
Value::MutablePair(car_ref, cdr_ref) => {
if !first {
write!(f, " ")?;
}
if let Ok(car) = car_ref.read() {
write!(f, "{car}")?;
} else {
write!(f, "...")?;
}
if let Ok(cdr) = cdr_ref.read() {
match &*cdr {
Value::Nil => Ok(()),
Value::MutablePair(_, _) => cdr.write_mutable_list_contents(f, false),
_ => write!(f, " . {cdr}"),
}
} else {
write!(f, " . ...")?;
Ok(())
}
}
Value::Pair(car, cdr) => {
if !first {
write!(f, " ")?;
}
write!(f, "{car}")?;
match &**cdr {
Value::Nil => Ok(()),
Value::Pair(_, _) => cdr.write_list_contents(f, false),
Value::MutablePair(_, _) => cdr.write_mutable_list_contents(f, false),
_ => write!(f, " . {cdr}"),
}
}
_ => write!(f, " . {self}"),
}
}
}
impl Environment {
pub fn new(parent: Option<Rc<Environment>>, generation: Generation) -> Self {
Self {
bindings: Rc::new(std::cell::RefCell::new(HashMap::new())),
parent,
generation,
name: None,
}
}
pub fn with_name(
parent: Option<Rc<Environment>>,
generation: Generation,
name: String,
) -> Self {
Self {
bindings: Rc::new(std::cell::RefCell::new(HashMap::new())),
parent,
generation,
name: Some(name),
}
}
pub fn lookup(&self, name: &str) -> Option<Value> {
if let Some(value) = self.bindings.borrow().get(name) {
return Some(value.clone());
}
if let Some(parent) = &self.parent {
parent.lookup(name)
} else {
None
}
}
pub fn define(&self, name: String, value: Value) {
self.bindings.borrow_mut().insert(name, value);
}
pub fn set(&self, name: &str, value: Value) -> bool {
if self.bindings.borrow().contains_key(name) {
self.bindings.borrow_mut().insert(name.to_string(), value);
return true;
}
if let Some(parent) = &self.parent {
parent.set(name, value)
} else {
false
}
}
pub fn extend(&self, generation: Generation) -> Rc<Environment> {
Rc::new(Environment::new(Some(Rc::new(self.clone())), generation))
}
pub fn variable_names(&self) -> Vec<String> {
self.bindings.borrow().keys().cloned().collect()
}
pub fn to_thread_safe(&self) -> Arc<ThreadSafeEnvironment> {
let parent = self.parent.as_ref().map(|p| p.to_thread_safe());
let bindings = self.bindings.borrow().clone();
Arc::new(ThreadSafeEnvironment {
bindings: Arc::new(std::sync::RwLock::new(bindings)),
parent,
generation: self.generation,
name: self.name.clone(),
})
}
pub fn to_thread_safe_live(&self) -> Arc<ThreadSafeEnvironment> {
let parent = self.parent.as_ref().map(|p| p.to_thread_safe_live());
Arc::new(ThreadSafeEnvironment {
bindings: Arc::new(std::sync::RwLock::new(self.bindings.borrow().clone())), parent,
generation: self.generation,
name: self.name.clone(),
})
}
}
impl ThreadSafeEnvironment {
pub fn new(parent: Option<Arc<ThreadSafeEnvironment>>, generation: Generation) -> Self {
Self {
bindings: Arc::new(std::sync::RwLock::new(HashMap::new())),
parent,
generation,
name: None,
}
}
pub fn with_name(
parent: Option<Arc<ThreadSafeEnvironment>>,
generation: Generation,
name: String,
) -> Self {
Self {
bindings: Arc::new(std::sync::RwLock::new(HashMap::new())),
parent,
generation,
name: Some(name),
}
}
pub fn lookup(&self, name: &str) -> Option<Value> {
if let Some(value) = self.bindings.read().unwrap().get(name) {
return Some(value.clone());
}
if let Some(parent) = &self.parent {
parent.lookup(name)
} else {
None
}
}
pub fn define(&self, name: String, value: Value) {
self.bindings.write().unwrap().insert(name, value);
}
pub fn define_cow(&self, name: String, value: Value) -> Arc<ThreadSafeEnvironment> {
let mut new_bindings = self.bindings.read().unwrap().clone();
new_bindings.insert(name, value);
Arc::new(ThreadSafeEnvironment {
bindings: Arc::new(std::sync::RwLock::new(new_bindings)),
parent: self.parent.clone(),
generation: self.generation,
name: self.name.clone(),
})
}
pub fn set(&self, name: &str, value: Value) -> bool {
if self.bindings.read().unwrap().contains_key(name) {
self.bindings.write().unwrap().insert(name.to_string(), value);
return true;
}
if let Some(parent) = &self.parent {
parent.set(name, value)
} else {
false
}
}
pub fn set_cow(&self, name: &str, value: Value) -> Option<Arc<ThreadSafeEnvironment>> {
if self.bindings.read().unwrap().contains_key(name) {
let mut new_bindings = self.bindings.read().unwrap().clone();
new_bindings.insert(name.to_string(), value);
return Some(Arc::new(ThreadSafeEnvironment {
bindings: Arc::new(std::sync::RwLock::new(new_bindings)),
parent: self.parent.clone(),
generation: self.generation,
name: self.name.clone(),
}));
}
if let Some(parent) = &self.parent {
if let Some(new_parent) = parent.set_cow(name, value) {
return Some(Arc::new(ThreadSafeEnvironment {
bindings: self.bindings.clone(),
parent: Some(new_parent),
generation: self.generation,
name: self.name.clone(),
}));
}
}
None
}
pub fn extend(&self, generation: Generation) -> Arc<ThreadSafeEnvironment> {
Arc::new(ThreadSafeEnvironment::new(
Some(Arc::new(self.clone())),
generation,
))
}
pub fn variable_names(&self) -> Vec<String> {
self.bindings.read().unwrap().keys().cloned().collect()
}
pub fn all_variable_names(&self) -> Vec<String> {
let mut names = self.variable_names();
if let Some(parent) = &self.parent {
names.extend(parent.all_variable_names());
}
names.sort();
names.dedup();
names
}
pub fn generation(&self) -> Generation {
self.generation
}
pub fn parent(&self) -> Option<&Arc<ThreadSafeEnvironment>> {
self.parent.as_ref()
}
pub fn name(&self) -> Option<&str> {
self.name.as_deref()
}
pub fn to_legacy(&self) -> Rc<Environment> {
let legacy_parent = self.parent.as_ref().map(|p| p.to_legacy());
Rc::new(Environment {
bindings: Rc::new(std::cell::RefCell::new(self.bindings.read().unwrap().clone())),
parent: legacy_parent,
generation: self.generation,
name: self.name.clone(),
})
}
pub fn from_legacy(legacy: &Environment) -> Arc<ThreadSafeEnvironment> {
let parent = legacy.parent.as_ref().map(|p| Self::from_legacy(p));
Arc::new(ThreadSafeEnvironment {
bindings: Arc::new(std::sync::RwLock::new(legacy.bindings.borrow().clone())),
parent,
generation: legacy.generation,
name: legacy.name.clone(),
})
}
}
unsafe impl Send for ThreadSafeEnvironment {}
unsafe impl Sync for ThreadSafeEnvironment {}
unsafe impl Send for Value {}
unsafe impl Sync for Value {}
unsafe impl Send for Procedure {}
unsafe impl Sync for Procedure {}
unsafe impl Send for CaseLambdaProcedure {}
unsafe impl Sync for CaseLambdaProcedure {}
unsafe impl Send for PrimitiveProcedure {}
unsafe impl Sync for PrimitiveProcedure {}
unsafe impl Send for Continuation {}
unsafe impl Sync for Continuation {}
unsafe impl Send for Frame {}
unsafe impl Sync for Frame {}
unsafe impl Send for SyntaxTransformer {}
unsafe impl Sync for SyntaxTransformer {}
unsafe impl Send for Port {}
unsafe impl Sync for Port {}
unsafe impl Send for PortImpl {}
unsafe impl Sync for PortImpl {}
unsafe impl Send for PortFileHandle {}
unsafe impl Sync for PortFileHandle {}
unsafe impl Send for StandardPort {}
unsafe impl Sync for StandardPort {}
unsafe impl Send for PortMode {}
unsafe impl Sync for PortMode {}
unsafe impl Send for PortDirection {}
unsafe impl Sync for PortDirection {}
unsafe impl Send for Promise {}
unsafe impl Sync for Promise {}
unsafe impl Send for TypeValue {}
unsafe impl Sync for TypeValue {}
unsafe impl Send for Parameter {}
unsafe impl Sync for Parameter {}
unsafe impl Send for RecordType {}
unsafe impl Sync for RecordType {}
unsafe impl Send for FieldInfo {}
unsafe impl Sync for FieldInfo {}
unsafe impl Send for Record {}
unsafe impl Sync for Record {}
impl Default for ThreadSafeEnvironment {
fn default() -> Self {
Self::new(None, 0)
}
}
impl Default for Environment {
fn default() -> Self {
Self::new(None, 0)
}
}
#[derive(Debug, Clone)]
pub struct StackTrace {
pub frames: Vec<StackFrame>,
}
#[derive(Debug, Clone)]
pub struct StackFrame {
pub name: Option<String>,
pub location: Option<Span>,
pub frame_type: FrameType,
}
#[derive(Debug, Clone)]
pub enum FrameType {
ProcedureCall,
SpecialForm(String),
Primitive(String),
MacroExpansion,
TopLevel,
}
impl StackTrace {
pub fn new() -> Self {
Self {
frames: Vec::new(),
}
}
pub fn push(&mut self, frame: StackFrame) {
self.frames.push(frame);
}
pub fn pop(&mut self) -> Option<StackFrame> {
self.frames.pop()
}
pub fn is_empty(&self) -> bool {
self.frames.is_empty()
}
pub fn len(&self) -> usize {
self.frames.len()
}
pub fn frames(&self) -> impl Iterator<Item = &StackFrame> {
self.frames.iter()
}
}
impl StackFrame {
pub fn procedure_call(name: Option<String>, location: Option<Span>) -> Self {
Self {
name,
location,
frame_type: FrameType::ProcedureCall,
}
}
pub fn special_form(form_name: String, location: Option<Span>) -> Self {
Self {
name: Some(form_name.clone()),
location,
frame_type: FrameType::SpecialForm(form_name),
}
}
pub fn primitive(name: String, location: Option<Span>) -> Self {
Self {
name: Some(name.clone()),
location,
frame_type: FrameType::Primitive(name),
}
}
pub fn macro_expansion(name: Option<String>, location: Option<Span>) -> Self {
Self {
name,
location,
frame_type: FrameType::MacroExpansion,
}
}
pub fn top_level(location: Option<Span>) -> Self {
Self {
name: None,
location,
frame_type: FrameType::TopLevel,
}
}
}
impl fmt::Display for StackTrace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.frames.is_empty() {
return writeln!(f, " (empty stack trace)");
}
for (i, frame) in self.frames.iter().enumerate() {
write!(f, " {i}: ")?;
match &frame.frame_type {
FrameType::ProcedureCall => {
if let Some(name) = &frame.name {
write!(f, "in procedure '{name}'")?;
} else {
write!(f, "in anonymous procedure")?;
}
}
FrameType::SpecialForm(form) => {
write!(f, "in special form '{form}'")?;
}
FrameType::Primitive(name) => {
write!(f, "in primitive '{name}'")?;
}
FrameType::MacroExpansion => {
if let Some(name) = &frame.name {
write!(f, "in macro '{name}'")?;
} else {
write!(f, "in macro expansion")?;
}
}
FrameType::TopLevel => {
write!(f, "at top level")?;
}
}
if let Some(location) = &frame.location {
write!(f, " (at {}:{})", location.start, location.end())?;
}
writeln!(f)?;
}
Ok(())
}
}
impl Default for StackTrace {
fn default() -> Self {
Self::new()
}
}
impl Continuation {
pub fn new(
stack: Vec<Frame>,
environment: Arc<ThreadSafeEnvironment>,
id: u64,
current_expr: Option<Spanned<Expr>>,
) -> Self {
Self {
stack,
environment,
id,
current_expr,
invoked: Arc::new(std::sync::atomic::AtomicBool::new(false)),
}
}
pub fn is_invoked(&self) -> bool {
self.invoked.load(std::sync::atomic::Ordering::SeqCst)
}
pub fn mark_invoked(&self) -> bool {
self.invoked.swap(true, std::sync::atomic::Ordering::SeqCst)
}
}