feat(parser,ir,backend): Support array

This commit is contained in:
2026-05-31 22:06:09 +08:00
parent c42575c1c6
commit 669c415bd7
13 changed files with 575 additions and 130 deletions
+100 -27
View File
@@ -1,6 +1,6 @@
use crate::{
ast::types::{
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, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt
},
diagnostic::{Diagnositics, span::Span},
frontend::{
@@ -259,6 +259,7 @@ impl Parser {
Ok(Param {
param_type: param_type.into(),
name,
dimensions: self.parse_array_dimensions(true)?,
name_span,
type_span,
})
@@ -300,7 +301,8 @@ impl Parser {
}
}
};
values.push(VarDeclStmtValue { name, name_span });
let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name, name_span, dimensions });
let mut last_name = true; // indicate whether the last parsed token is a variable name
while let Some(t) = self.peek() {
if matches!(t.value, TokenValue::Semicolon) { // statement end
@@ -319,7 +321,8 @@ impl Parser {
}
if let Some(ident) = self.peek().unwrap().value.as_ident() {
let span = self.next().unwrap().span;
values.push(VarDeclStmtValue { name: ident, name_span: span });
let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions });
last_name = true;
} else {
let token = self.next().unwrap().clone();
@@ -334,6 +337,50 @@ impl Parser {
Ok(VarDeclStmt { values, type_span, data_type: var_type.into() })
}
fn parse_array_dimensions(&mut self, allow_empty_first: bool) -> Result<Vec<ArrayDimension>, ParseProcessError> {
let mut dimensions = vec![];
while self.peek().is_some_and(|t| t.value == TokenValue::LBracket) {
let start_span = self.next().unwrap().span;
let value = if self.peek().is_some_and(|t| t.value == TokenValue::RBracket) {
if !allow_empty_first || !dimensions.is_empty() {
let span = self.peek().unwrap().span;
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(TokenValue::RBracket, "array dimension expression"),
span,
);
return Err(ParseProcessError::ErrorInMatch);
}
None
} else {
Some(self.parse_expr()?)
};
let end_span = match self.peek() {
Some(t) if t.value == TokenValue::RBracket => {
let span = t.span;
self.advance(1);
span
}
Some(_) => {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`]`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
None => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), start_span);
return Err(ParseProcessError::ErrorInMatch);
}
};
dimensions.push(ArrayDimension {
value,
span: Span::from_two(start_span, end_span),
});
}
Ok(dimensions)
}
fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result<BlockStmt, ParseProcessError> {
assert!(self.peek().is_some());
if self
@@ -598,7 +645,7 @@ impl Parser {
// }
// }
// }
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
fn parse_primary_atom(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let token = self.next().unwrap().clone();
match token.value {
@@ -712,6 +759,47 @@ impl Parser {
}
}
}
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
let mut expr = self.parse_primary_atom()?;
while self.peek().is_some_and(|t| t.value == TokenValue::LBracket) {
let start_span = expr.span;
self.advance(1);
let index = match self.peek() {
Some(_) => self.parse_expr()?,
None => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span);
return Err(ParseProcessError::ErrorInMatch);
}
};
let end_span = match self.peek() {
Some(t) if t.value == TokenValue::RBracket => {
let span = t.span;
self.advance(1);
span
}
Some(_) => {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`]`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
None => {
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.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),
};
}
Ok(expr)
}
fn parse_unary(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let token = self.peek().unwrap().clone();
@@ -937,40 +1025,21 @@ impl Parser {
}
fn parse_assign(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let is_assign = matches!(
(self.tokens.get(self.pos), self.tokens.get(self.pos + 1)),
(
Some(Token {
value: TokenValue::Ident(_),
..
}),
Some(Token {
value: TokenValue::Equal,
..
})
)
);
if !is_assign {
return self.parse_logical_or();
let lvalue = self.parse_logical_or()?;
if !self.peek().is_some_and(|t| t.value == TokenValue::Equal) {
return Ok(lvalue);
}
let lvalue_token = self.next().unwrap().clone();
let name = lvalue_token.value.as_ident().unwrap();
self.advance(1);
let rvalue = match self.peek() {
Some(_) => self.parse_assign()?,
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
lvalue_token.span,
lvalue.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
let lvalue = Expr {
value: ExprValue::Var(name),
span: lvalue_token.span,
};
let span = Span::from_two(lvalue.span, rvalue.span);
Ok(Expr {
value: ExprValue::Assign {
@@ -1100,4 +1169,8 @@ mod tests {
fn test_func() {
test_case("12-13,58-60");
}
#[test]
fn test_array() {
test_case("4-7,11,42,71,74-78,82,84,86,90,95,96,100,101,103");
}
}