use sim_kernel::{Error, Expr, Result, Symbol};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BindingScopeMode {
Lexical,
Dynamic,
Hybrid,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HygieneMode {
Hygienic,
Explicit,
Unhygienic,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BindingProfileModes {
pub scope: BindingScopeMode,
pub hygiene: HygieneMode,
}
impl Default for BindingProfileModes {
fn default() -> Self {
Self {
scope: BindingScopeMode::Lexical,
hygiene: HygieneMode::Hygienic,
}
}
}
impl BindingProfileModes {
pub fn from_options(options: &[(Symbol, Expr)]) -> Result<Self> {
let mut modes = Self::default();
for (key, value) in options {
if key_matches(key, "scope") || key_matches(key, "binding") {
modes.scope = parse_scope_mode(value)?;
} else if key_matches(key, "hygiene") {
modes.hygiene = parse_hygiene_mode(value)?;
}
}
Ok(modes)
}
}
fn parse_scope_mode(expr: &Expr) -> Result<BindingScopeMode> {
let symbol = symbol_value(expr, "binding scope mode")?;
match symbol.name.as_ref() {
"lexical" => Ok(BindingScopeMode::Lexical),
"dynamic" => Ok(BindingScopeMode::Dynamic),
"hybrid" => Ok(BindingScopeMode::Hybrid),
_ => Err(Error::Eval(format!(
"unsupported binding scope mode {symbol}"
))),
}
}
fn parse_hygiene_mode(expr: &Expr) -> Result<HygieneMode> {
let symbol = symbol_value(expr, "binding hygiene mode")?;
match symbol.name.as_ref() {
"hygienic" => Ok(HygieneMode::Hygienic),
"explicit" => Ok(HygieneMode::Explicit),
"unhygienic" => Ok(HygieneMode::Unhygienic),
_ => Err(Error::Eval(format!(
"unsupported binding hygiene mode {symbol}"
))),
}
}
fn symbol_value<'a>(expr: &'a Expr, expected: &'static str) -> Result<&'a Symbol> {
match expr {
Expr::Symbol(symbol) => Ok(symbol),
_ => Err(Error::TypeMismatch {
expected,
found: "non-symbol",
}),
}
}
fn key_matches(symbol: &Symbol, name: &str) -> bool {
symbol.name.as_ref() == name
}