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