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
+46 -1
View File
@@ -2,7 +2,7 @@ use petgraph::dot::{Config, Dot};
use petgraph::graph::{Graph, NodeIndex};
use crate::ast::types::{
ArrayDimension, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfStmt, Param, ReturnStmt, Statement, VarDeclStmt, VarDeclStmtValue, WhileStmt
ArrayDimension, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, ForInit, ForStmt, FuncDeclStmt, GlobalDeclStmt, IfStmt, Param, ReturnStmt, Statement, VarDeclStmt, VarDeclStmtValue, WhileStmt
};
pub type AstGraph = Graph<String, String>;
@@ -77,6 +77,9 @@ impl AstGraphBuilder {
for dimension in &value.dimensions {
self.add_array_dimension(node, dimension);
}
if let Some(expr) = &value.value {
self.add_expr(node, expr);
}
node
}
@@ -134,6 +137,7 @@ impl AstGraphBuilder {
},
Statement::If(if_stmt) => self.add_if_stmt(parent, if_stmt),
Statement::While(while_stmt) => self.add_while_stmt(parent, while_stmt),
Statement::For(for_stmt) => self.add_for_stmt(parent, for_stmt),
Statement::Break(break_stmt) => self.add_break_stmt(parent, break_stmt),
Statement::Continue(continue_stmt) => self.add_continue_stmt(parent, continue_stmt),
}
@@ -160,6 +164,42 @@ impl AstGraphBuilder {
self.add_block_stmt(node, &while_stmt.body);
node
}
fn add_for_stmt(&mut self, parent: NodeIndex, for_stmt: &ForStmt) -> NodeIndex {
let node = self.child(parent, for_stmt.to_string());
match &for_stmt.init {
Some(ForInit::Expr(expr)) => {
let init = self.child(node, "Init");
self.add_expr(init, expr);
}
Some(ForInit::VarDecl(var_decl)) => {
let init = self.child(node, "Init");
self.add_var_decl(init, var_decl);
}
None => {
self.child(node, "NoInit");
}
}
match &for_stmt.condition {
Some(expr) => {
let condition = self.child(node, "Condition");
self.add_expr(condition, expr);
}
None => {
self.child(node, "NoCondition");
}
}
match &for_stmt.update {
Some(expr) => {
let update = self.child(node, "Update");
self.add_expr(update, expr);
}
None => {
self.child(node, "NoUpdate");
}
}
self.add_block_stmt(node, &for_stmt.body);
node
}
fn add_break_stmt(&mut self, parent: NodeIndex, break_stmt: &BreakStmt) -> NodeIndex {
self.child(parent, break_stmt.to_string())
}
@@ -200,6 +240,11 @@ impl AstGraphBuilder {
self.add_expr(node, operand);
node
}
ExprValue::IncDec { operand, .. } => {
let node = self.child(parent, expr.value.to_string());
self.add_expr(node, operand);
node
}
}
}
}
+170 -38
View File
@@ -1,6 +1,6 @@
use crate::{
ast::types::{
ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt
ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, ForInit, ForStmt, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, IncDecOp, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt
},
diagnostic::{Diagnositics, span::Span},
lexer::{
@@ -46,6 +46,9 @@ impl Parser {
fn peek(&self) -> &Token {
self.tokens.get(self.pos).unwrap_or(&self.eof_token)
}
fn peek_n(&self, n: usize) -> &Token {
self.tokens.get(self.pos + n).unwrap_or(&self.eof_token)
}
fn next(&mut self) -> Token {
let token = self.peek().clone();
if !matches!(token.value, TokenValue::Eof) {
@@ -294,6 +297,10 @@ impl Parser {
// }
// }
fn parse_var_decl_stmt(&mut self, parse_type: ParseType) -> Result<VarDeclStmt, ParseProcessError> {
self.parse_var_decl_stmt_inner(parse_type, true)
}
fn parse_var_decl_stmt_inner(&mut self, parse_type: ParseType, consume_semicolon: bool) -> Result<VarDeclStmt, ParseProcessError> {
assert!(!self.is_eof());
let mut values = vec![];
let (var_type, name, type_span, name_span) = match self.parse_type_and_name(parse_type) {
@@ -307,7 +314,13 @@ impl Parser {
}
};
let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name, name_span, dimensions });
let value = if self.peek().value == TokenValue::Equal {
self.advance(1);
Some(self.parse_expr()?)
} else {
None
};
values.push(VarDeclStmtValue { name, name_span, dimensions, value });
let mut last_name = true; // indicate whether the last parsed token is a variable name
while !self.is_eof() {
if matches!(self.peek().value, TokenValue::Semicolon) { // statement end
@@ -327,7 +340,13 @@ impl Parser {
if let Some(ident) = self.peek().value.as_ident() {
let span = self.next().span;
let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions });
let value = if self.peek().value == TokenValue::Equal {
self.advance(1);
Some(self.parse_expr()?)
} else {
None
};
values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions, value });
last_name = true;
} else {
let token = self.next().clone();
@@ -338,7 +357,9 @@ impl Parser {
return Err(ParseProcessError::ErrorInMatch);
}
}
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
if consume_semicolon {
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
}
Ok(VarDeclStmt { values, type_span, data_type: var_type.into() })
}
@@ -457,6 +478,11 @@ impl Parser {
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
Err(_) => {},
}
match self.parse_for_stmt() {
Ok(for_stmt) => return Ok(Statement::For(for_stmt)),
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
Err(_) => {},
}
match self.parse_break_stmt() {
Ok(break_stmt) => return Ok(Statement::Break(break_stmt)),
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
@@ -593,6 +619,48 @@ impl Parser {
})
}
fn parse_for_stmt(&mut self) -> Result<ForStmt, ParseProcessError> {
assert!(!self.is_eof());
if self.peek().value != TokenValue::For {
return Err(ParseProcessError::TryNext);
}
self.advance(1);
self.must_match_token(&TokenValue::LParen, "`(`")?;
let init = if self.peek().value == TokenValue::Semicolon {
None
} else if matches!(self.peek().value, TokenValue::TypeIdent(_)) {
Some(ForInit::VarDecl(self.parse_var_decl_stmt_inner(ParseType::MustParse, false)?))
} else {
Some(ForInit::Expr(self.parse_expr()?))
};
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
let condition = if self.peek().value == TokenValue::Semicolon {
None
} else {
Some(self.parse_expr()?)
};
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
let update = if self.peek().value == TokenValue::RParen {
None
} else {
Some(self.parse_expr()?)
};
self.must_match_token(&TokenValue::RParen, "`)`")?;
let body;
if self.peek().value != TokenValue::LBrace {
let stmt = self.parse_stmt()?;
body = BlockStmt { statements: vec![stmt] };
} else {
body = self.parse_block_stmt(ParseType::MustParse)?;
}
Ok(ForStmt {
init,
condition,
update,
body,
})
}
fn parse_break_stmt(&mut self) -> Result<BreakStmt, ParseProcessError> {
assert!(!self.is_eof());
let start_span = self.peek().span;
@@ -747,41 +815,63 @@ impl Parser {
}
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
let mut expr = self.parse_primary_atom()?;
while self.peek().value == TokenValue::LBracket {
let start_span = expr.span;
self.advance(1);
let index = if self.is_eof() {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span);
return Err(ParseProcessError::ErrorInMatch);
} else {
self.parse_expr()?
};
let end_span = match &self.peek().value {
TokenValue::RBracket => {
let span = self.peek().span;
self.advance(1);
span
}
TokenValue::Eof => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.span);
return Err(ParseProcessError::ErrorInMatch);
}
_ => {
let token = self.next();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`]`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
expr = Expr {
value: ExprValue::ArrayAccess {
array: Box::new(expr),
index: Box::new(index),
},
span: Span::from_two(start_span, end_span),
loop {
if self.peek().value == TokenValue::LBracket {
let start_span = expr.span;
self.advance(1);
let index = if self.is_eof() {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span);
return Err(ParseProcessError::ErrorInMatch);
} else {
self.parse_expr()?
};
let end_span = match &self.peek().value {
TokenValue::RBracket => {
let span = self.peek().span;
self.advance(1);
span
}
TokenValue::Eof => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.span);
return Err(ParseProcessError::ErrorInMatch);
}
_ => {
let token = self.next();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`]`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
expr = Expr {
value: ExprValue::ArrayAccess {
array: Box::new(expr),
index: Box::new(index),
},
span: Span::from_two(start_span, end_span),
};
continue;
}
let op = match (&self.peek().value, &self.peek_n(1).value) {
(TokenValue::Plus, TokenValue::Plus) => Some(IncDecOp::Inc),
(TokenValue::Minus, TokenValue::Minus) => Some(IncDecOp::Dec),
_ => None,
};
if let Some(op) = op {
let end_span = self.peek_n(1).span;
self.advance(2);
expr = Expr {
span: Span::from_two(expr.span, end_span),
value: ExprValue::IncDec {
op,
operand: Box::new(expr),
is_prefix: false,
},
};
continue;
}
break;
}
Ok(expr)
}
@@ -790,6 +880,27 @@ impl Parser {
let token = self.peek().clone();
match token.value {
TokenValue::Plus => {
if self.peek_n(1).value == TokenValue::Plus {
self.advance(2);
let expr = if self.is_eof() {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
} else {
self.parse_unary()?
};
let span = Span::from_two(token.span, expr.span);
return Ok(Expr {
value: ExprValue::IncDec {
op: IncDecOp::Inc,
operand: Box::new(expr),
is_prefix: true,
},
span,
});
}
self.advance(1);
let expr = if self.is_eof() {
self.diagnostics.add_from_frontend_error(
@@ -810,6 +921,27 @@ impl Parser {
})
}
TokenValue::Minus => {
if self.peek_n(1).value == TokenValue::Minus {
self.advance(2);
let rhs = if self.is_eof() {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
} else {
self.parse_unary()?
};
let span = Span::from_two(token.span, rhs.span);
return Ok(Expr {
value: ExprValue::IncDec {
op: IncDecOp::Dec,
operand: Box::new(rhs),
is_prefix: true,
},
span,
});
}
self.advance(1);
let rhs = if self.is_eof() {
self.diagnostics.add_from_frontend_error(
+38
View File
@@ -18,6 +18,7 @@ pub struct VarDeclStmtValue {
pub name: String,
pub name_span: Span,
pub dimensions: Vec<ArrayDimension>,
pub value: Option<Expr>,
}
pub struct ArrayDimension {
@@ -44,6 +45,7 @@ pub enum Statement {
VarDecl(VarDeclStmt),
If(IfStmt),
While(WhileStmt),
For(ForStmt),
Break(BreakStmt),
Continue(ContinueStmt),
}
@@ -77,6 +79,16 @@ pub struct WhileStmt {
pub body: BlockStmt,
// pub span: Span,
}
pub struct ForStmt {
pub init: Option<ForInit>,
pub condition: Option<Expr>,
pub update: Option<Expr>,
pub body: BlockStmt,
}
pub enum ForInit {
Expr(Expr),
VarDecl(VarDeclStmt),
}
pub struct BreakStmt {
pub span: Span,
}
@@ -107,6 +119,11 @@ pub enum ExprValue {
op: UnaryOp,
operand: Box<Expr>,
},
IncDec {
op: IncDecOp,
operand: Box<Expr>,
is_prefix: bool,
},
FuncCall(String, Vec<Expr>),
Assign {
lvalue: Box<Expr>,
@@ -124,6 +141,11 @@ pub enum BinaryOp {
pub enum UnaryOp {
Add, Sub, Not,
}
#[derive(Clone, Copy)]
pub enum IncDecOp {
Inc,
Dec,
}
impl BinaryOp {
pub fn from_token_value(token_value: &TokenValue) -> Option<Self> {
match token_value {
@@ -227,6 +249,7 @@ impl fmt::Display for Statement {
Statement::VarDecl(_) => write!(f, "VarDeclStmt"),
Statement::If(_) => write!(f, "IfStmt"),
Statement::While(_) => write!(f, "WhileStmt"),
Statement::For(_) => write!(f, "ForStmt"),
Statement::Break(_) => write!(f, "BreakStmt"),
Statement::Continue(_) => write!(f, "ContinueStmt"),
}
@@ -249,6 +272,12 @@ impl fmt::Display for WhileStmt {
}
}
impl fmt::Display for ForStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ForStmt")
}
}
impl fmt::Display for BreakStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BreakStmt")
@@ -277,6 +306,7 @@ impl fmt::Display for ExprValue {
ExprValue::FuncCall(name, _) => write!(f, "FuncCall({})", name),
ExprValue::Assign { .. } => write!(f, "Assign"),
ExprValue::UnaryOp { op, .. } => write!(f, "UnaryOp({})", op),
ExprValue::IncDec { op, is_prefix, .. } => write!(f, "{}{}", if *is_prefix { "Prefix" } else { "Postfix" }, op),
}
}
}
@@ -317,6 +347,14 @@ impl fmt::Display for UnaryOp {
write!(f, "{}", op)
}
}
impl fmt::Display for IncDecOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IncDecOp::Inc => write!(f, "Inc"),
IncDecOp::Dec => write!(f, "Dec"),
}
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {