use crate::code_bld::CodeBuilder;
use crate::ctx::Context;
use crate::transformer::{Collection, Transformer};
use source_map_node::Node;
use swamp_semantic::{BooleanExpression, Expression, ForPattern, Iterable};
use swamp_types::TypeKind;
use swamp_types::TypeRef;
use swamp_vm_types::types::{Place, TypedRegister};
impl CodeBuilder<'_> {
pub fn emit_statement(&mut self, expr: &Expression, ctx: &Context) {
debug_assert!(matches!(&*expr.ty.kind, TypeKind::Unit | TypeKind::Never));
let output_destination = Place::new_unit();
self.emit_expression(&output_destination, expr, ctx);
}
pub(crate) fn emit_for_loop(
&mut self,
destination: &Place,
node: &Node,
for_pattern: &ForPattern,
iterable: &Iterable,
lambda_non_capturing_expr: &Expression,
ctx: &Context,
) {
let collection_type = &iterable.resolved_expression.ty;
let hwm = self.temp_registers.save_mark();
let variables_are_mutable = match for_pattern {
ForPattern::Single(var) => var.is_mutable(),
ForPattern::Pair(var1, var2) => var1.is_mutable() || var2.is_mutable(),
};
let allow_temporary = !variables_are_mutable;
let collection_ptr_reg = self.emit_scalar_rvalue_or_pointer_to_temporary(
&iterable.resolved_expression,
ctx,
allow_temporary,
);
let underlying_collection = collection_type;
match &*underlying_collection.kind {
TypeKind::StackStorage(_element_type, _)
| TypeKind::StackView(_element_type)
| TypeKind::QueueStorage(_element_type, _)
| TypeKind::QueueView(_element_type)
| TypeKind::DynamicLengthVecView(_element_type)
| TypeKind::VecStorage(_element_type, ..)
| TypeKind::FixedCapacityAndLengthArray(_element_type, _)
| TypeKind::SliceView(_element_type) => {
self.emit_for_loop_lambda(
destination,
node,
Collection::Vec,
&collection_ptr_reg,
collection_type,
for_pattern,
lambda_non_capturing_expr,
ctx,
);
}
TypeKind::SparseStorage(element_type, _) | TypeKind::SparseView(element_type) => {
self.emit_for_loop_lambda(
destination,
node,
Collection::Sparse,
&collection_ptr_reg,
collection_type,
for_pattern,
lambda_non_capturing_expr,
ctx,
);
}
TypeKind::DynamicLengthMapView(_key, _value)
| TypeKind::MapStorage(_key, _value, ..) => {
self.emit_for_loop_lambda(
destination,
node,
Collection::Map,
&collection_ptr_reg,
collection_type,
for_pattern,
lambda_non_capturing_expr,
ctx,
);
}
TypeKind::StringView(..) | TypeKind::StringStorage(..) => {
self.emit_for_loop_lambda(
destination,
node,
Collection::String,
&collection_ptr_reg,
collection_type,
for_pattern,
lambda_non_capturing_expr,
ctx,
);
}
_ => {
panic!("can not iterate this collection {underlying_collection}");
}
}
self.temp_registers.restore_to_mark(hwm);
}
fn emit_for_loop_lambda(
&mut self,
target_reg: &Place,
node: &Node,
collection: Collection,
source_collection: &TypedRegister,
source_collection_type: &TypeRef,
for_pattern: &ForPattern,
lambda_expr: &Expression,
ctx: &Context,
) {
let variables = match for_pattern {
ForPattern::Single(a) => vec![a.clone()],
ForPattern::Pair(a, b) => vec![a.clone(), b.clone()],
};
self.emit_iterate_over_collection_with_lambda(
target_reg,
node,
collection,
Transformer::For,
source_collection,
(variables, lambda_expr),
ctx,
);
}
pub(crate) fn emit_while_loop(
&mut self,
condition: &BooleanExpression,
expression: &Expression,
ctx: &Context,
) {
let ip_for_condition = self.builder.position();
let jump_on_false_condition = self.emit_condition_context(condition, ctx);
self.emit_statement(expression, ctx);
self.builder
.add_jmp(ip_for_condition, &expression.node, "jmp to while condition");
self.builder.patch_jump_here(jump_on_false_condition);
}
}