use crate::lexer::Span;
use thiserror::Error;
mod access;
mod cache;
mod compiler;
mod entry_points;
mod format;
mod host;
mod instruction;
mod json;
mod ops;
mod record;
mod schema;
mod state;
mod value;
mod vm;
pub use cache::{
CompiledLinkedProgram, CompiledProcessCache, CompiledProcessCacheKey, CompiledProgramCache,
CompiledProgramCacheStats, LinkedProgramCache, LinkedProgramCacheError,
};
#[allow(unused_imports)]
pub(crate) use compiler::*;
pub use entry_points::{
ExecutableProgram, compile, compile_linked, compile_linked_process,
compile_module_artifact_process, compile_process, execute, prewarm,
};
pub use host::{
AbilityOp, AbilityResult, ExecutionEnvironment, ExecutionHost, ExecutionHostError,
ExecutionMode, ProcessEvent, ProcessEventKind, ProcessSignal, ProcessStart, ResourceOperation,
Sleep, SleepKind,
};
#[allow(unused_imports)]
pub(crate) use instruction::*;
pub use json::from_json;
pub use record::Record;
#[allow(unused_imports)]
pub(crate) use record::{Symbol, intern_symbol, lookup_symbol, record_with_capacity, symbol_name};
#[allow(unused_imports)]
pub(crate) use schema::{
ValidationPlan, compile_schema_value, execute_validate_builtin, execute_validation_plan,
};
#[allow(unused_imports)]
pub(crate) use vm::*;
#[allow(unused_imports)]
pub(crate) use access::*;
#[allow(unused_imports)]
pub(crate) use format::*;
#[allow(unused_imports)]
pub(crate) use json::*;
#[allow(unused_imports)]
pub(crate) use ops::*;
pub use state::{Snapshot, State};
pub use value::{
ImageValue, LASH_HOST_VALUE_KEY, LASH_HOST_VALUE_TYPE_KEY, LASH_MODULE_REF_KEY,
LASH_PROCESS_NAME_KEY, LASH_PROCESS_REF_KEY, LASH_PROCESS_VALUE_KEY,
LASH_REQUIRED_SURFACE_REF_KEY, LASH_TYPE_KEY, ListValue, ProjectedBindingError,
ProjectedBindings, ProjectedFuture, ProjectedHostValue, ProjectedReadRequest,
ProjectedReadResponse, ProjectedValue, ResourceHandle, Value,
};
use vm::IterState;
#[derive(Clone, Debug, Error, PartialEq)]
pub enum RuntimeError {
#[error("unknown name `{name}`")]
UndefinedVariable { name: String },
#[error("`for` expects a list")]
NonListIteration,
#[error("`{keyword}` can only be used inside a process body")]
ProcessControlOutsideProcess { keyword: &'static str },
#[error("`{keyword}` can't be used inside a process body")]
ForegroundControlInsideProcess { keyword: &'static str },
#[error("unknown builtin `{name}`")]
UnknownBuiltin { name: String },
#[error("{message}")]
TypeError { message: String },
#[error("{message}")]
ValueError { message: String },
}
#[derive(Clone, Debug, Error, PartialEq)]
#[error("{error}")]
pub struct RuntimeFailure {
pub error: RuntimeError,
pub span: Option<Span>,
}
#[derive(Default)]
pub struct ExecutionScratch {
stack: Vec<Value>,
iter_stack: Vec<IterState>,
slot_values: Vec<Option<Value>>,
}
impl ExecutionScratch {
pub fn new() -> Self {
Self::default()
}
}
pub(crate) const COOPERATIVE_YIELD_INSTRUCTION_BUDGET: usize = 1024;
#[derive(Clone)]
pub struct CompiledProgram {
pub(crate) chunk: Chunk,
pub(crate) compile_stats: CompileStats,
}
impl std::fmt::Debug for CompiledProgram {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CompiledProgram")
.field("instruction_count", &self.chunk.code.len())
.field("compile_stats", &self.compile_stats)
.finish()
}
}
impl CompiledProgram {
pub fn compile_stats(&self) -> &CompileStats {
&self.compile_stats
}
pub fn static_graph_json(&self, module_ref: impl Into<String>) -> serde_json::Value {
if let Some(context) = &self.chunk.module_context {
crate::graph::static_graph_json_for_module_ref(
context.module_ref.clone(),
&context.process_refs,
)
} else {
crate::graph::static_graph_json_without_ir(module_ref)
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ExecutionOutcome {
Continued,
Finished(Value),
Failed(Value),
}
#[derive(Clone, Debug, Default)]
pub struct ProfileReport {
instruction_stats: Vec<ProfileStat>,
builtin_stats: Vec<ProfileStat>,
compile_stats: CompileStats,
}
impl ProfileReport {
pub fn instruction_stats(&self) -> &[ProfileStat] {
&self.instruction_stats
}
pub fn builtin_stats(&self) -> &[ProfileStat] {
&self.builtin_stats
}
pub fn compile_stats(&self) -> &CompileStats {
&self.compile_stats
}
pub fn merge(&mut self, other: &Self) {
merge_stats(&mut self.instruction_stats, &other.instruction_stats);
merge_stats(&mut self.builtin_stats, &other.builtin_stats);
self.compile_stats.merge(&other.compile_stats);
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct CompileStats {
pub type_literals_total: u64,
pub type_literals_const_folded: u64,
pub type_literals_dynamic: u64,
pub type_ref_sites: u64,
}
impl CompileStats {
pub fn merge(&mut self, other: &Self) {
self.type_literals_total += other.type_literals_total;
self.type_literals_const_folded += other.type_literals_const_folded;
self.type_literals_dynamic += other.type_literals_dynamic;
self.type_ref_sites += other.type_ref_sites;
}
}
#[derive(Clone, Debug, Default)]
pub struct ProfileStat {
pub name: &'static str,
pub count: u64,
pub total_ns: u128,
}
impl ProfileStat {
pub fn avg_ns(&self) -> u128 {
if self.count == 0 {
0
} else {
self.total_ns / self.count as u128
}
}
}
pub fn unwrap_type_value(value: &Value) -> Option<&Value> {
let record = value.as_record()?;
if record.len() != 1 {
return None;
}
record.get(LASH_TYPE_KEY)
}
#[cfg(test)]
mod tests;