1
0

Add a new parser method to handle errors

This commit is contained in:
Jeff 2024-10-13 13:01:58 -04:00
parent 3609fddaea
commit 12d34d6354
2 changed files with 125 additions and 27 deletions

View File

@ -72,13 +72,14 @@ impl Chunk {
.ok_or(ChunkError::InstructionUnderflow { position })
}
pub fn get_last_instruction(&self) -> Result<(&Instruction, &Span), ChunkError> {
let (instruction, position) =
self.instructions
pub fn get_last_instruction(
&self,
position: Span,
) -> Result<(&Instruction, &Span), ChunkError> {
let (instruction, position) = self
.instructions
.last()
.ok_or_else(|| ChunkError::InstructionUnderflow {
position: Span(0, 0),
})?;
.ok_or_else(|| ChunkError::InstructionUnderflow { position })?;
Ok((instruction, position))
}
@ -107,8 +108,8 @@ impl Chunk {
})
}
pub fn get_last_operation(&self) -> Result<Operation, ChunkError> {
self.get_last_instruction()
pub fn get_last_operation(&self, position: Span) -> Result<Operation, ChunkError> {
self.get_last_instruction(position)
.map(|(instruction, _)| instruction.operation())
}

View File

@ -517,7 +517,7 @@ impl<'src> Parser<'src> {
]
};
while let Ok(operation) = self.chunk.get_last_operation() {
while let Ok(operation) = self.chunk.get_last_operation(operator_position) {
if operation.is_math() {
let (instruction, position) = self.chunk.pop_instruction(self.current_position)?;
@ -778,7 +778,7 @@ impl<'src> Parser<'src> {
self.parse_expression()?;
if let Operation::LoadConstant = self.chunk.get_last_operation()? {
if let Operation::LoadConstant = self.chunk.get_last_operation(self.current_position)? {
self.increment_register()?;
}
@ -831,7 +831,7 @@ impl<'src> Parser<'src> {
self.parse_block(block_allowed)?;
}
let last_operation = self.chunk.get_last_operation()?;
let last_operation = self.chunk.get_last_operation(self.current_position)?;
if let (Operation::LoadConstant | Operation::LoadBoolean, Token::Else) =
(last_operation, self.current_token)
@ -927,10 +927,16 @@ impl<'src> Parser<'src> {
}
}
let returned = self.chunk.get_last_operation()? == Operation::Return;
let end_of_statement = matches!(self.current_token, Token::Eof | Token::RightCurlyBrace);
let has_semicolon = self.allow(Token::Semicolon)?;
let returned = self.chunk.get_last_operation(self.current_position)? == Operation::Return;
if allowed.implicit_return && self.parsed_expression && !returned && !has_semicolon {
if allowed.implicit_return
&& self.parsed_expression
&& end_of_statement
&& !has_semicolon
&& !returned
{
self.emit_instruction(Instruction::r#return(true), self.current_position);
}
@ -1043,7 +1049,7 @@ impl<'src> Parser<'src> {
.declare_local(identifier, r#type, is_mutable, register, position)?;
self.emit_instruction(
Instruction::define_local(register, local_index, is_mutable),
Instruction::define_local(self.current_register - 1, local_index, is_mutable),
position,
);
@ -1143,7 +1149,7 @@ impl<'src> Parser<'src> {
}
fn parse_call(&mut self) -> Result<(), ParseError> {
let last_instruction = self.chunk.get_last_instruction()?.0;
let last_instruction = self.chunk.get_last_instruction(self.current_position)?.0;
if !last_instruction.is_expression() {
return Err(ParseError::ExpectedExpression {
@ -1178,10 +1184,73 @@ impl<'src> Parser<'src> {
Ok(())
}
fn expect_expression(&mut self, _: Allowed) -> Result<(), ParseError> {
match self.current_token {
Token::Boolean(_)
| Token::Byte(_)
| Token::Character(_)
| Token::Float(_)
| Token::Identifier(_)
| Token::Integer(_)
| Token::String(_)
| Token::Break
| Token::If
| Token::Return
| Token::Map
| Token::Loop
| Token::Struct
| Token::BangEqual
| Token::DoubleAmpersand
| Token::DoubleEqual
| Token::DoublePipe
| Token::Equal
| Token::Greater
| Token::GreaterEqual
| Token::LeftCurlyBrace
| Token::LeftParenthesis
| Token::LeftSquareBrace
| Token::Less
| Token::LessEqual
| Token::Minus
| Token::MinusEqual
| Token::Percent
| Token::PercentEqual
| Token::Plus
| Token::PlusEqual
| Token::Slash
| Token::SlashEqual
| Token::Star
| Token::StarEqual => Ok(()),
Token::Eof
| Token::Async
| Token::Bool
| Token::Else
| Token::FloatKeyword
| Token::Fn
| Token::Int
| Token::Let
| Token::Mut
| Token::Str
| Token::While
| Token::Bang
| Token::Colon
| Token::Comma
| Token::Dot
| Token::DoubleDot
| Token::RightCurlyBrace
| Token::RightParenthesis
| Token::RightSquareBrace
| Token::Semicolon => Err(ParseError::ExpectedExpression {
found: self.current_token.to_owned(),
position: self.current_position,
}),
}
}
fn parse(&mut self, precedence: Precedence, allowed: Allowed) -> Result<(), ParseError> {
if let Some(prefix_parser) = ParseRule::from(&self.current_token).prefix {
log::debug!(
"{} is {precedence} prefix",
"{} is prefix with precedence {precedence}",
self.current_token.to_string().bold(),
);
@ -1193,7 +1262,7 @@ impl<'src> Parser<'src> {
while precedence <= infix_rule.precedence {
if let Some(infix_parser) = infix_rule.infix {
log::debug!(
"{} is {precedence} infix",
"{} is infix with precedence {precedence}",
self.current_token.to_string().bold(),
);
@ -1294,7 +1363,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Equality,
},
Token::Bool => todo!(),
Token::Bool => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Boolean(_) => ParseRule {
prefix: Some(Parser::parse_boolean),
infix: None,
@ -1311,13 +1384,21 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: None,
precedence: Precedence::None,
},
Token::Colon => todo!(),
Token::Colon => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Comma => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::None,
},
Token::Dot => todo!(),
Token::Dot => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::DoubleAmpersand => ParseRule {
prefix: None,
infix: Some(Parser::parse_logical_binary),
@ -1333,7 +1414,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: Some(Parser::parse_logical_binary),
precedence: Precedence::LogicalOr,
},
Token::DoubleDot => todo!(),
Token::DoubleDot => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Eof => ParseRule {
prefix: None,
infix: None,
@ -1354,7 +1439,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: None,
precedence: Precedence::None,
},
Token::FloatKeyword => todo!(),
Token::FloatKeyword => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Fn => ParseRule {
prefix: Some(Parser::parse_function),
infix: None,
@ -1380,7 +1469,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: None,
precedence: Precedence::None,
},
Token::Int => todo!(),
Token::Int => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Integer(_) => ParseRule {
prefix: Some(Parser::parse_integer),
infix: None,
@ -1414,7 +1507,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
Token::Let => ParseRule {
prefix: Some(Parser::parse_let_statement),
infix: None,
precedence: Precedence::None,
precedence: Precedence::Assignment,
},
Token::Loop => todo!(),
Token::Map => todo!(),
@ -1474,7 +1567,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
precedence: Precedence::None,
},
Token::Semicolon => ParseRule {
prefix: None,
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
@ -1498,7 +1591,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: Some(Parser::parse_math_binary),
precedence: Precedence::Assignment,
},
Token::Str => todo!(),
Token::Str => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::String(_) => ParseRule {
prefix: Some(Parser::parse_string),
infix: None,