Parser - Refactored error handling
This commit is contained in:
parent
acb29e7123
commit
0443754007
1 changed files with 63 additions and 74 deletions
131
src/parser.rs
131
src/parser.rs
|
@ -2,7 +2,7 @@ use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast,
|
ast,
|
||||||
errors::{ErrorHandler, ParserError},
|
errors::{ErrorHandler, ErrorKind, SloxError, SloxResult},
|
||||||
tokens::{Token, TokenType},
|
tokens::{Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,9 +62,6 @@ impl FunctionKind {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The result of one of the parser's functions.
|
|
||||||
type ParserResult<T> = Result<T, ParserError>;
|
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
/// Initialize the parser.
|
/// Initialize the parser.
|
||||||
pub fn new(tokens: Vec<Token>) -> Self {
|
pub fn new(tokens: Vec<Token>) -> Self {
|
||||||
|
@ -120,7 +117,7 @@ impl Parser {
|
||||||
match self.parse_statement() {
|
match self.parse_statement() {
|
||||||
Ok(node) => stmts.push(node),
|
Ok(node) => stmts.push(node),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
err.report(err_hdl);
|
err_hdl.report(err);
|
||||||
self.synchronize()
|
self.synchronize()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,7 +143,7 @@ impl Parser {
|
||||||
/// statement := loop_control_statement
|
/// statement := loop_control_statement
|
||||||
/// statement := return_statement
|
/// statement := return_statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_statement(&mut self) -> SloxResult<ast::StmtNode> {
|
||||||
if self.expect(&[TokenType::Var]).is_some() {
|
if self.expect(&[TokenType::Var]).is_some() {
|
||||||
self.parse_var_declaration()
|
self.parse_var_declaration()
|
||||||
} else if self.expect(&[TokenType::Fun]).is_some() {
|
} else if self.expect(&[TokenType::Fun]).is_some() {
|
||||||
|
@ -184,7 +181,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// expression_stmt := expression ";"
|
/// expression_stmt := expression ";"
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_expression_stmt(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_expression_stmt(&mut self) -> SloxResult<ast::StmtNode> {
|
||||||
let expression = self.parse_expression()?;
|
let expression = self.parse_expression()?;
|
||||||
self.consume(&TokenType::Semicolon, "expected ';' after expression")?;
|
self.consume(&TokenType::Semicolon, "expected ';' after expression")?;
|
||||||
Ok(ast::StmtNode::Expression(expression))
|
Ok(ast::StmtNode::Expression(expression))
|
||||||
|
@ -195,10 +192,10 @@ impl Parser {
|
||||||
/// var_declaration := "var" IDENTIFIER ";"
|
/// var_declaration := "var" IDENTIFIER ";"
|
||||||
/// var_declaration := "var" IDENTIFIER "=" expression ";"
|
/// var_declaration := "var" IDENTIFIER "=" expression ";"
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_var_declaration(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_var_declaration(&mut self) -> SloxResult<ast::StmtNode> {
|
||||||
let name = match self.peek().token_type {
|
let name = match self.peek().token_type {
|
||||||
TokenType::Identifier(_) => self.advance().clone(),
|
TokenType::Identifier(_) => self.advance().clone(),
|
||||||
_ => return Err(ParserError::new(self.peek(), "expected variable name")),
|
_ => return self.error("expected variable name"),
|
||||||
};
|
};
|
||||||
let initializer: Option<ast::ExprNode> = match self.expect(&[TokenType::Equal]) {
|
let initializer: Option<ast::ExprNode> = match self.expect(&[TokenType::Equal]) {
|
||||||
Some(_) => Some(self.parse_expression()?),
|
Some(_) => Some(self.parse_expression()?),
|
||||||
|
@ -217,16 +214,11 @@ impl Parser {
|
||||||
/// function := IDENTIFIER function_info
|
/// function := IDENTIFIER function_info
|
||||||
/// ```
|
/// ```
|
||||||
/// The `kind` parameter is used to generate error messages.
|
/// The `kind` parameter is used to generate error messages.
|
||||||
fn parse_fun_declaration(&mut self, kind: FunctionKind) -> ParserResult<ast::StmtNode> {
|
fn parse_fun_declaration(&mut self, kind: FunctionKind) -> SloxResult<ast::StmtNode> {
|
||||||
// Read the name
|
// Read the name
|
||||||
let name = match self.peek().token_type {
|
let name = match self.peek().token_type {
|
||||||
TokenType::Identifier(_) => self.advance().clone(),
|
TokenType::Identifier(_) => self.advance().clone(),
|
||||||
_ => {
|
_ => return self.error_mv(format!("expected {} name", kind.name())),
|
||||||
return Err(ParserError::new(
|
|
||||||
self.peek(),
|
|
||||||
&format!("expected {} name", kind.name()),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let (params, block) = self.parse_function_info(kind)?;
|
let (params, block) = self.parse_function_info(kind)?;
|
||||||
Ok(ast::StmtNode::FunDecl {
|
Ok(ast::StmtNode::FunDecl {
|
||||||
|
@ -244,7 +236,7 @@ impl Parser {
|
||||||
fn parse_function_info(
|
fn parse_function_info(
|
||||||
&mut self,
|
&mut self,
|
||||||
kind: FunctionKind,
|
kind: FunctionKind,
|
||||||
) -> ParserResult<(Vec<Token>, Vec<ast::StmtNode>)> {
|
) -> SloxResult<(Vec<Token>, Vec<ast::StmtNode>)> {
|
||||||
// Read the list of parameter names
|
// Read the list of parameter names
|
||||||
self.consume(
|
self.consume(
|
||||||
&TokenType::LeftParen,
|
&TokenType::LeftParen,
|
||||||
|
@ -256,26 +248,20 @@ impl Parser {
|
||||||
let mut names: HashSet<String> = HashSet::new();
|
let mut names: HashSet<String> = HashSet::new();
|
||||||
loop {
|
loop {
|
||||||
if params.len() >= kind.max_params() {
|
if params.len() >= kind.max_params() {
|
||||||
return Err(ParserError::new(
|
return self.error_mv(format!(
|
||||||
self.peek(),
|
|
||||||
&format!(
|
|
||||||
"{} can't have more than {} parameters",
|
"{} can't have more than {} parameters",
|
||||||
kind.name(),
|
kind.name(),
|
||||||
kind.max_params()
|
kind.max_params()
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if let TokenType::Identifier(name) = &self.peek().token_type {
|
if let TokenType::Identifier(name) = &self.peek().token_type {
|
||||||
if names.contains(name) {
|
if names.contains(name) {
|
||||||
return Err(ParserError::new(
|
return self.error_mv(format!("duplicate {} parameter", kind.name()));
|
||||||
self.peek(),
|
|
||||||
&format!("duplicate {} parameter", kind.name()),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
names.insert(name.to_owned());
|
names.insert(name.to_owned());
|
||||||
params.push(self.advance().clone());
|
params.push(self.advance().clone());
|
||||||
} else {
|
} else {
|
||||||
return Err(ParserError::new(self.peek(), "parameter name expected"));
|
return self.error("parameter name expected");
|
||||||
}
|
}
|
||||||
if self.expect(&[TokenType::Comma]).is_none() {
|
if self.expect(&[TokenType::Comma]).is_none() {
|
||||||
break;
|
break;
|
||||||
|
@ -302,7 +288,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// block := "{" statement* "}"
|
/// block := "{" statement* "}"
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_block(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_block(&mut self) -> SloxResult<ast::StmtNode> {
|
||||||
let mut stmts: Vec<ast::StmtNode> = Vec::new();
|
let mut stmts: Vec<ast::StmtNode> = Vec::new();
|
||||||
while !(self.check(&TokenType::RightBrace) || self.is_at_end()) {
|
while !(self.check(&TokenType::RightBrace) || self.is_at_end()) {
|
||||||
stmts.push(self.parse_statement()?);
|
stmts.push(self.parse_statement()?);
|
||||||
|
@ -316,7 +302,7 @@ impl Parser {
|
||||||
/// if_statement := "if" "(" expression ")" statement
|
/// if_statement := "if" "(" expression ")" statement
|
||||||
/// if_statement := "if" "(" expression ")" statement "else" statement
|
/// if_statement := "if" "(" expression ")" statement "else" statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_if_statement(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_if_statement(&mut self) -> SloxResult<ast::StmtNode> {
|
||||||
self.consume(&TokenType::LeftParen, "expected '(' after 'if'")?;
|
self.consume(&TokenType::LeftParen, "expected '(' after 'if'")?;
|
||||||
let expression = self.parse_expression()?;
|
let expression = self.parse_expression()?;
|
||||||
self.consume(
|
self.consume(
|
||||||
|
@ -340,15 +326,10 @@ impl Parser {
|
||||||
/// labelled_loop := "@" IDENTIFIER while_statement
|
/// labelled_loop := "@" IDENTIFIER while_statement
|
||||||
/// labelled_loop := "@" IDENTIFIER for_statement
|
/// labelled_loop := "@" IDENTIFIER for_statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_labelled_loop(&mut self) -> ParserResult<ast::StmtNode> {
|
fn parse_labelled_loop(&mut self) -> SloxResult<ast::StmtNode> {
|
||||||
let name_token = match self.peek().token_type {
|
let name_token = match self.peek().token_type {
|
||||||
TokenType::Identifier(_) => self.advance().clone(),
|
TokenType::Identifier(_) => self.advance().clone(),
|
||||||
_ => {
|
_ => return self.error("identifier expected after '@'"),
|
||||||
return Err(ParserError::new(
|
|
||||||
self.peek(),
|
|
||||||
"identifier expected after '@'",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.expect(&[TokenType::While]).is_some() {
|
if self.expect(&[TokenType::While]).is_some() {
|
||||||
|
@ -356,10 +337,7 @@ impl Parser {
|
||||||
} else if self.expect(&[TokenType::For]).is_some() {
|
} else if self.expect(&[TokenType::For]).is_some() {
|
||||||
self.parse_for_statement(Some(name_token))
|
self.parse_for_statement(Some(name_token))
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::new(
|
self.error("'while' or 'for' expected after loop label")
|
||||||
self.peek(),
|
|
||||||
"'while' or 'for' expected after loop label",
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +345,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// while_statement := "while" "(" expression ")" statement
|
/// while_statement := "while" "(" expression ")" statement
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_while_statement(&mut self, label: Option<Token>) -> ParserResult<ast::StmtNode> {
|
fn parse_while_statement(&mut self, label: Option<Token>) -> SloxResult<ast::StmtNode> {
|
||||||
self.consume(&TokenType::LeftParen, "expected '(' after 'while'")?;
|
self.consume(&TokenType::LeftParen, "expected '(' after 'while'")?;
|
||||||
let condition = self.parse_expression()?;
|
let condition = self.parse_expression()?;
|
||||||
self.consume(
|
self.consume(
|
||||||
|
@ -395,7 +373,7 @@ impl Parser {
|
||||||
/// for_initializer := expression
|
/// for_initializer := expression
|
||||||
/// for_initializer :=
|
/// for_initializer :=
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_for_statement(&mut self, label: Option<Token>) -> ParserResult<ast::StmtNode> {
|
fn parse_for_statement(&mut self, label: Option<Token>) -> SloxResult<ast::StmtNode> {
|
||||||
self.consume(&TokenType::LeftParen, "expected '(' after 'for'")?;
|
self.consume(&TokenType::LeftParen, "expected '(' after 'for'")?;
|
||||||
|
|
||||||
let initializer = if self.expect(&[TokenType::Semicolon]).is_some() {
|
let initializer = if self.expect(&[TokenType::Semicolon]).is_some() {
|
||||||
|
@ -458,11 +436,12 @@ impl Parser {
|
||||||
/// loop_control_statement := "break" ( IDENTIFIER )? ";"
|
/// loop_control_statement := "break" ( IDENTIFIER )? ";"
|
||||||
/// loop_control_statement := "continue" ( IDENTIFIER )? ";"
|
/// loop_control_statement := "continue" ( IDENTIFIER )? ";"
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_loop_control_statement(&mut self, stmt_token: &Token) -> ParserResult<ast::StmtNode> {
|
fn parse_loop_control_statement(&mut self, stmt_token: &Token) -> SloxResult<ast::StmtNode> {
|
||||||
if self.loop_state() == &LoopParsingState::None {
|
if self.loop_state() == &LoopParsingState::None {
|
||||||
return Err(ParserError::new(
|
return Err(SloxError::with_token(
|
||||||
|
ErrorKind::Parse,
|
||||||
stmt_token,
|
stmt_token,
|
||||||
&format!(
|
format!(
|
||||||
"'{}' statement found outside of loop body",
|
"'{}' statement found outside of loop body",
|
||||||
stmt_token.lexeme
|
stmt_token.lexeme
|
||||||
),
|
),
|
||||||
|
@ -473,9 +452,10 @@ impl Parser {
|
||||||
let name_token = self.advance().clone();
|
let name_token = self.advance().clone();
|
||||||
if !self.find_named_loop(&name_token.lexeme) {
|
if !self.find_named_loop(&name_token.lexeme) {
|
||||||
self.expect(&[TokenType::Semicolon]);
|
self.expect(&[TokenType::Semicolon]);
|
||||||
return Err(ParserError::new(
|
return Err(SloxError::with_token(
|
||||||
|
ErrorKind::Parse,
|
||||||
&name_token,
|
&name_token,
|
||||||
&format!("no reachable loop named '{}'", name_token.lexeme),
|
format!("no reachable loop named '{}'", name_token.lexeme),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
Some(name_token)
|
Some(name_token)
|
||||||
|
@ -497,7 +477,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// return_statement := "return" expression? ";"
|
/// return_statement := "return" expression? ";"
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_return_statement(&mut self, ret_token: &Token) -> ParserResult<ast::StmtNode> {
|
fn parse_return_statement(&mut self, ret_token: &Token) -> SloxResult<ast::StmtNode> {
|
||||||
if self.can_use_return() {
|
if self.can_use_return() {
|
||||||
let value = if self.check(&TokenType::Semicolon) {
|
let value = if self.check(&TokenType::Semicolon) {
|
||||||
None
|
None
|
||||||
|
@ -510,9 +490,10 @@ impl Parser {
|
||||||
value,
|
value,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::new(
|
Err(SloxError::with_token(
|
||||||
|
ErrorKind::Parse,
|
||||||
ret_token,
|
ret_token,
|
||||||
"'return' found outside of function",
|
"'return' found outside of function".to_owned(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -521,7 +502,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// expression := assignment
|
/// expression := assignment
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_expression(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_expression(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
self.parse_assignment()
|
self.parse_assignment()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +511,7 @@ impl Parser {
|
||||||
/// assignment := IDENTIFIER "=" equality
|
/// assignment := IDENTIFIER "=" equality
|
||||||
/// assignment := equality
|
/// assignment := equality
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_assignment(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_assignment(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
let expr = self.parse_logic_or()?;
|
let expr = self.parse_logic_or()?;
|
||||||
if let Some(equals) = self.expect(&[TokenType::Equal]) {
|
if let Some(equals) = self.expect(&[TokenType::Equal]) {
|
||||||
let value = self.parse_assignment()?;
|
let value = self.parse_assignment()?;
|
||||||
|
@ -540,7 +521,7 @@ impl Parser {
|
||||||
value: Box::new(value),
|
value: Box::new(value),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::new(&equals, "invalid assignment target"))
|
self.error("invalid assignment target")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
|
@ -551,7 +532,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// logic_or := logic_and ( "or" logic_and )*
|
/// logic_or := logic_and ( "or" logic_and )*
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_logic_or(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_logic_or(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_logic_and()?;
|
let mut expr = self.parse_logic_and()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::Or]) {
|
while let Some(operator) = self.expect(&[TokenType::Or]) {
|
||||||
let right = self.parse_logic_and()?;
|
let right = self.parse_logic_and()?;
|
||||||
|
@ -568,7 +549,7 @@ impl Parser {
|
||||||
/// ```
|
/// ```
|
||||||
/// logic_and := equality ( "and" equality )*
|
/// logic_and := equality ( "and" equality )*
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_logic_and(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_logic_and(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_equality()?;
|
let mut expr = self.parse_equality()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::And]) {
|
while let Some(operator) = self.expect(&[TokenType::And]) {
|
||||||
let right = self.parse_equality()?;
|
let right = self.parse_equality()?;
|
||||||
|
@ -586,7 +567,7 @@ impl Parser {
|
||||||
/// equality := comparison "==" comparison
|
/// equality := comparison "==" comparison
|
||||||
/// equality := comparison "!=" comparison
|
/// equality := comparison "!=" comparison
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_equality(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_equality(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_comparison()?;
|
let mut expr = self.parse_comparison()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::BangEqual, TokenType::EqualEqual]) {
|
while let Some(operator) = self.expect(&[TokenType::BangEqual, TokenType::EqualEqual]) {
|
||||||
let right = self.parse_comparison()?;
|
let right = self.parse_comparison()?;
|
||||||
|
@ -604,7 +585,7 @@ impl Parser {
|
||||||
/// comparison := term comparison_operator term
|
/// comparison := term comparison_operator term
|
||||||
/// comparison_operator := "<" | "<=" | ">" | ">="
|
/// comparison_operator := "<" | "<=" | ">" | ">="
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_comparison(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_comparison(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_term()?;
|
let mut expr = self.parse_term()?;
|
||||||
while let Some(operator) = self.expect(&[
|
while let Some(operator) = self.expect(&[
|
||||||
TokenType::Greater,
|
TokenType::Greater,
|
||||||
|
@ -627,7 +608,7 @@ impl Parser {
|
||||||
/// term := factor ( "+" factor )*
|
/// term := factor ( "+" factor )*
|
||||||
/// term := factor ( "-" factor )*
|
/// term := factor ( "-" factor )*
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_term(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_term(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_factor()?;
|
let mut expr = self.parse_factor()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::Minus, TokenType::Plus]) {
|
while let Some(operator) = self.expect(&[TokenType::Minus, TokenType::Plus]) {
|
||||||
let right = self.parse_factor()?;
|
let right = self.parse_factor()?;
|
||||||
|
@ -645,7 +626,7 @@ impl Parser {
|
||||||
/// factor := unary ( "*" unary )*
|
/// factor := unary ( "*" unary )*
|
||||||
/// factor := unary ( "/" unary )*
|
/// factor := unary ( "/" unary )*
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_factor(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_factor(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
let mut expr = self.parse_unary()?;
|
let mut expr = self.parse_unary()?;
|
||||||
while let Some(operator) = self.expect(&[TokenType::Slash, TokenType::Star]) {
|
while let Some(operator) = self.expect(&[TokenType::Slash, TokenType::Star]) {
|
||||||
let right = self.parse_unary()?;
|
let right = self.parse_unary()?;
|
||||||
|
@ -664,7 +645,7 @@ impl Parser {
|
||||||
/// unary := "!" unary
|
/// unary := "!" unary
|
||||||
/// unary := primary call_arguments*
|
/// unary := primary call_arguments*
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_unary(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_unary(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
if let Some(operator) = self.expect(&[TokenType::Bang, TokenType::Minus]) {
|
if let Some(operator) = self.expect(&[TokenType::Bang, TokenType::Minus]) {
|
||||||
Ok(ast::ExprNode::Unary {
|
Ok(ast::ExprNode::Unary {
|
||||||
operator,
|
operator,
|
||||||
|
@ -686,7 +667,7 @@ impl Parser {
|
||||||
/// primary := IDENTIFIER
|
/// primary := IDENTIFIER
|
||||||
/// primary := "fun" function_info
|
/// primary := "fun" function_info
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_primary(&mut self) -> ParserResult<ast::ExprNode> {
|
fn parse_primary(&mut self) -> SloxResult<ast::ExprNode> {
|
||||||
if self.expect(&[TokenType::LeftParen]).is_some() {
|
if self.expect(&[TokenType::LeftParen]).is_some() {
|
||||||
let expr = self.parse_expression()?;
|
let expr = self.parse_expression()?;
|
||||||
self.consume(&TokenType::RightParen, "expected ')' after expression")?;
|
self.consume(&TokenType::RightParen, "expected ')' after expression")?;
|
||||||
|
@ -708,7 +689,7 @@ impl Parser {
|
||||||
TokenType::Identifier(_) => Ok(ast::ExprNode::Variable {
|
TokenType::Identifier(_) => Ok(ast::ExprNode::Variable {
|
||||||
name: self.advance().clone(),
|
name: self.advance().clone(),
|
||||||
}),
|
}),
|
||||||
_ => Err(ParserError::new(self.peek(), "expected expression")),
|
_ => self.error("expected expression"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -718,18 +699,12 @@ impl Parser {
|
||||||
/// call := expression "(" arguments? ")"
|
/// call := expression "(" arguments? ")"
|
||||||
/// arguments := expression ( "," expression )*
|
/// arguments := expression ( "," expression )*
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_call_arguments(
|
fn parse_call_arguments(&mut self, callee: ast::ExprNode) -> Result<ast::ExprNode, SloxError> {
|
||||||
&mut self,
|
|
||||||
callee: ast::ExprNode,
|
|
||||||
) -> Result<ast::ExprNode, ParserError> {
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
if !self.check(&TokenType::RightParen) {
|
if !self.check(&TokenType::RightParen) {
|
||||||
loop {
|
loop {
|
||||||
if arguments.len() == 255 {
|
if arguments.len() == 255 {
|
||||||
return Err(ParserError::new(
|
return self.error("functions may not have more than 255 arguments");
|
||||||
self.peek(),
|
|
||||||
"functions may not have more than 255 arguments",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
arguments.push(self.parse_expression()?);
|
arguments.push(self.parse_expression()?);
|
||||||
if self.expect(&[TokenType::Comma]).is_none() {
|
if self.expect(&[TokenType::Comma]).is_none() {
|
||||||
|
@ -764,11 +739,11 @@ impl Parser {
|
||||||
|
|
||||||
/// Consume a token of a given type. If no matching token is found, a
|
/// Consume a token of a given type. If no matching token is found, a
|
||||||
/// parse error is returned instead. Otherwise the read pointer is moved.
|
/// parse error is returned instead. Otherwise the read pointer is moved.
|
||||||
fn consume(&mut self, token_type: &TokenType, error: &str) -> ParserResult<&Token> {
|
fn consume(&mut self, token_type: &TokenType, error: &str) -> SloxResult<&Token> {
|
||||||
if self.check(token_type) {
|
if self.check(token_type) {
|
||||||
Ok(self.advance())
|
Ok(self.advance())
|
||||||
} else {
|
} else {
|
||||||
Err(ParserError::new(self.peek(), error))
|
self.error(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -841,4 +816,18 @@ impl Parser {
|
||||||
pos -= 1;
|
pos -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate an error at the current token.
|
||||||
|
fn error<O>(&self, message: &str) -> SloxResult<O> {
|
||||||
|
self.error_mv(message.to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate an error at the current token.
|
||||||
|
fn error_mv<O>(&self, message: String) -> SloxResult<O> {
|
||||||
|
Err(SloxError::with_token(
|
||||||
|
ErrorKind::Parse,
|
||||||
|
self.peek(),
|
||||||
|
message,
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue