feat(ir,backend,frontend): Support for and revise ir array param generate

This commit is contained in:
2026-06-07 22:26:23 +08:00
parent 55636e07af
commit b7c2924e8b
11 changed files with 508 additions and 67 deletions
+71 -17
View File
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use crate::{
ast::types::{
ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt,
ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, ForInit, ForStmt, FuncDeclStmt,
GlobalDeclStmt, IfElseBranch, IfStmt, ReturnStmt, Statement, VarDeclStmt, WhileStmt,
},
diagnostic::{span::Span, Diagnositics},
@@ -10,7 +10,7 @@ use crate::{
err::SemaError,
hir::{
HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue,
HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirParam,
HirForInit, HirForStmt, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirParam,
HirReturnStmt, HirStatement, HirVarDeclStmt, HirVarDeclStmtValue, HirWhileStmt,
},
symbol::{FunctionId, FunctionSig, SymbolId, SymbolKind, SymbolTable},
@@ -39,7 +39,9 @@ impl Analyzer {
};
analyzer.declare_builtin_func("putint", vec![SemaType::I32], SemaType::Void);
analyzer.declare_builtin_func("putch", vec![SemaType::I32], SemaType::Void);
analyzer.declare_builtin_func("putarray", vec![SemaType::I32, SemaType::Array(Box::new(SemaType::I32), vec![0])], SemaType::Void);
analyzer.declare_builtin_func("getint", vec![], SemaType::I32);
analyzer.declare_builtin_func("getarray", vec![SemaType::Array(Box::new(SemaType::I32), vec![0])], SemaType::I32);
analyzer
}
@@ -102,10 +104,24 @@ impl Analyzer {
for value in var_decl.values {
let data_type = self.build_var_type(base_type.clone(), &value.dimensions, false);
match self.symbols.declare_variable(&value.name, kind, data_type) {
Ok(symbol) => values.push(HirVarDeclStmtValue {
symbol,
name_span: value.name_span,
}),
Ok(symbol) => {
let symbol_type = self.symbols.get_symbol(symbol).ty.clone();
let init = value.value.and_then(|expr| {
let span = expr.span;
let init = self.analyze_expr(expr)?;
if init.ty == SemaType::Void {
self.add_error(SemaError::InvalidOperand(SemaType::Void), span);
} else if !self.type_matches(&symbol_type, &init.ty) {
self.add_error(SemaError::TypeMismatch(symbol_type.clone(), init.ty.clone()), span);
}
Some(init)
});
values.push(HirVarDeclStmtValue {
symbol,
name_span: value.name_span,
value: init,
});
}
Err(e) => self.add_error(e, value.name_span),
}
}
@@ -185,20 +201,11 @@ impl Analyzer {
self.add_error(SemaError::InvalidArrayDimension, dimension.span);
}
}
None if is_param && i == 0 => {}
None if is_param && i == 0 => dims.push(0),
None => self.add_error(SemaError::InvalidArrayDimension, dimension.span),
}
}
if is_param {
let pointee_type = if dims.is_empty() {
base_type
} else {
SemaType::Array(Box::new(base_type), dims)
};
SemaType::Ptr(Box::new(pointee_type))
} else {
SemaType::Array(Box::new(base_type), dims)
}
SemaType::Array(Box::new(base_type), dims)
}
fn analyze_block_stmt(&mut self, block_stmt: BlockStmt) -> HirBlockStmt {
@@ -216,6 +223,7 @@ impl Analyzer {
Statement::Return(stmt) => Some(HirStatement::Return(self.analyze_return_stmt(stmt))),
Statement::If(stmt) => Some(HirStatement::If(self.analyze_if_stmt(stmt))),
Statement::While(stmt) => Some(HirStatement::While(self.analyze_while_stmt(stmt))),
Statement::For(stmt) => Some(HirStatement::For(self.analyze_for_stmt(stmt))),
Statement::Break(stmt) => Some(HirStatement::Break(self.analyze_break_stmt(stmt))),
Statement::Continue(stmt) => Some(HirStatement::Continue(self.analyze_continue_stmt(stmt))),
Statement::Block(stmt) => {
@@ -294,6 +302,26 @@ impl Analyzer {
}
}
fn analyze_for_stmt(&mut self, for_stmt: ForStmt) -> HirForStmt {
self.symbols.enter_scope();
let init = for_stmt.init.and_then(|init| match init {
ForInit::Expr(expr) => self.analyze_expr(expr).map(HirForInit::Expr),
ForInit::VarDecl(var_decl) => Some(HirForInit::VarDecl(self.analyze_var_decl(var_decl, SymbolKind::Local))),
});
let condition = for_stmt.condition.map(|expr| self.analyze_condition_expr(expr));
let update = for_stmt.update.and_then(|expr| self.analyze_expr(expr));
self.loop_depth += 1;
let body = self.analyze_block_stmt(for_stmt.body);
self.loop_depth -= 1;
self.symbols.exit_scope();
HirForStmt {
init,
condition,
update,
body,
}
}
fn analyze_break_stmt(&mut self, stmt: BreakStmt) -> HirBreakStmt {
if self.loop_depth == 0 {
self.add_error(SemaError::BreakOutsideLoop, stmt.span);
@@ -369,6 +397,27 @@ impl Analyzer {
span,
})
}
ExprValue::IncDec { op, operand, is_prefix } => {
if !matches!(operand.value, ExprValue::Var(_) | ExprValue::ArrayAccess { .. }) {
self.add_error(SemaError::InvalidAssignmentTarget, operand.span);
return None;
}
let operand_span = operand.span;
let operand = self.analyze_expr(*operand)?;
if !operand.ty.is_scalar() {
self.add_error(SemaError::InvalidOperand(operand.ty.clone()), operand_span);
return None;
}
Some(HirExpr {
ty: operand.ty.clone(),
value: HirExprValue::IncDec {
op,
operand: Box::new(operand),
is_prefix,
},
span,
})
}
ExprValue::BinaryOp { lhs, op, rhs } => self.analyze_binary_expr(*lhs, op, *rhs, span),
ExprValue::FuncCall(func_name, args) => self.analyze_func_call_expr(func_name, args, span),
}
@@ -524,6 +573,11 @@ impl Analyzer {
if expected == actual {
return true;
}
if let (SemaType::Array(expected_elem, expected_dims), SemaType::Array(actual_elem, actual_dims)) = (expected, actual) {
return expected_elem == actual_elem
&& expected_dims.len() == actual_dims.len()
&& expected_dims.iter().zip(actual_dims.iter()).all(|(expected_dim, actual_dim)| *expected_dim == 0 || expected_dim == actual_dim);
}
matches!((expected, actual), (SemaType::Ptr(expected_elem), SemaType::Array(_, _)) if actual.indexed_type().is_some_and(|ty| &ty == expected_elem.as_ref()))
}
}
+19
View File
@@ -18,6 +18,7 @@ pub struct HirVarDeclStmt {
pub struct HirVarDeclStmtValue {
pub symbol: SymbolId,
pub name_span: Span,
pub value: Option<HirExpr>,
}
pub struct HirFuncDeclStmt {
@@ -46,6 +47,7 @@ pub enum HirStatement {
VarDecl(HirVarDeclStmt),
If(HirIfStmt),
While(HirWhileStmt),
For(HirForStmt),
Break(HirBreakStmt),
Continue(HirContinueStmt),
}
@@ -67,6 +69,18 @@ pub struct HirWhileStmt {
pub body: HirBlockStmt,
}
pub struct HirForStmt {
pub init: Option<HirForInit>,
pub condition: Option<HirExpr>,
pub update: Option<HirExpr>,
pub body: HirBlockStmt,
}
pub enum HirForInit {
Expr(HirExpr),
VarDecl(HirVarDeclStmt),
}
pub struct HirBreakStmt {
pub span: Span,
}
@@ -102,6 +116,11 @@ pub enum HirExprValue {
op: UnaryOp,
operand: Box<HirExpr>,
},
IncDec {
op: crate::ast::types::IncDecOp,
operand: Box<HirExpr>,
is_prefix: bool,
},
FuncCall(FunctionId, Vec<HirExpr>),
Assign {
lvalue: Box<HirExpr>,
+2
View File
@@ -35,6 +35,8 @@ impl SemaType {
SemaType::Array(elem, dims) => {
if dims.len() == 1 {
Some((**elem).clone())
} else if dims.first().is_some_and(|dim| *dim == 0) {
Some(SemaType::Array(elem.clone(), dims[1..].to_vec()))
} else {
Some(SemaType::Array(elem.clone(), dims[1..].to_vec()))
}