refactor(ast): Split parser to multiple file
This commit is contained in:
-1284
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,310 @@
|
|||||||
|
use crate::{
|
||||||
|
ast::types::{
|
||||||
|
ArrayDimension, CompileUnit, FuncDeclStmt, GlobalDeclStmt, Param, VarDeclStmt, VarDeclStmtValue,
|
||||||
|
},
|
||||||
|
diagnostic::span::Span,
|
||||||
|
lexer::{
|
||||||
|
err::ParseError,
|
||||||
|
types::{TokenValue, TypeIdent},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{ParseProcessError, ParseType, Parser};
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub(super) fn parse_compile_unit(&mut self) -> CompileUnit {
|
||||||
|
let mut global_decls = vec![];
|
||||||
|
while !self.is_eof() {
|
||||||
|
if let Some(decl) = self.parse_global_decl_stmt() {
|
||||||
|
global_decls.push(decl);
|
||||||
|
} else {
|
||||||
|
self.until_next_token(&[TokenValue::Semicolon, TokenValue::RBrace]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CompileUnit { global_decls }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_global_decl_stmt(&mut self) -> Option<GlobalDeclStmt> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
match self.parse_func_decl_stmt() {
|
||||||
|
Ok(func_decl) => return Some(GlobalDeclStmt::FuncDecl(func_decl)),
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => {
|
||||||
|
return None
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
match self.parse_var_decl_stmt(ParseType::MustParse) {
|
||||||
|
Ok(var_decl) => return Some(GlobalDeclStmt::VarDecl(var_decl)),
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => {
|
||||||
|
return None
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
let token = self.next().clone();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, "ident"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
// fn until_next_stmt(&mut self) {
|
||||||
|
// // skip tokens until we find a semicolon or a right brace, which may indicate the end of the declaration
|
||||||
|
// while let Some(t) = self.peek() {
|
||||||
|
// if matches!(t.value, TokenValue::Semicolon | TokenValue::RBrace) {
|
||||||
|
// self.advance(1);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// self.advance(1);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
fn parse_type_and_name(&mut self, parse_type: ParseType) -> Result<(TypeIdent, String, Span, Span), ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let type_token = self.peek().clone();
|
||||||
|
let type_ident = match self.peek().value.as_type_ident() {
|
||||||
|
Some(ti) => ti,
|
||||||
|
None => {
|
||||||
|
if matches!(parse_type, ParseType::MustParse) {
|
||||||
|
let token = self.next().clone();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, "type ident"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
return Err(ParseProcessError::TryNext);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let type_span = type_token.span;
|
||||||
|
self.advance(1);
|
||||||
|
let name = match self.peek().value.as_ident() {
|
||||||
|
None if self.is_eof() => {
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::ExpectButEof("ident"),
|
||||||
|
type_span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
let next_span = self.peek().span;
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::CantCombineWith(type_token.value),
|
||||||
|
next_span
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
Some(ident) => ident,
|
||||||
|
};
|
||||||
|
let name_span = self.peek().span;
|
||||||
|
self.advance(1);
|
||||||
|
Ok((type_ident, name, type_span, name_span))
|
||||||
|
}
|
||||||
|
fn parse_func_decl_stmt(&mut self) -> Result<FuncDeclStmt, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let (return_type, name, ret_type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?;
|
||||||
|
if matches!(self.peek().value, TokenValue::LParen) {
|
||||||
|
} else {
|
||||||
|
self.back(2);
|
||||||
|
return Err(ParseProcessError::TryNext);
|
||||||
|
}
|
||||||
|
// from here we can be sure it's a function declaration, so we can report error if the syntax is wrong
|
||||||
|
let params = self.parse_param_list()?;
|
||||||
|
let body = if self.is_eof() {
|
||||||
|
let span = self.next().span;
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("function body"), span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_block_stmt(ParseType::MustParse)?
|
||||||
|
};
|
||||||
|
Ok(FuncDeclStmt {
|
||||||
|
return_type: return_type.into(),
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
body,
|
||||||
|
ret_type_span,
|
||||||
|
name_span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn parse_param_list(&mut self) -> Result<Vec<Param>, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
if self.peek().value != TokenValue::LParen {
|
||||||
|
let token = self.next().clone();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, "`(`"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
self.advance(1);
|
||||||
|
let mut params = vec![];
|
||||||
|
let mut last_is_var = false;
|
||||||
|
while !self.is_eof() {
|
||||||
|
if self.peek().value == TokenValue::RParen {
|
||||||
|
self.advance(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if last_is_var {
|
||||||
|
self.must_match_token(&TokenValue::Comma, "`,` or `)`")
|
||||||
|
.inspect_err(|_| self.until_next_token(&[TokenValue::RBrace]))?;
|
||||||
|
}
|
||||||
|
match self.parse_param() {
|
||||||
|
Ok(param) => {
|
||||||
|
params.push(param);
|
||||||
|
last_is_var = true;
|
||||||
|
}
|
||||||
|
Err(_e) => {
|
||||||
|
self.until_next_token(&[TokenValue::RParen]);
|
||||||
|
if self.last().value == TokenValue::RParen {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(params)
|
||||||
|
}
|
||||||
|
fn parse_param(&mut self) -> Result<Param, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let (param_type, name, type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?;
|
||||||
|
Ok(Param {
|
||||||
|
param_type: param_type.into(),
|
||||||
|
name,
|
||||||
|
dimensions: self.parse_array_dimensions(true)?,
|
||||||
|
name_span,
|
||||||
|
type_span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// fn must_match_semicolon(&mut self) -> Option<()> {
|
||||||
|
// if self
|
||||||
|
// .peek()
|
||||||
|
// .is_some_and(|t| matches!(t.value, TokenValue::Semicolon))
|
||||||
|
// {
|
||||||
|
// self.advance(1);
|
||||||
|
// Some(())
|
||||||
|
// } else {
|
||||||
|
// let token = self.next().clone();
|
||||||
|
// self.diagnostics
|
||||||
|
// .add_from_frontend_error(ParseError::UnexpectedToken(token.value, "`;`"), token.span);
|
||||||
|
// while let Some(t) = self.peek() {
|
||||||
|
// if matches!(t.value, TokenValue::Semicolon) {
|
||||||
|
// self.advance(1);
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// if matches!(t.value, TokenValue::RBrace) {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// self.advance(1);
|
||||||
|
// }
|
||||||
|
// None
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
pub(super) fn parse_var_decl_stmt(&mut self, parse_type: ParseType) -> Result<VarDeclStmt, ParseProcessError> {
|
||||||
|
self.parse_var_decl_stmt_inner(parse_type, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) 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) {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(_e) => {
|
||||||
|
if matches!(parse_type, ParseType::TryParse) {
|
||||||
|
return Err(ParseProcessError::TryNext);
|
||||||
|
} else {
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let dimensions = self.parse_array_dimensions(false)?;
|
||||||
|
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
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if last_name { // expect a comma after a variable name
|
||||||
|
self.must_match_token(&TokenValue::Comma, "`,` or `;`")?;
|
||||||
|
last_name = false;
|
||||||
|
}
|
||||||
|
// check eof again
|
||||||
|
if self.is_eof() {
|
||||||
|
let span = self.last().span;
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("`,` or `;`"), span);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if let Some(ident) = self.peek().value.as_ident() {
|
||||||
|
let span = self.next().span;
|
||||||
|
let dimensions = self.parse_array_dimensions(false)?;
|
||||||
|
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();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::CantCombineWith(TokenValue::TypeIdent(var_type)),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if consume_semicolon {
|
||||||
|
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||||
|
}
|
||||||
|
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().value == TokenValue::LBracket {
|
||||||
|
let start_span = self.next().span;
|
||||||
|
let value = if self.peek().value == TokenValue::RBracket {
|
||||||
|
if !allow_empty_first || !dimensions.is_empty() {
|
||||||
|
let span = self.peek().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().value {
|
||||||
|
TokenValue::RBracket => {
|
||||||
|
let span = self.peek().span;
|
||||||
|
self.advance(1);
|
||||||
|
span
|
||||||
|
}
|
||||||
|
TokenValue::Eof => {
|
||||||
|
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), start_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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
dimensions.push(ArrayDimension {
|
||||||
|
value,
|
||||||
|
span: Span::from_two(start_span, end_span),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(dimensions)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,486 @@
|
|||||||
|
use crate::{
|
||||||
|
ast::types::{BinaryOp, Expr, ExprValue, IncDecOp, UnaryOp},
|
||||||
|
diagnostic::span::Span,
|
||||||
|
lexer::{
|
||||||
|
err::ParseError,
|
||||||
|
types::TokenValue,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{ParseProcessError, Parser};
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
// fn parse_expr_tail(&mut self, left: Expr) -> Option<Expr> {
|
||||||
|
// match self.peek() {
|
||||||
|
// None => Some(left),
|
||||||
|
// Some(t1) => {
|
||||||
|
// // TODO: add delimiter judge to support better error recovery
|
||||||
|
// let op = BinaryOp::from_token_value(&t1.value)?;
|
||||||
|
// match op {
|
||||||
|
// BinaryOp::Add
|
||||||
|
// }
|
||||||
|
// let right = self.parse_term()?;
|
||||||
|
// let expr = Expr { value: ExprValue::BinaryOp { lhs: Box::new(left), op, rhs: Box::new(right) }, span: Span::from_two(left.span, right.span) };
|
||||||
|
// self.parse_expr_tail(expr)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
fn parse_primary_atom(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let token = self.next().clone();
|
||||||
|
match token.value {
|
||||||
|
TokenValue::Ident(name) => {
|
||||||
|
if matches!(self.peek().value, TokenValue::LParen) {
|
||||||
|
self.advance(1);
|
||||||
|
let mut args = vec![];
|
||||||
|
loop {
|
||||||
|
match &self.peek().value {
|
||||||
|
TokenValue::RParen => {
|
||||||
|
let end_span = self.peek().span;
|
||||||
|
self.advance(1);
|
||||||
|
return Ok(Expr {
|
||||||
|
value: ExprValue::FuncCall(name, args),
|
||||||
|
span: Span::from_two(token.span, end_span),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TokenValue::Eof => {
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::ExpectButEof("`)`"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
args.push(self.parse_expr()?);
|
||||||
|
match &self.peek().value {
|
||||||
|
TokenValue::Comma => {
|
||||||
|
self.advance(1);
|
||||||
|
}
|
||||||
|
TokenValue::RParen => {
|
||||||
|
let end_span = self.peek().span;
|
||||||
|
self.advance(1);
|
||||||
|
return Ok(Expr {
|
||||||
|
value: ExprValue::FuncCall(name, args),
|
||||||
|
span: Span::from_two(token.span, end_span),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TokenValue::Eof => {
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::ExpectButEof("`)`"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let token = self.next();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, "`,` or `)`"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Expr {
|
||||||
|
value: ExprValue::Var(name),
|
||||||
|
span: token.span,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
TokenValue::IntLit(value) => Ok(Expr {
|
||||||
|
value: ExprValue::IntLit(value),
|
||||||
|
span: token.span,
|
||||||
|
}),
|
||||||
|
TokenValue::LParen => {
|
||||||
|
let expr = if self.is_eof() {
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::ExpectButEof("expression"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_expr()?
|
||||||
|
};
|
||||||
|
match &self.peek().value {
|
||||||
|
TokenValue::RParen => {
|
||||||
|
let end_span = self.peek().span;
|
||||||
|
self.advance(1);
|
||||||
|
Ok(Expr {
|
||||||
|
span: Span::from_two(token.span, end_span),
|
||||||
|
..expr
|
||||||
|
})
|
||||||
|
}
|
||||||
|
TokenValue::Eof => {
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("`)`"), expr.span);
|
||||||
|
Err(ParseProcessError::ErrorInMatch)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let token = self.next();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, "`)`"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
Err(ParseProcessError::ErrorInMatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, "expression"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
Err(ParseProcessError::ErrorInMatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
let mut expr = self.parse_primary_atom()?;
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
fn parse_unary(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
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(
|
||||||
|
ParseError::ExpectButEof("expression"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_unary()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(token.span, expr.span);
|
||||||
|
Ok(Expr {
|
||||||
|
value: ExprValue::UnaryOp {
|
||||||
|
op: UnaryOp::Add,
|
||||||
|
operand: Box::new(expr),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
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(
|
||||||
|
ParseError::ExpectButEof("expression"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_unary()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(token.span, rhs.span);
|
||||||
|
Ok(Expr {
|
||||||
|
value: ExprValue::UnaryOp {
|
||||||
|
op: UnaryOp::Sub,
|
||||||
|
operand: Box::new(rhs),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
TokenValue::Not => {
|
||||||
|
self.advance(1);
|
||||||
|
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);
|
||||||
|
Ok(Expr {
|
||||||
|
value: ExprValue::UnaryOp {
|
||||||
|
op: UnaryOp::Not,
|
||||||
|
operand: Box::new(rhs),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => self.parse_primary(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn parse_multiplicative(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let mut left = self.parse_unary()?;
|
||||||
|
while !self.is_eof() {
|
||||||
|
let op = match self.peek().value {
|
||||||
|
TokenValue::Star => BinaryOp::Mul,
|
||||||
|
TokenValue::Slash => BinaryOp::Div,
|
||||||
|
TokenValue::Percent => BinaryOp::Mod,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
self.advance(1);
|
||||||
|
let right = if self.is_eof() {
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_unary()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(left.span, right.span);
|
||||||
|
left = Expr {
|
||||||
|
value: ExprValue::BinaryOp {
|
||||||
|
lhs: Box::new(left),
|
||||||
|
op,
|
||||||
|
rhs: Box::new(right),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(left)
|
||||||
|
}
|
||||||
|
fn parse_additive(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let mut left = self.parse_multiplicative()?;
|
||||||
|
while !self.is_eof() {
|
||||||
|
let op = match self.peek().value {
|
||||||
|
TokenValue::Plus => BinaryOp::Add,
|
||||||
|
TokenValue::Minus => BinaryOp::Sub,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
self.advance(1);
|
||||||
|
let right = if self.is_eof() {
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_multiplicative()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(left.span, right.span);
|
||||||
|
left = Expr {
|
||||||
|
value: ExprValue::BinaryOp {
|
||||||
|
lhs: Box::new(left),
|
||||||
|
op,
|
||||||
|
rhs: Box::new(right),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(left)
|
||||||
|
}
|
||||||
|
fn parse_relational(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let mut left = self.parse_additive()?;
|
||||||
|
while !self.is_eof() {
|
||||||
|
let op = match self.peek().value {
|
||||||
|
TokenValue::Less => BinaryOp::Less,
|
||||||
|
TokenValue::Greater => BinaryOp::Greater,
|
||||||
|
TokenValue::LessEqual => BinaryOp::LessEqual,
|
||||||
|
TokenValue::GreaterEqual => BinaryOp::GreaterEqual,
|
||||||
|
TokenValue::DoubleEqual => BinaryOp::Equal,
|
||||||
|
TokenValue::NotEqual => BinaryOp::NotEqual,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
self.advance(1);
|
||||||
|
let right = if self.is_eof() {
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_additive()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(left.span, right.span);
|
||||||
|
left = Expr {
|
||||||
|
value: ExprValue::BinaryOp {
|
||||||
|
lhs: Box::new(left),
|
||||||
|
op,
|
||||||
|
rhs: Box::new(right),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(left)
|
||||||
|
}
|
||||||
|
fn parse_logical_and(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let mut left = self.parse_relational()?;
|
||||||
|
while !self.is_eof() {
|
||||||
|
let op = match self.peek().value {
|
||||||
|
TokenValue::And => BinaryOp::And,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
self.advance(1);
|
||||||
|
let right = if self.is_eof() {
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_relational()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(left.span, right.span);
|
||||||
|
left = Expr {
|
||||||
|
value: ExprValue::BinaryOp {
|
||||||
|
lhs: Box::new(left),
|
||||||
|
op,
|
||||||
|
rhs: Box::new(right),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(left)
|
||||||
|
}
|
||||||
|
fn parse_logical_or(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let mut left = self.parse_logical_and()?;
|
||||||
|
while !self.is_eof() {
|
||||||
|
let op = match self.peek().value {
|
||||||
|
TokenValue::Or => BinaryOp::Or,
|
||||||
|
_ => break,
|
||||||
|
};
|
||||||
|
self.advance(1);
|
||||||
|
let right = if self.is_eof() {
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_logical_and()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(left.span, right.span);
|
||||||
|
left = Expr {
|
||||||
|
value: ExprValue::BinaryOp {
|
||||||
|
lhs: Box::new(left),
|
||||||
|
op,
|
||||||
|
rhs: Box::new(right),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(left)
|
||||||
|
}
|
||||||
|
fn parse_assign(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let lvalue = self.parse_logical_or()?;
|
||||||
|
if self.peek().value != TokenValue::Equal {
|
||||||
|
return Ok(lvalue);
|
||||||
|
}
|
||||||
|
self.advance(1);
|
||||||
|
let rvalue = if self.is_eof() {
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::ExpectButEof("expression"),
|
||||||
|
lvalue.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
} else {
|
||||||
|
self.parse_assign()?
|
||||||
|
};
|
||||||
|
let span = Span::from_two(lvalue.span, rvalue.span);
|
||||||
|
Ok(Expr {
|
||||||
|
value: ExprValue::Assign {
|
||||||
|
lvalue: Box::new(lvalue),
|
||||||
|
rvalue: Box::new(rvalue),
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub(super) fn parse_expr(&mut self) -> Result<Expr, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
self.parse_assign()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
use crate::{
|
||||||
|
ast::types::CompileUnit,
|
||||||
|
diagnostic::{Diagnositics, span::Span},
|
||||||
|
lexer::{
|
||||||
|
err::ParseError,
|
||||||
|
types::{Token, TokenValue},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod decl;
|
||||||
|
mod expr;
|
||||||
|
mod stmt;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
|
pub struct Parser {
|
||||||
|
tokens: Vec<Token>,
|
||||||
|
eof_token: Token,
|
||||||
|
pub diagnostics: Diagnositics,
|
||||||
|
pos: usize,
|
||||||
|
}
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum ParseType {
|
||||||
|
MustParse,
|
||||||
|
TryParse,
|
||||||
|
}
|
||||||
|
enum ParseProcessError {
|
||||||
|
TryNext,
|
||||||
|
ErrorInMatch
|
||||||
|
}
|
||||||
|
impl Parser {
|
||||||
|
pub fn new(tokens: Vec<Token>, diagnostics: Diagnositics) -> Self {
|
||||||
|
let eof_pos = tokens.last().map_or(0, |token| token.span.end);
|
||||||
|
Self {
|
||||||
|
tokens,
|
||||||
|
eof_token: Token {
|
||||||
|
value: TokenValue::Eof,
|
||||||
|
span: Span {
|
||||||
|
start: eof_pos,
|
||||||
|
end: eof_pos,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
diagnostics,
|
||||||
|
pos: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn parse(&mut self) -> CompileUnit {
|
||||||
|
self.parse_compile_unit()
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
self.pos += 1;
|
||||||
|
}
|
||||||
|
token
|
||||||
|
}
|
||||||
|
fn advance(&mut self, n: usize) {
|
||||||
|
self.pos += n;
|
||||||
|
assert!(self.pos <= self.tokens.len());
|
||||||
|
}
|
||||||
|
fn back(&mut self, n: usize) {
|
||||||
|
assert!(self.pos >= n);
|
||||||
|
self.pos -= n;
|
||||||
|
}
|
||||||
|
fn last(&self) -> &Token {
|
||||||
|
if self.pos == 0 {
|
||||||
|
&self.eof_token
|
||||||
|
} else {
|
||||||
|
self.tokens.get(self.pos - 1).unwrap_or(&self.eof_token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn is_eof(&self) -> bool {
|
||||||
|
matches!(self.peek().value, TokenValue::Eof)
|
||||||
|
}
|
||||||
|
fn must_match_token(&mut self, expected: &TokenValue, diagnostic_text: &'static str) -> Result<(), ParseProcessError> {
|
||||||
|
if &self.peek().value == expected {
|
||||||
|
self.advance(1);
|
||||||
|
Ok(())
|
||||||
|
} else if self.is_eof() {
|
||||||
|
let span = self.peek().span;
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span);
|
||||||
|
Err(ParseProcessError::ErrorInMatch)
|
||||||
|
} else {
|
||||||
|
let token = self.next();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, diagnostic_text),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
Err(ParseProcessError::ErrorInMatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn must_have_some(&mut self, diagnostic_text: &'static str) -> Result<(), ParseProcessError> {
|
||||||
|
if self.is_eof() {
|
||||||
|
let span = self.last().span;
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}
|
||||||
|
fn until_next_token(&mut self, expected: &[TokenValue]) {
|
||||||
|
while !self.is_eof() {
|
||||||
|
if expected.contains(&self.peek().value) {
|
||||||
|
self.advance(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.advance(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
use crate::{
|
||||||
|
ast::types::{
|
||||||
|
BlockStmt, BreakStmt, ContinueStmt, ForInit, ForStmt, IfElseBranch, IfStmt, ReturnStmt,
|
||||||
|
Statement, WhileStmt,
|
||||||
|
},
|
||||||
|
lexer::{
|
||||||
|
err::ParseError,
|
||||||
|
types::TokenValue,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{ParseProcessError, ParseType, Parser};
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub(super) fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result<BlockStmt, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
if self.peek().value != TokenValue::LBrace {
|
||||||
|
if parse_type == ParseType::MustParse {
|
||||||
|
let token = self.next().clone();
|
||||||
|
self.diagnostics.add_from_frontend_error(
|
||||||
|
ParseError::UnexpectedToken(token.value, "`{`"),
|
||||||
|
token.span,
|
||||||
|
);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
return Err(ParseProcessError::TryNext);
|
||||||
|
}
|
||||||
|
self.advance(1);
|
||||||
|
let mut statements = vec![];
|
||||||
|
// println!("parse block stmt");
|
||||||
|
loop {
|
||||||
|
if self.is_eof() {
|
||||||
|
let span = self.last().span;
|
||||||
|
self.diagnostics
|
||||||
|
.add_from_frontend_error(ParseError::ExpectButEof("`}`"), span);
|
||||||
|
return Err(ParseProcessError::ErrorInMatch);
|
||||||
|
}
|
||||||
|
if matches!(self.peek().value, TokenValue::Semicolon) {
|
||||||
|
// like a();;
|
||||||
|
self.advance(1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if matches!(self.peek().value, TokenValue::RBrace) {
|
||||||
|
self.advance(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// parse statement here
|
||||||
|
match self.parse_stmt() {
|
||||||
|
Ok(stmt) => statements.push(stmt),
|
||||||
|
Err(_) => {
|
||||||
|
self.until_next_token(&[TokenValue::Semicolon, TokenValue::RBrace]);
|
||||||
|
if self.last().value == TokenValue::RBrace {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// println!("finish parse block stmt");
|
||||||
|
Ok(BlockStmt {
|
||||||
|
statements
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
match self.parse_var_decl_stmt(ParseType::TryParse) {
|
||||||
|
Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||||
|
Err(_) => {},
|
||||||
|
};
|
||||||
|
match self.parse_return_stmt() {
|
||||||
|
Ok(return_stmt) => return Ok(Statement::Return(return_stmt)),
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||||
|
Err(_) => {},
|
||||||
|
};
|
||||||
|
match self.parse_if_stmt() {
|
||||||
|
Ok(if_stmt) => return Ok(Statement::If(if_stmt)),
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||||
|
Err(_) => {},
|
||||||
|
}
|
||||||
|
match self.parse_while_stmt() {
|
||||||
|
Ok(while_stmt) => return Ok(Statement::While(while_stmt)),
|
||||||
|
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),
|
||||||
|
Err(_) => {},
|
||||||
|
}
|
||||||
|
match self.parse_continue_stmt() {
|
||||||
|
Ok(continue_stmt) => return Ok(Statement::Continue(continue_stmt)),
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||||
|
Err(_) => {},
|
||||||
|
}
|
||||||
|
match self.parse_block_stmt(ParseType::TryParse) {
|
||||||
|
Ok(block_stmt) => return Ok(Statement::Block(block_stmt)),
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||||
|
Err(_) => {},
|
||||||
|
}
|
||||||
|
match self.parse_expr() {
|
||||||
|
Ok(expr) => {
|
||||||
|
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||||
|
return Ok(Statement::Expr(expr))
|
||||||
|
},
|
||||||
|
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||||
|
Err(_) => {},
|
||||||
|
}
|
||||||
|
self.until_next_token(&[TokenValue::Semicolon]);
|
||||||
|
Err(ParseProcessError::ErrorInMatch)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_return_stmt(&mut self) -> Result<ReturnStmt, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
if self.peek().value != TokenValue::Return {
|
||||||
|
return Err(ParseProcessError::TryNext);
|
||||||
|
}
|
||||||
|
let span = self.next().span;
|
||||||
|
let value = if matches!(self.peek().value, TokenValue::Semicolon) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.parse_expr()?)
|
||||||
|
};
|
||||||
|
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||||
|
Ok(ReturnStmt {
|
||||||
|
value,
|
||||||
|
span,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn parse_if_stmt(&mut self) -> Result<IfStmt, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
if self.peek().value != TokenValue::If {
|
||||||
|
return Err(ParseProcessError::TryNext);
|
||||||
|
}
|
||||||
|
self.advance(1);
|
||||||
|
self.must_match_token(&TokenValue::LParen, "`(`")?;
|
||||||
|
self.must_have_some("if condition expr")?;
|
||||||
|
let condition = self.parse_expr()?;
|
||||||
|
self.must_match_token(&TokenValue::RParen, "`)`")?;
|
||||||
|
let then_branch;
|
||||||
|
let mut ifelse_branch = vec![];
|
||||||
|
let mut else_branch = None;
|
||||||
|
self.must_have_some("if statement body")?;
|
||||||
|
if self.peek().value != TokenValue::LBrace {
|
||||||
|
let stmt = self.parse_stmt()?;
|
||||||
|
then_branch = BlockStmt { statements: vec![stmt] };
|
||||||
|
} else {
|
||||||
|
then_branch = self.parse_block_stmt(ParseType::MustParse)?;
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
if self.is_eof() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if self.peek().value == TokenValue::Else {
|
||||||
|
self.advance(1);
|
||||||
|
self.must_have_some("else body")?;
|
||||||
|
if self.peek().value != TokenValue::If {
|
||||||
|
self.back(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// else if
|
||||||
|
self.advance(1);
|
||||||
|
self.must_match_token(&TokenValue::LParen, "`(`")?;
|
||||||
|
self.must_have_some("else if condition expr")?;
|
||||||
|
let condition = self.parse_expr()?;
|
||||||
|
self.must_match_token(&TokenValue::RParen, "`)`")?;
|
||||||
|
let then_branch;
|
||||||
|
if self.peek().value != TokenValue::LBrace {
|
||||||
|
let stmt = self.parse_stmt()?;
|
||||||
|
then_branch = BlockStmt { statements: vec![stmt] };
|
||||||
|
} else {
|
||||||
|
then_branch = self.parse_block_stmt(ParseType::MustParse)?;
|
||||||
|
}
|
||||||
|
ifelse_branch.push(IfElseBranch { condition, then_branch });
|
||||||
|
} else {
|
||||||
|
// if end ?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.peek().value == TokenValue::Else {
|
||||||
|
// Parse else branch
|
||||||
|
self.advance(1);
|
||||||
|
self.must_have_some("else body")?;
|
||||||
|
if self.peek().value != TokenValue::LBrace {
|
||||||
|
let stmt = self.parse_stmt()?;
|
||||||
|
else_branch = Some(BlockStmt { statements: vec![stmt] });
|
||||||
|
} else {
|
||||||
|
else_branch = Some(self.parse_block_stmt(ParseType::MustParse)?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(IfStmt {
|
||||||
|
condition,
|
||||||
|
then_branch,
|
||||||
|
ifelse_branch,
|
||||||
|
else_branch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_while_stmt(&mut self) -> Result<WhileStmt, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
if self.peek().value != TokenValue::While {
|
||||||
|
return Err(ParseProcessError::TryNext);
|
||||||
|
}
|
||||||
|
self.advance(1);
|
||||||
|
self.must_match_token(&TokenValue::LParen, "`(`")?;
|
||||||
|
self.must_have_some("while condition expr")?;
|
||||||
|
let condition = 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(WhileStmt {
|
||||||
|
condition,
|
||||||
|
body,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if self.peek().value == TokenValue::Break {
|
||||||
|
self.advance(1);
|
||||||
|
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||||
|
Ok(BreakStmt {
|
||||||
|
span: start_span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ParseProcessError::TryNext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_continue_stmt(&mut self) -> Result<ContinueStmt, ParseProcessError> {
|
||||||
|
assert!(!self.is_eof());
|
||||||
|
let start_span = self.peek().span;
|
||||||
|
if self.peek().value == TokenValue::Continue {
|
||||||
|
self.advance(1);
|
||||||
|
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||||
|
Ok(ContinueStmt {
|
||||||
|
span: start_span,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(ParseProcessError::TryNext)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
use std::io::BufRead;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::fs::File;
|
||||||
|
use crate::ast::graph::AstGraphExt;
|
||||||
|
use crate::lexer::lexer::Lexer;
|
||||||
|
use crate::utils::case_list::CaseList;
|
||||||
|
use crate::utils::num_sequence::NumberSequence;
|
||||||
|
|
||||||
|
pub use super::*;
|
||||||
|
fn test_case(case_str: &str) {
|
||||||
|
let case_sequence = NumberSequence::from_str(case_str).unwrap();
|
||||||
|
let case_list = CaseList::from_dir(&Path::new("./testcases")).unwrap();
|
||||||
|
let mut error_case_cnt = 0;
|
||||||
|
for case_no in case_sequence {
|
||||||
|
let case_path = case_list.get_case_path(case_no).unwrap();
|
||||||
|
println!("{}", case_path.display());
|
||||||
|
let file = File::open(&case_path).unwrap();
|
||||||
|
let mut buf_reader = std::io::BufReader::new(file);
|
||||||
|
let mut lexer = Lexer::new();
|
||||||
|
let mut full_text = String::new();
|
||||||
|
loop {
|
||||||
|
let mut line = String::new();
|
||||||
|
let bytes_read = buf_reader.read_line(&mut line).unwrap();
|
||||||
|
if bytes_read == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
full_text.push_str(&line);
|
||||||
|
lexer.parse_next_str(&line);
|
||||||
|
}
|
||||||
|
let (tokens, diagnostics) = lexer.finish();
|
||||||
|
let mut is_error = false;
|
||||||
|
if !diagnostics.is_empty() {
|
||||||
|
diagnostics.print(&format!("{}", case_path.display()), &full_text);
|
||||||
|
is_error = true;
|
||||||
|
}
|
||||||
|
let mut parser = Parser::new(tokens, diagnostics);
|
||||||
|
let compile_unit = parser.parse_compile_unit();
|
||||||
|
let dot = compile_unit.to_dot();
|
||||||
|
let case_name = case_list.get_case_name(case_no).unwrap().strip_suffix(".c").unwrap();
|
||||||
|
std::fs::write(format!("output/{}.dot", case_name), dot).unwrap();
|
||||||
|
if !parser.diagnostics.is_empty() {
|
||||||
|
parser.diagnostics.print(&format!("{}", case_path.display()), &full_text);
|
||||||
|
is_error = true;
|
||||||
|
}
|
||||||
|
if is_error {
|
||||||
|
error_case_cnt += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if error_case_cnt > 0 {
|
||||||
|
panic!("Found {} cases with errors", error_case_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test_expr() {
|
||||||
|
test_case("0-3,14-25");
|
||||||
|
// test_case("0-3,14-25");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_if_while() {
|
||||||
|
test_case("26-32,34-41,46-51,57");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_error() {
|
||||||
|
test_case("999");
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
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