cas_compiler/expr/
loops.rs1use cas_compute::{numerical::value::Value, primitive::int};
2use cas_error::Error;
3use cas_parser::parser::{
4 ast::{for_expr::For, loop_expr::Loop, while_expr::While, RangeKind},
5 token::op::BinOpKind,
6};
7use crate::{item::Symbol, Compile, Compiler, InstructionKind};
8
9impl Compile for Loop {
10 fn compile(&self, compiler: &mut Compiler) -> Result<(), Error> {
11 let loop_start = compiler.new_end_label();
12 let loop_end = compiler.new_unassociated_label();
13
14 compiler.with_state(|state| {
15 state.loop_start = Some(loop_start);
18 state.loop_end = Some(loop_end);
19 }, |compiler| {
20 compiler.new_scope(|compiler| self.body.compile(compiler))?;
21 compiler.add_instr(InstructionKind::Drop);
22 Ok(())
23 })?;
24
25 compiler.add_instr(InstructionKind::Jump(loop_start));
26
27 compiler.set_end_label(loop_end);
31 Ok(())
32 }
33}
34
35impl Compile for While {
36 fn compile(&self, compiler: &mut Compiler) -> Result<(), Error> {
37 let condition_start = compiler.new_end_label();
38 self.condition.compile(compiler)?;
39
40 let end_with_no_break = compiler.new_unassociated_label();
41 let loop_end = compiler.new_unassociated_label();
42 compiler.add_instr_with_spans(
43 InstructionKind::JumpIfFalse(end_with_no_break),
44 vec![self.condition.span(), self.body.span()],
46 );
47 compiler.with_state(|state| {
48 state.loop_start = Some(condition_start);
51 state.loop_end = Some(loop_end);
52 }, |compiler| {
53 compiler.new_scope(|compiler| self.body.compile(compiler))?;
54 compiler.add_instr(InstructionKind::Drop);
55 Ok(())
56 })?;
57
58 compiler.add_instr(InstructionKind::Jump(condition_start));
59
60 compiler.set_end_label(end_with_no_break);
65 compiler.add_instr(InstructionKind::LoadConst(Value::Unit));
66
67 compiler.set_end_label(loop_end);
68 Ok(())
69 }
70}
71
72impl Compile for For {
73 fn compile(&self, compiler: &mut Compiler) -> Result<(), Error> {
74 compiler.new_scope(|compiler| {
93 let chunk = compiler.new_chunk_get(|compiler| {
96 self.range.end.compile(compiler)
97 })?;
98
99 self.range.start.compile(compiler)?;
101 let symbol_id = compiler.add_symbol(&self.variable)?;
102 compiler.add_instr(InstructionKind::AssignVar(symbol_id));
103
104 let condition_start = compiler.new_end_label();
107 compiler.add_instr(InstructionKind::LoadVar(Symbol::User(symbol_id)));
108 compiler.add_chunk_instrs(chunk);
109 match self.range.kind {
110 RangeKind::HalfOpen => compiler.add_instr(InstructionKind::Binary(BinOpKind::Less)),
111 RangeKind::Closed => compiler.add_instr(InstructionKind::Binary(BinOpKind::LessEq)),
112 }
113
114 let end_with_no_break = compiler.new_unassociated_label();
115 let loop_end = compiler.new_unassociated_label();
116 compiler.add_instr(InstructionKind::JumpIfFalse(end_with_no_break));
117
118 let index_start = compiler.new_unassociated_label();
120 compiler.with_state(|state| {
121 state.loop_start = Some(index_start);
124 state.loop_end = Some(loop_end);
125 }, |compiler| {
126 self.body.compile(compiler)?;
127 compiler.add_instr(InstructionKind::Drop);
128 Ok(())
129 })?;
130
131 compiler.set_end_label(index_start);
133 compiler.add_instr(InstructionKind::LoadVar(Symbol::User(symbol_id)));
134 compiler.add_instr(InstructionKind::LoadConst(Value::Integer(int(1))));
135 compiler.add_instr(InstructionKind::Binary(BinOpKind::Add));
136 compiler.add_instr(InstructionKind::AssignVar(symbol_id));
137
138 compiler.add_instr(InstructionKind::Jump(condition_start));
140
141 compiler.set_end_label(end_with_no_break);
147 compiler.add_instr(InstructionKind::LoadConst(Value::Unit));
148
149 compiler.set_end_label(loop_end);
150 Ok(())
151 })?;
152 Ok(())
153 }
154}