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 {
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 pub fn enable_memo(&mut self, fns: HashSet<String>) {
159 self.memo_fns = fns;
160 }
161
162 pub fn register_effect_set(&mut self, name: String, effects: Vec<String>) {
164 self.effect_aliases.insert(name, effects);
165 }
166
167 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 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 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 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 Err(RuntimeError::Error(
258 "Resolved lookup on non-Slots frame".to_string(),
259 ))
260 }
261 }
262 }
263
264 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}