feat(ir, parser): Support if/while/break/logical expr/cmp in parser and ir generator

This commit is contained in:
2026-05-14 15:54:31 +08:00
parent 41284dc14e
commit 7b6eede961
10 changed files with 1260 additions and 357 deletions
+32 -4
View File
@@ -2,8 +2,7 @@ use petgraph::dot::{Config, Dot};
use petgraph::graph::{Graph, NodeIndex};
use crate::ast::types::{
BlockStmt, CompileUnit, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, Param, ReturnStmt,
Statement, VarDeclStmt, VarDeclStmtValue,
BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfStmt, Param, ReturnStmt, Statement, VarDeclStmt, VarDeclStmtValue, WhileStmt
};
pub type AstGraph = Graph<String, String>;
@@ -116,7 +115,11 @@ impl AstGraphBuilder {
let node = self.child(parent, stmt.to_string());
self.add_var_decl(node, var_decl);
node
}
},
Statement::If(if_stmt) => self.add_if_stmt(parent, if_stmt),
Statement::While(while_stmt) => self.add_while_stmt(parent, while_stmt),
Statement::Break(break_stmt) => self.add_break_stmt(parent, break_stmt),
Statement::Continue(continue_stmt) => self.add_continue_stmt(parent, continue_stmt),
}
}
@@ -126,7 +129,27 @@ impl AstGraphBuilder {
None => self.child(parent, "Void"),
}
}
fn add_if_stmt(&mut self, parent: NodeIndex, if_stmt: &IfStmt) -> NodeIndex {
let node = self.child(parent, if_stmt.to_string());
self.add_expr(node, &if_stmt.condition);
self.add_block_stmt(node, &if_stmt.then_branch);
if let Some(else_branch) = &if_stmt.else_branch {
self.add_block_stmt(node, else_branch);
}
node
}
fn add_while_stmt(&mut self, parent: NodeIndex, while_stmt: &WhileStmt) -> NodeIndex {
let node = self.child(parent, while_stmt.to_string());
self.add_expr(node, &while_stmt.condition);
self.add_block_stmt(node, &while_stmt.body);
node
}
fn add_break_stmt(&mut self, parent: NodeIndex, break_stmt: &BreakStmt) -> NodeIndex {
self.child(parent, break_stmt.to_string())
}
fn add_continue_stmt(&mut self, parent: NodeIndex, continue_stmt: &ContinueStmt) -> NodeIndex {
self.child(parent, continue_stmt.to_string())
}
fn add_expr(&mut self, parent: NodeIndex, expr: &Expr) -> NodeIndex {
match &expr.value {
ExprValue::IntLit(_) | ExprValue::Var(_) => self.child(parent, expr.value.to_string()),
@@ -149,6 +172,11 @@ impl AstGraphBuilder {
self.add_expr(node, lvalue);
self.add_expr(node, rvalue);
node
},
ExprValue::UnaryOp { op: _, operand } => {
let node = self.child(parent, expr.value.to_string());
self.add_expr(node, operand);
node
}
}
}
+107 -19
View File
@@ -1,4 +1,4 @@
use crate::{diagnostic::span::Span, frontend::types::{TokenValue, TypeIdent}};
use crate::{diagnostic::span::Span, frontend::types::{Token, TokenValue, TypeIdent}};
use std::fmt;
pub struct CompileUnit {
@@ -11,12 +11,12 @@ pub enum GlobalDeclStmt {
pub struct VarDeclStmt {
pub values: Vec<VarDeclStmtValue>,
pub span: Span,
pub data_type: Type,
pub type_span: Span,
}
pub struct VarDeclStmtValue {
pub name: String,
pub var_type: Type,
pub span: Span,
pub name_span: Span,
}
@@ -25,11 +25,11 @@ pub struct FuncDeclStmt {
pub return_type: Type,
pub params: Vec<Param>,
pub body: BlockStmt,
pub span: Span,
pub ret_type_span: Span,
pub name_span: Span,
}
pub struct BlockStmt {
pub statements: Vec<Statement>,
pub span: Span,
}
pub enum Statement {
@@ -37,16 +37,46 @@ pub enum Statement {
Block(BlockStmt),
Expr(Expr),
VarDecl(VarDeclStmt),
If(IfStmt),
While(WhileStmt),
Break(BreakStmt),
Continue(ContinueStmt),
}
impl Statement {
pub fn span(&self) -> Span {
match self {
Statement::Return(s) => s.span,
Statement::Block(s) => s.span,
Statement::Expr(s) => s.span,
Statement::VarDecl(s) => s.span,
}
}
// impl Statement {
// pub fn span(&self) -> Span {
// match self {
// Statement::Return(s) => s.span,
// Statement::Block(s) => s.span,
// Statement::Expr(s) => s.span,
// Statement::VarDecl(s) => s.span,
// Statement::If(s) => s.span,
// Statement::While(s) => s.span,
// Statement::Break(s) => s.span,
// Statement::Continue(s) => s.span,
// }
// }
// }
pub struct IfStmt {
pub condition: Expr,
pub then_branch: BlockStmt,
pub ifelse_branch: Vec<IfElseBranch>,
pub else_branch: Option<BlockStmt>,
// pub span: Span,
}
pub struct IfElseBranch {
pub condition: Expr,
pub then_branch: BlockStmt,
}
pub struct WhileStmt {
pub condition: Expr,
pub body: BlockStmt,
// pub span: Span,
}
pub struct BreakStmt {
pub span: Span,
}
pub struct ContinueStmt {
pub span: Span,
}
pub struct ReturnStmt {
pub value: Option<Expr>,
@@ -64,6 +94,10 @@ pub enum ExprValue {
op: BinaryOp,
rhs: Box<Expr>
},
UnaryOp {
op: UnaryOp,
operand: Box<Expr>,
},
FuncCall(String, Vec<Expr>),
Assign {
lvalue: Box<Expr>,
@@ -74,8 +108,13 @@ pub enum ExprValue {
pub enum BinaryOp {
Add, Sub, Mul, Div, Mod,
Equal, NotEqual, Less, LessEqual, Greater, GreaterEqual,
And, Or,
}
#[derive(Clone, Copy)]
pub enum UnaryOp {
Add, Sub, Not,
}
impl BinaryOp {
pub fn from_token_value(token_value: &TokenValue) -> Option<Self> {
match token_value {
@@ -90,10 +129,20 @@ impl BinaryOp {
TokenValue::LessEqual => Some(BinaryOp::LessEqual),
TokenValue::Greater => Some(BinaryOp::Greater),
TokenValue::GreaterEqual => Some(BinaryOp::GreaterEqual),
TokenValue::And => Some(BinaryOp::And),
TokenValue::Or => Some(BinaryOp::Or),
_ => None,
}
}
pub fn is_logical(&self) -> bool {
matches!(self, BinaryOp::And | BinaryOp::Or)
}
pub fn is_cmp(&self) -> bool {
matches!(self, BinaryOp::Equal | BinaryOp::NotEqual | BinaryOp::Less | BinaryOp::LessEqual | BinaryOp::Greater | BinaryOp::GreaterEqual)
}
}
#[derive(Clone, Copy)]
pub enum Type {
Int,
@@ -110,7 +159,8 @@ impl From<TypeIdent> for Type {
pub struct Param {
pub name: String,
pub param_type: Type,
pub span: Span,
pub name_span: Span,
pub type_span: Span,
}
impl fmt::Display for CompileUnit {
@@ -136,7 +186,7 @@ impl fmt::Display for VarDeclStmt {
impl fmt::Display for VarDeclStmtValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {}", self.var_type, self.name)
write!(f, "{}", self.name)
}
}
@@ -159,16 +209,42 @@ impl fmt::Display for Statement {
Statement::Block(_) => write!(f, "BlockStmt"),
Statement::Expr(_) => write!(f, "ExprStmt"),
Statement::VarDecl(_) => write!(f, "VarDeclStmt"),
Statement::If(_) => write!(f, "IfStmt"),
Statement::While(_) => write!(f, "WhileStmt"),
Statement::Break(_) => write!(f, "BreakStmt"),
Statement::Continue(_) => write!(f, "ContinueStmt"),
}
}
}
impl fmt::Display for IfStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "IfStmt")
}
}
impl fmt::Display for ReturnStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ReturnStmt")
}
}
impl fmt::Display for WhileStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "WhileStmt")
}
}
impl fmt::Display for BreakStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BreakStmt")
}
}
impl fmt::Display for ContinueStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ContinueStmt")
}
}
impl fmt::Display for Expr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.value)
@@ -183,6 +259,7 @@ impl fmt::Display for ExprValue {
ExprValue::BinaryOp { op, .. } => write!(f, "BinaryOp({})", op),
ExprValue::FuncCall(name, _) => write!(f, "FuncCall({})", name),
ExprValue::Assign { .. } => write!(f, "Assign"),
ExprValue::UnaryOp { op, .. } => write!(f, "UnaryOp({})", op),
}
}
}
@@ -207,11 +284,22 @@ impl fmt::Display for BinaryOp {
BinaryOp::LessEqual => "<=",
BinaryOp::Greater => ">",
BinaryOp::GreaterEqual => ">=",
BinaryOp::And => "&&",
BinaryOp::Or => "||",
};
write!(f, "{}", op)
}
}
impl fmt::Display for UnaryOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match self {
UnaryOp::Add => "+",
UnaryOp::Sub => "-",
UnaryOp::Not => "!",
};
write!(f, "{}", op)
}
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {