refactor(sema): Separated from ir

This commit is contained in:
2026-05-31 20:59:18 +08:00
parent 1eca4a225b
commit c42575c1c6
10 changed files with 829 additions and 260 deletions
+78 -246
View File
@@ -1,13 +1,11 @@
use std::{collections::{BTreeMap, BTreeSet}, vec};
use std::{collections::BTreeMap, vec};
use crate::{ast::types::{BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, ReturnStmt, Statement, VarDeclStmt, WhileStmt}, diagnostic::Diagnositics, ir::{err::IRError, types::{BinaryOp, CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}}};
use crate::{ir::types::{BinaryOp, CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}, sema::{analyzer::Analyzer as SemaAnalyzer, hir::{HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirWhileStmt}, symbol::{FunctionId, SymbolId}}};
use crate::ast::types::BinaryOp as AstBinaryOp;
use crate::ast::types::UnaryOp as AstUnaryOp;
pub struct Generator {
pub struct Generator<'a> {
sema: &'a SemaAnalyzer,
var_manager: VariableManager,
function_map: BTreeMap<String, Function>,
current_func_return_type: Option<IRType>,
diagnostic: Diagnositics,
current_exit_label: Vec<Option<(usize, usize)>>, // true exit, false exit
// About exit label passing:
// for non-logical parent expr, current_exit_label is None
@@ -19,24 +17,11 @@ pub struct Generator {
label_counter: usize
}
impl Generator {
pub fn new() -> Self {
let mut function_map = BTreeMap::new();
function_map.insert("putint".to_string(), Function {
name: "putint".to_string(),
parameter_types: vec![IRType::I32],
return_type: IRType::Void,
});
function_map.insert("getint".to_string(), Function {
name: "getint".to_string(),
parameter_types: vec![],
return_type: IRType::I32,
});
impl<'a> Generator<'a> {
pub fn new(sema: &'a SemaAnalyzer) -> Self {
Self {
sema,
var_manager: VariableManager::new(),
current_func_return_type: None,
diagnostic: Diagnositics::new(),
function_map,
current_exit_label: vec![],
while_exit_label: vec![],
func_exit: None,
@@ -48,15 +33,22 @@ impl Generator {
self.label_counter += 1;
label
}
pub fn emit(&mut self, compile_unit: CompileUnit) -> Vec<IRInstr> {
pub fn emit(&mut self, compile_unit: HirCompileUnit) -> Vec<IRInstr> {
self.generate_compile_unit(compile_unit)
}
pub fn get_diagnostics(&self) -> &Diagnositics {
&self.diagnostic
fn ir_function(&self, function_id: FunctionId) -> Function {
let sig = self.sema.get_function_sig(function_id);
Function {
name: sig.name.clone(),
parameter_types: sig.parameter_types.iter().map(|ty| (*ty).into()).collect(),
return_type: sig.return_type.into(),
}
}
fn generate_compile_unit(&mut self, compile_unit: CompileUnit) -> Vec<IRInstr> {
fn generate_compile_unit(&mut self, compile_unit: HirCompileUnit) -> Vec<IRInstr> {
let mut instrs = vec![];
use GlobalDeclStmt::*;
use HirGlobalDeclStmt::*;
for decl in compile_unit.global_decls {
match decl {
VarDecl(var_decl) => {
@@ -70,48 +62,29 @@ impl Generator {
instrs
}
fn generate_var_decl(&mut self, var_decl: VarDeclStmt, is_global: bool) -> Vec<IRInstr> {
fn generate_var_decl(&mut self, var_decl: HirVarDeclStmt, is_global: bool) -> Vec<IRInstr> {
let mut instrs = vec![];
let var_type = if is_global { VariableType::Global } else { VariableType::Local };
for value in var_decl.values {
match self.var_manager.declare_variable(&value.name, var_type, var_decl.data_type.into()) {
Ok(var) => {
if is_global { instrs.push(IRInstr::Declare(var)); }
}
Err(e) => {
self.diagnostic.add_from_ir_error(e, value.name_span);
}
let var = self.var_manager.declare_symbol(value.symbol, var_type, var_decl.data_type.into());
if is_global {
instrs.push(IRInstr::Declare(var));
}
}
instrs
}
fn generate_func_decl(&mut self, func_decl: FuncDeclStmt) -> Vec<IRInstr> {
if self.function_map.contains_key(&func_decl.name) {
self.diagnostic.add_from_ir_error(IRError::FunctionHasBeenDefined(func_decl.name.clone()), func_decl.name_span);
return vec![];
}
self.current_func_return_type = Some(func_decl.return_type.into());
self.var_manager.enter_scope();
let parameters: Vec<Variable> = match func_decl.params.iter().map(|param| {
match self.var_manager.declare_variable(&param.name, VariableType::Local, param.param_type.into()) {
Ok(var) => Ok(var),
Err(e) => {
self.diagnostic.add_from_ir_error(e, param.name_span);
Err(())
}
}
}).collect() {
Ok(p) => p,
Err(()) => return vec![],
};
fn generate_func_decl(&mut self, func_decl: HirFuncDeclStmt) -> Vec<IRInstr> {
let parameters: Vec<Variable> = func_decl.params.iter()
.map(|param| self.var_manager.declare_symbol(param.symbol, VariableType::Local, param.param_type.into()))
.collect();
let temp_parameters = parameters.iter().enumerate()
.map(|(i, param)| self.var_manager.declare_param_temp(param.data_type, i))
.collect::<Vec<_>>();
let mut body_instrs = vec![];
self.func_exit = Some((self.request_label(), {
let ret_type = func_decl.return_type.into();
let ret_type = func_decl.sig.return_type.into();
if ret_type != IRType::Void {
Some(self.var_manager.declare_unamed_local(ret_type))
} else {
@@ -133,18 +106,12 @@ impl Generator {
let func_exit = self.func_exit.take().unwrap();
body_instrs.push(IRInstr::Label(func_exit.0));
body_instrs.push(IRInstr::Exit(func_exit.1));
self.var_manager.exit_scope();
self.current_func_return_type = None;
self.var_manager.clear_local_counter();
let func = Function {
name: func_decl.name,
parameter_types: temp_parameters.iter().map(|v| v.data_type).collect(),
return_type: func_decl.return_type.into(),
};
self.function_map.insert(func.name.clone(), func.clone());
let mut func = self.ir_function(func_decl.sig.id);
func.parameter_types = temp_parameters.iter().map(|v| v.data_type).collect();
vec![IRInstr::DefineFunc(func, temp_parameters, body_instrs)]
}
fn generate_block_stmt(&mut self, block_stmt: BlockStmt) -> Vec<IRInstr> {
fn generate_block_stmt(&mut self, block_stmt: HirBlockStmt) -> Vec<IRInstr> {
let mut instrs = vec![];
for stmt in block_stmt.statements {
instrs.extend(self.generate_statement(stmt));
@@ -152,8 +119,8 @@ impl Generator {
instrs
}
fn generate_statement(&mut self, stmt: Statement) -> Vec<IRInstr> {
use Statement::*;
fn generate_statement(&mut self, stmt: HirStatement) -> Vec<IRInstr> {
use HirStatement::*;
let instrs = match stmt {
Return(return_stmt) => self.generate_return_stmt(return_stmt),
If(if_stmt) => self.generate_if_stmt(if_stmt),
@@ -161,10 +128,7 @@ impl Generator {
Break(break_stmt) => self.generate_break_stmt(break_stmt),
Continue(continue_stmt) => self.generate_continue_stmt(continue_stmt),
Block(block_stmt) => {
self.var_manager.enter_scope();
let block_instrs = self.generate_block_stmt(block_stmt);
self.var_manager.exit_scope();
block_instrs
self.generate_block_stmt(block_stmt)
},
Expr(expr) => {
self.current_exit_label.push(None);
@@ -183,16 +147,11 @@ impl Generator {
instrs
}
fn generate_return_stmt(&mut self, return_stmt: ReturnStmt) -> Vec<IRInstr> {
fn generate_return_stmt(&mut self, return_stmt: HirReturnStmt) -> Vec<IRInstr> {
let mut instrs = vec![];
let func_exit = self.func_exit.unwrap();
match return_stmt.value {
Some(expr) => {
if func_exit.1.is_none() {
// shouldn't return value but return stmt has expr;
self.diagnostic.add_from_ir_error(IRError::ReturnExpressionOnVoidFunction, return_stmt.span);
return vec![];
}
self.current_exit_label.push(None);
let (value_instrs, value_var) = match self.generate_expr(expr) {
Some(res) => res,
@@ -202,37 +161,21 @@ impl Generator {
}
};
self.current_exit_label.pop();
if value_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), return_stmt.span);
self.current_exit_label.pop();
return vec![];
}
instrs.extend(value_instrs);
instrs.push(IRInstr::Move(func_exit.1.unwrap(), MoveRValue::Var(value_var.unwrap())));
// if value_var.is_none() {
// self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), return_stmt.span);
// return vec![];
// }
// let value_var = value_var.unwrap();
}
None => {
if func_exit.1.is_some() {
// should return value but return stmt has no expr;
self.diagnostic.add_from_ir_error(IRError::TypeMismatch(self.current_func_return_type.unwrap(), IRType::Void), return_stmt.span);
}
},
None => {},
}
instrs.push(IRInstr::Goto(func_exit.0));
instrs
}
fn generate_while_stmt(&mut self, while_stmt: WhileStmt) -> Vec<IRInstr> {
fn generate_while_stmt(&mut self, while_stmt: HirWhileStmt) -> Vec<IRInstr> {
let mut instrs = vec![];
let cond_label = self.request_label();
let body_label = self.request_label();
let exit_label = self.request_label();
instrs.push(IRInstr::Label(cond_label));
self.current_exit_label.push(Some((body_label, exit_label)));
let while_cond_span = while_stmt.condition.span;
let (cond_instrs, cond_var) = match self.generate_expr(while_stmt.condition) {
Some(res) => res,
None => {
@@ -241,10 +184,6 @@ impl Generator {
}
};
self.current_exit_label.pop();
if cond_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), while_cond_span);
return vec![];
}
instrs.extend(cond_instrs);
instrs.push(IRInstr::Label(body_label));
self.while_exit_label.push((cond_label, exit_label));
@@ -254,7 +193,7 @@ impl Generator {
instrs.push(IRInstr::Label(exit_label));
instrs
}
fn generate_if_stmt(&mut self, if_stmt: IfStmt) -> Vec<IRInstr> {
fn generate_if_stmt(&mut self, if_stmt: HirIfStmt) -> Vec<IRInstr> {
let mut instrs = vec![];
let then_label = self.request_label();
let exit_label = self.request_label();
@@ -273,7 +212,6 @@ impl Generator {
labels.push(exit_label);
// now generate if expr, true exit to labels[0], false exit to labels[1]
self.current_exit_label.push(Some((labels[0], labels[1])));
let cond_span = if_stmt.condition.span;
let (cond_instrs, cond_var) = match self.generate_expr(if_stmt.condition) {
Some(res) => res,
None => {
@@ -282,19 +220,14 @@ impl Generator {
}
};
self.current_exit_label.pop();
if cond_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), cond_span);
return vec![];
}
instrs.extend(cond_instrs);
instrs.push(IRInstr::Label(labels[0]));
instrs.extend(self.generate_block_stmt(if_stmt.then_branch));
instrs.push(IRInstr::Goto(exit_label));
for (i, else_if_branch) in if_stmt.ifelse_branch.into_iter().enumerate() {
let IfElseBranch { condition: else_if_cond, then_branch: else_if_block } = else_if_branch;
let HirIfElseBranch { condition: else_if_cond, then_branch: else_if_block } = else_if_branch;
instrs.push(IRInstr::Label(labels[i * 2 + 1]));
self.current_exit_label.push(Some((labels[i * 2 + 2], labels[i * 2 + 3])));
let else_if_cond_span = else_if_cond.span;
let (else_if_cond_instrs, else_if_cond_var) = match self.generate_expr(else_if_cond) {
Some(res) => res,
None => {
@@ -303,10 +236,6 @@ impl Generator {
}
};
self.current_exit_label.pop();
if else_if_cond_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), else_if_cond_span);
return vec![];
}
instrs.extend(else_if_cond_instrs);
instrs.push(IRInstr::Label(labels[i * 2 + 2]));
instrs.extend(self.generate_block_stmt(else_if_block));
@@ -320,71 +249,47 @@ impl Generator {
instrs.push(IRInstr::Label(exit_label));
instrs
}
fn generate_continue_stmt(&mut self, stmt: ContinueStmt) -> Vec<IRInstr> {
fn generate_continue_stmt(&mut self, _stmt: HirContinueStmt) -> Vec<IRInstr> {
if let Some((continue_label, _)) = self.while_exit_label.last() {
vec![IRInstr::Goto(*continue_label)]
} else {
self.diagnostic.add_from_ir_error(IRError::ContinueOutsideLoop, stmt.span);
vec![]
}
}
fn generate_break_stmt(&mut self, stmt: BreakStmt) -> Vec<IRInstr> {
fn generate_break_stmt(&mut self, _stmt: HirBreakStmt) -> Vec<IRInstr> {
if let Some((_, break_label)) = self.while_exit_label.last() {
vec![IRInstr::Goto(*break_label)]
} else {
self.diagnostic.add_from_ir_error(IRError::BreakOutsideLoop, stmt.span);
vec![]
}
}
fn generate_expr(&mut self, expr: Expr) -> Option<(Vec<IRInstr>, Option<Variable>)> {
fn generate_expr(&mut self, expr: HirExpr) -> Option<(Vec<IRInstr>, Option<Variable>)> {
// there may be some expr that doesn't produce value, like void func call
let (mut instrs, var) = match expr.value {
ExprValue::IntLit(i) => {
HirExprValue::IntLit(i) => {
// TODO: convert check
let var = self.var_manager.declare_temp(IRType::I32);
(vec![IRInstr::Move(var, MoveRValue::ConstInt(i as i32))], Some(var))
},
ExprValue::Var(name) => {
if let Some(var) = self.var_manager.get_variable(&name) {
(vec![], Some(var))
} else {
self.diagnostic.add_from_ir_error(IRError::VariableNotFound(name.clone()), expr.span);
return None;
}
HirExprValue::Var(symbol) => {
let var = self.var_manager.get_symbol(symbol).unwrap();
(vec![], Some(var))
},
ExprValue::Assign { lvalue, rvalue } => {
// TODO: only support simple variable assignment now, need to support more complex lvalue in the future
if let ExprValue::Var(name) = lvalue.value {
let var = match self.var_manager.get_variable(&name) {
Some(var) => var,
None => {
self.diagnostic.add_from_ir_error(IRError::VariableNotFound(name.clone()), lvalue.span);
return None;
}
};
self.current_exit_label.push(None);
let rvalue_span = rvalue.span;
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
self.current_exit_label.pop();
// TODO: further check
// if var.data_type != rvalue_var.data_type {
// self.diagnostic.add_from_ir_error(IRError::TypeMismatch(var.data_type, rvalue_var.data_type), lvalue.span);
// return (vec![], None);
// }
if rvalue_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), rvalue_span);
return None;
}
instrs.push(IRInstr::Move(var, MoveRValue::Var(rvalue_var.unwrap())));
let temp_var = self.var_manager.declare_temp(var.data_type);
instrs.push(IRInstr::Move(temp_var, MoveRValue::Var(var)));
(instrs, Some(temp_var))
HirExprValue::Assign { lvalue, rvalue } => {
let var = if let HirExprValue::Var(symbol) = lvalue.value {
self.var_manager.get_symbol(symbol).unwrap()
} else {
self.diagnostic.add_from_ir_error(IRError::InvalidAssignmentTarget, lvalue.span);
return None;
}
};
self.current_exit_label.push(None);
let (mut instrs, rvalue_var) = self.generate_expr(*rvalue)?;
self.current_exit_label.pop();
instrs.push(IRInstr::Move(var, MoveRValue::Var(rvalue_var.unwrap())));
let temp_var = self.var_manager.declare_temp(var.data_type);
instrs.push(IRInstr::Move(temp_var, MoveRValue::Var(var)));
(instrs, Some(temp_var))
},
ExprValue::UnaryOp { op, operand } => {
HirExprValue::UnaryOp { op, operand } => {
let mut parent_is_logical = true;
let exit_passdown = if matches!(op, AstUnaryOp::Not) {
Some(self.current_exit_label.last().cloned().flatten().map_or_else(|| {
@@ -409,13 +314,8 @@ impl Generator {
self.current_exit_label.push(exit_passdown);
let operand_span = operand.span;
let (mut instrs, operand_var) = self.generate_expr(*operand)?;
self.current_exit_label.pop();
if operand_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), operand_span);
return None;
}
let operand_var = operand_var.unwrap();
let dest_var = match op {
AstUnaryOp::Add => {
@@ -449,10 +349,7 @@ impl Generator {
};
(instrs, Some(dest_var))
},
ExprValue::BinaryOp { lhs, op, rhs } => {
let lhs_span = lhs.span;
let rhs_span = rhs.span;
HirExprValue::BinaryOp { lhs, op, rhs } => {
// +--------+-------------------------+-------------------------+-------------------------+
// | parent | (true_exit, false_exit) | (true_exit, false_exit) | (true_exit, false_exit) |
// | self | and(next) | or(next) | others |
@@ -494,18 +391,10 @@ impl Generator {
self.current_exit_label.push(lhs_exit_passdown);
let (mut instrs, left_var) = self.generate_expr(*lhs)?;
self.current_exit_label.pop();
if left_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), lhs_span);
return None;
}
let mut left_var = left_var.unwrap();
self.current_exit_label.push(rhs_exit_passdown);
let (right_instrs, right_var) = self.generate_expr(*rhs)?;
self.current_exit_label.pop();
if right_var.is_none() {
self.diagnostic.add_from_ir_error(IRError::InvalidOperand(IRType::Void), rhs_span);
return None;
}
let mut right_var = right_var.unwrap();
// check implicit convert
let convert_to;
@@ -513,13 +402,7 @@ impl Generator {
// we dont really care since we use cmp
convert_to = left_var.data_type;
} else {
if let Some(ty) = IRType::get_elevate_result(left_var.data_type, right_var.data_type) {
convert_to = ty;
} else {
self.diagnostic.add_from_ir_error(IRError::IncompatiableOperand(left_var.data_type, right_var.data_type), lhs_span);
self.diagnostic.add_from_ir_error(IRError::IncompatiableOperand(left_var.data_type, right_var.data_type), rhs_span);
return None;
}
convert_to = IRType::get_elevate_result(left_var.data_type, right_var.data_type).unwrap();
}
// do implicit convert if needed
// TODO: further check
@@ -606,50 +489,18 @@ impl Generator {
// }
(instrs, Some(dest_var))
},
ExprValue::FuncCall(func_name, args) => {
HirExprValue::FuncCall(func_id, args) => {
let mut instrs = vec![];
let mut arg_vars = vec![];
let func_def = if let Some(func_def) = self.function_map.get(&func_name) {
func_def
} else {
self.diagnostic.add_from_ir_error(IRError::FunctionNotFound(func_name.clone()), expr.span);
return None;
}.clone();
let func_def = self.ir_function(func_id);
if args.len() < func_def.parameter_types.len() {
self.diagnostic.add_from_ir_error(IRError::TooFewArguments(func_def.parameter_types.len(), args.len()), expr.span);
return None;
}
if args.len() > func_def.parameter_types.len() {
self.diagnostic.add_from_ir_error(IRError::TooManyArguments(func_def.parameter_types.len(), args.len()), expr.span);
return None;
}
let mut has_error = false;
for parameter_type in &func_def.parameter_types {
if matches!(parameter_type, IRType::Void) {
self.diagnostic.add_from_ir_error(IRError::InvalidParameterType(IRType::Void), expr.span);
has_error = true;
}
}
if has_error {
return None;
}
for (i, arg) in args.into_iter().enumerate() {
for arg in args.into_iter() {
self.current_exit_label.push(None);
let (arg_instrs, arg_var) = self.generate_expr(arg)?;
self.current_exit_label.pop();
let parameter_type = func_def.parameter_types.get(i).unwrap();
if *parameter_type != arg_var.map_or(IRType::Void, |v| v.data_type) {
self.diagnostic.add_from_ir_error(IRError::TypeMismatch(*parameter_type, arg_var.map_or(IRType::Void, |v| v.data_type)), expr.span);
has_error = true;
continue;
}
instrs.extend(arg_instrs);
arg_vars.push(arg_var.unwrap());
}
if has_error {
return None;
}
let ret_variable = if matches!(func_def.return_type, IRType::Void) {
None
} else {
@@ -671,8 +522,7 @@ impl Generator {
}
struct VariableManager {
variable_map: BTreeMap<String, Vec<Variable>>,
scopes: Vec<BTreeSet<String>>,
variable_map: BTreeMap<SymbolId, Variable>,
global_counter: usize,
local_counter: usize,
local_var_type: Vec<Variable>,
@@ -682,27 +532,12 @@ impl VariableManager {
pub fn new() -> Self {
Self {
variable_map: BTreeMap::new(),
scopes: vec![BTreeSet::new()],
global_counter: 0,
local_counter: 0,
local_var_type: vec![],
}
}
pub fn enter_scope(&mut self) {
self.scopes.push(BTreeSet::new());
}
pub fn exit_scope(&mut self) {
let variables = self.scopes.pop().unwrap();
for var in variables {
self.variable_map.get_mut(&var).unwrap().pop();
}
}
fn declare_variable(&mut self, name: &str, var_type: VariableType, var_data_type: IRType) -> Result<Variable, IRError> {
if self.scopes.last().unwrap().contains(name) {
return Err(IRError::VariableHasBeenDefined(name.to_string()));
}
fn declare_symbol(&mut self, symbol: SymbolId, var_type: VariableType, var_data_type: IRType) -> Variable {
let variable = match var_type {
VariableType::Global => {
let var = Variable { index: self.global_counter, var_type, data_type: var_data_type };
@@ -716,18 +551,11 @@ impl VariableManager {
}
_ => unreachable!(),
};
self.variable_map.entry(name.to_string()).or_default().push(variable);
self.scopes.last_mut().unwrap().insert(name.to_string());
self.variable_map.insert(symbol, variable);
if matches!(var_type, VariableType::Local) {
self.local_var_type.push(variable);
}
Ok(variable)
}
pub fn declare_gloabal(&mut self, name: &str, var_data_type: IRType) -> Result<Variable, IRError> {
self.declare_variable(name, VariableType::Global, var_data_type)
}
pub fn declare_local(&mut self, name: &str, var_data_type: IRType) -> Result<Variable, IRError> {
self.declare_variable(name, VariableType::Local, var_data_type)
variable
}
pub fn declare_temp(&mut self, var_data_type: IRType) -> Variable {
let var = Variable { index: self.local_counter, var_type: VariableType::Temp, data_type: var_data_type };
@@ -750,12 +578,13 @@ impl VariableManager {
pub fn clear_local_counter(&mut self) {
self.local_counter = 0;
self.local_var_type.clear();
self.variable_map.retain(|_, var| matches!(var.var_type, VariableType::Global));
}
pub fn get_cur_func_variables(&self) -> Vec<Variable> {
self.local_var_type.iter().cloned().collect()
}
pub fn get_variable(&self, name: &str) -> Option<Variable> {
self.variable_map.get(name).and_then(|vars| vars.last()).cloned()
pub fn get_symbol(&self, symbol: SymbolId) -> Option<Variable> {
self.variable_map.get(&symbol).cloned()
}
}
@@ -769,6 +598,7 @@ mod tests {
use std::io::Write;
use crate::frontend::lexer::Lexer;
use crate::frontend::parser::Parser;
use crate::sema::analyzer::Analyzer;
use crate::utils::case_list::CaseList;
use crate::utils::num_sequence::NumberSequence;
@@ -806,12 +636,14 @@ mod tests {
parser.diagnostics.print(&format!("{}", case_path.display()), &full_text);
is_error = true;
}
let mut generator = Generator::new();
let ir = generator.emit(compile_unit);
if !generator.diagnostic.is_empty() {
generator.diagnostic.print(&format!("{}", case_path.display()), &full_text);
let mut analyzer = Analyzer::new();
let hir = analyzer.analyze(compile_unit);
if !analyzer.get_diagnostics().is_empty() {
analyzer.get_diagnostics().print(&format!("{}", case_path.display()), &full_text);
is_error = true;
}
let mut generator = Generator::new(&analyzer);
let ir = generator.emit(hir);
let mut ir_file = File::create(format!("output/{}.ir", case_name)).unwrap();
for instr in ir {
writeln!(ir_file, "{}", instr).unwrap();
@@ -838,4 +670,4 @@ mod tests {
fn test_func() {
test_case("12-13,58-60");
}
}
}