Skip to content

Commit 84adfac

Browse files
author
DigitalCodeCrafter
committed
added if expression
- kos codegen not yet updated
1 parent a6a2601 commit 84adfac

18 files changed

Lines changed: 257 additions & 45 deletions

src/ast_interpreter.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,15 @@ fn eval_expr<'a>(expr: &Expr<'a>, env: &Env<'a>) -> Result<Value, EvalError> {
115115
tail_expr.as_ref().map(|expr| eval_expr(expr, &inner_env)).unwrap_or(Ok(Value::Unit))
116116
}
117117

118+
ExprKind::If { cond, then_branch, else_brach } => {
119+
let result = eval_expr(cond, env)?;
120+
match result {
121+
Value::Bool(true) => eval_expr(then_branch, env),
122+
Value::Bool(false) => else_brach.as_ref().map(|b| eval_expr(b, env)).unwrap_or(Ok(Value::Unit)),
123+
_ => return Err(EvalError::InvalidType(result, Value::Bool(false), expr.span))
124+
}
125+
}
126+
118127
ExprKind::Error(_) => Err(EvalError::InvalidExpression(expr.span)),
119128
}
120129
}

src/backend/kerboscript.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ impl KosEmitter {
9595
self.emit_indent();
9696
match term {
9797
Terminator::Goto(_) => todo!("Some good way to handle this too."),
98+
99+
Terminator::Branch(_, _, _) => todo!("Some good way to handle this... "),
100+
98101
Terminator::Return(op) => {
99102
self.emit("return ");
100103
self.emit_operand(op);

src/grammar.ebnf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ nud = Number
2222
| "-", Expression
2323
| "(", Expression, ")"
2424
| "{", { Statement }, "}"
25+
| "if", Expression, Block, [ "else", Block ]
2526
;
2627
2728
led = "==", Expression

src/mir/lowerer.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,42 @@ impl MirBuilder<'_> {
120120
}
121121
}
122122

123+
t::ExprKind::If { cond, then_branch, else_branch: Some(else_branch) } => {
124+
let cond_place = Place { local: self.new_local(expr.ty.clone()), projection: Vec::new() };
125+
self.lower_expr(cond_place.clone(), *cond);
126+
let then_block = self.new_block();
127+
let else_block = self.new_block();
128+
let join_block = self.new_block();
129+
self.set_terminator(Terminator::Branch(Operand::Move(cond_place), then_block, else_block));
130+
131+
self.switch_block(then_block);
132+
self.lower_expr(dest.clone(), *then_branch);
133+
self.set_terminator(Terminator::Goto(join_block));
134+
135+
self.switch_block(else_block);
136+
self.lower_expr(dest, *else_branch);
137+
self.set_terminator(Terminator::Goto(join_block));
138+
139+
self.switch_block(join_block);
140+
return;
141+
}
142+
143+
t::ExprKind::If { cond, then_branch, else_branch: None } => {
144+
let cond_place = Place { local: self.new_local(expr.ty.clone()), projection: Vec::new() };
145+
self.lower_expr(cond_place.clone(), *cond);
146+
let then_block = self.new_block();
147+
let join_block = self.new_block();
148+
self.set_terminator(Terminator::Branch(Operand::Move(cond_place), then_block, join_block));
149+
150+
self.switch_block(then_block);
151+
let fresh = Place { local: self.new_local(then_branch.ty.clone()), projection: Vec::new() };
152+
self.lower_expr(fresh, *then_branch);
153+
self.set_terminator(Terminator::Goto(join_block));
154+
155+
self.switch_block(join_block);
156+
RValue::Use(Operand::Const(Const::Unit))
157+
}
158+
123159
t::ExprKind::Error(_) => RValue::Poison,
124160
};
125161

@@ -138,6 +174,22 @@ impl MirBuilder<'_> {
138174
let block = &mut self.blocks[self.current_block.0 as usize];
139175
block.instrs.push(instr);
140176
}
177+
178+
fn set_terminator(&mut self, terminator: Terminator) {
179+
let block = &mut self.blocks[self.current_block.0 as usize];
180+
block.terminator = terminator;
181+
}
182+
183+
fn switch_block(&mut self, block: BlockId) {
184+
assert!((block.0 as usize) < self.blocks.len(), "[Lowerer] Internal error: switched to non-existing block");
185+
self.current_block = block;
186+
}
187+
188+
fn new_block(&mut self) -> BlockId {
189+
let id = BlockId(self.blocks.len() as u32);
190+
self.blocks.push(Block { instrs: vec![], terminator: Terminator::Unreachable });
191+
id
192+
}
141193
}
142194

143195

