#![allow(clippy::too_many_lines)] use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet, VecDeque};
pub use crate::kernel::Form;
use crate::kernel::{NamespaceLoadState, NamespaceRegistry, Var as KernelVar, VarOrigin};
use crate::lang::data::List as PList;
use crate::lang::data::{
Atom as PAtom, Cons as PCons, Deque as PDeque, Keyword, Map as PMap, MapEntry as PMapEntry,
OrderedMap as POrderedMap, OrderedSet as POrderedSet, Pointer as PPointer,
PriorityMap as PPriorityMap, Queue as PQueue, Seq as PSeq, Set as PSet,
SortedMap as PSortedMap, SortedSet as PSortedSet, Symbol, TaggedLiteral as PTaggedLiteral,
Trie as PTrie, Tuple as PTuple, Vector as PVector,
};
use crate::lang::data::{Metadata, MetadataValue};
use crate::lang::data::{
MutableList, MutableMap, MutableOrderedMap, MutableOrderedSet, MutableQueue, MutableSet,
MutableSortedMap, MutableSortedSet, MutableTrie, MutableVector,
};
use crate::lang::hash::JavaHash;
use crate::lang::protocol::{
IDisplay, IEmpty, IFn, IMetadata, INamespaced, IPopFirst, IPopLast, IToMutable, IToPersistent,
};
use crate::numeric::{self, ArithmeticOp};
pub use crate::task::{
LocalPromiseProvider, Promise, PromiseProvider, PromiseRejection, PromiseState,
};
use num_bigint::BigInt;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
thread_local! {
static ACTIVE_EVALUATION_INTERRUPT: RefCell<Option<Rc<dyn Fn() -> Option<String>>>> =
const { RefCell::new(None) };
static ACTIVE_EXCEPTION_SITE: RefCell<Option<ExceptionSite>> = const { RefCell::new(None) };
}
pub(crate) fn with_exception_site<R>(site: ExceptionSite, operation: impl FnOnce() -> R) -> R {
ACTIVE_EXCEPTION_SITE.with(|active| {
let previous = active.replace(Some(site));
let result = operation();
active.replace(previous);
result
})
}
pub(crate) fn current_exception_site() -> Option<ExceptionSite> {
ACTIVE_EXCEPTION_SITE.with(|active| active.borrow().clone())
}
pub(crate) fn exception_site_at(line: usize, column: usize) -> Option<ExceptionSite> {
Some(current_exception_site().map_or(
ExceptionSite {
namespace: None,
resource: None,
line,
column,
},
|mut site| {
site.line = line;
site.column = column;
site
},
))
}
const SOURCE_LOCATION_KEY: &str = "hara/source-location";
fn source_location_metadata(line: usize, column: usize) -> Form {
Form::Map(vec![(
Form::Keyword(SOURCE_LOCATION_KEY.into()),
Form::Map(vec![
(Form::Keyword("line".into()), Form::Number(line as i64)),
(Form::Keyword("column".into()), Form::Number(column as i64)),
]),
)])
}
pub fn attach_exception_sites(node: &crate::kernel::SpannedForm) -> Form {
let rebuilt = match &node.form {
Form::List(values)
if values.first().is_some_and(
|value| matches!(value, Form::Symbol(name) if name == "quote" || name == "'"),
) =>
{
Form::List(values.clone())
}
Form::List(values) if node.children.len() == values.len() => {
Form::List(node.children.iter().map(attach_exception_sites).collect())
}
Form::List(values) if node.children.len() + 1 == values.len() => {
let mut rebuilt = vec![values[0].clone()];
rebuilt.extend(node.children.iter().map(attach_exception_sites));
Form::List(rebuilt)
}
Form::Vector(values) if node.children.len() == values.len() => {
Form::Vector(node.children.iter().map(attach_exception_sites).collect())
}
Form::Set(values) if node.children.len() == values.len() => {
Form::Set(node.children.iter().map(attach_exception_sites).collect())
}
Form::Map(values) if node.children.len() == values.len() * 2 => Form::Map(
node.children
.chunks_exact(2)
.map(|pair| {
(
attach_exception_sites(&pair[0]),
attach_exception_sites(&pair[1]),
)
})
.collect(),
),
Form::Tagged(tag, _) if node.children.len() == 1 => Form::Tagged(
tag.clone(),
Box::new(attach_exception_sites(&node.children[0])),
),
Form::Metadata(metadata, _) if node.children.len() == 1 => Form::Metadata(
metadata.clone(),
Box::new(attach_exception_sites(&node.children[0])),
),
form => form.clone(),
};
let Form::List(values) = form_without_metadata(&rebuilt) else {
return rebuilt;
};
let Some(Form::Symbol(operator)) = values.first() else {
return rebuilt;
};
if !matches!(operator.as_str(), "throw" | "ex" | "std.foundation/ex") {
return rebuilt;
}
Form::Metadata(
Box::new(source_location_metadata(
node.span.start.line,
node.span.start.column,
)),
Box::new(rebuilt),
)
}
pub(crate) fn exception_location_from_metadata(metadata: &Form) -> Option<(usize, usize)> {
let Form::Map(entries) = form_without_metadata(metadata) else {
return None;
};
let location = entries.iter().find_map(|(key, value)| {
matches!(key, Form::Keyword(name) if name == SOURCE_LOCATION_KEY).then_some(value)
})?;
let Form::Map(entries) = form_without_metadata(location) else {
return None;
};
let number = |name: &str| {
entries.iter().find_map(|(key, value)| {
matches!(key, Form::Keyword(candidate) if candidate == name).then(|| match value {
Form::Number(value) if *value >= 0 => Some(*value as usize),
_ => None,
})?
})
};
Some((number("line")?, number("column")?))
}
pub(crate) fn with_evaluation_interrupt<R>(
interrupt: Rc<dyn Fn() -> Option<String>>,
operation: impl FnOnce() -> R,
) -> R {
ACTIVE_EVALUATION_INTERRUPT.with(|active| {
let previous = active.replace(Some(interrupt));
let result = operation();
active.replace(previous);
result
})
}
pub(crate) fn check_evaluation_interrupt() -> Result<(), String> {
ACTIVE_EVALUATION_INTERRUPT.with(|active| {
active
.borrow()
.as_ref()
.and_then(|interrupt| interrupt())
.map_or(Ok(()), Err)
})
}
#[path = "fiber.rs"]
mod fiber;
#[path = "core/native_result.rs"]
mod native_result;
pub use native_result::{ResultStatus, ResultValue};
#[cfg(not(feature = "raw-wasm"))]
#[path = "native_crypto.rs"]
mod native_crypto;
#[cfg(feature = "raw-wasm")]
mod native_crypto {
use super::Value;
pub(super) fn operation(_operation: &str, _arguments: Vec<Value>) -> Result<Value, String> {
Err("std.native.Crypto is unavailable in raw Wasm".into())
}
}
pub(crate) use fiber::Cont;
pub use fiber::{EvalFiber, EvalFiberState, Step};
include!("core/registry.rs");
include!("core/native_declarations.rs");
include!("core/value.rs");
include!("core/vm_tool.rs");
#[cfg(all(feature = "bytecode-vm", not(feature = "raw-wasm")))]
include!("core/package_tool.rs");
#[cfg(any(not(feature = "bytecode-vm"), feature = "raw-wasm"))]
pub(crate) fn package_tool_provider_values() -> Vec<(&'static str, Value)> {
Vec::new()
}
#[cfg(any(not(feature = "bytecode-vm"), feature = "raw-wasm"))]
pub(crate) fn hbx_operation(_operation: &str, _arguments: Vec<Value>) -> Result<Value, String> {
Err("std.native.HBX is unavailable in this runtime profile".into())
}
include!("core/inspection.rs");
include!("core/environment.rs");
include!("core/native.rs");
include!("core/provider.rs");
include!("core/async_value.rs");
include!("core/primitive.rs");
include!("core/protocol.rs");
include!("core/operation.rs");
include!("core/form.rs");
include!("core/namespace.rs");
include!("core/special_forms.rs");
include!("core/bootstrap.rs");