use crate::asm_generation::{
compiler_constants::*, convert_expression_to_asm, AsmNamespace, RegisterSequencer,
};
use crate::asm_lang::{
ConstantRegister, Op, VirtualImmediate12, VirtualImmediate18, VirtualImmediate24, VirtualOp,
VirtualRegister,
};
use crate::{
error::*,
semantic_analysis::{ast_node::TypedEnumDeclaration, TypedExpression},
type_engine::resolve_type,
CompileResult, Ident, Literal,
};
pub(crate) fn convert_enum_instantiation_to_asm<'sc>(
decl: &TypedEnumDeclaration<'sc>,
variant_name: &Ident<'sc>,
tag: usize,
contents: &Option<Box<TypedExpression<'sc>>>,
return_register: &VirtualRegister,
namespace: &mut AsmNamespace<'sc>,
register_sequencer: &mut RegisterSequencer,
) -> CompileResult<'sc, Vec<Op<'sc>>> {
let mut warnings = vec![];
let mut errors = vec![];
let mut asm_buf = vec![];
let data_label = namespace.insert_data_value(&Literal::U64(tag as u64));
let tag_register = register_sequencer.next();
asm_buf.push(Op::unowned_load_data_comment(
tag_register.clone(),
data_label,
format!("{} enum instantiation", decl.name.primary_name),
));
let pointer_register = register_sequencer.next();
asm_buf.push(Op::unowned_register_move_comment(
pointer_register.clone(),
VirtualRegister::Constant(ConstantRegister::StackPointer),
"load $sp for enum pointer",
));
let ty = match resolve_type(decl.as_type(), &decl.span) {
Ok(o) => o,
Err(e) => {
errors.push(e.into());
return err(warnings, errors);
}
};
let size_of_enum: u64 = 1 + match ty.size_in_words(&variant_name.span) {
Ok(o) => o,
Err(e) => {
errors.push(e);
return err(warnings, errors);
}
};
if size_of_enum > EIGHTEEN_BITS {
errors.push(CompileError::Unimplemented(
"Stack variables which exceed 2^18 words in size are not supported yet.",
decl.clone().span,
));
return err(warnings, errors);
}
asm_buf.push(Op::unowned_stack_allocate_memory(
VirtualImmediate24::new_unchecked(
size_of_enum * 8,
"this size is manually checked to be lower than 2^24",
),
));
asm_buf.push(Op::new(
VirtualOp::MCLI(
pointer_register.clone(),
VirtualImmediate18::new_unchecked(
size_of_enum,
"the enum was manually checked to be under 2^18 words in size",
),
),
decl.clone().span,
));
asm_buf.push(Op::write_register_to_memory(
pointer_register.clone(),
tag_register,
VirtualImmediate12::new_unchecked(0, "constant num; infallible"),
decl.clone().span,
));
if let Some(instantiation) = contents {
let return_register = register_sequencer.next();
let mut asm = check!(
convert_expression_to_asm(
&*instantiation,
namespace,
&return_register,
register_sequencer
),
return err(warnings, errors),
warnings,
errors
);
asm_buf.append(&mut asm);
asm_buf.push(Op::write_register_to_memory_comment(
pointer_register.clone(),
return_register,
VirtualImmediate12::new_unchecked(1, "this is the constant 1; infallible"), instantiation.span.clone(),
format!("{} enum contents", decl.name.primary_name),
));
}
asm_buf.push(Op::register_move(
return_register.clone(),
pointer_register,
decl.clone().span,
));
ok(asm_buf, warnings, errors)
}