use std::rc::Rc;
use super::{Chunk, Environment};
use crate::ll::{
codegen::variables::{LocalIndex, UpvalueIndex},
error::LanguageErrorKind,
gc::Memory,
value::RawValue,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CaptureKind {
Local(LocalIndex),
Upvalue(UpvalueIndex),
}
pub type ForeignFunction =
Box<dyn Fn(&Environment, &mut Memory, &[RawValue]) -> Result<RawValue, LanguageErrorKind>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Control {
GcCollect,
}
pub enum FunctionKind {
Bytecode { chunk: Rc<Chunk>, captured_locals: Vec<CaptureKind> },
Foreign(ForeignFunction),
Control(Control),
}
impl std::fmt::Debug for FunctionKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bytecode { chunk, captured_locals } => f
.debug_struct("Bytecode")
.field("chunk", chunk)
.field("captured_locals", captured_locals)
.finish(),
Self::Foreign(..) => f.debug_struct("Foreign").finish_non_exhaustive(),
Self::Control(ctl) => f.debug_tuple("Control").field(ctl).finish(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum FunctionParameterCount {
Fixed(u16),
Varargs,
}
impl FunctionParameterCount {
pub fn to_fixed(self) -> Option<u16> {
if let Self::Fixed(v) = self {
Some(v)
} else {
None
}
}
}
impl From<u16> for FunctionParameterCount {
fn from(count: u16) -> Self {
Self::Fixed(count)
}
}
impl std::fmt::Debug for FunctionParameterCount {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
match self {
Self::Fixed(num) => write!(f, "Fixed({num})"),
Self::Varargs => write!(f, "Varargs"),
}
} else {
match self {
Self::Fixed(num) => write!(f, "{num}"),
Self::Varargs => write!(f, "..."),
}
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct MethodParameterCount(u8);
impl MethodParameterCount {
pub fn from_count_without_self(count: impl TryInto<u8>) -> Result<Self, LanguageErrorKind> {
count
.try_into()
.ok()
.and_then(|x| x.checked_add(1))
.map(Self)
.ok_or(LanguageErrorKind::TooManyParameters)
}
pub const fn from_count_with_self(count: u8) -> Self {
Self(count)
}
pub fn from_fixed_function_parameter_count(count: u16) -> Result<Self, LanguageErrorKind> {
Self::from_count_without_self(
u8::try_from(count).map_err(|_| LanguageErrorKind::TooManyParameters)?,
)
}
pub const fn to_count_without_self(self) -> u8 {
self.0 - 1
}
pub const fn to_count_with_self(self) -> u8 {
self.0
}
}
impl From<u8> for MethodParameterCount {
fn from(count: u8) -> Self {
Self(count)
}
}
impl std::fmt::Debug for MethodParameterCount {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug)]
pub struct Function {
pub name: Rc<str>,
pub parameter_count: FunctionParameterCount,
pub kind: FunctionKind,
pub hidden_in_stack_traces: bool,
}