use crate::{
diagnostics::LoweringError,
lowering::{
ast_lowering::declaration::{lower_inner_struct, lower_sym_decl},
ir::{
basic_block::{BlockId, Terminator},
function::FunctionBuilder,
},
},
parser::{
Span,
ast::{
declaration::DeclStmt,
statement::{BlockStmt, Stmt, StmtKind},
},
},
};
use super::control_flow::{lower_for, lower_if, lower_while};
use super::declaration::{lower_inner_function, lower_var_declaration};
use super::expression::lower_expr;
pub fn lower_stmt(func: &mut FunctionBuilder, stmt: &Stmt) -> Result<(), LoweringError> {
match &stmt.kind {
StmtKind::Decl(decl) => lower_declaration(func, decl, &stmt.span)?,
StmtKind::Return(expr) => {
let (value, value_ty_idx) = lower_expr(func, expr, Some(func.return_ty))?;
if value_ty_idx != func.return_ty {
return Err(LoweringError::MismatchedReturnType {
expected: func.get_type(func.return_ty, stmt.span)?,
found: func.get_type(value_ty_idx, stmt.span)?,
span: stmt.span,
});
}
func.get_basic_block_mut(func.last_block_idx()).terminator =
Terminator::Return(Some(value), Some(stmt.span));
}
StmtKind::Block(block_stmt) => {
let curr_block_idx = func.last_block_idx();
func.get_basic_block_mut(curr_block_idx).terminator = Terminator::Branch {
target: curr_block_idx + 1,
span: None,
};
let _ = lower_block(
func,
block_stmt,
Terminator::Branch {
target: curr_block_idx + 2,
span: None,
},
)?;
}
StmtKind::Expr(expr) => {
let _ = lower_expr(func, expr, None)?;
}
StmtKind::If(if_stmt) => lower_if(func, if_stmt)?,
StmtKind::While(while_stmt) => lower_while(func, while_stmt, stmt.span)?,
StmtKind::For(for_stmt) => lower_for(func, for_stmt, stmt.span)?,
}
Ok(())
}
fn lower_declaration(
func: &mut FunctionBuilder,
stmt: &DeclStmt,
span: &Span,
) -> Result<(), LoweringError> {
match stmt {
DeclStmt::Var(var_decl) => {
lower_var_declaration(func, var_decl, *span)?;
}
DeclStmt::Struct(struct_decl) => {
let _ = lower_inner_struct(func, struct_decl)?;
}
DeclStmt::Sym(sym_decl) => lower_sym_decl(func, sym_decl, *span)?,
DeclStmt::Func(func_decl) => lower_inner_function(func, func_decl, *span)?,
}
Ok(())
}
pub fn lower_block(
func: &mut FunctionBuilder,
block: &BlockStmt,
terminator: Terminator,
) -> Result<BlockId, LoweringError> {
let old_sym_table = func.sym_table.clone();
let block_id = func.add_block(terminator, Some(block.span));
for s in block.stmts.iter() {
lower_stmt(func, s)?;
}
func.sym_table = old_sym_table;
Ok(block_id)
}