feat(parser,ir,backend): Support array
This commit is contained in:
+100
-27
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user