feat(ir,backend,frontend): Support for and revise ir array param generate
This commit is contained in:
+71
-17
@@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user