magc 0.8.0

The Mag Language Compiler
Documentation
use super::Compilelet;
use crate::compiler::Compiler;
use crate::types::{CompilerResult, Expression, ExpressionKind};
use strontium::machine::instruction::Instruction;
use strontium::machine::register::RegisterValue;

pub struct ConditionalCompilelet;

impl Compilelet for ConditionalCompilelet {
    fn compile(
        &self,
        compiler: &mut Compiler,
        expression: Expression,
        target_register: Option<String>,
    ) -> CompilerResult<Vec<Instruction>> {
        let ExpressionKind::Conditional(cond) = expression.kind else {
            return Ok(vec![]);
        };

        let mut instructions = vec![];

        let cond_reg = compiler.registers.allocate_register();
        instructions.extend(compiler.compile_expression(*cond.condition, Some(cond_reg.clone()))?);

        let else_label = compiler.alloc_label();
        let end_label = compiler.alloc_label();

        instructions.push(Instruction::JumpCToLabel {
            id: else_label,
            conditional_address: cond_reg,
        });

        let dest = target_register.unwrap_or_else(|| compiler.registers.allocate_register());
        instructions.extend(compiler.compile_expression(*cond.then_arm, Some(dest.clone()))?);

        instructions.push(Instruction::JumpToLabel { id: end_label });

        instructions.push(Instruction::LabelTarget { id: else_label });
        match cond.else_arm {
            Some(else_expr) => {
                instructions.extend(compiler.compile_expression(*else_expr, Some(dest.clone()))?);
            }
            None => {
                instructions.push(Instruction::Load {
                    value: RegisterValue::Empty,
                    register: dest.clone(),
                });
            }
        }
        instructions.push(Instruction::LabelTarget { id: end_label });

        Ok(instructions)
    }
}