1use super::core::{
2 expand_runtime_block, expected_builder_type, match_cannot_succeed,
3 match_requires_code_but_cannot_have_code, resolved_name_kind, staged_builtin_arg_mismatch,
4};
5use super::meta_types_builder::{
6 builder_bindings_to_locals, coerce_meta_value_to_staged_meta_type, coerce_meta_value_to_type,
7 eval_meta_expr_arg, eval_meta_int_arg, eval_meta_string_arg, eval_meta_type_arg,
8 eval_meta_typed_expr_arg, expand_builder_expr, expr_builder_locals,
9};
10use super::quote_expand::{
11 coerce_value_to_code_for_match, expand_quoted_expr, match_quote_code, promote_splice_value,
12 runtime_splice_value_to_expr,
13};
14use super::quote_match::match_quote_pattern_type;
15use super::*;
16
17pub(super) fn expand_runtime_expr(
18 program: &Program,
19 expr: &Expr,
20 function_table: &BTreeMap<String, &MetaFunctionDecl>,
21 runtime_scope: &RuntimeScope,
22 template_env: &BTreeMap<String, MetaValue>,
23 mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
24) -> Result<Expr, MetaEvalError> {
25 match expr {
26 Expr::Ident { .. } | Expr::Int(_) | Expr::Number(_) | Expr::String(_) | Expr::Bool(_) => {
27 Ok(expr.clone())
28 }
29 Expr::Call { callee, args, span } => Ok(Expr::Call {
30 callee: Box::new(expand_runtime_expr(
31 program,
32 callee,
33 function_table,
34 runtime_scope,
35 template_env,
36 builder_env_cursor.as_deref_mut(),
37 )?),
38 args: args
39 .iter()
40 .map(|arg| {
41 expand_runtime_call_arg(
42 program,
43 arg,
44 function_table,
45 runtime_scope,
46 template_env,
47 builder_env_cursor.as_deref_mut(),
48 )
49 })
50 .collect::<Result<Vec<_>, _>>()?,
51 span: *span,
52 }),
53 Expr::IntrinsicCall { name, args, span } => Ok(Expr::IntrinsicCall {
54 name: name.clone(),
55 args: args
56 .iter()
57 .map(|arg| {
58 expand_runtime_call_arg(
59 program,
60 arg,
61 function_table,
62 runtime_scope,
63 template_env,
64 builder_env_cursor.as_deref_mut(),
65 )
66 })
67 .collect::<Result<Vec<_>, _>>()?,
68 span: *span,
69 }),
70 Expr::Field { base, field } => Ok(Expr::Field {
71 base: Box::new(expand_runtime_expr(
72 program,
73 base,
74 function_table,
75 runtime_scope,
76 template_env,
77 builder_env_cursor.as_deref_mut(),
78 )?),
79 field: field.clone(),
80 }),
81 Expr::Index { base, index } => Ok(Expr::Index {
82 base: Box::new(expand_runtime_expr(
83 program,
84 base,
85 function_table,
86 runtime_scope,
87 template_env,
88 builder_env_cursor.as_deref_mut(),
89 )?),
90 index: Box::new(expand_runtime_expr(
91 program,
92 index,
93 function_table,
94 runtime_scope,
95 template_env,
96 builder_env_cursor.as_deref_mut(),
97 )?),
98 }),
99 Expr::SliceRange { base, start, end } => Ok(Expr::SliceRange {
100 base: Box::new(expand_runtime_expr(
101 program,
102 base,
103 function_table,
104 runtime_scope,
105 template_env,
106 builder_env_cursor.as_deref_mut(),
107 )?),
108 start: start
109 .as_ref()
110 .map(|expr| {
111 expand_runtime_expr(
112 program,
113 expr,
114 function_table,
115 runtime_scope,
116 template_env,
117 builder_env_cursor.as_deref_mut(),
118 )
119 .map(Box::new)
120 })
121 .transpose()?,
122 end: end
123 .as_ref()
124 .map(|expr| {
125 expand_runtime_expr(
126 program,
127 expr,
128 function_table,
129 runtime_scope,
130 template_env,
131 builder_env_cursor.as_deref_mut(),
132 )
133 .map(Box::new)
134 })
135 .transpose()?,
136 }),
137 Expr::Prefix { op, value } => Ok(Expr::Prefix {
138 op: *op,
139 value: Box::new(expand_runtime_expr(
140 program,
141 value,
142 function_table,
143 runtime_scope,
144 template_env,
145 builder_env_cursor.as_deref_mut(),
146 )?),
147 }),
148 Expr::Binary { op, lhs, rhs } => Ok(Expr::Binary {
149 op: *op,
150 lhs: Box::new(expand_runtime_expr(
151 program,
152 lhs,
153 function_table,
154 runtime_scope,
155 template_env,
156 builder_env_cursor.as_deref_mut(),
157 )?),
158 rhs: Box::new(expand_runtime_expr(
159 program,
160 rhs,
161 function_table,
162 runtime_scope,
163 template_env,
164 builder_env_cursor.as_deref_mut(),
165 )?),
166 }),
167 Expr::Relational { op, lhs, rhs } => Ok(Expr::Relational {
168 op: *op,
169 lhs: Box::new(expand_runtime_expr(
170 program,
171 lhs,
172 function_table,
173 runtime_scope,
174 template_env,
175 builder_env_cursor.as_deref_mut(),
176 )?),
177 rhs: Box::new(expand_runtime_expr(
178 program,
179 rhs,
180 function_table,
181 runtime_scope,
182 template_env,
183 builder_env_cursor.as_deref_mut(),
184 )?),
185 }),
186 Expr::Array { items, span } => Ok(Expr::Array {
187 items: items
188 .iter()
189 .map(|item| {
190 expand_runtime_expr(
191 program,
192 item,
193 function_table,
194 runtime_scope,
195 template_env,
196 builder_env_cursor.as_deref_mut(),
197 )
198 })
199 .collect::<Result<Vec<_>, _>>()?,
200 span: *span,
201 }),
202 Expr::Tuple { items, span } => Ok(Expr::Tuple {
203 items: items
204 .iter()
205 .map(|item| {
206 expand_runtime_expr(
207 program,
208 item,
209 function_table,
210 runtime_scope,
211 template_env,
212 builder_env_cursor.as_deref_mut(),
213 )
214 })
215 .collect::<Result<Vec<_>, _>>()?,
216 span: *span,
217 }),
218 Expr::StructLit { name, fields, span } => Ok(Expr::StructLit {
219 name: name.clone(),
220 fields: fields
221 .iter()
222 .map(|field| {
223 Ok(NamedExprField {
224 name: field.name.clone(),
225 value: expand_runtime_expr(
226 program,
227 &field.value,
228 function_table,
229 runtime_scope,
230 template_env,
231 builder_env_cursor.as_deref_mut(),
232 )?,
233 })
234 })
235 .collect::<Result<Vec<_>, MetaEvalError>>()?,
236 span: *span,
237 }),
238 Expr::Block(block) => Ok(Expr::Block(expand_runtime_block(
239 program,
240 block,
241 function_table,
242 runtime_scope,
243 template_env,
244 builder_env_cursor.as_deref_mut(),
245 )?)),
246 Expr::Splice(meta_expr) => {
247 let mut env = template_env.clone();
248 let value = eval_meta_expr(
249 program,
250 meta_expr,
251 &mut env,
252 function_table,
253 runtime_scope,
254 builder_env_cursor.as_deref_mut(),
255 )?;
256 runtime_splice_value_to_expr(value)
257 }
258 }
259}
260
261pub(super) fn expand_runtime_call_arg(
262 program: &Program,
263 arg: &CallArg,
264 function_table: &BTreeMap<String, &MetaFunctionDecl>,
265 runtime_scope: &RuntimeScope,
266 template_env: &BTreeMap<String, MetaValue>,
267 builder_env_cursor: Option<&mut BuilderEnvCursor>,
268) -> Result<CallArg, MetaEvalError> {
269 match arg {
270 CallArg::Expr(expr) => Ok(CallArg::Expr(expand_runtime_expr(
271 program,
272 expr,
273 function_table,
274 runtime_scope,
275 template_env,
276 builder_env_cursor,
277 )?)),
278 CallArg::Spread(expr) => Ok(CallArg::Spread(expand_runtime_expr(
279 program,
280 expr,
281 function_table,
282 runtime_scope,
283 template_env,
284 builder_env_cursor,
285 )?)),
286 CallArg::Type(ty) => Ok(CallArg::Type(ty.clone())),
287 }
288}
289
290#[derive(Debug)]
291pub(super) struct MetaBlockOutcome {
292 pub(super) last_value: Option<MetaValue>,
293 pub(super) emitted_runtime_stmts: Vec<Stmt>,
294}
295
296pub(super) fn eval_meta_block(
297 program: &Program,
298 block: &MetaBlock,
299 env: &mut BTreeMap<String, MetaValue>,
300 function_table: &BTreeMap<String, &MetaFunctionDecl>,
301 emit_runtime_stmts: bool,
302 runtime_scope: &RuntimeScope,
303 mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
304) -> Result<MetaBlockOutcome, MetaEvalError> {
305 let mut last_value = None;
306 let mut emitted_runtime_stmts = Vec::new();
307
308 for statement in &block.statements {
309 let step = eval_meta_stmt(
310 program,
311 statement,
312 env,
313 function_table,
314 emit_runtime_stmts,
315 runtime_scope,
316 builder_env_cursor.as_deref_mut(),
317 )?;
318 if let Some(value) = step.last_value {
319 last_value = Some(value);
320 }
321 emitted_runtime_stmts.extend(step.emitted_runtime_stmts);
322 }
323
324 Ok(MetaBlockOutcome {
325 last_value,
326 emitted_runtime_stmts,
327 })
328}
329
330pub(super) fn eval_meta_stmt(
331 program: &Program,
332 statement: &MetaStmt,
333 env: &mut BTreeMap<String, MetaValue>,
334 function_table: &BTreeMap<String, &MetaFunctionDecl>,
335 emit_runtime_stmts: bool,
336 runtime_scope: &RuntimeScope,
337 mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
338) -> Result<MetaBlockOutcome, MetaEvalError> {
339 let semantic_stmt_entry = builder_env_cursor
340 .as_deref_mut()
341 .and_then(|cursor| cursor.next_stmt_entry().cloned());
342 match statement {
343 MetaStmt::Let { name, value } => {
344 let value = eval_meta_expr(
345 program,
346 value,
347 env,
348 function_table,
349 runtime_scope,
350 builder_env_cursor.as_deref_mut(),
351 )?;
352 env.insert(name.clone(), value);
353 Ok(MetaBlockOutcome {
354 last_value: None,
355 emitted_runtime_stmts: Vec::new(),
356 })
357 }
358 MetaStmt::Expr { expr } => {
359 let value = eval_meta_expr(
360 program,
361 expr,
362 env,
363 function_table,
364 runtime_scope,
365 builder_env_cursor.as_deref_mut(),
366 )?;
367 let emitted_runtime_stmts = if emit_runtime_stmts {
368 runtime_stmts_from_meta_value(&value)
369 } else {
370 Vec::new()
371 };
372 Ok(MetaBlockOutcome {
373 last_value: Some(value),
374 emitted_runtime_stmts,
375 })
376 }
377 MetaStmt::Match { value, arms } => {
378 let matched = eval_meta_expr(
379 program,
380 value,
381 env,
382 function_table,
383 runtime_scope,
384 builder_env_cursor.as_deref_mut(),
385 )?;
386
387 if semantic_stmt_entry
388 .as_ref()
389 .and_then(|entry| entry.match_info.as_ref())
390 .is_some_and(match_requires_code_but_cannot_have_code)
391 {
392 return Err(MetaEvalError::MatchExpectedCode);
393 }
394 if semantic_stmt_entry
395 .as_ref()
396 .and_then(|entry| entry.match_info.as_ref())
397 .is_some_and(match_cannot_succeed)
398 {
399 return Err(MetaEvalError::NoMatchArm);
400 }
401
402 for arm in arms {
403 let mut captures = BTreeMap::new();
404 let arm_matches = match &arm.pattern {
405 MetaMatchPattern::Wildcard => true,
406 MetaMatchPattern::Int(value) => {
407 matches!(matched, MetaValue::Int(actual) if actual == *value)
408 }
409 MetaMatchPattern::Bool(value) => {
410 matches!(matched, MetaValue::Bool(actual) if actual == *value)
411 }
412 MetaMatchPattern::String(value) => {
413 matches!(&matched, MetaValue::String(actual) if actual == value)
414 }
415 MetaMatchPattern::Quote(pattern) => {
416 let code = coerce_value_to_code_for_match(matched.clone())
417 .ok_or(MetaEvalError::MatchExpectedCode)?;
418 match_quote_code(pattern, &code, &mut captures)
419 }
420 MetaMatchPattern::Type(pattern_ty) => match &matched {
421 MetaValue::Type(target_ty) => {
422 match_quote_pattern_type(pattern_ty, target_ty)
423 }
424 _ => {
425 let code = coerce_value_to_code_for_match(matched.clone())
426 .ok_or(MetaEvalError::MatchExpectedCode)?;
427 matches!(&code, CodeValue::Type(target_ty) if match_quote_pattern_type(pattern_ty, target_ty))
428 }
429 },
430 };
431 if !arm_matches {
432 continue;
433 }
434
435 let mut arm_env = env.clone();
436 arm_env.extend(captures);
437 let arm_value = eval_meta_expr(
438 program,
439 &arm.result,
440 &mut arm_env,
441 function_table,
442 runtime_scope,
443 builder_env_cursor.as_deref_mut(),
444 )?;
445 let arm_value = coerce_meta_value_to_staged_meta_type(
446 arm_value,
447 semantic_stmt_entry
448 .as_ref()
449 .and_then(|entry| entry.match_info.as_ref())
450 .and_then(|info| info.converged_arm_type.as_ref()),
451 )?;
452 let emitted_runtime_stmts = if emit_runtime_stmts {
453 runtime_stmts_from_meta_value(&arm_value)
454 } else {
455 Vec::new()
456 };
457 return Ok(MetaBlockOutcome {
458 last_value: Some(arm_value),
459 emitted_runtime_stmts,
460 });
461 }
462
463 Err(MetaEvalError::NoMatchArm)
464 }
465 MetaStmt::Meta { body } => eval_meta_block(
466 program,
467 body,
468 env,
469 function_table,
470 emit_runtime_stmts,
471 runtime_scope,
472 builder_env_cursor,
473 ),
474 }
475}
476
477pub(super) fn runtime_stmts_from_meta_value(value: &MetaValue) -> Vec<Stmt> {
478 match value {
479 MetaValue::Expr { expr, .. } => vec![Stmt::Expr {
480 expr: expr.clone(),
481 has_semi: true,
482 }],
483 _ => Vec::new(),
484 }
485}
486
487pub(super) fn eval_meta_expr(
488 program: &Program,
489 expr: &MetaExpr,
490 env: &mut BTreeMap<String, MetaValue>,
491 function_table: &BTreeMap<String, &MetaFunctionDecl>,
492 runtime_scope: &RuntimeScope,
493 mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
494) -> Result<MetaValue, MetaEvalError> {
495 let semantic_entry = builder_env_cursor
496 .as_deref_mut()
497 .and_then(|cursor| cursor.next_meta_entry().cloned());
498 match expr {
499 MetaExpr::Ident(name) => {
500 if let Some(value) = env.get(name) {
501 return Ok(value.clone());
502 }
503 if runtime_scope.contains_key(name) {
504 return Err(MetaEvalError::RuntimeBindingUnavailable { name: name.clone() });
505 }
506 if let Some(kind) = semantic_entry
507 .as_ref()
508 .and_then(|entry| entry.resolved_name.as_ref())
509 .and_then(resolved_name_kind)
510 {
511 return Err(MetaEvalError::KnownNameNotMetaValue {
512 name: name.clone(),
513 kind,
514 });
515 }
516 Err(MetaEvalError::UnknownBinding { name: name.clone() })
517 }
518 MetaExpr::Int(value) => Ok(MetaValue::Int(*value)),
519 MetaExpr::Bool(value) => Ok(MetaValue::Bool(*value)),
520 MetaExpr::String(value) => Ok(MetaValue::String(value.clone())),
521 MetaExpr::Type(ty) => Ok(MetaValue::Type(ty.clone())),
522 MetaExpr::Call { callee, args } => {
523 let staged_call_info = semantic_entry
524 .as_ref()
525 .and_then(|entry| entry.call_info.as_ref());
526 let staged_builtin = staged_call_info.and_then(|info| info.builtin);
527 let resolved_callee = staged_builtin
528 .map(builtin_meta_call_name)
529 .or_else(|| staged_call_info.map(|info| info.callee.as_str()))
530 .unwrap_or(callee.as_str());
531 if let Some(builtin) = staged_builtin {
532 if let Some((expected, actual)) =
533 staged_call_info.and_then(staged_builtin_arg_mismatch)
534 {
535 return Err(MetaEvalError::TypeMismatch {
536 expected: expected.to_owned(),
537 actual,
538 });
539 }
540 if let Some(value) = eval_builtin_meta_call(
541 program,
542 builtin_meta_call_name(builtin),
543 args,
544 env,
545 function_table,
546 runtime_scope,
547 builder_env_cursor.as_deref_mut(),
548 )? {
549 return coerce_meta_value_to_staged_meta_type(
550 value,
551 staged_call_info.and_then(|info| info.result_type.as_ref()),
552 );
553 }
554 return Err(MetaEvalError::ArityMismatch {
555 name: builtin_meta_call_name(builtin).to_owned(),
556 expected: builtin_meta_call_arity(builtin),
557 actual: args.len(),
558 });
559 }
560 if let Some(value) = eval_builtin_meta_call(
561 program,
562 resolved_callee,
563 args,
564 env,
565 function_table,
566 runtime_scope,
567 builder_env_cursor.as_deref_mut(),
568 )? {
569 return coerce_meta_value_to_staged_meta_type(
570 value,
571 staged_call_info.and_then(|info| info.result_type.as_ref()),
572 );
573 }
574 let function = function_table
575 .get(resolved_callee)
576 .copied()
577 .ok_or_else(|| MetaEvalError::UnknownMetaFunction {
578 name: resolved_callee.to_owned(),
579 })?;
580
581 if args.len() != function.params.len() {
582 return Err(MetaEvalError::ArityMismatch {
583 name: resolved_callee.to_owned(),
584 expected: function.params.len(),
585 actual: args.len(),
586 });
587 }
588
589 let mut call_env = BTreeMap::new();
590 for (param, arg) in function.params.iter().zip(args.iter()) {
591 let arg_value = eval_meta_expr(
592 program,
593 arg,
594 env,
595 function_table,
596 runtime_scope,
597 builder_env_cursor.as_deref_mut(),
598 )?;
599 let arg_value = coerce_meta_value_to_type(program, arg_value, ¶m.ty)?;
600 call_env.insert(param.name.clone(), arg_value);
601 }
602
603 let outcome = eval_meta_block(
604 program,
605 &function.body,
606 &mut call_env,
607 function_table,
608 false,
609 runtime_scope,
610 None,
611 )?;
612 let value = outcome
613 .last_value
614 .ok_or_else(|| MetaEvalError::MissingReturnValue {
615 name: function.name.clone(),
616 })?;
617 let value = coerce_meta_value_to_staged_meta_type(
618 value,
619 staged_call_info.and_then(|info| info.result_type.as_ref()),
620 )?;
621 coerce_meta_value_to_type(program, value, &function.return_type)
622 }
623 MetaExpr::BuildExpr(expr) => {
624 let semantic_locals = builder_env_cursor
625 .as_deref_mut()
626 .and_then(|cursor| cursor.next_env().map(builder_bindings_to_locals));
627 let expr = expand_builder_expr(
628 program,
629 expr,
630 env,
631 function_table,
632 runtime_scope,
633 builder_env_cursor.as_deref_mut(),
634 )?;
635 let locals = expr_builder_locals(env, runtime_scope, semantic_locals.as_deref());
636 let (expr, ty) =
637 elaborate_meta_generated_expr(program, &expr, &locals).map_err(|error| {
638 MetaEvalError::Elab {
639 message: semantic_entry
640 .as_ref()
641 .and_then(|entry| entry.meta_type.as_ref())
642 .and_then(expected_builder_type)
643 .map(|expected| format!("while building `Expr[{expected}]`: {}", error))
644 .unwrap_or_else(|| error.to_string()),
645 }
646 })?;
647 Ok(MetaValue::Expr { expr, ty })
648 }
649 MetaExpr::Quote(quoted_expr) => Ok(MetaValue::Code(match quoted_expr.as_ref() {
650 QuotedCode::Expr(expr) => CodeValue::Expr(expand_quoted_expr(
651 program,
652 expr,
653 env,
654 function_table,
655 runtime_scope,
656 builder_env_cursor.as_deref_mut(),
657 )?),
658 QuotedCode::Type(ty) => CodeValue::Type(ty.clone()),
659 })),
660 MetaExpr::Splice(value) => {
661 let value = eval_meta_expr(
662 program,
663 value,
664 env,
665 function_table,
666 runtime_scope,
667 builder_env_cursor,
668 )?;
669 promote_splice_value(value)
670 }
671 }
672}
673
674pub(super) fn eval_builtin_meta_call(
675 program: &Program,
676 callee: &str,
677 args: &[MetaExpr],
678 env: &mut BTreeMap<String, MetaValue>,
679 function_table: &BTreeMap<String, &MetaFunctionDecl>,
680 runtime_scope: &RuntimeScope,
681 mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
682) -> Result<Option<MetaValue>, MetaEvalError> {
683 let Some(spec) = builtin_spec_by_name(callee) else {
684 return Ok(None);
685 };
686 let builtin_name = spec.name;
687 match spec.kind {
688 crate::semantic::BuiltinMetaCallKind::StringConcat => {
689 let [left_expr, right_expr] = args else {
690 return Ok(None);
691 };
692 let left = eval_meta_string_arg(
693 program,
694 left_expr,
695 env,
696 function_table,
697 runtime_scope,
698 builder_env_cursor.as_deref_mut(),
699 )?;
700 let right = eval_meta_string_arg(
701 program,
702 right_expr,
703 env,
704 function_table,
705 runtime_scope,
706 builder_env_cursor.as_deref_mut(),
707 )?;
708 Ok(Some(MetaValue::String(string_concat(&left, &right))))
709 }
710 crate::semantic::BuiltinMetaCallKind::StringStartsWith => {
711 let [value_expr, prefix_expr] = args else {
712 return Ok(None);
713 };
714 let value = eval_meta_string_arg(
715 program,
716 value_expr,
717 env,
718 function_table,
719 runtime_scope,
720 builder_env_cursor.as_deref_mut(),
721 )?;
722 let prefix = eval_meta_string_arg(
723 program,
724 prefix_expr,
725 env,
726 function_table,
727 runtime_scope,
728 builder_env_cursor.as_deref_mut(),
729 )?;
730 Ok(Some(MetaValue::Bool(string_starts_with(&value, &prefix))))
731 }
732 crate::semantic::BuiltinMetaCallKind::StringDrop => {
733 let [value_expr, count_expr] = args else {
734 return Ok(None);
735 };
736 let value = eval_meta_string_arg(
737 program,
738 value_expr,
739 env,
740 function_table,
741 runtime_scope,
742 builder_env_cursor.as_deref_mut(),
743 )?;
744 let count = eval_meta_int_arg(
745 program,
746 count_expr,
747 env,
748 function_table,
749 runtime_scope,
750 builder_env_cursor.as_deref_mut(),
751 )?;
752 let count =
753 usize::try_from(count).expect("meta string drop count must be non-negative");
754 Ok(Some(MetaValue::String(string_drop(&value, count))))
755 }
756 crate::semantic::BuiltinMetaCallKind::StringTake => {
757 let [value_expr, count_expr] = args else {
758 return Ok(None);
759 };
760 let value = eval_meta_string_arg(
761 program,
762 value_expr,
763 env,
764 function_table,
765 runtime_scope,
766 builder_env_cursor.as_deref_mut(),
767 )?;
768 let count = eval_meta_int_arg(
769 program,
770 count_expr,
771 env,
772 function_table,
773 runtime_scope,
774 builder_env_cursor.as_deref_mut(),
775 )?;
776 let count =
777 usize::try_from(count).expect("meta string take count must be non-negative");
778 Ok(Some(MetaValue::String(string_take(&value, count))))
779 }
780 crate::semantic::BuiltinMetaCallKind::TupleIsEmpty => {
781 let [tuple_expr] = args else {
782 return Ok(None);
783 };
784 let tuple = eval_meta_expr_arg(
785 program,
786 tuple_expr,
787 env,
788 function_table,
789 runtime_scope,
790 builder_env_cursor.as_deref_mut(),
791 )?;
792 let Some(is_empty) = tuple_expr_is_empty(&tuple) else {
793 return Err(MetaEvalError::ExpectedTupleCode {
794 builtin: builtin_name,
795 });
796 };
797 Ok(Some(MetaValue::Bool(is_empty)))
798 }
799 crate::semantic::BuiltinMetaCallKind::TupleHead => {
800 let [tuple_expr] = args else {
801 return Ok(None);
802 };
803 let (tuple, tuple_ty) = eval_meta_typed_expr_arg(
804 program,
805 tuple_expr,
806 env,
807 function_table,
808 runtime_scope,
809 builder_env_cursor.as_deref_mut(),
810 )?;
811 let (head, ty) = match tuple_expr_head(tuple, &tuple_ty) {
812 Ok(value) => value,
813 Err(TupleExprBuiltinError::NotTupleExpr) => {
814 return Err(MetaEvalError::ExpectedTupleCode {
815 builtin: builtin_name,
816 });
817 }
818 Err(TupleExprBuiltinError::EmptyTuple) => return Err(MetaEvalError::NoMatchArm),
819 };
820 Ok(Some(MetaValue::Expr { expr: head, ty }))
821 }
822 crate::semantic::BuiltinMetaCallKind::TupleTail => {
823 let [tuple_expr] = args else {
824 return Ok(None);
825 };
826 let (tuple, tuple_ty) = eval_meta_typed_expr_arg(
827 program,
828 tuple_expr,
829 env,
830 function_table,
831 runtime_scope,
832 builder_env_cursor.as_deref_mut(),
833 )?;
834 let Some((tail, ty)) = tuple_expr_tail(tuple, &tuple_ty) else {
835 return Err(MetaEvalError::ExpectedTupleCode {
836 builtin: builtin_name,
837 });
838 };
839 Ok(Some(MetaValue::Expr { expr: tail, ty }))
840 }
841 crate::semantic::BuiltinMetaCallKind::TupleTypeHead => {
842 let [tuple_expr] = args else {
843 return Ok(None);
844 };
845 let tuple = eval_meta_type_arg(
846 program,
847 tuple_expr,
848 env,
849 function_table,
850 runtime_scope,
851 builder_env_cursor.as_deref_mut(),
852 )?;
853 let head = match tuple_type_head_builtin(&tuple) {
854 Ok(value) => value,
855 Err(TupleTypeBuiltinError::EmptyTuple) => return Err(MetaEvalError::NoMatchArm),
856 Err(TupleTypeBuiltinError::NotTupleType) => {
857 return Err(MetaEvalError::ExpectedTupleType {
858 builtin: builtin_name,
859 });
860 }
861 };
862 Ok(Some(MetaValue::Type(head)))
863 }
864 crate::semantic::BuiltinMetaCallKind::TupleTypeTail => {
865 let [tuple_expr] = args else {
866 return Ok(None);
867 };
868 let tuple = eval_meta_type_arg(
869 program,
870 tuple_expr,
871 env,
872 function_table,
873 runtime_scope,
874 builder_env_cursor.as_deref_mut(),
875 )?;
876 let tail = match tuple_type_tail_builtin(&tuple) {
877 Ok(value) => value,
878 Err(TupleTypeBuiltinError::NotTupleType) => {
879 return Err(MetaEvalError::ExpectedTupleType {
880 builtin: builtin_name,
881 });
882 }
883 Err(TupleTypeBuiltinError::EmptyTuple) => unreachable!(),
884 };
885 Ok(Some(MetaValue::Type(tail)))
886 }
887 }
888}