1use indexmap::IndexMap;
2use somni_parser::{
3 Location,
4 ast::{
5 Body, Expression, For, Function, If, LeftHandExpression, LiteralValue, Loop,
6 RightHandExpression, Statement, TypeHint, VariableDefinition,
7 },
8 lexer,
9 parser::DefaultTypeSet,
10};
11
12use crate::{
13 EvalError, ExprContext, FunctionCallError, RefPointee, Type, TypeSet, TypedValue,
14 value::{LoadStore, Place, Reference, SomniStruct},
15};
16
17pub struct ExpressionVisitor<'a, C, T = DefaultTypeSet> {
19 pub context: &'a mut C,
21 pub source: &'a str,
23 pub _marker: std::marker::PhantomData<T>,
25}
26
27impl<'a, C, T> ExpressionVisitor<'a, C, T>
28where
29 C: ExprContext<T>,
30 T: TypeSet,
31{
32 fn visit_variable(&mut self, variable: &lexer::Token) -> Result<TypedValue<T>, EvalError> {
33 let name = variable.source(self.source);
34 self.context.try_load_variable(name).ok_or(EvalError {
35 message: format!("Variable {name} was not found").into_boxed_str(),
36 location: variable.location,
37 })
38 }
39
40 pub fn visit_expression(
42 &mut self,
43 expression: &Expression<T::Parser>,
44 ) -> Result<TypedValue<T>, EvalError> {
45 let result = match expression {
46 Expression::Expression { expression } => {
47 self.visit_right_hand_expression(expression)?
48 }
49 Expression::Assignment {
50 left_expr,
51 operator: _,
52 right_expr,
53 } => {
54 let rhs = self.visit_right_hand_expression(right_expr)?;
55 let assign_result = match left_expr {
56 LeftHandExpression::Name { variable } => {
57 let name = variable.source(self.source);
58 self.context.assign_variable(name, &rhs)
59 }
60 LeftHandExpression::Deref { .. } | LeftHandExpression::Field { .. } => {
61 let place = self.resolve_place_lhs(left_expr)?;
62 self.context.store_place(&place, &rhs)
63 }
64 };
65
66 if let Err(error) = assign_result {
67 return Err(EvalError {
68 message: error,
69 location: expression.location(),
70 });
71 }
72
73 TypedValue::Void
74 }
75 };
76
77 Ok(result)
78 }
79
80 pub fn visit_right_hand_expression(
82 &mut self,
83 expression: &RightHandExpression<T::Parser>,
84 ) -> Result<TypedValue<T>, EvalError> {
85 let result = match expression {
86 RightHandExpression::Variable { variable } => self.visit_variable(variable)?,
87 RightHandExpression::Literal { value } => match &value.value {
88 LiteralValue::Integer(value) => TypedValue::<T>::MaybeSignedInt(*value),
89 LiteralValue::Float(value) => TypedValue::<T>::Float(*value),
90 LiteralValue::String(value) => value.store(self.context.type_context()),
91 LiteralValue::Boolean(value) => TypedValue::<T>::Bool(*value),
92 },
93 RightHandExpression::UnaryOperator { name, operand } => {
94 match name.source(self.source) {
95 "!" => {
96 let operand = self.visit_right_hand_expression(operand)?;
97
98 match TypedValue::<T>::not(self.context.type_context(), operand) {
99 Ok(r) => r,
100 Err(error) => {
101 return Err(EvalError {
102 message: format!("Failed to evaluate expression: {error}")
103 .into_boxed_str(),
104 location: expression.location(),
105 });
106 }
107 }
108 }
109
110 "-" => {
111 let value = self.visit_right_hand_expression(operand)?;
112 let ty = value.type_of();
113 TypedValue::<T>::negate(self.context.type_context(), value).map_err(
114 |e| EvalError {
115 message: format!("Cannot negate {ty}: {e}").into_boxed_str(),
116 location: operand.location(),
117 },
118 )?
119 }
120
121 "&" => {
122 let place = self.resolve_place_rhs(operand)?;
123 let value = self.context.load_place(&place).map_err(|e| EvalError {
124 message: e,
125 location: operand.location(),
126 })?;
127 let pointee =
128 RefPointee::from_type(value.type_of()).ok_or_else(|| EvalError {
129 message: String::from("Cannot take a reference to a reference")
130 .into_boxed_str(),
131 location: operand.location(),
132 })?;
133 TypedValue::Ref(Reference::new(pointee, place))
134 }
135 "*" => {
136 let value = self.visit_right_hand_expression(operand)?;
137 let TypedValue::Ref(reference) = value else {
138 return Err(EvalError {
139 message: format!("Cannot dereference {}", value.type_of())
140 .into_boxed_str(),
141 location: operand.location(),
142 });
143 };
144 self.context
145 .load_place(reference.place())
146 .map_err(|e| EvalError {
147 message: format!("Failed to load variable from address: {e}")
148 .into_boxed_str(),
149 location: operand.location(),
150 })?
151 }
152 _ => {
153 return Err(EvalError {
154 message: format!(
155 "Unknown unary operator: {}",
156 name.source(self.source)
157 )
158 .into_boxed_str(),
159 location: expression.location(),
160 });
161 }
162 }
163 }
164 RightHandExpression::BinaryOperator { name, operands } => {
165 let lhs = self.visit_right_hand_expression(&operands[0])?;
166
167 let short_circuiting = ["&&", "||"];
168 let operator = name.source(self.source);
169
170 if short_circuiting.contains(&operator) {
172 return match operator {
173 "&&" if lhs == TypedValue::<T>::Bool(false) => Ok(TypedValue::Bool(false)),
174 "||" if lhs == TypedValue::<T>::Bool(true) => Ok(TypedValue::Bool(true)),
175 _ => self.visit_right_hand_expression(&operands[1]),
176 };
177 }
178
179 let rhs = self.visit_right_hand_expression(&operands[1])?;
181
182 if matches!(operator, "==" | "!=") {
185 let is_aggregate =
186 |v: &TypedValue<T>| matches!(v, TypedValue::Struct(_) | TypedValue::Ref(_));
187 if is_aggregate(&lhs) || is_aggregate(&rhs) {
188 let equal = lhs == rhs;
189 return Ok(TypedValue::Bool(if operator == "==" {
190 equal
191 } else {
192 !equal
193 }));
194 }
195 }
196
197 let type_context = self.context.type_context();
198 let result = match operator {
199 "+" => TypedValue::<T>::add(type_context, lhs, rhs),
200 "-" => TypedValue::<T>::subtract(type_context, lhs, rhs),
201 "*" => TypedValue::<T>::multiply(type_context, lhs, rhs),
202 "/" => TypedValue::<T>::divide(type_context, lhs, rhs),
203 "%" => TypedValue::<T>::modulo(type_context, lhs, rhs),
204 "<" => TypedValue::<T>::less_than(type_context, lhs, rhs),
205 ">" => TypedValue::<T>::less_than(type_context, rhs, lhs),
206 "<=" => TypedValue::<T>::less_than_or_equal(type_context, lhs, rhs),
207 ">=" => TypedValue::<T>::less_than_or_equal(type_context, rhs, lhs),
208 "==" => TypedValue::<T>::equals(type_context, lhs, rhs),
209 "!=" => TypedValue::<T>::not_equals(type_context, lhs, rhs),
210 "|" => TypedValue::<T>::bitwise_or(type_context, lhs, rhs),
211 "^" => TypedValue::<T>::bitwise_xor(type_context, lhs, rhs),
212 "&" => TypedValue::<T>::bitwise_and(type_context, lhs, rhs),
213 "<<" => TypedValue::<T>::shift_left(type_context, lhs, rhs),
214 ">>" => TypedValue::<T>::shift_right(type_context, lhs, rhs),
215
216 other => {
217 return Err(EvalError {
218 message: format!("Unknown binary operator: {other}").into_boxed_str(),
219 location: expression.location(),
220 });
221 }
222 };
223
224 match result {
225 Ok(r) => r,
226 Err(error) => {
227 return Err(EvalError {
228 message: format!("Failed to evaluate expression: {error}")
229 .into_boxed_str(),
230 location: expression.location(),
231 });
232 }
233 }
234 }
235 RightHandExpression::FunctionCall { name, arguments } => {
236 let function_name = name.source(self.source);
237 let mut args = Vec::with_capacity(arguments.len());
238 for arg in arguments {
239 args.push(self.visit_right_hand_expression(arg)?);
240 }
241
242 match self.context.call_function(function_name, &args) {
243 Ok(result) => result,
244 Err(FunctionCallError::IncorrectArgumentCount { expected }) => {
245 return Err(EvalError {
246 message: format!(
247 "{function_name} takes {expected} arguments, {} given",
248 args.len()
249 )
250 .into_boxed_str(),
251 location: expression.location(),
252 });
253 }
254 Err(FunctionCallError::IncorrectArgumentType { idx, expected }) => {
255 return Err(EvalError {
256 message: format!(
257 "{function_name} expects argument {idx} to be {expected}, got {}",
258 args[idx].type_of()
259 )
260 .into_boxed_str(),
261 location: arguments[idx].location(),
262 });
263 }
264 Err(FunctionCallError::FunctionNotFound) => {
265 return Err(EvalError {
266 message: format!("Function {function_name} is not found")
267 .into_boxed_str(),
268 location: expression.location(),
269 });
270 }
271 Err(FunctionCallError::Other(error)) => {
272 return Err(EvalError {
273 message: format!("Failed to call {function_name}: {error}")
274 .into_boxed_str(),
275 location: expression.location(),
276 });
277 }
278 }
279 }
280 RightHandExpression::FieldAccess { base, field, .. } => {
281 let base_value = self.visit_right_hand_expression(base)?;
284 let base_value = match base_value {
285 TypedValue::Ref(reference) => self
286 .context
287 .load_place(reference.place())
288 .map_err(|e| EvalError {
289 message: e,
290 location: base.location(),
291 })?,
292 other => other,
293 };
294
295 let field_name = field.source(self.source);
296 let TypedValue::Struct(structure) = base_value else {
297 return Err(EvalError {
298 message: format!(
299 "Cannot access field `{field_name}` of {}",
300 base_value.type_of()
301 )
302 .into_boxed_str(),
303 location: base.location(),
304 });
305 };
306
307 match structure.fields().get(field_name) {
308 Some(value) => value.clone(),
309 None => {
310 return Err(EvalError {
311 message: format!(
312 "Struct `{}` has no field `{field_name}`",
313 structure.name()
314 )
315 .into_boxed_str(),
316 location: field.location,
317 });
318 }
319 }
320 }
321 RightHandExpression::StructLiteral { name, fields, .. } => {
322 self.visit_struct_literal(name, fields, expression.location())?
323 }
324 };
325
326 Ok(result)
327 }
328
329 fn visit_struct_literal(
332 &mut self,
333 name: &lexer::Token,
334 fields: &[somni_parser::ast::StructLiteralField<T::Parser>],
335 location: Location,
336 ) -> Result<TypedValue<T>, EvalError> {
337 let struct_name = name.source(self.source);
338 let schema = self
339 .context
340 .struct_fields(struct_name)
341 .ok_or_else(|| EvalError {
342 message: format!("Unknown struct `{struct_name}`").into_boxed_str(),
343 location: name.location,
344 })?;
345
346 let mut provided: IndexMap<Box<str>, (TypedValue<T>, Location)> = IndexMap::new();
348 for field in fields {
349 let field_name = field.name.source(self.source);
350 if !schema.iter().any(|(n, _)| &**n == field_name) {
351 return Err(EvalError {
352 message: format!("Struct `{struct_name}` has no field `{field_name}`")
353 .into_boxed_str(),
354 location: field.name.location,
355 });
356 }
357 let value = self.visit_right_hand_expression(&field.value)?;
358 if provided
359 .insert(Box::from(field_name), (value, field.name.location))
360 .is_some()
361 {
362 return Err(EvalError {
363 message: format!("Duplicate field `{field_name}` in struct `{struct_name}`")
364 .into_boxed_str(),
365 location: field.name.location,
366 });
367 }
368 }
369
370 let mut out = IndexMap::with_capacity(schema.len());
372 for (field_name, field_type) in &schema {
373 let (value, field_location) =
374 provided.swap_remove(field_name).ok_or_else(|| EvalError {
375 message: format!("Missing field `{field_name}` in struct `{struct_name}`")
376 .into_boxed_str(),
377 location,
378 })?;
379 let coerced = self.typecheck_named(value, field_type, false, field_location)?;
380 out.insert(field_name.clone(), coerced);
381 }
382
383 Ok(TypedValue::Struct(SomniStruct::new(
384 Box::from(struct_name),
385 out,
386 )))
387 }
388
389 fn resolve_place_rhs(
393 &mut self,
394 expr: &RightHandExpression<T::Parser>,
395 ) -> Result<Place, EvalError> {
396 match expr {
397 RightHandExpression::Variable { variable } => {
398 let name = variable.source(self.source);
399 self.context
400 .place_of_variable(name)
401 .map_err(|message| EvalError {
402 message,
403 location: variable.location,
404 })
405 }
406 RightHandExpression::UnaryOperator { name, operand }
407 if name.source(self.source) == "*" =>
408 {
409 let value = self.visit_right_hand_expression(operand)?;
410 match value {
411 TypedValue::Ref(reference) => Ok(reference.into_place()),
412 other => Err(EvalError {
413 message: format!("Cannot dereference {}", other.type_of()).into_boxed_str(),
414 location: operand.location(),
415 }),
416 }
417 }
418 RightHandExpression::FieldAccess { base, field, .. } => {
419 let base_place = self.resolve_place_rhs(base)?;
420 let container = self.container_place(base_place, base.location())?;
421 self.append_field(container, field)
422 }
423 other => Err(EvalError {
424 message: String::from("Cannot take the address of this expression")
425 .into_boxed_str(),
426 location: other.location(),
427 }),
428 }
429 }
430
431 fn resolve_place_lhs(&mut self, lhs: &LeftHandExpression) -> Result<Place, EvalError> {
433 match lhs {
434 LeftHandExpression::Name { variable } => {
435 let name = variable.source(self.source);
436 self.context
437 .place_of_variable(name)
438 .map_err(|message| EvalError {
439 message,
440 location: variable.location,
441 })
442 }
443 LeftHandExpression::Deref { name, .. } => {
444 let value = self.visit_variable(name)?;
445 match value {
446 TypedValue::Ref(reference) => Ok(reference.into_place()),
447 other => Err(EvalError {
448 message: format!("Cannot dereference {}", other.type_of()).into_boxed_str(),
449 location: name.location,
450 }),
451 }
452 }
453 LeftHandExpression::Field { base, field, .. } => {
454 let base_place = self.resolve_place_lhs(base)?;
455 let container = self.container_place(base_place, base.location())?;
456 self.append_field(container, field)
457 }
458 }
459 }
460
461 fn container_place(
465 &mut self,
466 base_place: Place,
467 base_location: Location,
468 ) -> Result<Place, EvalError> {
469 let base_value = self
470 .context
471 .load_place(&base_place)
472 .map_err(|message| EvalError {
473 message,
474 location: base_location,
475 })?;
476 Ok(match base_value {
477 TypedValue::Ref(reference) => reference.into_place(),
478 _ => base_place,
479 })
480 }
481
482 fn append_field(&mut self, container: Place, field: &lexer::Token) -> Result<Place, EvalError> {
485 let container_value = self
486 .context
487 .load_place(&container)
488 .map_err(|message| EvalError {
489 message,
490 location: field.location,
491 })?;
492 let field_name = field.source(self.source);
493 let TypedValue::Struct(structure) = &container_value else {
494 return Err(EvalError {
495 message: format!(
496 "Cannot access field `{field_name}` of {}",
497 container_value.type_of()
498 )
499 .into_boxed_str(),
500 location: field.location,
501 });
502 };
503 if !structure.fields().contains_key(field_name) {
504 return Err(EvalError {
505 message: format!("Struct `{}` has no field `{field_name}`", structure.name())
506 .into_boxed_str(),
507 location: field.location,
508 });
509 }
510
511 let mut path = container.path.into_vec();
512 path.push(Box::from(field_name));
513 Ok(Place {
514 root: container.root,
515 path: path.into_boxed_slice(),
516 })
517 }
518
519 fn typecheck_with_hint(
520 &self,
521 value: TypedValue<T>,
522 hint: Option<TypeHint>,
523 ) -> Result<TypedValue<T>, EvalError> {
524 let Some(hint) = hint else {
525 return Ok(value);
527 };
528
529 self.typecheck_named(
530 value,
531 hint.type_name.source(self.source),
532 false,
533 hint.type_name.location,
534 )
535 }
536
537 fn typecheck_named(
540 &self,
541 value: TypedValue<T>,
542 type_name: &str,
543 is_ref: bool,
544 location: Location,
545 ) -> Result<TypedValue<T>, EvalError> {
546 if is_ref {
547 return match &value {
550 TypedValue::Ref(_) => Ok(value),
551 other => Err(EvalError {
552 message: format!("Expected &{type_name}, got {}", other.type_of())
553 .into_boxed_str(),
554 location,
555 }),
556 };
557 }
558
559 match Type::from_name(type_name) {
560 Ok(ty) => self.typecheck(value, ty, location),
561 Err(_) => match &value {
562 TypedValue::Struct(structure) if structure.name() == type_name => Ok(value),
565 TypedValue::Struct(structure) => Err(EvalError {
566 message: format!(
567 "Expected struct `{type_name}`, got struct `{}`",
568 structure.name()
569 )
570 .into_boxed_str(),
571 location,
572 }),
573 other => {
574 if self.context.struct_fields(type_name).is_some() {
575 Err(EvalError {
576 message: format!(
577 "Expected struct `{type_name}`, got {}",
578 other.type_of()
579 )
580 .into_boxed_str(),
581 location,
582 })
583 } else {
584 Err(EvalError {
585 message: format!("Unknown type `{type_name}`").into_boxed_str(),
586 location,
587 })
588 }
589 }
590 },
591 }
592 }
593
594 fn typecheck(
595 &self,
596 value: TypedValue<T>,
597 hint: Type,
598 location: Location,
599 ) -> Result<TypedValue<T>, EvalError> {
600 match (value, hint) {
601 (value, hint) if value.type_of() == hint => Ok(value),
602 (TypedValue::MaybeSignedInt(val), Type::Int) => Ok(TypedValue::Int(val)),
603 (TypedValue::MaybeSignedInt(val), Type::SignedInt) => Ok(TypedValue::<T>::SignedInt(
604 T::to_signed(val).map_err(|_| EvalError {
605 message: format!("Failed to cast {val:?} to signed int").into_boxed_str(),
606 location,
607 })?,
608 )),
609 (value, hint) => Err(EvalError {
610 message: format!("Expected {hint}, got {}", value.type_of()).into_boxed_str(),
611 location,
612 }),
613 }
614 }
615
616 pub fn visit_function(
618 &mut self,
619 function: &Function<T::Parser>,
620 args: &[TypedValue<T>],
621 ) -> Result<TypedValue<T>, EvalError> {
622 for (arg, arg_value) in function.arguments.iter().zip(args.iter()) {
623 let arg_name = arg.name.source(self.source);
624
625 let arg_value = self.typecheck_named(
626 arg_value.clone(),
627 arg.arg_type.type_name.source(self.source),
628 arg.reference_token.is_some(),
629 arg.arg_type.type_name.location,
630 )?;
631
632 self.context.declare(arg_name, arg_value);
633 }
634
635 let retval = match self.visit_body(&function.body)? {
636 StatementResult::Return(typed_value) | StatementResult::ImplicitReturn(typed_value) => {
637 typed_value
638 }
639 StatementResult::EndOfBody => TypedValue::Void,
640 StatementResult::LoopBreak | StatementResult::LoopContinue => todo!(),
641 };
642
643 let retval =
644 self.typecheck_with_hint(retval, function.return_decl.as_ref().map(|d| d.return_type))?;
645
646 Ok(retval)
647 }
648
649 fn visit_body(&mut self, body: &Body<T::Parser>) -> Result<StatementResult<T>, EvalError> {
650 self.context.open_scope();
651
652 let mut body_result = StatementResult::EndOfBody;
653 for statement in body.statements.iter() {
654 if let Some(retval) = self.visit_statement(statement)? {
655 body_result = retval;
656 match body_result {
657 StatementResult::ImplicitReturn(_) => {}
658 _ => break,
659 }
660 } else {
661 body_result = StatementResult::EndOfBody;
663 }
664 }
665
666 self.context.close_scope();
667 Ok(body_result)
668 }
669
670 fn visit_statement(
671 &mut self,
672 statement: &Statement<T::Parser>,
673 ) -> Result<Option<StatementResult<T>>, EvalError> {
674 match statement {
675 Statement::Return(return_with_value) => {
676 return self
677 .visit_right_hand_expression(&return_with_value.expression)
678 .map(|rv| Some(StatementResult::Return(rv)));
679 }
680 Statement::ImplicitReturn(expression) => {
681 return self
682 .visit_right_hand_expression(expression)
683 .map(|rv| Some(StatementResult::ImplicitReturn(rv)));
684 }
685 Statement::EmptyReturn(_) => {
686 return Ok(Some(StatementResult::Return(TypedValue::Void)));
687 }
688 Statement::If(if_statement) => return self.visit_if(if_statement),
689 Statement::Loop(loop_statement) => return self.visit_loop(loop_statement),
690 Statement::For(for_statement) => return self.visit_for(for_statement),
691 Statement::Break(_) => return Ok(Some(StatementResult::LoopBreak)),
692 Statement::Continue(_) => return Ok(Some(StatementResult::LoopContinue)),
693 Statement::Scope(body) => {
694 return self.visit_body(body).map(|r| match r {
695 StatementResult::EndOfBody => None,
696 r => Some(r),
697 });
698 }
699 Statement::VariableDefinition(variable_definition) => {
700 self.visit_declaration(variable_definition)?;
701 }
702 Statement::Expression { expression, .. } => {
703 self.visit_expression(expression)?;
704 }
705 }
706
707 Ok(None)
708 }
709
710 fn visit_declaration(&mut self, decl: &VariableDefinition<T::Parser>) -> Result<(), EvalError> {
711 let name = decl.identifier.source(self.source);
712 let value = self.visit_right_hand_expression(&decl.initializer)?;
713
714 let value = self.typecheck_with_hint(value, decl.type_token)?;
715
716 self.context.declare(name, value);
717
718 Ok(())
719 }
720
721 fn visit_if(
722 &mut self,
723 if_statement: &If<T::Parser>,
724 ) -> Result<Option<StatementResult<T>>, EvalError> {
725 let condition = self.visit_right_hand_expression(&if_statement.condition)?;
726
727 let condition = self.typecheck(condition, Type::Bool, if_statement.condition.location())?;
728
729 let body = if condition == TypedValue::Bool(true) {
730 &if_statement.body
731 } else if let Some(ref else_branch) = if_statement.else_branch {
732 &else_branch.else_body
733 } else {
734 return Ok(None);
736 };
737
738 let retval = match self.visit_body(body)? {
739 StatementResult::EndOfBody => None,
740 other => Some(other),
741 };
742 Ok(retval)
743 }
744
745 fn visit_loop(
746 &mut self,
747 loop_statement: &Loop<T::Parser>,
748 ) -> Result<Option<StatementResult<T>>, EvalError> {
749 loop {
750 match self.visit_body(&loop_statement.body)? {
751 ret @ StatementResult::Return(_) => return Ok(Some(ret)),
752 StatementResult::LoopBreak => return Ok(None),
753 StatementResult::LoopContinue
754 | StatementResult::EndOfBody
755 | StatementResult::ImplicitReturn(_) => {}
756 }
757 }
758 }
759
760 fn visit_for(
761 &mut self,
762 for_statement: &For<T::Parser>,
763 ) -> Result<Option<StatementResult<T>>, EvalError> {
764 let iterable = self.visit_right_hand_expression(&for_statement.iterable)?;
766 let TypedValue::Iter(iter) = iterable else {
767 return Err(EvalError {
768 message: format!("Expected an iterator, got {}", iterable.type_of())
769 .into_boxed_str(),
770 location: for_statement.iterable.location(),
771 });
772 };
773
774 let elem_ty = match for_statement.var_type.as_ref() {
778 Some(var_type) => Some(
779 Type::from_name(var_type.type_name.source(self.source)).map_err(|message| {
780 EvalError {
781 message,
782 location: var_type.type_name.location,
783 }
784 })?,
785 ),
786 None => None,
787 };
788 let var_name = for_statement.variable.source(self.source);
789
790 loop {
791 let Some(value) = self.context.type_context().iter_next(&iter) else {
792 return Ok(None);
793 };
794 let value = match elem_ty {
798 Some(elem_ty) => self.typecheck(value, elem_ty, for_statement.variable.location)?,
799 None => value,
800 };
801
802 self.context.open_scope();
804 self.context.declare(var_name, value);
805
806 let body_result = self.visit_body(&for_statement.body);
807 self.context.close_scope();
808
809 match body_result? {
810 ret @ StatementResult::Return(_) => return Ok(Some(ret)),
811 StatementResult::LoopBreak => return Ok(None),
812 StatementResult::LoopContinue
813 | StatementResult::EndOfBody
814 | StatementResult::ImplicitReturn(_) => {}
815 }
816 }
817 }
818}
819
820enum StatementResult<T: TypeSet> {
821 Return(TypedValue<T>),
822 ImplicitReturn(TypedValue<T>),
823 LoopBreak,
824 LoopContinue,
825 EndOfBody,
826}