Skip to main content

aver/interpreter/
core.rs

1use super::*;
2
3impl Interpreter {
4    pub fn new() -> Self {
5        let mut global = HashMap::new();
6
7        console::register(&mut global);
8        http::register(&mut global);
9        http_server::register(&mut global);
10        disk::register(&mut global);
11        tcp::register(&mut global);
12        int::register(&mut global);
13        float::register(&mut global);
14        string::register(&mut global);
15        list::register(&mut global);
16        map::register(&mut global);
17        char::register(&mut global);
18        byte::register(&mut global);
19
20        // Result and Option namespaces — constructors for Ok/Err/Some/None
21        {
22            let mut members = HashMap::new();
23            members.insert(
24                "Ok".to_string(),
25                Value::Builtin("__ctor:Result.Ok".to_string()),
26            );
27            members.insert(
28                "Err".to_string(),
29                Value::Builtin("__ctor:Result.Err".to_string()),
30            );
31            for (name, builtin_name) in result::extra_members() {
32                members.insert(name.to_string(), Value::Builtin(builtin_name));
33            }
34            global.insert(
35                "Result".to_string(),
36                Value::Namespace {
37                    name: "Result".to_string(),
38                    members,
39                },
40            );
41        }
42        {
43            let mut members = HashMap::new();
44            members.insert(
45                "Some".to_string(),
46                Value::Builtin("__ctor:Option.Some".to_string()),
47            );
48            members.insert("None".to_string(), Value::None);
49            for (name, builtin_name) in option::extra_members() {
50                members.insert(name.to_string(), Value::Builtin(builtin_name));
51            }
52            global.insert(
53                "Option".to_string(),
54                Value::Namespace {
55                    name: "Option".to_string(),
56                    members,
57                },
58            );
59        }
60
61        let rc_global = global
62            .into_iter()
63            .map(|(k, v)| (k, Rc::new(v)))
64            .collect::<HashMap<_, _>>();
65
66        let mut record_schemas = HashMap::new();
67        record_schemas.insert(
68            "HttpResponse".to_string(),
69            vec![
70                "status".to_string(),
71                "body".to_string(),
72                "headers".to_string(),
73            ],
74        );
75        record_schemas.insert(
76            "HttpRequest".to_string(),
77            vec![
78                "method".to_string(),
79                "path".to_string(),
80                "body".to_string(),
81                "headers".to_string(),
82            ],
83        );
84        record_schemas.insert(
85            "Header".to_string(),
86            vec!["name".to_string(), "value".to_string()],
87        );
88        record_schemas.insert(
89            "Tcp.Connection".to_string(),
90            vec!["id".to_string(), "host".to_string(), "port".to_string()],
91        );
92
93        Interpreter {
94            env: vec![EnvFrame::Owned(rc_global)],
95            module_cache: HashMap::new(),
96            record_schemas,
97            call_stack: Vec::new(),
98            effect_aliases: HashMap::new(),
99            active_local_slots: None,
100            memo_fns: HashSet::new(),
101            memo_cache: HashMap::new(),
102            execution_mode: ExecutionMode::Normal,
103            recorded_effects: Vec::new(),
104            replay_effects: Vec::new(),
105            replay_pos: 0,
106            validate_replay_args: false,
107        }
108    }
109
110    pub fn execution_mode(&self) -> ExecutionMode {
111        self.execution_mode
112    }
113
114    pub fn set_execution_mode_normal(&mut self) {
115        self.execution_mode = ExecutionMode::Normal;
116        self.recorded_effects.clear();
117        self.replay_effects.clear();
118        self.replay_pos = 0;
119        self.validate_replay_args = false;
120    }
121
122    pub fn start_recording(&mut self) {
123        self.execution_mode = ExecutionMode::Record;
124        self.recorded_effects.clear();
125        self.replay_effects.clear();
126        self.replay_pos = 0;
127        self.validate_replay_args = false;
128    }
129
130    pub fn start_replay(&mut self, effects: Vec<EffectRecord>, validate_args: bool) {
131        self.execution_mode = ExecutionMode::Replay;
132        self.replay_effects = effects;
133        self.replay_pos = 0;
134        self.validate_replay_args = validate_args;
135        self.recorded_effects.clear();
136    }
137
138    pub fn take_recorded_effects(&mut self) -> Vec<EffectRecord> {
139        std::mem::take(&mut self.recorded_effects)
140    }
141
142    pub fn replay_progress(&self) -> (usize, usize) {
143        (self.replay_pos, self.replay_effects.len())
144    }
145
146    pub fn ensure_replay_consumed(&self) -> Result<(), RuntimeError> {
147        if self.execution_mode == ExecutionMode::Replay
148            && self.replay_pos < self.replay_effects.len()
149        {
150            return Err(RuntimeError::ReplayUnconsumed {
151                remaining: self.replay_effects.len() - self.replay_pos,
152            });
153        }
154        Ok(())
155    }
156
157    /// Mark a set of function names as eligible for auto-memoization.
158    pub fn enable_memo(&mut self, fns: HashSet<String>) {
159        self.memo_fns = fns;
160    }
161
162    /// Register a named effect set alias.
163    pub fn register_effect_set(&mut self, name: String, effects: Vec<String>) {
164        self.effect_aliases.insert(name, effects);
165    }
166
167    /// Expand effect names one level: aliases → concrete effect names.
168    pub(super) fn expand_effects(&self, effects: &[String]) -> Vec<String> {
169        let mut result = Vec::new();
170        for e in effects {
171            if let Some(expanded) = self.effect_aliases.get(e) {
172                result.extend(expanded.iter().cloned());
173            } else {
174                result.push(e.clone());
175            }
176        }
177        result
178    }
179
180    // -------------------------------------------------------------------------
181    // Environment management
182    // -------------------------------------------------------------------------
183    pub(super) fn push_env(&mut self, frame: EnvFrame) {
184        self.env.push(frame);
185    }
186
187    pub(super) fn pop_env(&mut self) {
188        if self.env.len() > 1 {
189            self.env.pop();
190        }
191    }
192
193    pub(super) fn last_owned_scope_mut(
194        &mut self,
195    ) -> Result<&mut HashMap<String, Rc<Value>>, RuntimeError> {
196        let frame = self
197            .env
198            .last_mut()
199            .ok_or_else(|| RuntimeError::Error("No active scope".to_string()))?;
200        match frame {
201            EnvFrame::Owned(scope) => Ok(scope),
202            EnvFrame::Shared(_) | EnvFrame::Slots(_) => Err(RuntimeError::Error(
203                "Cannot define name in non-owned frame".to_string(),
204            )),
205        }
206    }
207
208    pub(super) fn lookup_rc(&self, name: &str) -> Result<&Rc<Value>, RuntimeError> {
209        for frame in self.env.iter().rev() {
210            let found = match frame {
211                EnvFrame::Owned(scope) => scope.get(name),
212                EnvFrame::Shared(scope) => scope.get(name),
213                // Slots frames are indexed by slot, not by name — skip in name-based lookup
214                EnvFrame::Slots(_) => None,
215            };
216            if let Some(v) = found {
217                return Ok(v);
218            }
219        }
220        Err(RuntimeError::Error(format!(
221            "Undefined variable: '{}'",
222            name
223        )))
224    }
225
226    pub(super) fn global_scope_clone(&self) -> Result<HashMap<String, Rc<Value>>, RuntimeError> {
227        let frame = self
228            .env
229            .first()
230            .ok_or_else(|| RuntimeError::Error("No global scope".to_string()))?;
231        match frame {
232            EnvFrame::Owned(scope) => Ok(scope.clone()),
233            EnvFrame::Shared(scope) => Ok((**scope).clone()),
234            EnvFrame::Slots(_) => Err(RuntimeError::Error(
235                "Invalid global scope frame: Slots".to_string(),
236            )),
237        }
238    }
239
240    pub fn lookup(&self, name: &str) -> Result<Value, RuntimeError> {
241        self.lookup_rc(name).map(|rc| (**rc).clone())
242    }
243
244    pub fn define(&mut self, name: String, val: Value) {
245        if let Ok(scope) = self.last_owned_scope_mut() {
246            scope.insert(name, Rc::new(val));
247        }
248    }
249
250    /// O(1) slot-based variable lookup for resolved function bodies.
251    pub(super) fn lookup_slot(&self, slot: u16) -> Result<Value, RuntimeError> {
252        let idx = self.env.len() - 1;
253        match &self.env[idx] {
254            EnvFrame::Slots(v) => Ok(v[slot as usize].as_ref().clone()),
255            _ => {
256                // Fallback — shouldn't happen if resolver is correct
257                Err(RuntimeError::Error(
258                    "Resolved lookup on non-Slots frame".to_string(),
259                ))
260            }
261        }
262    }
263
264    /// Define a value in the current Slots frame at the given slot index.
265    pub(super) fn define_slot(&mut self, slot: u16, val: Value) {
266        let idx = self.env.len() - 1;
267        if let EnvFrame::Slots(v) = &mut self.env[idx] {
268            v[slot as usize] = Rc::new(val);
269        }
270    }
271
272    pub fn define_module_path(&mut self, path: &str, val: Value) -> Result<(), RuntimeError> {
273        let parts: Vec<&str> = path.split('.').filter(|s| !s.is_empty()).collect();
274        if parts.is_empty() {
275            return Err(RuntimeError::Error("Empty module path".to_string()));
276        }
277        if parts.len() == 1 {
278            self.define(parts[0].to_string(), val);
279            return Ok(());
280        }
281
282        let scope = self.last_owned_scope_mut()?;
283        let head = parts[0];
284        let tail = &parts[1..];
285
286        if let Some(rc_existing) = scope.remove(head) {
287            let existing = Rc::try_unwrap(rc_existing).unwrap_or_else(|rc| (*rc).clone());
288            match existing {
289                Value::Namespace { name, mut members } => {
290                    Self::insert_namespace_path(&mut members, tail, val)?;
291                    scope.insert(
292                        head.to_string(),
293                        Rc::new(Value::Namespace { name, members }),
294                    );
295                    Ok(())
296                }
297                _ => Err(RuntimeError::Error(format!(
298                    "Cannot mount module '{}': '{}' is not a namespace",
299                    parts.join("."),
300                    head
301                ))),
302            }
303        } else {
304            let mut members = HashMap::new();
305            Self::insert_namespace_path(&mut members, tail, val)?;
306            scope.insert(
307                head.to_string(),
308                Rc::new(Value::Namespace {
309                    name: head.to_string(),
310                    members,
311                }),
312            );
313            Ok(())
314        }
315    }
316
317    pub(super) fn insert_namespace_path(
318        scope: &mut HashMap<String, Value>,
319        parts: &[&str],
320        val: Value,
321    ) -> Result<(), RuntimeError> {
322        if parts.len() == 1 {
323            scope.insert(parts[0].to_string(), val);
324            return Ok(());
325        }
326
327        let head = parts[0];
328        let tail = &parts[1..];
329
330        if let Some(existing) = scope.remove(head) {
331            match existing {
332                Value::Namespace { name, mut members } => {
333                    Self::insert_namespace_path(&mut members, tail, val)?;
334                    scope.insert(head.to_string(), Value::Namespace { name, members });
335                    Ok(())
336                }
337                _ => Err(RuntimeError::Error(format!(
338                    "Cannot mount module '{}': '{}' is not a namespace",
339                    parts.join("."),
340                    head
341                ))),
342            }
343        } else {
344            let mut members = HashMap::new();
345            Self::insert_namespace_path(&mut members, tail, val)?;
346            scope.insert(
347                head.to_string(),
348                Value::Namespace {
349                    name: head.to_string(),
350                    members,
351                },
352            );
353            Ok(())
354        }
355    }
356
357    pub(super) fn module_cache_key(path: &Path) -> String {
358        canonicalize_path(path).to_string_lossy().to_string()
359    }
360
361    pub(super) fn module_decl(items: &[TopLevel]) -> Option<&Module> {
362        items.iter().find_map(|item| {
363            if let TopLevel::Module(m) = item {
364                Some(m)
365            } else {
366                None
367            }
368        })
369    }
370
371    pub(super) fn exposed_set(items: &[TopLevel]) -> Option<HashSet<String>> {
372        Self::module_decl(items).and_then(|m| {
373            if m.exposes.is_empty() {
374                None
375            } else {
376                Some(m.exposes.iter().cloned().collect())
377            }
378        })
379    }
380
381    pub(super) fn cycle_display(loading: &[String], next: &str) -> String {
382        let mut chain = loading
383            .iter()
384            .map(|key| {
385                Path::new(key)
386                    .file_stem()
387                    .and_then(|s| s.to_str())
388                    .unwrap_or(key)
389                    .to_string()
390            })
391            .collect::<Vec<_>>();
392        chain.push(
393            Path::new(next)
394                .file_stem()
395                .and_then(|s| s.to_str())
396                .unwrap_or(next)
397                .to_string(),
398        );
399        chain.join(" -> ")
400    }
401
402    pub fn load_module(
403        &mut self,
404        name: &str,
405        base_dir: &str,
406        loading: &mut Vec<String>,
407        loading_set: &mut HashSet<String>,
408    ) -> Result<Value, RuntimeError> {
409        let path = find_module_file(name, base_dir).ok_or_else(|| {
410            RuntimeError::Error(format!("Module '{}' not found in '{}'", name, base_dir))
411        })?;
412        let cache_key = Self::module_cache_key(&path);
413
414        if let Some(cached) = self.module_cache.get(&cache_key) {
415            return Ok(cached.clone());
416        }
417
418        if loading_set.contains(&cache_key) {
419            return Err(RuntimeError::Error(format!(
420                "Circular import: {}",
421                Self::cycle_display(loading, &cache_key)
422            )));
423        }
424
425        loading.push(cache_key.clone());
426        loading_set.insert(cache_key.clone());
427        let result = (|| -> Result<Value, RuntimeError> {
428            let src = std::fs::read_to_string(&path).map_err(|e| {
429                RuntimeError::Error(format!("Cannot read '{}': {}", path.display(), e))
430            })?;
431            let mut items = parse_source(&src).map_err(|e| {
432                RuntimeError::Error(format!("Parse error in '{}': {}", path.display(), e))
433            })?;
434            crate::resolver::resolve_program(&mut items);
435
436            if let Some(module) = Self::module_decl(&items) {
437                let expected = name.rsplit('.').next().unwrap_or(name);
438                if module.name != expected {
439                    return Err(RuntimeError::Error(format!(
440                        "Module name mismatch: expected '{}' (from '{}'), found '{}' in '{}'",
441                        expected,
442                        name,
443                        module.name,
444                        path.display()
445                    )));
446                }
447            }
448
449            let mut sub = Interpreter::new();
450
451            if let Some(module) = Self::module_decl(&items) {
452                for dep_name in &module.depends {
453                    let dep_ns = self.load_module(dep_name, base_dir, loading, loading_set)?;
454                    sub.define_module_path(dep_name, dep_ns)?;
455                }
456            }
457
458            for item in &items {
459                if let TopLevel::EffectSet { name, effects } = item {
460                    sub.register_effect_set(name.clone(), effects.clone());
461                }
462            }
463            for item in &items {
464                if let TopLevel::TypeDef(td) = item {
465                    sub.register_type_def(td);
466                }
467            }
468            for item in &items {
469                if let TopLevel::FnDef(fd) = item {
470                    sub.exec_fn_def(fd)?;
471                }
472            }
473            let module_globals = Rc::new(sub.global_scope_clone()?);
474
475            let exposed = Self::exposed_set(&items);
476            let mut members = HashMap::new();
477            for item in &items {
478                if let TopLevel::FnDef(fd) = item {
479                    let include = match &exposed {
480                        Some(set) => set.contains(&fd.name),
481                        None => !fd.name.starts_with('_'),
482                    };
483                    if include {
484                        let mut val = sub.lookup(&fd.name).map_err(|_| {
485                            RuntimeError::Error(format!("Failed to export '{}.{}'", name, fd.name))
486                        })?;
487                        if let Value::Fn { home_globals, .. } = &mut val {
488                            *home_globals = Some(Rc::clone(&module_globals));
489                        }
490                        members.insert(fd.name.clone(), val);
491                    }
492                }
493            }
494
495            Ok(Value::Namespace {
496                name: name.to_string(),
497                members,
498            })
499        })();
500        loading.pop();
501        loading_set.remove(&cache_key);
502
503        match result {
504            Ok(ns) => {
505                self.module_cache.insert(cache_key, ns.clone());
506                Ok(ns)
507            }
508            Err(e) => Err(e),
509        }
510    }
511}