use cas_compute::{numerical::value::Value, primitive::int};
use cas_error::Error;
use cas_parser::parser::{ast::{Product, RangeKind}, token::op::BinOpKind};
use crate::{item::Symbol, Compile, Compiler, InstructionKind};
impl Compile for Product {
fn compile(&self, compiler: &mut Compiler) -> Result<(), Error> {
compiler.new_scope(|compiler| {
compiler.add_instr(InstructionKind::LoadConst(Value::Integer(int(1))));
let chunk = compiler.new_chunk_get(|compiler| {
self.range.end.compile(compiler)
})?;
self.range.start.compile(compiler)?;
let symbol_id = compiler.add_symbol(&self.variable)?;
compiler.add_instr(InstructionKind::AssignVar(symbol_id));
let condition_start = compiler.new_end_label();
compiler.add_instr(InstructionKind::LoadVar(Symbol::User(symbol_id)));
compiler.add_chunk_instrs(chunk);
match self.range.kind {
RangeKind::HalfOpen => compiler.add_instr(InstructionKind::Binary(BinOpKind::Less)),
RangeKind::Closed => compiler.add_instr(InstructionKind::Binary(BinOpKind::LessEq)),
}
let loop_end = compiler.new_unassociated_label();
compiler.add_instr(InstructionKind::JumpIfFalse(loop_end));
self.body.compile(compiler)?;
compiler.add_instr(InstructionKind::Binary(BinOpKind::Mul));
compiler.add_instr(InstructionKind::LoadVar(Symbol::User(symbol_id)));
compiler.add_instr(InstructionKind::LoadConst(Value::Integer(int(1))));
compiler.add_instr(InstructionKind::Binary(BinOpKind::Add));
compiler.add_instr(InstructionKind::AssignVar(symbol_id));
compiler.add_instr(InstructionKind::Jump(condition_start));
compiler.set_end_label(loop_end);
Ok(())
})?;
Ok(())
}
}