use super::opcode::Instruction;
use super::source_map::SourceMap;
use crate::core::Value;
use crate::kernel::SchemaType;
use std::collections::HashMap;
pub const MAX_CONSTANTS: usize = 1 << 24;
pub const MAX_INSTRUCTIONS: usize = 1 << 24;
pub const MAX_LOCALS: usize = u16::MAX as usize;
pub const MAX_OPERAND_STACK: usize = 4096;
pub const MAX_PRIMITIVE_ARGUMENTS: usize = u8::MAX as usize;
pub const MAX_CAPTURES: usize = u8::MAX as usize;
pub type FunctionId = u16;
#[derive(Debug, Clone)]
pub struct CatchEntry {
pub class: String,
pub binding: u16,
pub target: u32,
}
#[derive(Debug, Clone)]
pub struct TryEntry {
pub start: u32,
pub end: u32,
pub depth: u16,
pub catches: Vec<CatchEntry>,
pub finally: Option<u32>,
pub pending_value: Option<u16>,
pub pending_error: Option<u16>,
}
#[derive(Debug, Clone)]
pub struct FunctionPrototype {
pub name: Option<String>,
pub async_function: bool,
pub arity: u16,
pub variadic: bool,
pub capture_count: u16,
pub local_count: u16,
pub max_stack: u16,
pub code: Vec<Instruction>,
pub source_map: SourceMap,
pub handlers: Vec<TryEntry>,
}
#[derive(Debug, Clone)]
pub struct Program {
pub namespace: Option<String>,
pub constants: Vec<Value>,
pub var_metadata: Vec<std::rc::Rc<crate::lang::data::Metadata>>,
pub schema_types: HashMap<String, SchemaType>,
pub function_types: HashMap<String, SchemaType>,
pub inferred_function_types: HashMap<String, SchemaType>,
pub functions: Vec<FunctionPrototype>,
pub entry: FunctionId,
}
impl Program {
pub fn entry_function(&self) -> &FunctionPrototype {
&self.functions[self.entry as usize]
}
pub fn function_schema(&self, function: FunctionId) -> Option<&SchemaType> {
let prototype = self.functions.get(function as usize)?;
let name = prototype.name.as_deref()?;
let qualified = if name.contains('/') {
name.to_owned()
} else {
format!("{}/{}", self.namespace.as_deref()?, name)
};
let mut schema = self
.function_types
.get(&qualified)
.or_else(|| self.inferred_function_types.get(&qualified))?;
let mut visited = std::collections::HashSet::new();
while let SchemaType::Reference(target) = schema {
if !visited.insert(target.as_str()) {
return Some(schema);
}
let Some(resolved) = self.schema_types.get(target) else {
return Some(schema);
};
schema = resolved;
}
Some(schema)
}
pub fn function_has_i64_parameters(&self, function: FunctionId) -> bool {
let Some(prototype) = self.functions.get(function as usize) else {
return false;
};
let Some(SchemaType::Function(arities)) = self.function_schema(function) else {
return false;
};
arities.iter().any(|arity| {
arity.fixed.len() == usize::from(prototype.arity)
&& arity.rest.is_some() == prototype.variadic
&& arity
.fixed
.iter()
.all(|value| {
matches!(value, SchemaType::Primitive(name) if name == "int" || name == "long")
})
&& arity.rest.as_deref().is_none_or(
|value| {
matches!(value, SchemaType::Primitive(name) if name == "int" || name == "long")
},
)
})
}
}