1use super::*;
2
3impl Interpreter {
4 pub fn eval_expr(&mut self, expr: &Expr) -> Result<Value, RuntimeError> {
5 match expr {
6 Expr::Literal(lit) => Ok(self.eval_literal(lit)),
7 Expr::Resolved(slot) => self.lookup_slot(*slot),
8 Expr::Ident(name) => self.lookup(name),
9 Expr::Attr(obj, field) => {
10 if let Expr::Ident(name) = obj.as_ref() {
12 let rc = self.lookup_rc(name)?;
13 return match rc.as_ref() {
14 Value::Namespace { name, members } => {
15 members.get(field.as_str()).cloned().ok_or_else(|| {
16 RuntimeError::Error(format!("Unknown member '{}.{}'", name, field))
17 })
18 }
19 Value::Record { fields, .. } => fields
20 .iter()
21 .find(|(k, _)| k == field)
22 .map(|(_, v)| Ok(v.clone()))
23 .unwrap_or_else(|| {
24 Err(RuntimeError::Error(format!("Unknown field '{}'", field)))
25 }),
26 _ => Err(RuntimeError::Error(format!(
27 "Field access '{}' is not supported on this value",
28 field
29 ))),
30 };
31 }
32 let obj_val = self.eval_expr(obj)?;
34 match obj_val {
35 Value::Record { fields, .. } => fields
36 .into_iter()
37 .find(|(k, _)| k == field)
38 .map(|(_, v)| Ok(v))
39 .unwrap_or_else(|| {
40 Err(RuntimeError::Error(format!("Unknown field '{}'", field)))
41 }),
42 Value::Namespace { name, members } => {
43 members.get(field).cloned().ok_or_else(|| {
44 RuntimeError::Error(format!("Unknown member '{}.{}'", name, field))
45 })
46 }
47 _ => Err(RuntimeError::Error(format!(
48 "Field access '{}' is not supported on this value",
49 field
50 ))),
51 }
52 }
53 Expr::FnCall(fn_expr, args) => {
54 let fn_val = self.eval_expr(fn_expr)?;
55 let mut arg_vals = Vec::new();
56 for a in args {
57 arg_vals.push(self.eval_expr(a)?);
58 }
59 self.call_value(fn_val, arg_vals)
60 }
61 Expr::BinOp(op, left, right) => {
62 let lv = self.eval_expr(left)?;
63 let rv = self.eval_expr(right)?;
64 self.eval_binop(op, lv, rv)
65 }
66 Expr::Match { subject, arms, .. } => {
67 let sv = self.eval_expr(subject)?;
68 self.eval_match(sv, arms)
69 }
70 Expr::Pipe(left, right) => {
71 let left_val = self.eval_expr(left)?;
72 let fn_val = self.eval_expr(right)?;
73 self.call_value(fn_val, vec![left_val])
74 }
75 Expr::Constructor(name, arg) => {
76 let arg_val = match arg {
77 Some(a) => self.eval_expr(a)?,
78 None => Value::Unit,
79 };
80 match name.as_str() {
81 "Ok" => Ok(Value::Ok(Box::new(arg_val))),
82 "Err" => Ok(Value::Err(Box::new(arg_val))),
83 "Some" => Ok(Value::Some(Box::new(arg_val))),
84 "None" => Ok(Value::None),
85 _ => Err(RuntimeError::Error(format!(
86 "Unknown constructor: {}",
87 name
88 ))),
89 }
90 }
91 Expr::ErrorProp(inner) => {
92 let val = self.eval_expr(inner)?;
93 match val {
94 Value::Ok(v) => Ok(*v),
95 Value::Err(e) => Err(RuntimeError::ErrProp(e)),
96 _ => Err(RuntimeError::Error(
97 "Operator '?' can only be applied to Result".to_string(),
98 )),
99 }
100 }
101 Expr::InterpolatedStr(parts) => {
102 let mut result = String::new();
103 for part in parts {
104 match part {
105 StrPart::Literal(s) => result.push_str(s),
106 StrPart::Parsed(expr) => {
107 let val = self.eval_expr(expr)?;
108 result.push_str(&aver_repr(&val));
109 }
110 }
111 }
112 Ok(Value::Str(result))
113 }
114 Expr::List(elements) => {
115 let mut values = Vec::new();
116 for elem in elements {
117 values.push(self.eval_expr(elem)?);
118 }
119 Ok(list_from_vec(values))
120 }
121 Expr::Tuple(items) => {
122 let mut values = Vec::with_capacity(items.len());
123 for item in items {
124 values.push(self.eval_expr(item)?);
125 }
126 Ok(Value::Tuple(values))
127 }
128 Expr::MapLiteral(entries) => self.eval_map_literal(entries),
129 Expr::RecordCreate { type_name, fields } => self.eval_record_create(type_name, fields),
130 Expr::RecordUpdate {
131 type_name,
132 base,
133 updates,
134 } => self.eval_record_update(type_name, base, updates),
135 Expr::TailCall(boxed) => self.eval_tail_call(boxed),
136 }
137 }
138
139 #[inline(never)]
141 pub(super) fn eval_tail_call(
142 &mut self,
143 boxed: &(String, Vec<Expr>),
144 ) -> Result<Value, RuntimeError> {
145 let (target, args) = boxed;
146 let mut vals = Vec::with_capacity(args.len());
147 for a in args {
148 vals.push(self.eval_expr(a)?);
149 }
150 Err(RuntimeError::TailCall(Box::new((target.clone(), vals))))
151 }
152
153 #[inline(never)]
156 fn eval_record_create(
157 &mut self,
158 type_name: &str,
159 fields: &[(String, Expr)],
160 ) -> Result<Value, RuntimeError> {
161 let mut field_vals = Vec::with_capacity(fields.len());
162 let mut seen = HashSet::new();
163 for (name, expr) in fields {
164 if !seen.insert(name.clone()) {
165 return Err(RuntimeError::Error(format!(
166 "Record '{}' field '{}' provided more than once",
167 type_name, name
168 )));
169 }
170 let val = self.eval_expr(expr)?;
171 field_vals.push((name.clone(), val));
172 }
173
174 if let Some(schema) = self.record_schemas.get(type_name) {
175 let mut by_name = HashMap::with_capacity(field_vals.len());
176 for (name, val) in field_vals {
177 by_name.insert(name, val);
178 }
179
180 for provided in by_name.keys() {
181 if !schema.iter().any(|f| f == provided) {
182 return Err(RuntimeError::Error(format!(
183 "Record '{}' has no field '{}'",
184 type_name, provided
185 )));
186 }
187 }
188
189 let mut ordered = Vec::with_capacity(schema.len());
190 for required in schema {
191 let val = by_name.remove(required).ok_or_else(|| {
192 RuntimeError::Error(format!(
193 "Record '{}' missing required field '{}'",
194 type_name, required
195 ))
196 })?;
197 ordered.push((required.clone(), val));
198 }
199
200 return Ok(Value::Record {
201 type_name: type_name.to_string(),
202 fields: ordered,
203 });
204 }
205
206 Ok(Value::Record {
207 type_name: type_name.to_string(),
208 fields: field_vals,
209 })
210 }
211
212 #[inline(never)]
214 fn eval_record_update(
215 &mut self,
216 type_name: &str,
217 base: &Expr,
218 updates: &[(String, Expr)],
219 ) -> Result<Value, RuntimeError> {
220 let base_val = self.eval_expr(base)?;
221 let (base_type, base_fields) = match base_val {
222 Value::Record {
223 type_name: t,
224 fields,
225 } => (t, fields),
226 _ => {
227 return Err(RuntimeError::Error(format!(
228 "{}.update: base must be a {} record",
229 type_name, type_name
230 )));
231 }
232 };
233 if base_type != type_name {
234 return Err(RuntimeError::Error(format!(
235 "{}.update: base is a {} record, expected {}",
236 type_name, base_type, type_name
237 )));
238 }
239
240 let mut update_vals = Vec::with_capacity(updates.len());
241 for (name, expr) in updates {
242 let val = self.eval_expr(expr)?;
243 update_vals.push((name.clone(), val));
244 }
245
246 if let Some(schema) = self.record_schemas.get(type_name) {
248 for (field_name, _) in &update_vals {
249 if !schema.iter().any(|f| f == field_name) {
250 return Err(RuntimeError::Error(format!(
251 "Record '{}' has no field '{}'",
252 type_name, field_name
253 )));
254 }
255 }
256 }
257
258 let mut fields: Vec<(String, Value)> = base_fields;
260 for (upd_name, upd_val) in update_vals {
261 if let Some(field) = fields.iter_mut().find(|(k, _)| k == &upd_name) {
262 field.1 = upd_val;
263 } else {
264 return Err(RuntimeError::Error(format!(
265 "Record '{}' has no field '{}'",
266 type_name, upd_name
267 )));
268 }
269 }
270
271 Ok(Value::Record {
272 type_name: type_name.to_string(),
273 fields,
274 })
275 }
276
277 #[inline(never)]
278 fn eval_map_literal(&mut self, entries: &[(Expr, Expr)]) -> Result<Value, RuntimeError> {
279 let mut map = HashMap::with_capacity(entries.len());
280 for (key_expr, value_expr) in entries {
281 let key = self.eval_expr(key_expr)?;
282 if !Self::is_hashable_map_key(&key) {
283 return Err(RuntimeError::Error(
284 "Map literal key must be Int, Float, String, or Bool".to_string(),
285 ));
286 }
287 let value = self.eval_expr(value_expr)?;
288 map.insert(key, value);
289 }
290 Ok(Value::Map(map))
291 }
292
293 fn is_hashable_map_key(value: &Value) -> bool {
294 matches!(
295 value,
296 Value::Int(_) | Value::Float(_) | Value::Str(_) | Value::Bool(_)
297 )
298 }
299
300 pub(super) fn eval_literal(&self, lit: &Literal) -> Value {
301 match lit {
302 Literal::Int(i) => Value::Int(*i),
303 Literal::Float(f) => Value::Float(*f),
304 Literal::Str(s) => Value::Str(s.clone()),
305 Literal::Bool(b) => Value::Bool(*b),
306 }
307 }
308
309 pub(super) fn call_value(
311 &mut self,
312 fn_val: Value,
313 args: Vec<Value>,
314 ) -> Result<Value, RuntimeError> {
315 match &fn_val {
316 Value::Builtin(name) => {
317 self.ensure_effects_allowed(name, Self::builtin_effects(name).iter().copied())?;
318 self.call_builtin(name, &args)
319 }
320 Value::Fn { .. } => self.call_fn_ref(&fn_val, args),
321 _ => Err(RuntimeError::Error(format!(
322 "Cannot call value: {:?}",
323 fn_val
324 ))),
325 }
326 }
327
328 pub(super) fn call_fn_ref(
333 &mut self,
334 fn_val: &Value,
335 args: Vec<Value>,
336 ) -> Result<Value, RuntimeError> {
337 let Value::Fn {
338 name,
339 params,
340 effects,
341 body,
342 resolution,
343 memo_eligible,
344 home_globals,
345 ..
346 } = fn_val
347 else {
348 return Err(RuntimeError::Error(format!(
349 "Cannot call value: {:?}",
350 fn_val
351 )));
352 };
353
354 if args.len() != params.len() {
355 return Err(RuntimeError::Error(format!(
356 "Function '{}' expects {} arguments, got {}",
357 name,
358 params.len(),
359 args.len()
360 )));
361 }
362 self.ensure_effects_allowed(name, effects.iter().map(String::as_str))?;
363
364 let is_memo = *memo_eligible;
366 let memo_key = if is_memo {
367 let key = hash_memo_args(&args);
368 if let Some(cached) = self
369 .memo_cache
370 .entry(name.clone())
371 .or_default()
372 .get(key, &args)
373 {
374 return Ok(cached);
375 }
376 Some((key, args.clone()))
377 } else {
378 None
379 };
380
381 self.call_stack.push(CallFrame {
382 name: name.clone(),
383 effects: effects.clone(),
384 });
385
386 let prev_local_slots = self.active_local_slots.take();
387 let saved_frames: Vec<EnvFrame> = self.env.drain(1..).collect();
388 let prev_global = if let Some(home) = home_globals {
389 let global = self
390 .env
391 .first_mut()
392 .ok_or_else(|| RuntimeError::Error("No global scope".to_string()))?;
393 Some(std::mem::replace(global, EnvFrame::Shared(Rc::clone(home))))
394 } else {
395 None
396 };
397
398 let result = if let Some(res) = resolution {
399 let mut slots = vec![Rc::new(Value::Unit); res.local_count as usize];
402 for ((param_name, _), arg_val) in params.iter().zip(args.into_iter()) {
403 if let Some(&slot) = res.local_slots.get(param_name) {
404 slots[slot as usize] = Rc::new(arg_val);
405 }
406 }
407 self.active_local_slots = Some(res.local_slots.clone());
408 self.push_env(EnvFrame::Slots(slots));
409 let r = match &**body {
410 FnBody::Expr(e) => self.eval_expr(e),
411 FnBody::Block(stmts) => self.exec_body_resolved(stmts, &res.local_slots),
412 };
413 self.pop_env();
414 r
415 } else {
416 let mut params_scope = HashMap::new();
418 for ((param_name, _), arg_val) in params.iter().zip(args.into_iter()) {
419 params_scope.insert(param_name.clone(), Rc::new(arg_val));
420 }
421 self.push_env(EnvFrame::Owned(params_scope));
422 let r = match &**body {
423 FnBody::Expr(e) => self.eval_expr(e),
424 FnBody::Block(stmts) => self.exec_body(stmts),
425 };
426 self.pop_env();
427 r
428 };
429
430 let result = match result {
432 Err(RuntimeError::TailCall(boxed)) => {
433 let (target, new_args) = *boxed;
434 self.tco_trampoline(name, params, body, resolution, target, new_args)
435 }
436 other => other,
437 };
438
439 self.active_local_slots = prev_local_slots;
440 if let Some(prev) = prev_global {
441 if let Some(global) = self.env.first_mut() {
442 *global = prev;
443 }
444 }
445 self.env.truncate(1);
446 self.env.extend(saved_frames);
447
448 self.call_stack.pop();
449 let final_result = match result {
450 Ok(v) => Ok(v),
451 Err(RuntimeError::ErrProp(e)) => Ok(Value::Err(e)),
452 Err(e) => Err(e),
453 };
454
455 if let (Some((key, memo_args)), Ok(val)) = (memo_key, &final_result) {
457 let fn_name = name.clone();
458 let cache = self.memo_cache.entry(fn_name).or_default();
459 cache.insert(key, memo_args, val.clone(), MEMO_CACHE_CAP_PER_FN);
460 }
461
462 final_result
463 }
464
465 #[inline(never)]
469 pub(super) fn tco_trampoline(
470 &mut self,
471 orig_name: &str,
472 orig_params: &[(String, String)],
473 orig_body: &Rc<FnBody>,
474 orig_resolution: &Option<FnResolution>,
475 first_target: String,
476 first_args: Vec<Value>,
477 ) -> Result<Value, RuntimeError> {
478 let mut cur_name = orig_name.to_string();
479 let mut cur_params: Vec<(String, String)> = orig_params.to_vec();
480 let mut cur_body = Rc::clone(orig_body);
481 let mut cur_resolution = orig_resolution.clone();
482
483 let mut target = first_target;
485 let mut new_args = first_args;
486
487 loop {
488 if target != cur_name {
490 let target_fn = self.lookup(&target)?;
491 match target_fn {
492 Value::Fn {
493 name: tn,
494 params: tp,
495 effects: te,
496 body: tb,
497 resolution: tr,
498 ..
499 } => {
500 cur_name = tn;
501 cur_params = tp;
502 cur_body = tb;
503 cur_resolution = tr;
504 if let Some(frame) = self.call_stack.last_mut() {
505 frame.name = cur_name.clone();
506 frame.effects = te;
507 }
508 }
509 _ => {
510 return Err(RuntimeError::Error(format!(
511 "TCO target '{}' is not a function",
512 target
513 )));
514 }
515 }
516 }
517
518 let exec_result = if let Some(ref res) = cur_resolution {
520 let mut slots = vec![Rc::new(Value::Unit); res.local_count as usize];
521 for ((param_name, _), arg_val) in cur_params.iter().zip(new_args.into_iter()) {
522 if let Some(&slot) = res.local_slots.get(param_name) {
523 slots[slot as usize] = Rc::new(arg_val);
524 }
525 }
526 self.active_local_slots = Some(res.local_slots.clone());
527 self.push_env(EnvFrame::Slots(slots));
528 let r = match &*cur_body {
529 FnBody::Expr(e) => self.eval_expr(e),
530 FnBody::Block(stmts) => self.exec_body_resolved(stmts, &res.local_slots),
531 };
532 self.pop_env();
533 r
534 } else {
535 let mut params_scope = HashMap::new();
536 for ((param_name, _), arg_val) in cur_params.iter().zip(new_args.into_iter()) {
537 params_scope.insert(param_name.clone(), Rc::new(arg_val));
538 }
539 let saved_frames: Vec<EnvFrame> = self.env.drain(1..).collect();
540 self.push_env(EnvFrame::Owned(params_scope));
541 let r = match &*cur_body {
542 FnBody::Expr(e) => self.eval_expr(e),
543 FnBody::Block(stmts) => self.exec_body(stmts),
544 };
545 self.pop_env();
546 self.env.extend(saved_frames);
547 r
548 };
549
550 match exec_result {
551 Err(RuntimeError::TailCall(boxed)) => {
552 let (next_target, next_args) = *boxed;
553 target = next_target;
554 new_args = next_args;
555 continue;
556 }
557 other => return other,
558 }
559 }
560 }
561}