src/mir/mir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub struct Block {
2121
#[derive(Debug, PartialEq)]
2222
pub enum Terminator {
2323
Goto(BlockId),
24+
Branch(Operand, BlockId, BlockId),
2425
Return(Operand),
2526
Unreachable,
2627
}

src/mir/passes/const_prop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ fn prop_in_terminator(const_map: &HashMap<LocalId, Const>, term: &mut Terminator
6767
match term {
6868
Terminator::Goto(_) => {},
6969
Terminator::Return(op) => prop_in_operand(const_map, op),
70+
Terminator::Branch(op, _, _) => prop_in_operand(const_map, op),
7071
Terminator::Unreachable => {},
7172
}
7273
}

src/mir/passes/copy_prop.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ fn prop_in_terminator(copy_map: &HashMap<LocalId, LocalId>, term: &mut Terminato
6666
match term {
6767
Terminator::Goto(_) => {},
6868
Terminator::Return(op) => prop_in_operand(copy_map, op),
69+
Terminator::Branch(op, _, _) => prop_in_operand(copy_map, op),
6970
Terminator::Unreachable => {},
7071
}
7172
}

src/mir/passes/dead_local_elim.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::collections::HashSet;
2-
use crate::mir::{Block, DebugKind, Instr, LocalId, Operand, Place, RValue, passes::Pass};
2+
use crate::mir::{Block, DebugKind, Instr, LocalId, Operand, Place, RValue, Terminator, passes::Pass};
33

44

55
pub struct DeadLocalElim;
@@ -44,6 +44,7 @@ fn find_live_in_block(used: &mut HashSet<LocalId>, block: &Block) {
4444
}
4545
}
4646
}
47+
find_live_in_term(used, &block.terminator);
4748
}
4849

4950
fn find_live_in_rval(used: &mut HashSet<LocalId>, rval: &RValue) {
@@ -58,6 +59,15 @@ fn find_live_in_rval(used: &mut HashSet<LocalId>, rval: &RValue) {
5859
}
5960
}
6061

62+
fn find_live_in_term(used: &mut HashSet<LocalId>, term: &Terminator) {
63+
match term {
64+
Terminator::Goto(_) => {},
65+
Terminator::Return(op) => find_live_in_op(used, op),
66+
Terminator::Branch(op, _, _) => find_live_in_op(used, op),
67+
Terminator::Unreachable => {},
68+
}
69+
}
70+
6171
fn find_live_in_op(used: &mut HashSet<LocalId>, op: &Operand) {
6272
match op {
6373
Operand::Copy(place) |
@@ -85,6 +95,7 @@ fn remap_in_block(remap: &[Option<LocalId>], block: &mut Block) {
8595
}
8696
}
8797
});
98+
remap_in_term(remap, &mut block.terminator);
8899
}
89100

90101
fn remap_in_rval(remap: &[Option<LocalId>], rval: &mut RValue) {
@@ -99,6 +110,15 @@ fn remap_in_rval(remap: &[Option<LocalId>], rval: &mut RValue) {
99110
}
100111
}
101112

113+
fn remap_in_term(remap: &[Option<LocalId>], term: &mut Terminator) {
114+
match term {
115+
Terminator::Goto(_) => {},
116+
Terminator::Return(op) => remap_in_op(remap, op),
117+
Terminator::Branch(op, _, _) => remap_in_op(remap, op),
118+
Terminator::Unreachable => {},
119+
}
120+
}
121+
102122
fn remap_in_op(remap: &[Option<LocalId>], op: &mut Operand) {
103123
match op {
104124
Operand::Copy(place) |

src/mir/pretty.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub fn format_instr(i: &Instr) -> String {
7676
pub fn format_terminator(t: &Terminator) -> String {
7777
match t {
7878
Terminator::Goto(b) => format!("goto block{}", b.index()),
79+
Terminator::Branch(op, then_block, else_block) => format!("branch {} [then -> block{}, else -> block{}]", format_operand(op), then_block.index(), else_block.index()),
7980
Terminator::Return(op) => format!("return {}", format_operand(op)),
8081
Terminator::Unreachable => "unreachable".to_string(),
8182
}

src/mir/verifier.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ impl IRVerifier<'_> {
8686
match term {
8787
Terminator::Goto(id) => self.verify_block_id(*id),
8888
Terminator::Return(op) => self.verify_operand(op),
89+
Terminator::Branch(op, then_block, else_block) => {
90+
self.verify_operand(op);
91+
self.verify_block_id(*then_block);
92+
self.verify_block_id(*else_block);
93+
}
8994
Terminator::Unreachable => {}
9095
}
9196
}

0 commit comments

Comments
 (0)