1use crate::env::Env;
2use crate::error::EvalError;
3use crate::heap::{Heap, ThunkState};
4use crate::value::Value;
5use tidepool_repr::{
6 AltCon, CoreExpr, CoreFrame, DataConId, DataConTable, Literal, PrimOpKind, VarId,
7};
8
9pub fn env_from_datacon_table(table: &DataConTable) -> Env {
14 let mut env = Env::new();
15 for dc in table.iter() {
16 let var = VarId(dc.id.0);
17 if dc.rep_arity == 0 {
18 env.insert(var, Value::Con(dc.id, vec![]));
20 } else {
21 env.insert(var, Value::ConFun(dc.id, dc.rep_arity as usize, vec![]));
22 }
23 }
24 env
25}
26
27pub fn eval(expr: &CoreExpr, env: &Env, heap: &mut dyn Heap) -> Result<Value, EvalError> {
29 if expr.nodes.is_empty() {
30 return Err(EvalError::TypeMismatch {
31 expected: "non-empty expression",
32 got: crate::error::ValueKind::Other("empty tree".into()),
33 });
34 }
35 let res = eval_at(expr, expr.nodes.len() - 1, env, heap)?;
36 force(res, heap)
37}
38
39pub fn force(val: Value, heap: &mut dyn Heap) -> Result<Value, EvalError> {
41 match val {
42 Value::ThunkRef(id) => {
43 match heap.read(id).clone() {
44 ThunkState::Evaluated(v) => force(v, heap),
45 ThunkState::BlackHole => Err(EvalError::InfiniteLoop(id)),
46 ThunkState::Unevaluated(env, expr) => {
47 heap.write(id, ThunkState::BlackHole);
48 match eval(&expr, &env, heap) {
49 Ok(result) => {
50 heap.write(id, ThunkState::Evaluated(result.clone()));
51 Ok(result)
52 }
53 Err(err) => {
54 heap.write(id, ThunkState::Unevaluated(env, expr));
57 Err(err)
58 }
59 }
60 }
61 }
62 }
63 other => Ok(other),
64 }
65}
66
67pub fn deep_force(val: Value, heap: &mut dyn Heap) -> Result<Value, EvalError> {
72 use tidepool_repr::DataConId;
73
74 const MAX_DEPTH: usize = 100_000;
75
76 enum Work {
77 Force(Value),
78 BuildCon(DataConId, usize), BuildConFun(DataConId, usize, usize), }
81
82 let mut stack: Vec<Work> = vec![Work::Force(val)];
83 let mut results: Vec<Value> = Vec::new();
84
85 while let Some(work) = stack.pop() {
86 if stack.len() > MAX_DEPTH {
87 return Err(EvalError::DepthLimit);
88 }
89 match work {
90 Work::Force(v) => match v {
91 Value::ThunkRef(id) => {
92 let forced = force(Value::ThunkRef(id), heap)?;
93 stack.push(Work::Force(forced));
94 }
95 Value::Con(tag, fields) => {
96 let n = fields.len();
97 stack.push(Work::BuildCon(tag, n));
98 for f in fields.into_iter().rev() {
100 stack.push(Work::Force(f));
101 }
102 }
103 Value::ConFun(tag, arity, args) => {
104 let n = args.len();
105 stack.push(Work::BuildConFun(tag, arity, n));
106 for a in args.into_iter().rev() {
107 stack.push(Work::Force(a));
108 }
109 }
110 other => results.push(other),
111 },
112 Work::BuildCon(tag, n) => {
113 let start = results.len() - n;
114 let fields = results.split_off(start);
115 results.push(Value::Con(tag, fields));
116 }
117 Work::BuildConFun(tag, arity, n) => {
118 let start = results.len() - n;
119 let args = results.split_off(start);
120 results.push(Value::ConFun(tag, arity, args));
121 }
122 }
123 }
124
125 results.pop().ok_or(EvalError::TypeMismatch {
126 expected: "non-empty result stack",
127 got: crate::error::ValueKind::Closure,
128 })
129}
130
131fn eval_at(
133 expr: &CoreExpr,
134 idx: usize,
135 env: &Env,
136 heap: &mut dyn Heap,
137) -> Result<Value, EvalError> {
138 match &expr.nodes[idx] {
139 CoreFrame::Var(v) => {
140 let tag = (v.0 >> 56) as u8;
141 if tag == tidepool_repr::ERROR_SENTINEL_TAG {
142 let kind = v.0 & 0xFF;
144 return Err(match kind {
145 0 => EvalError::TypeMismatch {
146 expected: "non-zero divisor",
147 got: crate::error::ValueKind::Other("division by zero".into()),
148 },
149 1 => EvalError::TypeMismatch {
150 expected: "no overflow",
151 got: crate::error::ValueKind::Other("arithmetic overflow".into()),
152 },
153 2 => EvalError::UserError,
154 3 => EvalError::Undefined,
155 _ => EvalError::UserError,
156 });
157 }
158 env.get(v).cloned().ok_or(EvalError::UnboundVar(*v))
159 }
160 CoreFrame::Lit(lit) => Ok(Value::Lit(lit.clone())),
161 CoreFrame::App { fun, arg } => {
162 let fun_val = force(eval_at(expr, *fun, env, heap)?, heap)?;
163 let arg_val = eval_at(expr, *arg, env, heap)?;
164 match fun_val {
165 Value::Closure(clos_env, binder, body) => {
166 let mut new_env = clos_env;
167 new_env.insert(binder, arg_val);
168 eval(&body, &new_env, heap)
169 }
170 Value::ConFun(tag, arity, mut args) => {
171 args.push(arg_val);
172 if args.len() == arity {
173 Ok(Value::Con(tag, args))
176 } else {
177 Ok(Value::ConFun(tag, arity, args))
178 }
179 }
180 _ => Err(EvalError::NotAFunction),
181 }
182 }
183 CoreFrame::Lam { binder, body } => {
184 let body_expr = expr.extract_subtree(*body);
185 Ok(Value::Closure(env.clone(), *binder, body_expr))
186 }
187 CoreFrame::LetNonRec { binder, rhs, body } => {
188 let rhs_val = if matches!(&expr.nodes[*rhs], CoreFrame::Lam { .. }) {
189 eval_at(expr, *rhs, env, heap)? } else {
191 let thunk_id = heap.alloc(env.clone(), expr.extract_subtree(*rhs));
192 Value::ThunkRef(thunk_id)
193 };
194 let new_env = env.update(*binder, rhs_val);
195 eval_at(expr, *body, &new_env, heap)
196 }
197 CoreFrame::LetRec { bindings, body } => {
198 let mut new_env = env.clone();
199 let mut thunks = Vec::new();
200
201 for (binder, rhs_idx) in bindings {
204 let tid = heap.alloc(Env::new(), CoreExpr { nodes: vec![] });
205 new_env = new_env.update(*binder, Value::ThunkRef(tid));
206 thunks.push((*binder, tid, *rhs_idx));
207 }
208
209 for (binder, tid, rhs_idx) in &thunks {
211 if matches!(&expr.nodes[*rhs_idx], CoreFrame::Lam { .. }) {
212 let lam_val = eval_at(expr, *rhs_idx, &new_env, heap)?;
213 heap.write(*tid, ThunkState::Evaluated(lam_val.clone()));
214 new_env = new_env.update(*binder, lam_val);
215 } else {
216 let rhs_subtree = expr.extract_subtree(*rhs_idx);
217 heap.write(*tid, ThunkState::Unevaluated(new_env.clone(), rhs_subtree));
218 }
219 }
220
221 eval_at(expr, *body, &new_env, heap)
222 }
223 CoreFrame::Con { tag, fields } => {
224 let mut field_vals = Vec::with_capacity(fields.len());
225 for &f in fields {
226 match &expr.nodes[f] {
232 CoreFrame::Var(_)
233 | CoreFrame::Lit(_)
234 | CoreFrame::Con { .. }
235 | CoreFrame::Lam { .. }
236 | CoreFrame::PrimOp { .. } => {
237 field_vals.push(eval_at(expr, f, env, heap)?);
238 }
239 _ => {
240 let subtree = expr.extract_subtree(f);
241 let thunk_id = heap.alloc(env.clone(), subtree);
242 field_vals.push(Value::ThunkRef(thunk_id));
243 }
244 }
245 }
246 Ok(Value::Con(*tag, field_vals))
247 }
248 CoreFrame::Case {
249 scrutinee,
250 binder,
251 alts,
252 } => {
253 let scrut_val = force(eval_at(expr, *scrutinee, env, heap)?, heap)?;
254 let case_env = env.update(*binder, scrut_val.clone());
255
256 let mut default_alt = None;
259 for alt in alts {
260 match &alt.con {
261 AltCon::DataAlt(tag) => {
262 if let Value::Con(con_tag, fields) = &scrut_val {
263 if con_tag == tag {
264 if fields.len() != alt.binders.len() {
265 return Err(EvalError::ArityMismatch {
266 context: "case binders",
267 expected: alt.binders.len(),
268 got: fields.len(),
269 });
270 }
271 let mut alt_env = case_env;
272 for (b, v) in alt.binders.iter().zip(fields.iter()) {
273 alt_env = alt_env.update(*b, v.clone());
274 }
275 return eval_at(expr, alt.body, &alt_env, heap);
276 }
277 }
278 }
279 AltCon::LitAlt(lit) => {
280 if let Value::Lit(l) = &scrut_val {
281 if l == lit {
282 return eval_at(expr, alt.body, &case_env, heap);
283 }
284 }
285 }
286 AltCon::Default => {
287 default_alt = Some(alt);
288 }
289 }
290 }
291 if let Some(alt) = default_alt {
292 return eval_at(expr, alt.body, &case_env, heap);
293 }
294 Err(EvalError::NoMatchingAlt)
295 }
296 CoreFrame::PrimOp { op, args } => {
297 let mut arg_vals = Vec::with_capacity(args.len());
298 for &arg in args {
299 let val = force(eval_at(expr, arg, env, heap)?, heap)?;
300 arg_vals.push(val);
301 }
302 match op {
304 PrimOpKind::ShowDoubleAddr => {
305 if arg_vals.len() != 1 {
306 return Err(EvalError::ArityMismatch {
307 context: "arguments",
308 expected: 1,
309 got: arg_vals.len(),
310 });
311 }
312 let d = match &arg_vals[0] {
314 Value::Lit(Literal::LitDouble(bits)) => f64::from_bits(*bits),
315 Value::Con(_, fields) if fields.len() == 1 => {
316 let forced = force(fields[0].clone(), heap)?;
317 expect_double(&forced)?
318 }
319 other => {
320 return Err(EvalError::TypeMismatch {
321 expected: "Double# or D# Double#",
322 got: crate::error::ValueKind::Other(format!("{:?}", other)),
323 })
324 }
325 };
326 let s = eval_haskell_show_double(d);
327 let mut bytes = s.into_bytes();
328 bytes.push(0); Ok(Value::Lit(Literal::LitString(bytes)))
330 }
331 _ => dispatch_primop(*op, arg_vals),
332 }
333 }
334 CoreFrame::Join {
335 label,
336 params,
337 rhs,
338 body,
339 } => {
340 let join_val = Value::JoinCont(params.clone(), expr.extract_subtree(*rhs), env.clone());
341 let join_var = VarId(label.0 | (1u64 << 63)); let new_env = env.update(join_var, join_val);
343 eval_at(expr, *body, &new_env, heap)
344 }
345 CoreFrame::Jump { label, args } => {
346 let join_var = VarId(label.0 | (1u64 << 63));
347 match env.get(&join_var) {
348 Some(Value::JoinCont(params, rhs_expr, join_env)) => {
349 if params.len() != args.len() {
350 return Err(EvalError::ArityMismatch {
351 context: "arguments",
352 expected: params.len(),
353 got: args.len(),
354 });
355 }
356 let params = params.clone();
357 let rhs_expr = rhs_expr.clone();
358 let mut new_env = join_env.clone();
359 for (param, arg_idx) in params.iter().zip(args.iter()) {
360 let arg_val = eval_at(expr, *arg_idx, env, heap)?;
361 new_env = new_env.update(*param, arg_val);
362 }
363 eval(&rhs_expr, &new_env, heap)
364 }
365 _ => Err(EvalError::UnboundJoin(*label)),
366 }
367 }
368 }
369}
370
371fn dispatch_primop(op: PrimOpKind, args: Vec<Value>) -> Result<Value, EvalError> {
372 match op {
373 PrimOpKind::IntAdd => {
374 let (a, b) = bin_op_int(op, &args)?;
375 Ok(Value::Lit(Literal::LitInt(a.wrapping_add(b))))
376 }
377 PrimOpKind::IntSub => {
378 let (a, b) = bin_op_int(op, &args)?;
379 Ok(Value::Lit(Literal::LitInt(a.wrapping_sub(b))))
380 }
381 PrimOpKind::IntMul => {
382 let (a, b) = bin_op_int(op, &args)?;
383 Ok(Value::Lit(Literal::LitInt(a.wrapping_mul(b))))
384 }
385 PrimOpKind::IntNegate => {
386 if args.len() != 1 {
387 return Err(EvalError::ArityMismatch {
388 context: "arguments",
389 expected: 1,
390 got: args.len(),
391 });
392 }
393 let a = expect_int(&args[0])?;
394 Ok(Value::Lit(Literal::LitInt(a.wrapping_neg())))
395 }
396 PrimOpKind::IntEq => cmp_int(op, &args, |a, b| a == b),
397 PrimOpKind::IntNe => cmp_int(op, &args, |a, b| a != b),
398 PrimOpKind::IntLt => cmp_int(op, &args, |a, b| a < b),
399 PrimOpKind::IntLe => cmp_int(op, &args, |a, b| a <= b),
400 PrimOpKind::IntGt => cmp_int(op, &args, |a, b| a > b),
401 PrimOpKind::IntGe => cmp_int(op, &args, |a, b| a >= b),
402 PrimOpKind::IntAnd => {
403 let (a, b) = bin_op_int(op, &args)?;
404 Ok(Value::Lit(Literal::LitInt(a & b)))
405 }
406 PrimOpKind::IntOr => {
407 let (a, b) = bin_op_int(op, &args)?;
408 Ok(Value::Lit(Literal::LitInt(a | b)))
409 }
410 PrimOpKind::IntXor => {
411 let (a, b) = bin_op_int(op, &args)?;
412 Ok(Value::Lit(Literal::LitInt(a ^ b)))
413 }
414 PrimOpKind::IntNot => {
415 if args.len() != 1 {
416 return Err(EvalError::ArityMismatch {
417 context: "arguments",
418 expected: 1,
419 got: args.len(),
420 });
421 }
422 let a = expect_int(&args[0])?;
423 Ok(Value::Lit(Literal::LitInt(!a)))
424 }
425 PrimOpKind::IntShl => {
426 let (a, b) = bin_op_int(op, &args)?;
427 Ok(Value::Lit(Literal::LitInt(a.wrapping_shl(b as u32))))
428 }
429 PrimOpKind::IntShra => {
430 let (a, b) = bin_op_int(op, &args)?;
431 Ok(Value::Lit(Literal::LitInt(a.wrapping_shr(b as u32))))
432 }
433 PrimOpKind::IntShrl => {
434 let (a, b) = bin_op_int(op, &args)?;
435 Ok(Value::Lit(Literal::LitInt(
436 (a as u64).wrapping_shr(b as u32) as i64,
437 )))
438 }
439
440 PrimOpKind::WordAdd => {
441 let (a, b) = bin_op_word(op, &args)?;
442 Ok(Value::Lit(Literal::LitWord(a.wrapping_add(b))))
443 }
444 PrimOpKind::WordSub => {
445 let (a, b) = bin_op_word(op, &args)?;
446 Ok(Value::Lit(Literal::LitWord(a.wrapping_sub(b))))
447 }
448 PrimOpKind::WordMul => {
449 let (a, b) = bin_op_word(op, &args)?;
450 Ok(Value::Lit(Literal::LitWord(a.wrapping_mul(b))))
451 }
452 PrimOpKind::WordEq => cmp_word(op, &args, |a, b| a == b),
453 PrimOpKind::WordNe => cmp_word(op, &args, |a, b| a != b),
454 PrimOpKind::WordLt => cmp_word(op, &args, |a, b| a < b),
455 PrimOpKind::WordLe => cmp_word(op, &args, |a, b| a <= b),
456 PrimOpKind::WordGt => cmp_word(op, &args, |a, b| a > b),
457 PrimOpKind::WordGe => cmp_word(op, &args, |a, b| a >= b),
458 PrimOpKind::WordQuot => {
459 let (a, b) = bin_op_word(op, &args)?;
460 if b == 0 {
461 return Err(EvalError::InternalError(
462 "division by zero (quotWord#)".into(),
463 ));
464 }
465 Ok(Value::Lit(Literal::LitWord(a.wrapping_div(b))))
466 }
467 PrimOpKind::WordRem => {
468 let (a, b) = bin_op_word(op, &args)?;
469 if b == 0 {
470 return Err(EvalError::InternalError(
471 "division by zero (remWord#)".into(),
472 ));
473 }
474 Ok(Value::Lit(Literal::LitWord(a.wrapping_rem(b))))
475 }
476 PrimOpKind::WordAnd => {
477 let (a, b) = bin_op_word(op, &args)?;
478 Ok(Value::Lit(Literal::LitWord(a & b)))
479 }
480 PrimOpKind::WordOr => {
481 let (a, b) = bin_op_word(op, &args)?;
482 Ok(Value::Lit(Literal::LitWord(a | b)))
483 }
484 PrimOpKind::WordXor => {
485 let (a, b) = bin_op_word(op, &args)?;
486 Ok(Value::Lit(Literal::LitWord(a ^ b)))
487 }
488 PrimOpKind::WordNot => {
489 if args.len() != 1 {
490 return Err(EvalError::ArityMismatch {
491 context: "arguments",
492 expected: 1,
493 got: args.len(),
494 });
495 }
496 let a = expect_word(&args[0])?;
497 Ok(Value::Lit(Literal::LitWord(!a)))
498 }
499 PrimOpKind::WordShl => {
500 if args.len() != 2 {
501 return Err(EvalError::ArityMismatch {
502 context: "arguments",
503 expected: 2,
504 got: args.len(),
505 });
506 }
507 let a = expect_word(&args[0])?;
508 let b = expect_int(&args[1])?;
509 Ok(Value::Lit(Literal::LitWord(a.wrapping_shl(b as u32))))
510 }
511 PrimOpKind::WordShrl => {
512 if args.len() != 2 {
513 return Err(EvalError::ArityMismatch {
514 context: "arguments",
515 expected: 2,
516 got: args.len(),
517 });
518 }
519 let a = expect_word(&args[0])?;
520 let b = expect_int(&args[1])?;
521 Ok(Value::Lit(Literal::LitWord(a.wrapping_shr(b as u32))))
522 }
523
524 PrimOpKind::DoubleAdd => {
525 let (a, b) = bin_op_double(op, &args)?;
526 Ok(Value::Lit(Literal::LitDouble((a + b).to_bits())))
527 }
528 PrimOpKind::DoubleSub => {
529 let (a, b) = bin_op_double(op, &args)?;
530 Ok(Value::Lit(Literal::LitDouble((a - b).to_bits())))
531 }
532 PrimOpKind::DoubleMul => {
533 let (a, b) = bin_op_double(op, &args)?;
534 Ok(Value::Lit(Literal::LitDouble((a * b).to_bits())))
535 }
536 PrimOpKind::DoubleDiv => {
537 let (a, b) = bin_op_double(op, &args)?;
538 Ok(Value::Lit(Literal::LitDouble((a / b).to_bits())))
539 }
540 PrimOpKind::DoubleEq => cmp_double(op, &args, |a, b| a == b),
541 PrimOpKind::DoubleNe => cmp_double(op, &args, |a, b| a != b),
542 PrimOpKind::DoubleLt => cmp_double(op, &args, |a, b| a < b),
543 PrimOpKind::DoubleLe => cmp_double(op, &args, |a, b| a <= b),
544 PrimOpKind::DoubleGt => cmp_double(op, &args, |a, b| a > b),
545 PrimOpKind::DoubleGe => cmp_double(op, &args, |a, b| a >= b),
546 PrimOpKind::DoubleNegate => {
547 if args.len() != 1 {
548 return Err(EvalError::ArityMismatch {
549 context: "arguments",
550 expected: 1,
551 got: args.len(),
552 });
553 }
554 let a = expect_double(&args[0])?;
555 Ok(Value::Lit(Literal::LitDouble((-a).to_bits())))
556 }
557 PrimOpKind::DoubleFabs => {
558 if args.len() != 1 {
559 return Err(EvalError::ArityMismatch {
560 context: "arguments",
561 expected: 1,
562 got: args.len(),
563 });
564 }
565 let a = expect_double(&args[0])?;
566 Ok(Value::Lit(Literal::LitDouble(a.abs().to_bits())))
567 }
568 PrimOpKind::DoubleSqrt => {
569 if args.len() != 1 {
570 return Err(EvalError::ArityMismatch {
571 context: "arguments",
572 expected: 1,
573 got: args.len(),
574 });
575 }
576 let a = expect_double(&args[0])?;
577 Ok(Value::Lit(Literal::LitDouble(a.sqrt().to_bits())))
578 }
579 PrimOpKind::DoubleExp => {
580 if args.len() != 1 {
581 return Err(EvalError::ArityMismatch {
582 context: "arguments",
583 expected: 1,
584 got: args.len(),
585 });
586 }
587 let a = expect_double(&args[0])?;
588 Ok(Value::Lit(Literal::LitDouble(a.exp().to_bits())))
589 }
590 PrimOpKind::DoubleExpM1 => {
591 if args.len() != 1 {
592 return Err(EvalError::ArityMismatch {
593 context: "arguments",
594 expected: 1,
595 got: args.len(),
596 });
597 }
598 let a = expect_double(&args[0])?;
599 Ok(Value::Lit(Literal::LitDouble(a.exp_m1().to_bits())))
600 }
601 PrimOpKind::DoubleLog => {
602 if args.len() != 1 {
603 return Err(EvalError::ArityMismatch {
604 context: "arguments",
605 expected: 1,
606 got: args.len(),
607 });
608 }
609 let a = expect_double(&args[0])?;
610 Ok(Value::Lit(Literal::LitDouble(a.ln().to_bits())))
611 }
612 PrimOpKind::DoubleLog1P => {
613 if args.len() != 1 {
614 return Err(EvalError::ArityMismatch {
615 context: "arguments",
616 expected: 1,
617 got: args.len(),
618 });
619 }
620 let a = expect_double(&args[0])?;
621 Ok(Value::Lit(Literal::LitDouble(a.ln_1p().to_bits())))
622 }
623 PrimOpKind::DoubleSin => {
624 if args.len() != 1 {
625 return Err(EvalError::ArityMismatch {
626 context: "arguments",
627 expected: 1,
628 got: args.len(),
629 });
630 }
631 let a = expect_double(&args[0])?;
632 Ok(Value::Lit(Literal::LitDouble(a.sin().to_bits())))
633 }
634 PrimOpKind::DoubleCos => {
635 if args.len() != 1 {
636 return Err(EvalError::ArityMismatch {
637 context: "arguments",
638 expected: 1,
639 got: args.len(),
640 });
641 }
642 let a = expect_double(&args[0])?;
643 Ok(Value::Lit(Literal::LitDouble(a.cos().to_bits())))
644 }
645 PrimOpKind::DoubleTan => {
646 if args.len() != 1 {
647 return Err(EvalError::ArityMismatch {
648 context: "arguments",
649 expected: 1,
650 got: args.len(),
651 });
652 }
653 let a = expect_double(&args[0])?;
654 Ok(Value::Lit(Literal::LitDouble(a.tan().to_bits())))
655 }
656 PrimOpKind::DoubleAsin => {
657 if args.len() != 1 {
658 return Err(EvalError::ArityMismatch {
659 context: "arguments",
660 expected: 1,
661 got: args.len(),
662 });
663 }
664 let a = expect_double(&args[0])?;
665 Ok(Value::Lit(Literal::LitDouble(a.asin().to_bits())))
666 }
667 PrimOpKind::DoubleAcos => {
668 if args.len() != 1 {
669 return Err(EvalError::ArityMismatch {
670 context: "arguments",
671 expected: 1,
672 got: args.len(),
673 });
674 }
675 let a = expect_double(&args[0])?;
676 Ok(Value::Lit(Literal::LitDouble(a.acos().to_bits())))
677 }
678 PrimOpKind::DoubleAtan => {
679 if args.len() != 1 {
680 return Err(EvalError::ArityMismatch {
681 context: "arguments",
682 expected: 1,
683 got: args.len(),
684 });
685 }
686 let a = expect_double(&args[0])?;
687 Ok(Value::Lit(Literal::LitDouble(a.atan().to_bits())))
688 }
689 PrimOpKind::DoubleSinh => {
690 if args.len() != 1 {
691 return Err(EvalError::ArityMismatch {
692 context: "arguments",
693 expected: 1,
694 got: args.len(),
695 });
696 }
697 let a = expect_double(&args[0])?;
698 Ok(Value::Lit(Literal::LitDouble(a.sinh().to_bits())))
699 }
700 PrimOpKind::DoubleCosh => {
701 if args.len() != 1 {
702 return Err(EvalError::ArityMismatch {
703 context: "arguments",
704 expected: 1,
705 got: args.len(),
706 });
707 }
708 let a = expect_double(&args[0])?;
709 Ok(Value::Lit(Literal::LitDouble(a.cosh().to_bits())))
710 }
711 PrimOpKind::DoubleTanh => {
712 if args.len() != 1 {
713 return Err(EvalError::ArityMismatch {
714 context: "arguments",
715 expected: 1,
716 got: args.len(),
717 });
718 }
719 let a = expect_double(&args[0])?;
720 Ok(Value::Lit(Literal::LitDouble(a.tanh().to_bits())))
721 }
722 PrimOpKind::DoubleAsinh => {
723 if args.len() != 1 {
724 return Err(EvalError::ArityMismatch {
725 context: "arguments",
726 expected: 1,
727 got: args.len(),
728 });
729 }
730 let a = expect_double(&args[0])?;
731 Ok(Value::Lit(Literal::LitDouble(a.asinh().to_bits())))
732 }
733 PrimOpKind::DoubleAcosh => {
734 if args.len() != 1 {
735 return Err(EvalError::ArityMismatch {
736 context: "arguments",
737 expected: 1,
738 got: args.len(),
739 });
740 }
741 let a = expect_double(&args[0])?;
742 Ok(Value::Lit(Literal::LitDouble(a.acosh().to_bits())))
743 }
744 PrimOpKind::DoubleAtanh => {
745 if args.len() != 1 {
746 return Err(EvalError::ArityMismatch {
747 context: "arguments",
748 expected: 1,
749 got: args.len(),
750 });
751 }
752 let a = expect_double(&args[0])?;
753 Ok(Value::Lit(Literal::LitDouble(a.atanh().to_bits())))
754 }
755 PrimOpKind::DoublePower => {
756 if args.len() != 2 {
757 return Err(EvalError::ArityMismatch {
758 context: "arguments",
759 expected: 2,
760 got: args.len(),
761 });
762 }
763 let a = expect_double(&args[0])?;
764 let b = expect_double(&args[1])?;
765 Ok(Value::Lit(Literal::LitDouble(a.powf(b).to_bits())))
766 }
767 PrimOpKind::FloatAdd => {
768 let (a, b) = bin_op_float(op, &args)?;
769 Ok(Value::Lit(Literal::LitFloat((a + b).to_bits() as u64)))
770 }
771 PrimOpKind::FloatSub => {
772 let (a, b) = bin_op_float(op, &args)?;
773 Ok(Value::Lit(Literal::LitFloat((a - b).to_bits() as u64)))
774 }
775 PrimOpKind::FloatMul => {
776 let (a, b) = bin_op_float(op, &args)?;
777 Ok(Value::Lit(Literal::LitFloat((a * b).to_bits() as u64)))
778 }
779 PrimOpKind::FloatDiv => {
780 let (a, b) = bin_op_float(op, &args)?;
781 Ok(Value::Lit(Literal::LitFloat((a / b).to_bits() as u64)))
782 }
783 PrimOpKind::FloatNegate => {
784 if args.len() != 1 {
785 return Err(EvalError::ArityMismatch {
786 context: "arguments",
787 expected: 1,
788 got: args.len(),
789 });
790 }
791 let a = expect_float(&args[0])?;
792 Ok(Value::Lit(Literal::LitFloat((-a).to_bits() as u64)))
793 }
794 PrimOpKind::FloatEq => cmp_float(op, &args, |a, b| a == b),
795 PrimOpKind::FloatNe => cmp_float(op, &args, |a, b| a != b),
796 PrimOpKind::FloatLt => cmp_float(op, &args, |a, b| a < b),
797 PrimOpKind::FloatLe => cmp_float(op, &args, |a, b| a <= b),
798 PrimOpKind::FloatGt => cmp_float(op, &args, |a, b| a > b),
799 PrimOpKind::FloatGe => cmp_float(op, &args, |a, b| a >= b),
800
801 PrimOpKind::CharEq => cmp_char(op, &args, |a, b| a == b),
802 PrimOpKind::CharNe => cmp_char(op, &args, |a, b| a != b),
803 PrimOpKind::CharLt => cmp_char(op, &args, |a, b| a < b),
804 PrimOpKind::CharLe => cmp_char(op, &args, |a, b| a <= b),
805 PrimOpKind::CharGt => cmp_char(op, &args, |a, b| a > b),
806 PrimOpKind::CharGe => cmp_char(op, &args, |a, b| a >= b),
807 PrimOpKind::Int2Word => {
808 if args.len() != 1 {
809 return Err(EvalError::ArityMismatch {
810 context: "arguments",
811 expected: 1,
812 got: args.len(),
813 });
814 }
815 let a = expect_int(&args[0])?;
816 Ok(Value::Lit(Literal::LitWord(a as u64)))
817 }
818 PrimOpKind::Word2Int => {
819 if args.len() != 1 {
820 return Err(EvalError::ArityMismatch {
821 context: "arguments",
822 expected: 1,
823 got: args.len(),
824 });
825 }
826 let a = expect_word(&args[0])?;
827 Ok(Value::Lit(Literal::LitInt(a as i64)))
828 }
829 PrimOpKind::Narrow8Int => {
830 if args.len() != 1 {
831 return Err(EvalError::ArityMismatch {
832 context: "arguments",
833 expected: 1,
834 got: args.len(),
835 });
836 }
837 let a = expect_int(&args[0])?;
838 Ok(Value::Lit(Literal::LitInt(a as i8 as i64)))
839 }
840 PrimOpKind::Narrow16Int => {
841 if args.len() != 1 {
842 return Err(EvalError::ArityMismatch {
843 context: "arguments",
844 expected: 1,
845 got: args.len(),
846 });
847 }
848 let a = expect_int(&args[0])?;
849 Ok(Value::Lit(Literal::LitInt(a as i16 as i64)))
850 }
851 PrimOpKind::Narrow32Int => {
852 if args.len() != 1 {
853 return Err(EvalError::ArityMismatch {
854 context: "arguments",
855 expected: 1,
856 got: args.len(),
857 });
858 }
859 let a = expect_int(&args[0])?;
860 Ok(Value::Lit(Literal::LitInt(a as i32 as i64)))
861 }
862 PrimOpKind::Narrow8Word => {
863 if args.len() != 1 {
864 return Err(EvalError::ArityMismatch {
865 context: "arguments",
866 expected: 1,
867 got: args.len(),
868 });
869 }
870 let a = expect_word(&args[0])?;
871 Ok(Value::Lit(Literal::LitWord(a as u8 as u64)))
872 }
873 PrimOpKind::Narrow16Word => {
874 if args.len() != 1 {
875 return Err(EvalError::ArityMismatch {
876 context: "arguments",
877 expected: 1,
878 got: args.len(),
879 });
880 }
881 let a = expect_word(&args[0])?;
882 Ok(Value::Lit(Literal::LitWord(a as u16 as u64)))
883 }
884 PrimOpKind::Narrow32Word => {
885 if args.len() != 1 {
886 return Err(EvalError::ArityMismatch {
887 context: "arguments",
888 expected: 1,
889 got: args.len(),
890 });
891 }
892 let a = expect_word(&args[0])?;
893 Ok(Value::Lit(Literal::LitWord(a as u32 as u64)))
894 }
895 PrimOpKind::Int2Double => {
896 if args.len() != 1 {
897 return Err(EvalError::ArityMismatch {
898 context: "arguments",
899 expected: 1,
900 got: args.len(),
901 });
902 }
903 let a = expect_int(&args[0])?;
904 Ok(Value::Lit(Literal::LitDouble((a as f64).to_bits())))
905 }
906 PrimOpKind::Double2Int => {
907 if args.len() != 1 {
908 return Err(EvalError::ArityMismatch {
909 context: "arguments",
910 expected: 1,
911 got: args.len(),
912 });
913 }
914 let a = expect_double(&args[0])?;
915 Ok(Value::Lit(Literal::LitInt(a as i64)))
916 }
917 PrimOpKind::DecodeDoubleMantissa => {
918 if args.len() != 1 {
919 return Err(EvalError::ArityMismatch {
920 context: "arguments",
921 expected: 1,
922 got: args.len(),
923 });
924 }
925 let d = expect_double(&args[0])?;
926 let (man, _) = eval_decode_double_int64(d);
927 Ok(Value::Lit(Literal::LitInt(man)))
928 }
929 PrimOpKind::DecodeDoubleExponent => {
930 if args.len() != 1 {
931 return Err(EvalError::ArityMismatch {
932 context: "arguments",
933 expected: 1,
934 got: args.len(),
935 });
936 }
937 let d = expect_double(&args[0])?;
938 let (_, exp) = eval_decode_double_int64(d);
939 Ok(Value::Lit(Literal::LitInt(exp)))
940 }
941 PrimOpKind::ShowDoubleAddr => {
942 unreachable!("ShowDoubleAddr should be intercepted in eval_at")
944 }
945 PrimOpKind::Int2Float => {
946 if args.len() != 1 {
947 return Err(EvalError::ArityMismatch {
948 context: "arguments",
949 expected: 1,
950 got: args.len(),
951 });
952 }
953 let a = expect_int(&args[0])?;
954 Ok(Value::Lit(Literal::LitFloat((a as f32).to_bits() as u64)))
955 }
956 PrimOpKind::Float2Int => {
957 if args.len() != 1 {
958 return Err(EvalError::ArityMismatch {
959 context: "arguments",
960 expected: 1,
961 got: args.len(),
962 });
963 }
964 let a = expect_float(&args[0])?;
965 Ok(Value::Lit(Literal::LitInt(a as i64)))
966 }
967 PrimOpKind::Double2Float => {
968 if args.len() != 1 {
969 return Err(EvalError::ArityMismatch {
970 context: "arguments",
971 expected: 1,
972 got: args.len(),
973 });
974 }
975 let a = expect_double(&args[0])?;
976 Ok(Value::Lit(Literal::LitFloat((a as f32).to_bits() as u64)))
977 }
978 PrimOpKind::Float2Double => {
979 if args.len() != 1 {
980 return Err(EvalError::ArityMismatch {
981 context: "arguments",
982 expected: 1,
983 got: args.len(),
984 });
985 }
986 let a = expect_float(&args[0])?;
987 Ok(Value::Lit(Literal::LitDouble((a as f64).to_bits())))
988 }
989
990 PrimOpKind::SeqOp => {
991 if args.len() != 2 {
992 return Err(EvalError::ArityMismatch {
993 context: "arguments",
994 expected: 2,
995 got: args.len(),
996 });
997 }
998 Ok(args[1].clone())
999 }
1000 PrimOpKind::DataToTag => {
1001 if args.len() != 1 {
1002 return Err(EvalError::ArityMismatch {
1003 context: "arguments",
1004 expected: 1,
1005 got: args.len(),
1006 });
1007 }
1008 if let Value::Con(DataConId(tag), _) = &args[0] {
1009 Ok(Value::Lit(Literal::LitInt(*tag as i64)))
1010 } else {
1011 Err(EvalError::TypeMismatch {
1012 expected: "Data constructor",
1013 got: crate::error::ValueKind::Other(format!("{:?}", args[0])),
1014 })
1015 }
1016 }
1017 PrimOpKind::IntQuot => {
1018 let (a, b) = bin_op_int(op, &args)?;
1019 if b == 0 {
1020 return Err(EvalError::InternalError(
1021 "division by zero (quotInt#)".into(),
1022 ));
1023 }
1024 Ok(Value::Lit(Literal::LitInt(a.wrapping_div(b))))
1025 }
1026 PrimOpKind::IntRem => {
1027 let (a, b) = bin_op_int(op, &args)?;
1028 if b == 0 {
1029 return Err(EvalError::InternalError(
1030 "division by zero (remInt#)".into(),
1031 ));
1032 }
1033 Ok(Value::Lit(Literal::LitInt(a.wrapping_rem(b))))
1034 }
1035 PrimOpKind::Chr => {
1036 if args.len() != 1 {
1037 return Err(EvalError::ArityMismatch {
1038 context: "arguments",
1039 expected: 1,
1040 got: args.len(),
1041 });
1042 }
1043 let n = expect_int(&args[0])?;
1044 let code = u32::try_from(n).map_err(|_| EvalError::TypeMismatch {
1045 expected: "valid Unicode codepoint (0..=0x10FFFF)",
1046 got: crate::error::ValueKind::Other(format!("out of range: {}", n)),
1047 })?;
1048 let c = char::from_u32(code).ok_or_else(|| EvalError::TypeMismatch {
1049 expected: "valid Unicode codepoint",
1050 got: crate::error::ValueKind::Other(format!("invalid codepoint: {}", n)),
1051 })?;
1052 Ok(Value::Lit(Literal::LitChar(c)))
1053 }
1054 PrimOpKind::Ord => {
1055 if args.len() != 1 {
1056 return Err(EvalError::ArityMismatch {
1057 context: "arguments",
1058 expected: 1,
1059 got: args.len(),
1060 });
1061 }
1062 let c = expect_char(&args[0])?;
1063 Ok(Value::Lit(Literal::LitInt(c as i64)))
1064 }
1065 PrimOpKind::IndexCharOffAddr => {
1066 if args.len() != 2 {
1067 return Err(EvalError::ArityMismatch {
1068 context: "arguments",
1069 expected: 2,
1070 got: args.len(),
1071 });
1072 }
1073 let bytes = match &args[0] {
1074 Value::Lit(Literal::LitString(bs)) => bs,
1075 other => {
1076 return Err(EvalError::TypeMismatch {
1077 expected: "Addr# (LitString)",
1078 got: crate::error::ValueKind::Other(format!("{:?}", other)),
1079 })
1080 }
1081 };
1082 let offset = expect_int(&args[1])? as usize;
1083 let ch = bytes.get(offset).copied().unwrap_or(0);
1084 Ok(Value::Lit(Literal::LitChar(ch as char)))
1085 }
1086 PrimOpKind::PlusAddr => {
1087 if args.len() != 2 {
1090 return Err(EvalError::ArityMismatch {
1091 context: "arguments",
1092 expected: 2,
1093 got: args.len(),
1094 });
1095 }
1096 let bytes = match &args[0] {
1097 Value::Lit(Literal::LitString(bs)) => bs,
1098 other => {
1099 return Err(EvalError::TypeMismatch {
1100 expected: "Addr# (LitString)",
1101 got: crate::error::ValueKind::Other(format!("{:?}", other)),
1102 })
1103 }
1104 };
1105 let offset = expect_int(&args[1])? as usize;
1106 if offset > bytes.len() {
1107 return Err(EvalError::TypeMismatch {
1108 expected: "valid byte offset",
1109 got: crate::error::ValueKind::Other(format!(
1110 "offset {} exceeds length {}",
1111 offset,
1112 bytes.len()
1113 )),
1114 });
1115 }
1116 Ok(Value::Lit(Literal::LitString(bytes[offset..].to_vec())))
1117 }
1118 PrimOpKind::ReallyUnsafePtrEquality => Ok(Value::Lit(Literal::LitInt(0))),
1119 PrimOpKind::Raise => Err(EvalError::UserError),
1120 PrimOpKind::IndexArray | PrimOpKind::TagToEnum => Err(EvalError::UnsupportedPrimOp(op)),
1121
1122 PrimOpKind::NewByteArray => {
1124 let size = expect_int(&args[0])? as usize;
1125 Ok(Value::ByteArray(std::sync::Arc::new(
1126 std::sync::Mutex::new(vec![0u8; size]),
1127 )))
1128 }
1129 PrimOpKind::ReadWord8Array => {
1130 let ba = expect_byte_array(&args[0])?;
1131 let idx = expect_int(&args[1])? as usize;
1132 let bytes = ba
1133 .lock()
1134 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1135 let val = *bytes.get(idx).unwrap_or(&0);
1136 Ok(Value::Lit(Literal::LitWord(val as u64)))
1137 }
1138 PrimOpKind::WriteWord8Array => {
1139 let ba = expect_byte_array(&args[0])?;
1140 let idx = expect_int(&args[1])? as usize;
1141 let val = expect_int_like(&args[2])? as u8;
1142 let mut bytes = ba
1143 .lock()
1144 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1145 if idx < bytes.len() {
1146 bytes[idx] = val;
1147 }
1148 Ok(Value::ByteArray(ba.clone()))
1149 }
1150 PrimOpKind::SizeofMutableByteArray => {
1151 let ba = expect_byte_array(&args[0])?;
1152 let len = ba
1153 .lock()
1154 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?
1155 .len();
1156 Ok(Value::Lit(Literal::LitInt(len as i64)))
1157 }
1158 PrimOpKind::UnsafeFreezeByteArray => {
1159 Ok(args[0].clone())
1161 }
1162 PrimOpKind::CopyByteArray | PrimOpKind::CopyMutableByteArray => {
1163 let src_ba = expect_byte_array(&args[0])?;
1165 let src_off = expect_int(&args[1])? as usize;
1166 let dst_ba = expect_byte_array(&args[2])?;
1167 let dst_off = expect_int(&args[3])? as usize;
1168 let len = expect_int(&args[4])? as usize;
1169 let src_data: Vec<u8> = {
1171 let src = src_ba
1172 .lock()
1173 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1174 let end = src_off.checked_add(len);
1175 if end.is_none() || end.unwrap() > src.len() {
1176 return Err(EvalError::TypeMismatch {
1177 expected: "valid src range",
1178 got: crate::error::ValueKind::Other(format!(
1179 "range {}..{} exceeds length {}",
1180 src_off,
1181 src_off + len,
1182 src.len()
1183 )),
1184 });
1185 }
1186 src[src_off..end.unwrap()].to_vec()
1187 };
1188 {
1189 let mut dst = dst_ba
1190 .lock()
1191 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1192 let end = dst_off.checked_add(len);
1193 if end.is_none() || end.unwrap() > dst.len() {
1194 return Err(EvalError::TypeMismatch {
1195 expected: "valid dst range",
1196 got: crate::error::ValueKind::Other(format!(
1197 "range {}..{} exceeds length {}",
1198 dst_off,
1199 dst_off + len,
1200 dst.len()
1201 )),
1202 });
1203 }
1204 dst[dst_off..end.unwrap()].copy_from_slice(&src_data);
1205 }
1206 Ok(Value::ByteArray(dst_ba.clone()))
1207 }
1208 PrimOpKind::CopyAddrToByteArray => {
1209 let src_bytes = match &args[0] {
1211 Value::Lit(Literal::LitString(bs)) => bs,
1212 other => {
1213 return Err(EvalError::TypeMismatch {
1214 expected: "Addr# (LitString)",
1215 got: crate::error::ValueKind::Other(format!("{:?}", other)),
1216 })
1217 }
1218 };
1219 let dst_ba = expect_byte_array(&args[1])?;
1220 let dst_off = expect_int(&args[2])? as usize;
1221 let len = expect_int(&args[3])? as usize;
1222 let mut dst = dst_ba
1223 .lock()
1224 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1225 let src_end = std::cmp::min(src_bytes.len(), len);
1226 let end = dst_off.checked_add(src_end);
1227 if end.is_none() || end.unwrap() > dst.len() {
1228 return Err(EvalError::TypeMismatch {
1229 expected: "valid dst range",
1230 got: crate::error::ValueKind::Other(format!(
1231 "range {}..{} exceeds length {}",
1232 dst_off,
1233 dst_off + src_end,
1234 dst.len()
1235 )),
1236 });
1237 }
1238 dst[dst_off..end.unwrap()].copy_from_slice(&src_bytes[..src_end]);
1239 drop(dst);
1240 Ok(Value::ByteArray(dst_ba.clone()))
1241 }
1242 PrimOpKind::ShrinkMutableByteArray => {
1243 let ba = expect_byte_array(&args[0])?;
1244 let new_size = expect_int(&args[1])? as usize;
1245 ba.lock()
1246 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?
1247 .truncate(new_size);
1248 Ok(Value::ByteArray(ba.clone()))
1249 }
1250 PrimOpKind::ResizeMutableByteArray => {
1251 let ba = expect_byte_array(&args[0])?;
1252 let new_size = expect_int(&args[1])? as usize;
1253 let mut bytes = ba
1254 .lock()
1255 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1256 bytes.resize(new_size, 0);
1257 drop(bytes);
1258 Ok(Value::ByteArray(ba.clone()))
1259 }
1260 PrimOpKind::Clz8 => {
1261 let w = expect_word(&args[0])?;
1262 Ok(Value::Lit(Literal::LitWord(
1263 (w as u8).leading_zeros() as u64
1264 )))
1265 }
1266 PrimOpKind::IntToInt64 => {
1267 Ok(args[0].clone())
1269 }
1270 PrimOpKind::Int64ToWord64 => {
1271 let n = expect_int(&args[0])?;
1272 Ok(Value::Lit(Literal::LitWord(n as u64)))
1273 }
1274 PrimOpKind::TimesInt2Hi | PrimOpKind::TimesInt2Lo | PrimOpKind::TimesInt2Overflow => {
1275 let a = expect_int(&args[0])? as i128;
1276 let b = expect_int(&args[1])? as i128;
1277 let result = a * b;
1278 match op {
1279 PrimOpKind::TimesInt2Overflow => {
1280 let overflowed = result > i64::MAX as i128 || result < i64::MIN as i128;
1281 Ok(Value::Lit(Literal::LitInt(if overflowed { 1 } else { 0 })))
1282 }
1283 PrimOpKind::TimesInt2Hi => Ok(Value::Lit(Literal::LitInt((result >> 64) as i64))),
1284 PrimOpKind::TimesInt2Lo => Ok(Value::Lit(Literal::LitInt(result as i64))),
1285 _ => Err(EvalError::InternalError(format!(
1286 "unexpected TimesInt2 variant: {:?}",
1287 op
1288 ))),
1289 }
1290 }
1291
1292 PrimOpKind::IndexWord8Array => {
1293 let ba = expect_byte_array(&args[0])?;
1294 let idx_val = expect_int(&args[1])?;
1295 if idx_val < 0 {
1296 return Err(EvalError::TypeMismatch {
1297 expected: "non-negative array index",
1298 got: crate::error::ValueKind::Other(format!("negative index: {}", idx_val)),
1299 });
1300 }
1301 let idx = idx_val as usize;
1302 let bytes = ba
1303 .lock()
1304 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1305 let val = *bytes.get(idx).unwrap_or(&0);
1306 Ok(Value::Lit(Literal::LitWord(val as u64)))
1307 }
1308 PrimOpKind::IndexWord8OffAddr => {
1309 let bytes = match &args[0] {
1311 Value::Lit(Literal::LitString(bs)) => bs,
1312 other => {
1313 return Err(EvalError::TypeMismatch {
1314 expected: "Addr# (LitString)",
1315 got: crate::error::ValueKind::Other(format!("{:?}", other)),
1316 })
1317 }
1318 };
1319 let idx = expect_int(&args[1])? as usize;
1320 let val = bytes.get(idx).copied().unwrap_or(0);
1321 Ok(Value::Lit(Literal::LitWord(val as u64)))
1322 }
1323 PrimOpKind::CompareByteArrays => {
1324 let ba1 = expect_byte_array(&args[0])?;
1326 let off1 = expect_int(&args[1])? as usize;
1327 let ba2 = expect_byte_array(&args[2])?;
1328 let off2 = expect_int(&args[3])? as usize;
1329 let len = expect_int(&args[4])? as usize;
1330 let slice1: Vec<u8> = {
1332 let b = ba1
1333 .lock()
1334 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1335 let end1 = off1.checked_add(len);
1336 if end1.is_none() || end1.unwrap() > b.len() {
1337 return Err(EvalError::TypeMismatch {
1338 expected: "valid byte range for ba1",
1339 got: crate::error::ValueKind::Other(format!(
1340 "range {}..{} exceeds length {}",
1341 off1,
1342 off1 + len,
1343 b.len()
1344 )),
1345 });
1346 }
1347 b[off1..end1.unwrap()].to_vec()
1348 };
1349 let slice2: Vec<u8> = {
1350 let b = ba2
1351 .lock()
1352 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1353 let end2 = off2.checked_add(len);
1354 if end2.is_none() || end2.unwrap() > b.len() {
1355 return Err(EvalError::TypeMismatch {
1356 expected: "valid byte range for ba2",
1357 got: crate::error::ValueKind::Other(format!(
1358 "range {}..{} exceeds length {}",
1359 off2,
1360 off2 + len,
1361 b.len()
1362 )),
1363 });
1364 }
1365 b[off2..end2.unwrap()].to_vec()
1366 };
1367 let result = slice1.cmp(&slice2);
1368 Ok(Value::Lit(Literal::LitInt(match result {
1369 std::cmp::Ordering::Less => -1,
1370 std::cmp::Ordering::Equal => 0,
1371 std::cmp::Ordering::Greater => 1,
1372 })))
1373 }
1374 PrimOpKind::WordToWord8 => {
1375 let w = expect_word(&args[0])?;
1377 Ok(Value::Lit(Literal::LitWord(w & 0xFF)))
1378 }
1379 PrimOpKind::Word64And => {
1380 let (a, b) = bin_op_word(op, &args)?;
1381 Ok(Value::Lit(Literal::LitWord(a & b)))
1382 }
1383 PrimOpKind::Int64ToInt => {
1384 Ok(args[0].clone())
1386 }
1387 PrimOpKind::Word64ToInt64 => {
1388 let w = match &args[0] {
1390 Value::Lit(Literal::LitWord(w)) => *w,
1391 Value::Lit(Literal::LitInt(i)) => *i as u64,
1392 other => {
1393 return Err(EvalError::TypeMismatch {
1394 expected: "Word64#",
1395 got: crate::error::ValueKind::Other(format!("{:?}", other)),
1396 })
1397 }
1398 };
1399 Ok(Value::Lit(Literal::LitInt(w as i64)))
1400 }
1401 PrimOpKind::Word8ToWord => {
1402 Ok(args[0].clone())
1404 }
1405 PrimOpKind::Word8Lt => {
1406 let (a, b) = bin_op_word(op, &args)?;
1407 Ok(Value::Lit(Literal::LitInt(if a < b { 1 } else { 0 })))
1408 }
1409 PrimOpKind::Int64Ge => {
1410 let (a, b) = bin_op_int(op, &args)?;
1411 Ok(Value::Lit(Literal::LitInt(if a >= b { 1 } else { 0 })))
1412 }
1413 PrimOpKind::Int64Negate => {
1414 let a = expect_int_like(&args[0])?;
1415 Ok(Value::Lit(Literal::LitInt(-a)))
1416 }
1417 PrimOpKind::Int64Shra => {
1418 let (a, b) = bin_op_int(op, &args)?;
1419 Ok(Value::Lit(Literal::LitInt(a >> (b as u32))))
1420 }
1421 PrimOpKind::Word64Shl => {
1422 let (a, b) = bin_op_word(op, &args)?;
1423 Ok(Value::Lit(Literal::LitWord(a << (b as u32))))
1424 }
1425 PrimOpKind::Word8Ge => {
1426 let (a, b) = bin_op_word(op, &args)?;
1427 Ok(Value::Lit(Literal::LitInt(if a >= b { 1 } else { 0 })))
1428 }
1429 PrimOpKind::Word8Sub => {
1430 let (a, b) = bin_op_word(op, &args)?;
1431 Ok(Value::Lit(Literal::LitWord(a.wrapping_sub(b) & 0xFF)))
1432 }
1433 PrimOpKind::SizeofByteArray => {
1434 let ba = expect_byte_array(&args[0])?;
1435 let len = ba
1436 .lock()
1437 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?
1438 .len();
1439 Ok(Value::Lit(Literal::LitInt(len as i64)))
1440 }
1441 PrimOpKind::IndexWordArray => {
1442 let ba = expect_byte_array(&args[0])?;
1445 let idx_val = expect_int_like(&args[1])?;
1446 if idx_val < 0 {
1447 return Err(EvalError::TypeMismatch {
1448 expected: "non-negative array index",
1449 got: crate::error::ValueKind::Other(format!("negative index: {}", idx_val)),
1450 });
1451 }
1452 let idx = idx_val as usize;
1453 let bytes = ba
1454 .lock()
1455 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1456 let offset = idx.checked_mul(8);
1457 let end = offset.and_then(|o| o.checked_add(8));
1458
1459 if offset.is_none() || end.is_none() || end.unwrap() > bytes.len() {
1460 return Err(EvalError::TypeMismatch {
1461 expected: "valid IndexWordArray index",
1462 got: crate::error::ValueKind::Other(format!(
1463 "index {} out of bounds (len={})",
1464 idx,
1465 bytes.len()
1466 )),
1467 });
1468 }
1469 let offset = offset.unwrap();
1470 let end = end.unwrap();
1471 let word =
1472 u64::from_ne_bytes(bytes[offset..end].try_into().map_err(|_| {
1473 EvalError::InternalError("8-byte slice conversion failed".into())
1474 })?);
1475 Ok(Value::Lit(Literal::LitWord(word)))
1476 }
1477 PrimOpKind::Int64Mul => {
1478 let (a, b) = bin_op_int(op, &args)?;
1479 Ok(Value::Lit(Literal::LitInt(a.wrapping_mul(b))))
1480 }
1481 PrimOpKind::Word64Or => {
1482 let (a, b) = bin_op_word(op, &args)?;
1483 Ok(Value::Lit(Literal::LitWord(a | b)))
1484 }
1485 PrimOpKind::Word8Le => {
1486 let (a, b) = bin_op_word(op, &args)?;
1487 Ok(Value::Lit(Literal::LitInt(if a <= b { 1 } else { 0 })))
1488 }
1489 PrimOpKind::Int64Add => {
1490 let (a, b) = bin_op_int(op, &args)?;
1491 Ok(Value::Lit(Literal::LitInt(a.wrapping_add(b))))
1492 }
1493 PrimOpKind::Int64Gt => {
1494 let (a, b) = bin_op_int(op, &args)?;
1495 Ok(Value::Lit(Literal::LitInt(if a > b { 1 } else { 0 })))
1496 }
1497 PrimOpKind::Int64Lt => {
1498 let (a, b) = bin_op_int(op, &args)?;
1499 Ok(Value::Lit(Literal::LitInt(if a < b { 1 } else { 0 })))
1500 }
1501 PrimOpKind::Int64Le => {
1502 let (a, b) = bin_op_int(op, &args)?;
1503 Ok(Value::Lit(Literal::LitInt(if a <= b { 1 } else { 0 })))
1504 }
1505 PrimOpKind::Int64Sub => {
1506 let (a, b) = bin_op_int(op, &args)?;
1507 Ok(Value::Lit(Literal::LitInt(a.wrapping_sub(b))))
1508 }
1509 PrimOpKind::Int64Shl => {
1510 let (a, b) = bin_op_int(op, &args)?;
1511 Ok(Value::Lit(Literal::LitInt(a.wrapping_shl(b as u32))))
1512 }
1513 PrimOpKind::Word8Add => {
1514 let (a, b) = bin_op_word(op, &args)?;
1515 Ok(Value::Lit(Literal::LitWord((a.wrapping_add(b)) & 0xFF)))
1516 }
1517 PrimOpKind::WriteWordArray => {
1518 let ba = expect_byte_array(&args[0])?;
1520 let idx_val = expect_int_like(&args[1])?;
1521 if idx_val < 0 {
1522 return Err(EvalError::TypeMismatch {
1523 expected: "non-negative array index",
1524 got: crate::error::ValueKind::Other(format!("negative index: {}", idx_val)),
1525 });
1526 }
1527 let idx = idx_val as usize;
1528 let val = expect_word(&args[2])?;
1529 let mut bytes = ba
1530 .lock()
1531 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1532
1533 let offset = idx.checked_mul(8);
1534 let end = offset.and_then(|o| o.checked_add(8));
1535
1536 if let (Some(o), Some(e)) = (offset, end) {
1537 if e <= bytes.len() {
1538 bytes[o..e].copy_from_slice(&val.to_ne_bytes());
1539 }
1540 }
1541 Ok(Value::ByteArray(ba.clone()))
1542 }
1543 PrimOpKind::ReadWordArray => {
1544 let ba = expect_byte_array(&args[0])?;
1546 let idx_val = expect_int_like(&args[1])?;
1547 if idx_val < 0 {
1548 return Err(EvalError::TypeMismatch {
1549 expected: "non-negative array index",
1550 got: crate::error::ValueKind::Other(format!("negative index: {}", idx_val)),
1551 });
1552 }
1553 let idx = idx_val as usize;
1554 let bytes = ba
1555 .lock()
1556 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1557 let offset = idx.checked_mul(8);
1558 let end = offset.and_then(|o| o.checked_add(8));
1559
1560 if offset.is_none() || end.is_none() || end.unwrap() > bytes.len() {
1561 return Err(EvalError::TypeMismatch {
1562 expected: "valid ReadWordArray index",
1563 got: crate::error::ValueKind::Other(format!(
1564 "index {} out of bounds (len={})",
1565 idx,
1566 bytes.len()
1567 )),
1568 });
1569 }
1570 let offset = offset.unwrap();
1571 let end = end.unwrap();
1572 let word =
1573 u64::from_ne_bytes(bytes[offset..end].try_into().map_err(|_| {
1574 EvalError::InternalError("8-byte slice conversion failed".into())
1575 })?);
1576 Ok(Value::Lit(Literal::LitWord(word)))
1577 }
1578 PrimOpKind::SetByteArray => {
1579 let ba = expect_byte_array(&args[0])?;
1582 let offset = expect_int_like(&args[1])? as usize;
1583 let count = expect_int_like(&args[2])? as usize;
1584 let val = expect_int_like(&args[3])? as u8;
1585 let mut bytes = ba
1586 .lock()
1587 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1588 if offset > bytes.len() {
1589 return Err(EvalError::TypeMismatch {
1590 expected: "valid byte offset",
1591 got: crate::error::ValueKind::Other(format!(
1592 "offset {} exceeds length {}",
1593 offset,
1594 bytes.len()
1595 )),
1596 });
1597 }
1598 let end = offset
1599 .checked_add(count)
1600 .unwrap_or(bytes.len())
1601 .min(bytes.len());
1602 for b in &mut bytes[offset..end] {
1603 *b = val;
1604 }
1605 Ok(Value::ByteArray(ba.clone()))
1606 }
1607 PrimOpKind::AddIntCVal => {
1608 let (a, b) = bin_op_int(op, &args)?;
1610 Ok(Value::Lit(Literal::LitInt(a.wrapping_add(b))))
1611 }
1612 PrimOpKind::AddIntCCarry => {
1613 let (a, b) = bin_op_int(op, &args)?;
1615 let overflow = a.checked_add(b).is_none();
1616 Ok(Value::Lit(Literal::LitInt(if overflow { 1 } else { 0 })))
1617 }
1618 PrimOpKind::SubWordCVal => {
1619 let (a, b) = bin_op_word(op, &args)?;
1621 Ok(Value::Lit(Literal::LitWord(a.wrapping_sub(b))))
1622 }
1623 PrimOpKind::SubWordCCarry => {
1624 let (a, b) = bin_op_word(op, &args)?;
1626 Ok(Value::Lit(Literal::LitInt(if a < b { 1 } else { 0 })))
1627 }
1628 PrimOpKind::AddWordCVal => {
1629 let (a, b) = bin_op_word(op, &args)?;
1630 Ok(Value::Lit(Literal::LitWord(a.wrapping_add(b))))
1631 }
1632 PrimOpKind::AddWordCCarry => {
1633 let (a, b) = bin_op_word(op, &args)?;
1634 let carry = a.checked_add(b).is_none();
1635 Ok(Value::Lit(Literal::LitInt(if carry { 1 } else { 0 })))
1636 }
1637 PrimOpKind::TimesWord2Hi => {
1638 let (a, b) = bin_op_word(op, &args)?;
1640 let product = (a as u128) * (b as u128);
1641 Ok(Value::Lit(Literal::LitWord((product >> 64) as u64)))
1642 }
1643 PrimOpKind::TimesWord2Lo => {
1644 let (a, b) = bin_op_word(op, &args)?;
1646 Ok(Value::Lit(Literal::LitWord(a.wrapping_mul(b))))
1647 }
1648 PrimOpKind::QuotRemWordVal => {
1649 let (a, b) = bin_op_word(op, &args)?;
1651 if b == 0 {
1652 return Err(EvalError::InternalError(
1653 "division by zero (quotRemWord# quot)".into(),
1654 ));
1655 }
1656 Ok(Value::Lit(Literal::LitWord(a / b)))
1657 }
1658 PrimOpKind::QuotRemWordRem => {
1659 let (a, b) = bin_op_word(op, &args)?;
1661 if b == 0 {
1662 return Err(EvalError::InternalError(
1663 "division by zero (quotRemWord# rem)".into(),
1664 ));
1665 }
1666 Ok(Value::Lit(Literal::LitWord(a % b)))
1667 }
1668
1669 PrimOpKind::FfiStrlen => {
1671 let bytes = match &args[0] {
1673 Value::Lit(Literal::LitString(bs)) => bs,
1674 other => {
1675 return Err(EvalError::TypeMismatch {
1676 expected: "Addr# (LitString)",
1677 got: crate::error::ValueKind::Other(format!("{:?}", other)),
1678 })
1679 }
1680 };
1681 let len = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
1682 Ok(Value::Lit(Literal::LitInt(len as i64)))
1683 }
1684 PrimOpKind::FfiTextMeasureOff => {
1685 let ba = expect_byte_array(&args[0])?;
1688 let off_raw = expect_int_like(&args[1])?;
1689 let n_chars_raw = expect_int_like(&args[2])?;
1690 if off_raw < 0 || n_chars_raw < 0 {
1691 return Err(EvalError::TypeMismatch {
1692 expected: "non-negative offset and length",
1693 got: crate::error::ValueKind::Other(format!(
1694 "off={}, n_chars={}",
1695 off_raw, n_chars_raw
1696 )),
1697 });
1698 }
1699 let off = off_raw as usize;
1700 let n_chars = n_chars_raw as usize;
1701 let bytes = ba
1702 .lock()
1703 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1704 if off > bytes.len() {
1705 return Err(EvalError::TypeMismatch {
1706 expected: "valid byte offset",
1707 got: crate::error::ValueKind::Other(format!(
1708 "offset {} exceeds length {}",
1709 off,
1710 bytes.len()
1711 )),
1712 });
1713 }
1714 let slice = &bytes[off..];
1715 let mut byte_count = 0usize;
1716 let mut chars_counted = 0usize;
1717 while chars_counted < n_chars && byte_count < slice.len() {
1718 let b = slice[byte_count];
1719 let char_len = if b < 0x80 {
1720 1
1721 } else if b < 0xE0 {
1722 2
1723 } else if b < 0xF0 {
1724 3
1725 } else {
1726 4
1727 };
1728 byte_count += char_len;
1729 chars_counted += 1;
1730 }
1731 Ok(Value::Lit(Literal::LitInt(byte_count as i64)))
1732 }
1733 PrimOpKind::FfiTextMemchr => {
1734 let ba = expect_byte_array(&args[0])?;
1738 let off_raw = expect_int_like(&args[1])?;
1739 let len_raw = expect_int_like(&args[2])?;
1740 if off_raw < 0 || len_raw < 0 {
1741 return Err(EvalError::TypeMismatch {
1742 expected: "non-negative offset and length",
1743 got: crate::error::ValueKind::Other(format!(
1744 "off={}, len={}",
1745 off_raw, len_raw
1746 )),
1747 });
1748 }
1749 let off = off_raw as usize;
1750 let len = len_raw as usize;
1751 let needle = expect_int_like(&args[3])? as u8;
1752 let bytes = ba
1753 .lock()
1754 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1755 if off > bytes.len() {
1756 return Err(EvalError::TypeMismatch {
1757 expected: "valid byte offset",
1758 got: crate::error::ValueKind::Other(format!(
1759 "offset {} exceeds length {}",
1760 off,
1761 bytes.len()
1762 )),
1763 });
1764 }
1765 let end = off.checked_add(len).unwrap_or(bytes.len()).min(bytes.len());
1766 let result = bytes[off..end].iter().position(|&b| b == needle);
1767 Ok(Value::Lit(Literal::LitInt(match result {
1768 Some(pos) => pos as i64,
1769 None => -1,
1770 })))
1771 }
1772 PrimOpKind::FfiTextReverse => {
1773 let dst_ba = expect_byte_array(&args[0])?;
1776 let src_ba = expect_byte_array(&args[1])?;
1777 let off_raw = expect_int_like(&args[2])?;
1778 let len_raw = expect_int_like(&args[3])?;
1779 if off_raw < 0 || len_raw < 0 {
1780 return Err(EvalError::TypeMismatch {
1781 expected: "non-negative offset and length",
1782 got: crate::error::ValueKind::Other(format!(
1783 "off={}, len={}",
1784 off_raw, len_raw
1785 )),
1786 });
1787 }
1788 let off = off_raw as usize;
1789 let len = len_raw as usize;
1790 let src_slice: Vec<u8> = {
1792 let src = src_ba
1793 .lock()
1794 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1795 let end = off.checked_add(len);
1796 if end.is_none() || end.unwrap() > src.len() {
1797 return Err(EvalError::TypeMismatch {
1798 expected: "valid byte range",
1799 got: crate::error::ValueKind::Other(format!(
1800 "range {}..{} exceeds length {}",
1801 off,
1802 off + len,
1803 src.len()
1804 )),
1805 });
1806 }
1807 src[off..end.unwrap()].to_vec()
1808 };
1809 let mut chars: Vec<&[u8]> = Vec::new();
1811 let mut i = 0;
1812 while i < src_slice.len() {
1813 let b = src_slice[i];
1814 let char_len = if b < 0x80 {
1815 1
1816 } else if b < 0xE0 {
1817 2
1818 } else if b < 0xF0 {
1819 3
1820 } else {
1821 4
1822 };
1823 let end = std::cmp::min(i + char_len, src_slice.len());
1824 chars.push(&src_slice[i..end]);
1825 i = end;
1826 }
1827 chars.reverse();
1828 let reversed: Vec<u8> = chars.into_iter().flatten().copied().collect();
1829 {
1830 let mut dst = dst_ba
1831 .lock()
1832 .map_err(|e| EvalError::InternalError(format!("mutex poisoned: {e}")))?;
1833 let copy_len = std::cmp::min(reversed.len(), dst.len());
1834 dst[..copy_len].copy_from_slice(&reversed[..copy_len]);
1835 }
1836 Ok(Value::ByteArray(dst_ba.clone()))
1837 }
1838
1839 PrimOpKind::NewSmallArray
1841 | PrimOpKind::ReadSmallArray
1842 | PrimOpKind::WriteSmallArray
1843 | PrimOpKind::IndexSmallArray
1844 | PrimOpKind::SizeofSmallArray
1845 | PrimOpKind::SizeofSmallMutableArray
1846 | PrimOpKind::UnsafeFreezeSmallArray
1847 | PrimOpKind::UnsafeThawSmallArray
1848 | PrimOpKind::CopySmallArray
1849 | PrimOpKind::CopySmallMutableArray
1850 | PrimOpKind::CloneSmallArray
1851 | PrimOpKind::CloneSmallMutableArray
1852 | PrimOpKind::ShrinkSmallMutableArray
1853 | PrimOpKind::CasSmallArray
1854 | PrimOpKind::NewArray
1855 | PrimOpKind::ReadArray
1856 | PrimOpKind::WriteArray
1857 | PrimOpKind::SizeofArray
1858 | PrimOpKind::SizeofMutableArray
1859 | PrimOpKind::UnsafeFreezeArray
1860 | PrimOpKind::UnsafeThawArray
1861 | PrimOpKind::CopyArray
1862 | PrimOpKind::CopyMutableArray
1863 | PrimOpKind::CloneArray
1864 | PrimOpKind::CloneMutableArray
1865 | PrimOpKind::PopCnt
1866 | PrimOpKind::PopCnt8
1867 | PrimOpKind::PopCnt16
1868 | PrimOpKind::PopCnt32
1869 | PrimOpKind::PopCnt64
1870 | PrimOpKind::Ctz
1871 | PrimOpKind::Ctz8
1872 | PrimOpKind::Ctz16
1873 | PrimOpKind::Ctz32
1874 | PrimOpKind::Ctz64 => Err(EvalError::UnsupportedPrimOp(op)),
1875 }
1876}
1877
1878fn expect_byte_array(v: &Value) -> Result<&crate::value::SharedByteArray, EvalError> {
1879 if let Value::ByteArray(ba) = v {
1880 Ok(ba)
1881 } else {
1882 Err(EvalError::TypeMismatch {
1883 expected: "ByteArray#",
1884 got: crate::error::ValueKind::Other(format!("{:?}", v)),
1885 })
1886 }
1887}
1888
1889fn expect_int_like(v: &Value) -> Result<i64, EvalError> {
1891 match v {
1892 Value::Lit(Literal::LitInt(n)) => Ok(*n),
1893 Value::Lit(Literal::LitWord(n)) => Ok(*n as i64),
1894 _ => Err(EvalError::TypeMismatch {
1895 expected: "Int# or Word#",
1896 got: crate::error::ValueKind::Other(format!("{:?}", v)),
1897 }),
1898 }
1899}
1900
1901fn expect_int(v: &Value) -> Result<i64, EvalError> {
1902 if let Value::Lit(Literal::LitInt(n)) = v {
1903 Ok(*n)
1904 } else {
1905 Err(EvalError::TypeMismatch {
1906 expected: "Int#",
1907 got: crate::error::ValueKind::Other(format!("{:?}", v)),
1908 })
1909 }
1910}
1911
1912fn expect_word(v: &Value) -> Result<u64, EvalError> {
1913 match v {
1914 Value::Lit(Literal::LitWord(n)) => Ok(*n),
1915 Value::Lit(Literal::LitInt(n)) => Ok(*n as u64),
1916 _ => Err(EvalError::TypeMismatch {
1917 expected: "Word#",
1918 got: crate::error::ValueKind::Other(format!("{:?}", v)),
1919 }),
1920 }
1921}
1922
1923fn expect_double(v: &Value) -> Result<f64, EvalError> {
1924 if let Value::Lit(Literal::LitDouble(bits)) = v {
1925 Ok(f64::from_bits(*bits))
1926 } else {
1927 Err(EvalError::TypeMismatch {
1928 expected: "Double#",
1929 got: crate::error::ValueKind::Other(format!("{:?}", v)),
1930 })
1931 }
1932}
1933
1934fn expect_float(v: &Value) -> Result<f32, EvalError> {
1935 if let Value::Lit(Literal::LitFloat(bits)) = v {
1936 Ok(f32::from_bits(*bits as u32))
1937 } else {
1938 Err(EvalError::TypeMismatch {
1939 expected: "Float#",
1940 got: crate::error::ValueKind::Other(format!("{:?}", v)),
1941 })
1942 }
1943}
1944
1945fn expect_char(v: &Value) -> Result<char, EvalError> {
1946 if let Value::Lit(Literal::LitChar(c)) = v {
1947 Ok(*c)
1948 } else {
1949 Err(EvalError::TypeMismatch {
1950 expected: "Char#",
1951 got: crate::error::ValueKind::Other(format!("{:?}", v)),
1952 })
1953 }
1954}
1955
1956macro_rules! bin_op {
1957 ($name:ident, $extract:ident, $t:ty) => {
1958 fn $name(_op: PrimOpKind, args: &[Value]) -> Result<($t, $t), EvalError> {
1959 if args.len() != 2 {
1960 return Err(EvalError::ArityMismatch {
1961 context: "arguments",
1962 expected: 2,
1963 got: args.len(),
1964 });
1965 }
1966 Ok(($extract(&args[0])?, $extract(&args[1])?))
1967 }
1968 };
1969}
1970
1971bin_op!(bin_op_int, expect_int, i64);
1972bin_op!(bin_op_word, expect_word, u64);
1973
1974fn eval_decode_double_int64(d: f64) -> (i64, i64) {
1975 if d == 0.0 || d.is_nan() {
1976 return (0, 0);
1977 }
1978 if d.is_infinite() {
1979 return (if d > 0.0 { 1 } else { -1 }, 0);
1980 }
1981 let bits = d.to_bits();
1982 let sign: i64 = if bits >> 63 == 0 { 1 } else { -1 };
1983 let raw_exp = ((bits >> 52) & 0x7ff) as i32;
1984 let raw_man = (bits & 0x000f_ffff_ffff_ffff) as i64;
1985 let (man, exp) = if raw_exp == 0 {
1986 (raw_man, 1 - 1023 - 52)
1987 } else {
1988 (raw_man | (1i64 << 52), raw_exp - 1023 - 52)
1989 };
1990 let man = sign * man;
1991 if man != 0 {
1992 let tz = man.unsigned_abs().trailing_zeros();
1993 (man >> tz, (exp + tz as i32) as i64)
1994 } else {
1995 (0, 0)
1996 }
1997}
1998
1999fn eval_haskell_show_double(d: f64) -> String {
2001 if d.is_nan() {
2002 return "NaN".to_string();
2003 }
2004 if d.is_infinite() {
2005 return if d > 0.0 { "Infinity" } else { "-Infinity" }.to_string();
2006 }
2007 if d == 0.0 {
2008 return if d.is_sign_negative() { "-0.0" } else { "0.0" }.to_string();
2009 }
2010 let abs = d.abs();
2011 if (0.1..1.0e7).contains(&abs) {
2012 let s = format!("{}", d);
2013 if s.contains('.') {
2014 s
2015 } else {
2016 format!("{}.0", s)
2017 }
2018 } else {
2019 format!("{:e}", d)
2020 }
2021}
2022
2023bin_op!(bin_op_double, expect_double, f64);
2024bin_op!(bin_op_float, expect_float, f32);
2025bin_op!(bin_op_char, expect_char, char);
2026
2027macro_rules! cmp_fn {
2028 ($name:ident, $bin_op:ident, $t:ty) => {
2029 fn $name(
2030 op: PrimOpKind,
2031 args: &[Value],
2032 f: impl Fn($t, $t) -> bool,
2033 ) -> Result<Value, EvalError> {
2034 let (a, b) = $bin_op(op, args)?;
2035 Ok(Value::Lit(Literal::LitInt(if f(a, b) { 1 } else { 0 })))
2036 }
2037 };
2038}
2039
2040cmp_fn!(cmp_int, bin_op_int, i64);
2041cmp_fn!(cmp_word, bin_op_word, u64);
2042cmp_fn!(cmp_double, bin_op_double, f64);
2043cmp_fn!(cmp_float, bin_op_float, f32);
2044cmp_fn!(cmp_char, bin_op_char, char);
2045
2046#[cfg(test)]
2047mod tests {
2048 use super::*;
2049 use tidepool_repr::{Alt, AltCon, CoreFrame, DataConId, JoinId, Literal, RecursiveTree, VarId};
2050
2051 #[test]
2052 fn test_eval_lit() {
2053 let expr = RecursiveTree {
2054 nodes: vec![CoreFrame::Lit(Literal::LitInt(42))],
2055 };
2056 let mut heap = crate::heap::VecHeap::new();
2057 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2058 if let Value::Lit(Literal::LitInt(n)) = res {
2059 assert_eq!(n, 42);
2060 } else {
2061 panic!("Expected LitInt(42), got {:?}", res);
2062 }
2063 }
2064
2065 #[test]
2066 fn test_eval_var() {
2067 let expr = RecursiveTree {
2068 nodes: vec![CoreFrame::Var(VarId(1))],
2069 };
2070 let mut env = Env::new();
2071 env.insert(VarId(1), Value::Lit(Literal::LitInt(42)));
2072 let mut heap = crate::heap::VecHeap::new();
2073 let res = eval(&expr, &env, &mut heap).unwrap();
2074 if let Value::Lit(Literal::LitInt(n)) = res {
2075 assert_eq!(n, 42);
2076 } else {
2077 panic!("Expected LitInt(42), got {:?}", res);
2078 }
2079 }
2080
2081 #[test]
2082 fn test_eval_unbound_var() {
2083 let expr = RecursiveTree {
2084 nodes: vec![CoreFrame::Var(VarId(1))],
2085 };
2086 let mut heap = crate::heap::VecHeap::new();
2087 let res = eval(&expr, &Env::new(), &mut heap);
2088 assert!(matches!(res, Err(EvalError::UnboundVar(VarId(1)))));
2089 }
2090
2091 #[test]
2092 fn test_eval_lam_identity() {
2093 let nodes = vec![
2094 CoreFrame::Var(VarId(1)),
2095 CoreFrame::Lam {
2096 binder: VarId(1),
2097 body: 0,
2098 },
2099 CoreFrame::Lit(Literal::LitInt(42)),
2100 CoreFrame::App { fun: 1, arg: 2 },
2101 ];
2102 let expr = CoreExpr { nodes };
2103 let mut heap = crate::heap::VecHeap::new();
2104 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2105 if let Value::Lit(Literal::LitInt(n)) = res {
2106 assert_eq!(n, 42);
2107 } else {
2108 panic!("Expected LitInt(42), got {:?}", res);
2109 }
2110 }
2111
2112 #[test]
2113 fn test_eval_let_nonrec() {
2114 let nodes = vec![
2115 CoreFrame::Lit(Literal::LitInt(1)),
2116 CoreFrame::Var(VarId(1)),
2117 CoreFrame::LetNonRec {
2118 binder: VarId(1),
2119 rhs: 0,
2120 body: 1,
2121 },
2122 ];
2123 let expr = CoreExpr { nodes };
2124 let mut heap = crate::heap::VecHeap::new();
2125 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2126 if let Value::Lit(Literal::LitInt(n)) = res {
2127 assert_eq!(n, 1);
2128 } else {
2129 panic!("Expected LitInt(1), got {:?}", res);
2130 }
2131 }
2132
2133 #[test]
2134 fn test_eval_con() {
2135 let nodes = vec![
2136 CoreFrame::Lit(Literal::LitInt(42)),
2137 CoreFrame::Con {
2138 tag: DataConId(1),
2139 fields: vec![0],
2140 },
2141 ];
2142 let expr = CoreExpr { nodes };
2143 let mut heap = crate::heap::VecHeap::new();
2144 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2145 if let Value::Con(tag, fields) = res {
2146 assert_eq!(tag.0, 1);
2147 assert_eq!(fields.len(), 1);
2148 if let Value::Lit(Literal::LitInt(n)) = fields[0] {
2149 assert_eq!(n, 42);
2150 } else {
2151 panic!("Expected LitInt(42)");
2152 }
2153 } else {
2154 panic!("Expected Con");
2155 }
2156 }
2157
2158 #[test]
2159 fn test_eval_primop_add() {
2160 let nodes = vec![
2161 CoreFrame::Lit(Literal::LitInt(1)),
2162 CoreFrame::Lit(Literal::LitInt(2)),
2163 CoreFrame::PrimOp {
2164 op: PrimOpKind::IntAdd,
2165 args: vec![0, 1],
2166 },
2167 ];
2168 let expr = CoreExpr { nodes };
2169 let mut heap = crate::heap::VecHeap::new();
2170 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2171 if let Value::Lit(Literal::LitInt(n)) = res {
2172 assert_eq!(n, 3);
2173 } else {
2174 panic!("Expected LitInt(3)");
2175 }
2176 }
2177
2178 #[test]
2179 fn test_eval_case_data() {
2180 let nodes = vec![
2181 CoreFrame::Lit(Literal::LitInt(42)),
2182 CoreFrame::Con {
2183 tag: DataConId(1),
2184 fields: vec![0],
2185 },
2186 CoreFrame::Var(VarId(10)),
2187 CoreFrame::Case {
2188 scrutinee: 1,
2189 binder: VarId(11),
2190 alts: vec![Alt {
2191 con: AltCon::DataAlt(DataConId(1)),
2192 binders: vec![VarId(10)],
2193 body: 2,
2194 }],
2195 },
2196 ];
2197 let expr = CoreExpr { nodes };
2198 let mut heap = crate::heap::VecHeap::new();
2199 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2200 if let Value::Lit(Literal::LitInt(n)) = res {
2201 assert_eq!(n, 42);
2202 } else {
2203 panic!("Expected LitInt(42)");
2204 }
2205 }
2206
2207 #[test]
2208 fn test_eval_case_binder() {
2209 let nodes = vec![
2210 CoreFrame::Lit(Literal::LitInt(42)),
2211 CoreFrame::Con {
2212 tag: DataConId(1),
2213 fields: vec![0],
2214 },
2215 CoreFrame::Var(VarId(11)),
2216 CoreFrame::Case {
2217 scrutinee: 1,
2218 binder: VarId(11),
2219 alts: vec![Alt {
2220 con: AltCon::DataAlt(DataConId(1)),
2221 binders: vec![VarId(10)],
2222 body: 2,
2223 }],
2224 },
2225 ];
2226 let expr = CoreExpr { nodes };
2227 let mut heap = crate::heap::VecHeap::new();
2228 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2229 if let Value::Con(tag, _) = res {
2230 assert_eq!(tag.0, 1);
2231 } else {
2232 panic!("Expected Con");
2233 }
2234 }
2235
2236 #[test]
2237 fn test_eval_case_lit_default() {
2238 let nodes = vec![
2239 CoreFrame::Lit(Literal::LitInt(3)),
2240 CoreFrame::Lit(Literal::LitInt(10)),
2241 CoreFrame::Lit(Literal::LitInt(20)),
2242 CoreFrame::Lit(Literal::LitInt(30)),
2243 CoreFrame::Case {
2244 scrutinee: 0,
2245 binder: VarId(10),
2246 alts: vec![
2247 Alt {
2248 con: AltCon::LitAlt(Literal::LitInt(1)),
2249 binders: vec![],
2250 body: 1,
2251 },
2252 Alt {
2253 con: AltCon::LitAlt(Literal::LitInt(2)),
2254 binders: vec![],
2255 body: 2,
2256 },
2257 Alt {
2258 con: AltCon::Default,
2259 binders: vec![],
2260 body: 3,
2261 },
2262 ],
2263 },
2264 ];
2265 let expr = CoreExpr { nodes };
2266 let mut heap = crate::heap::VecHeap::new();
2267 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2268 if let Value::Lit(Literal::LitInt(n)) = res {
2269 assert_eq!(n, 30);
2270 } else {
2271 panic!("Expected LitInt(30)");
2272 }
2273 }
2274
2275 #[test]
2276 fn test_eval_data_to_tag() {
2277 let nodes = vec![
2278 CoreFrame::Con {
2279 tag: DataConId(5),
2280 fields: vec![],
2281 },
2282 CoreFrame::PrimOp {
2283 op: PrimOpKind::DataToTag,
2284 args: vec![0],
2285 },
2286 ];
2287 let expr = CoreExpr { nodes };
2288 let mut heap = crate::heap::VecHeap::new();
2289 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2290 if let Value::Lit(Literal::LitInt(n)) = res {
2291 assert_eq!(n, 5);
2292 } else {
2293 panic!("Expected LitInt(5)");
2294 }
2295 }
2296
2297 #[test]
2298 fn test_eval_let_rec_forward_refs() {
2299 let nodes = vec![
2301 CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::Var(VarId(1)), CoreFrame::Var(VarId(2)), CoreFrame::LetRec {
2305 bindings: vec![(VarId(1), 0), (VarId(2), 1)],
2306 body: 2,
2307 }, ];
2309 let expr = CoreExpr { nodes };
2310 let mut heap = crate::heap::VecHeap::new();
2311 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2312 if let Value::Lit(Literal::LitInt(n)) = res {
2313 assert_eq!(n, 1);
2314 } else {
2315 panic!("Expected LitInt(1)");
2316 }
2317 }
2318
2319 #[test]
2320 fn test_eval_join_simple() {
2321 let nodes = vec![
2323 CoreFrame::Var(VarId(10)), CoreFrame::Lit(Literal::LitInt(42)), CoreFrame::Jump {
2326 label: JoinId(1),
2327 args: vec![1],
2328 }, CoreFrame::Join {
2330 label: JoinId(1),
2331 params: vec![VarId(10)],
2332 rhs: 0,
2333 body: 2,
2334 }, ];
2336 let expr = CoreExpr { nodes };
2337 let mut heap = crate::heap::VecHeap::new();
2338 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2339 if let Value::Lit(Literal::LitInt(n)) = res {
2340 assert_eq!(n, 42);
2341 } else {
2342 panic!("Expected LitInt(42), got {:?}", res);
2343 }
2344 }
2345
2346 #[test]
2347 fn test_eval_join_multi_param() {
2348 let nodes = vec![
2350 CoreFrame::Var(VarId(10)), CoreFrame::Var(VarId(11)), CoreFrame::PrimOp {
2353 op: PrimOpKind::IntAdd,
2354 args: vec![0, 1],
2355 }, CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::Lit(Literal::LitInt(2)), CoreFrame::Jump {
2359 label: JoinId(1),
2360 args: vec![3, 4],
2361 }, CoreFrame::Join {
2363 label: JoinId(1),
2364 params: vec![VarId(10), VarId(11)],
2365 rhs: 2,
2366 body: 5,
2367 }, ];
2369 let expr = CoreExpr { nodes };
2370 let mut heap = crate::heap::VecHeap::new();
2371 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2372 if let Value::Lit(Literal::LitInt(n)) = res {
2373 assert_eq!(n, 3);
2374 } else {
2375 panic!("Expected LitInt(3)");
2376 }
2377 }
2378
2379 #[test]
2380 fn test_eval_unbound_jump() {
2381 let nodes = vec![CoreFrame::Jump {
2382 label: JoinId(1),
2383 args: vec![],
2384 }];
2385 let expr = CoreExpr { nodes };
2386 let mut heap = crate::heap::VecHeap::new();
2387 let res = eval(&expr, &Env::new(), &mut heap);
2388 assert!(matches!(res, Err(EvalError::UnboundJoin(JoinId(1)))));
2389 }
2390
2391 #[test]
2392 fn test_thunk_lazy() {
2393 let nodes = vec![
2395 CoreFrame::Var(VarId(999)), CoreFrame::Lit(Literal::LitInt(42)), CoreFrame::LetNonRec {
2398 binder: VarId(1),
2399 rhs: 0,
2400 body: 1,
2401 }, ];
2403 let expr = CoreExpr { nodes };
2404 let mut heap = crate::heap::VecHeap::new();
2405 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2406 if let Value::Lit(Literal::LitInt(n)) = res {
2407 assert_eq!(n, 42);
2408 } else {
2409 panic!("Expected LitInt(42)");
2410 }
2411 }
2412
2413 #[test]
2414 fn test_thunk_caching() {
2415 let nodes = vec![
2417 CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::PrimOp {
2419 op: PrimOpKind::IntAdd,
2420 args: vec![0, 0],
2421 }, CoreFrame::Var(VarId(1)), CoreFrame::PrimOp {
2424 op: PrimOpKind::IntAdd,
2425 args: vec![2, 2],
2426 }, CoreFrame::LetNonRec {
2428 binder: VarId(1),
2429 rhs: 1,
2430 body: 3,
2431 }, ];
2433 let expr = CoreExpr { nodes };
2434 let mut heap = crate::heap::VecHeap::new();
2435 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2436 if let Value::Lit(Literal::LitInt(n)) = res {
2437 assert_eq!(n, 4);
2438 } else {
2439 panic!("Expected LitInt(4)");
2440 }
2441 }
2442
2443 #[test]
2444 fn test_thunk_blackhole() {
2445 let nodes = vec![
2447 CoreFrame::Var(VarId(1)), CoreFrame::LetRec {
2449 bindings: vec![(VarId(1), 0)],
2450 body: 0,
2451 }, ];
2453 let expr = CoreExpr { nodes };
2454 let mut heap = crate::heap::VecHeap::new();
2455 let res = eval(&expr, &Env::new(), &mut heap);
2456 assert!(matches!(res, Err(EvalError::InfiniteLoop(_))));
2457 }
2458
2459 #[test]
2460 fn test_letrec_mutual_recursion() {
2461 let nodes = vec![
2463 CoreFrame::Var(VarId(11)), CoreFrame::Var(VarId(2)), CoreFrame::App { fun: 1, arg: 0 }, CoreFrame::Lam {
2467 binder: VarId(11),
2468 body: 2,
2469 }, CoreFrame::Var(VarId(12)), CoreFrame::Lam {
2472 binder: VarId(12),
2473 body: 4,
2474 }, CoreFrame::Var(VarId(1)), CoreFrame::Lit(Literal::LitInt(42)), CoreFrame::App { fun: 6, arg: 7 }, CoreFrame::LetRec {
2479 bindings: vec![(VarId(1), 3), (VarId(2), 5)],
2480 body: 8,
2481 }, ];
2483 let expr = CoreExpr { nodes };
2484 let mut heap = crate::heap::VecHeap::new();
2485 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2486 if let Value::Lit(Literal::LitInt(n)) = res {
2487 assert_eq!(n, 42);
2488 } else {
2489 panic!("Expected LitInt(42)");
2490 }
2491 }
2492
2493 #[test]
2494 fn test_eval_join_scoping() {
2495 let nodes = vec![
2501 CoreFrame::Lit(Literal::LitInt(100)), CoreFrame::Var(VarId(10)), CoreFrame::Var(VarId(20)), CoreFrame::PrimOp {
2505 op: PrimOpKind::IntAdd,
2506 args: vec![1, 2],
2507 }, CoreFrame::Lit(Literal::LitInt(200)), CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::Jump {
2511 label: JoinId(1),
2512 args: vec![5],
2513 }, CoreFrame::LetNonRec {
2515 binder: VarId(20),
2516 rhs: 4,
2517 body: 6,
2518 }, CoreFrame::Join {
2520 label: JoinId(1),
2521 params: vec![VarId(10)],
2522 rhs: 3,
2523 body: 7,
2524 }, CoreFrame::LetNonRec {
2526 binder: VarId(20),
2527 rhs: 0,
2528 body: 8,
2529 }, ];
2531 let expr = CoreExpr { nodes };
2532 let mut heap = crate::heap::VecHeap::new();
2533 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2534 if let Value::Lit(Literal::LitInt(n)) = res {
2535 assert_eq!(n, 101);
2536 } else {
2537 panic!("Expected LitInt(101)");
2538 }
2539 }
2540
2541 #[test]
2542 fn test_thunk_poison_restoration() {
2543 let nodes = vec![
2545 CoreFrame::Var(VarId(999)), CoreFrame::LetNonRec {
2547 binder: VarId(1),
2548 rhs: 0,
2549 body: 0,
2550 }, ];
2552 let expr = CoreExpr { nodes };
2553 let mut heap = crate::heap::VecHeap::new();
2554
2555 let res1 = eval(&expr, &Env::new(), &mut heap);
2557 assert!(matches!(res1, Err(EvalError::UnboundVar(_))));
2558
2559 let res2 = eval(&expr, &Env::new(), &mut heap);
2561 assert!(matches!(res2, Err(EvalError::UnboundVar(_))));
2562 }
2563
2564 #[test]
2565 fn test_eval_jump_arity_mismatch() {
2566 let nodes = vec![
2568 CoreFrame::Var(VarId(10)), CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::Lit(Literal::LitInt(2)), CoreFrame::Jump {
2572 label: JoinId(1),
2573 args: vec![1, 2],
2574 }, CoreFrame::Join {
2576 label: JoinId(1),
2577 params: vec![VarId(10)],
2578 rhs: 0,
2579 body: 3,
2580 }, ];
2582 let expr = CoreExpr { nodes };
2583 let mut heap = crate::heap::VecHeap::new();
2584 let res = eval(&expr, &Env::new(), &mut heap);
2585 assert!(matches!(res, Err(EvalError::ArityMismatch { .. })));
2586 }
2587
2588 #[test]
2589 fn test_eval_case_no_match() {
2590 let nodes = vec![
2591 CoreFrame::Lit(Literal::LitInt(42)), CoreFrame::Case {
2593 scrutinee: 0,
2594 binder: VarId(1),
2595 alts: vec![Alt {
2596 con: AltCon::LitAlt(Literal::LitInt(1)),
2597 binders: vec![],
2598 body: 0,
2599 }],
2600 }, ];
2602 let expr = CoreExpr { nodes };
2603 let mut heap = crate::heap::VecHeap::new();
2604 let res = eval(&expr, &Env::new(), &mut heap);
2605 assert!(matches!(res, Err(EvalError::NoMatchingAlt)));
2606 }
2607
2608 #[test]
2609 fn test_eval_primop_invalid_char() {
2610 let nodes = vec![
2611 CoreFrame::Lit(Literal::LitInt(0x110000)), CoreFrame::PrimOp {
2613 op: PrimOpKind::Chr,
2614 args: vec![0],
2615 }, ];
2617 let expr = CoreExpr { nodes };
2618 let mut heap = crate::heap::VecHeap::new();
2619 let res = eval(&expr, &Env::new(), &mut heap);
2620 assert!(matches!(res, Err(EvalError::TypeMismatch { .. })));
2621 }
2622
2623 #[test]
2624 fn test_eval_primop_ffi_bounds() {
2625 let ba = std::sync::Arc::new(std::sync::Mutex::new(vec![0u8; 10]));
2626 let mut env = Env::new();
2627 env.insert(VarId(100), Value::ByteArray(ba));
2628
2629 let nodes = vec![
2630 CoreFrame::Var(VarId(100)), CoreFrame::Lit(Literal::LitInt(20)), CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::PrimOp {
2634 op: PrimOpKind::FfiTextMeasureOff,
2635 args: vec![0, 1, 2],
2636 }, ];
2638 let expr = CoreExpr { nodes };
2639 let mut heap = crate::heap::VecHeap::new();
2640 let res = eval(&expr, &env, &mut heap);
2641 assert!(matches!(res, Err(EvalError::TypeMismatch { .. })));
2642 }
2643
2644 #[test]
2645 fn test_eval_primop_ffi_text_reverse_negative() {
2646 let src = std::sync::Arc::new(std::sync::Mutex::new(vec![b'a', b'b', b'c']));
2647 let dst = std::sync::Arc::new(std::sync::Mutex::new(vec![0u8; 3]));
2648 let mut env = Env::new();
2649 env.insert(VarId(100), Value::ByteArray(dst));
2650 env.insert(VarId(101), Value::ByteArray(src));
2651
2652 let nodes = vec![
2653 CoreFrame::Var(VarId(100)), CoreFrame::Var(VarId(101)), CoreFrame::Lit(Literal::LitInt(-1)), CoreFrame::Lit(Literal::LitInt(3)), CoreFrame::PrimOp {
2658 op: PrimOpKind::FfiTextReverse,
2659 args: vec![0, 1, 2, 3],
2660 },
2661 ];
2662 let expr = CoreExpr { nodes };
2663 let mut heap = crate::heap::VecHeap::new();
2664 let res = eval(&expr, &env, &mut heap);
2665 assert!(matches!(res, Err(EvalError::TypeMismatch { .. })));
2666 }
2667
2668 #[test]
2669 fn test_eval_primop_negative_index() {
2670 let ba = std::sync::Arc::new(std::sync::Mutex::new(vec![0u8; 16]));
2671 let mut env = Env::new();
2672 env.insert(VarId(100), Value::ByteArray(ba));
2673
2674 let nodes = vec![
2675 CoreFrame::Var(VarId(100)), CoreFrame::Lit(Literal::LitInt(-1)), CoreFrame::PrimOp {
2678 op: PrimOpKind::IndexWordArray,
2679 args: vec![0, 1],
2680 }, ];
2682 let expr = CoreExpr { nodes };
2683 let mut heap = crate::heap::VecHeap::new();
2684 let res = eval(&expr, &env, &mut heap);
2685 assert!(matches!(res, Err(EvalError::TypeMismatch { .. })));
2686 }
2687
2688 #[test]
2689 fn test_eval_primop_arity_mismatch() {
2690 let nodes = vec![
2691 CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::PrimOp {
2693 op: PrimOpKind::IntAdd,
2694 args: vec![0], }, ];
2697 let expr = CoreExpr { nodes };
2698 let mut heap = crate::heap::VecHeap::new();
2699 let res = eval(&expr, &Env::new(), &mut heap);
2700 assert!(matches!(res, Err(EvalError::ArityMismatch { .. })));
2701 }
2702
2703 #[test]
2704 fn test_eval_force_non_thunk() {
2705 let mut heap = crate::heap::VecHeap::new();
2706 let val = Value::Lit(Literal::LitInt(42));
2707 let res = force(val, &mut heap).unwrap();
2708 if let Value::Lit(Literal::LitInt(n)) = res {
2709 assert_eq!(n, 42);
2710 } else {
2711 panic!("Expected LitInt(42)");
2712 }
2713 }
2714
2715 #[test]
2716 fn test_eval_deeply_nested_con() {
2717 let nodes = vec![
2719 CoreFrame::Lit(Literal::LitInt(42)), CoreFrame::Con {
2721 tag: DataConId(1),
2722 fields: vec![0],
2723 }, CoreFrame::Con {
2725 tag: DataConId(2),
2726 fields: vec![1],
2727 }, ];
2729 let expr = CoreExpr { nodes };
2730 let mut heap = crate::heap::VecHeap::new();
2731 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2732 match res {
2733 Value::Con(tag, fields) => {
2734 assert_eq!(tag.0, 2);
2735 assert_eq!(fields.len(), 1);
2736 match &fields[0] {
2737 Value::Con(tag2, fields2) => {
2738 assert_eq!(tag2.0, 1);
2739 assert_eq!(fields2.len(), 1);
2740 match &fields2[0] {
2741 Value::Lit(Literal::LitInt(n)) => assert_eq!(*n, 42),
2742 _ => panic!("Expected LitInt(42)"),
2743 }
2744 }
2745 _ => panic!("Expected inner Con"),
2746 }
2747 }
2748 _ => panic!("Expected outer Con"),
2749 }
2750 }
2751
2752 #[test]
2753 fn test_eval_case_default_binder() {
2754 let nodes = vec![
2756 CoreFrame::Lit(Literal::LitInt(42)), CoreFrame::Var(VarId(1)), CoreFrame::Case {
2759 scrutinee: 0,
2760 binder: VarId(1),
2761 alts: vec![Alt {
2762 con: AltCon::Default,
2763 binders: vec![],
2764 body: 1,
2765 }],
2766 }, ];
2768 let expr = CoreExpr { nodes };
2769 let mut heap = crate::heap::VecHeap::new();
2770 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2771 if let Value::Lit(Literal::LitInt(n)) = res {
2772 assert_eq!(n, 42);
2773 } else {
2774 panic!("Expected LitInt(42)");
2775 }
2776 }
2777
2778 #[test]
2779 fn test_eval_empty_con() {
2780 let nodes = vec![CoreFrame::Con {
2781 tag: DataConId(1),
2782 fields: vec![],
2783 }];
2784 let expr = CoreExpr { nodes };
2785 let mut heap = crate::heap::VecHeap::new();
2786 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2787 if let Value::Con(tag, fields) = res {
2788 assert_eq!(tag.0, 1);
2789 assert!(fields.is_empty());
2790 } else {
2791 panic!("Expected empty Con");
2792 }
2793 }
2794
2795 #[test]
2796 fn test_eval_unbound_var_lazy() {
2797 let nodes = vec![
2799 CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::Var(VarId(999)), CoreFrame::Var(VarId(1)), CoreFrame::LetNonRec {
2803 binder: VarId(2),
2804 rhs: 1,
2805 body: 2,
2806 }, CoreFrame::LetNonRec {
2808 binder: VarId(1),
2809 rhs: 0,
2810 body: 3,
2811 }, ];
2813 let expr = CoreExpr { nodes };
2814 let mut heap = crate::heap::VecHeap::new();
2815 let res = eval(&expr, &Env::new(), &mut heap).unwrap();
2817 if let Value::Lit(Literal::LitInt(n)) = res {
2818 assert_eq!(n, 1);
2819 } else {
2820 panic!("Expected LitInt(1)");
2821 }
2822 }
2823
2824 #[test]
2825 fn test_eval_unbound_var_forced_err() {
2826 let nodes = vec![
2828 CoreFrame::Lit(Literal::LitInt(1)), CoreFrame::Var(VarId(999)), CoreFrame::Var(VarId(2)), CoreFrame::LetNonRec {
2832 binder: VarId(2),
2833 rhs: 1,
2834 body: 2,
2835 }, CoreFrame::LetNonRec {
2837 binder: VarId(1),
2838 rhs: 0,
2839 body: 3,
2840 }, ];
2842 let expr = CoreExpr { nodes };
2843 let mut heap = crate::heap::VecHeap::new();
2844 let res = eval(&expr, &Env::new(), &mut heap);
2846 assert!(matches!(res, Err(EvalError::UnboundVar(VarId(999)))));
2847 }
2848}