1use sim_kernel::{Error, Expr, Result, Symbol};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5pub enum BindingScopeMode {
6 Lexical,
8 Dynamic,
10 Hybrid,
12}
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub enum HygieneMode {
17 Hygienic,
19 Explicit,
21 Unhygienic,
23}
24
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
30pub struct BindingProfileModes {
31 pub scope: BindingScopeMode,
33 pub hygiene: HygieneMode,
35}
36
37impl Default for BindingProfileModes {
38 fn default() -> Self {
39 Self {
40 scope: BindingScopeMode::Lexical,
41 hygiene: HygieneMode::Hygienic,
42 }
43 }
44}
45
46impl BindingProfileModes {
47 pub fn from_options(options: &[(Symbol, Expr)]) -> Result<Self> {
68 let mut modes = Self::default();
69 for (key, value) in options {
70 if key_matches(key, "scope") || key_matches(key, "binding") {
71 modes.scope = parse_scope_mode(value)?;
72 } else if key_matches(key, "hygiene") {
73 modes.hygiene = parse_hygiene_mode(value)?;
74 }
75 }
76 Ok(modes)
77 }
78}
79
80fn parse_scope_mode(expr: &Expr) -> Result<BindingScopeMode> {
81 let symbol = symbol_value(expr, "binding scope mode")?;
82 match symbol.name.as_ref() {
83 "lexical" => Ok(BindingScopeMode::Lexical),
84 "dynamic" => Ok(BindingScopeMode::Dynamic),
85 "hybrid" => Ok(BindingScopeMode::Hybrid),
86 _ => Err(Error::Eval(format!(
87 "unsupported binding scope mode {symbol}"
88 ))),
89 }
90}
91
92fn parse_hygiene_mode(expr: &Expr) -> Result<HygieneMode> {
93 let symbol = symbol_value(expr, "binding hygiene mode")?;
94 match symbol.name.as_ref() {
95 "hygienic" => Ok(HygieneMode::Hygienic),
96 "explicit" => Ok(HygieneMode::Explicit),
97 "unhygienic" => Ok(HygieneMode::Unhygienic),
98 _ => Err(Error::Eval(format!(
99 "unsupported binding hygiene mode {symbol}"
100 ))),
101 }
102}
103
104fn symbol_value<'a>(expr: &'a Expr, expected: &'static str) -> Result<&'a Symbol> {
105 match expr {
106 Expr::Symbol(symbol) => Ok(symbol),
107 _ => Err(Error::TypeMismatch {
108 expected,
109 found: "non-symbol",
110 }),
111 }
112}
113
114fn key_matches(symbol: &Symbol, name: &str) -> bool {
115 symbol.name.as_ref() == name
116}