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 }) .ok_or(ChunkError::InstructionUnderflow { position })
} }
pub fn get_last_instruction(&self) -> Result<(&Instruction, &Span), ChunkError> { pub fn get_last_instruction(
let (instruction, position) = &self,
self.instructions position: Span,
) -> Result<(&Instruction, &Span), ChunkError> {
let (instruction, position) = self
.instructions
.last() .last()
.ok_or_else(|| ChunkError::InstructionUnderflow { .ok_or_else(|| ChunkError::InstructionUnderflow { position })?;
position: Span(0, 0),
})?;
Ok((instruction, position)) Ok((instruction, position))
} }
@ -107,8 +108,8 @@ impl Chunk {
}) })
} }
pub fn get_last_operation(&self) -> Result<Operation, ChunkError> { pub fn get_last_operation(&self, position: Span) -> Result<Operation, ChunkError> {
self.get_last_instruction() self.get_last_instruction(position)
.map(|(instruction, _)| instruction.operation()) .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() { if operation.is_math() {
let (instruction, position) = self.chunk.pop_instruction(self.current_position)?; let (instruction, position) = self.chunk.pop_instruction(self.current_position)?;
@ -778,7 +778,7 @@ impl<'src> Parser<'src> {
self.parse_expression()?; 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()?; self.increment_register()?;
} }
@ -831,7 +831,7 @@ impl<'src> Parser<'src> {
self.parse_block(block_allowed)?; 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) = if let (Operation::LoadConstant | Operation::LoadBoolean, Token::Else) =
(last_operation, self.current_token) (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 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); 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)?; .declare_local(identifier, r#type, is_mutable, register, position)?;
self.emit_instruction( self.emit_instruction(
Instruction::define_local(register, local_index, is_mutable), Instruction::define_local(self.current_register - 1, local_index, is_mutable),
position, position,
); );
@ -1143,7 +1149,7 @@ impl<'src> Parser<'src> {
} }
fn parse_call(&mut self) -> Result<(), ParseError> { 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() { if !last_instruction.is_expression() {
return Err(ParseError::ExpectedExpression { return Err(ParseError::ExpectedExpression {
@ -1178,10 +1184,73 @@ impl<'src> Parser<'src> {
Ok(()) 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> { fn parse(&mut self, precedence: Precedence, allowed: Allowed) -> Result<(), ParseError> {
if let Some(prefix_parser) = ParseRule::from(&self.current_token).prefix { if let Some(prefix_parser) = ParseRule::from(&self.current_token).prefix {
log::debug!( log::debug!(
"{} is {precedence} prefix", "{} is prefix with precedence {precedence}",
self.current_token.to_string().bold(), self.current_token.to_string().bold(),
); );
@ -1193,7 +1262,7 @@ impl<'src> Parser<'src> {
while precedence <= infix_rule.precedence { while precedence <= infix_rule.precedence {
if let Some(infix_parser) = infix_rule.infix { if let Some(infix_parser) = infix_rule.infix {
log::debug!( log::debug!(
"{} is {precedence} infix", "{} is infix with precedence {precedence}",
self.current_token.to_string().bold(), self.current_token.to_string().bold(),
); );
@ -1294,7 +1363,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: Some(Parser::parse_comparison_binary), infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Equality, precedence: Precedence::Equality,
}, },
Token::Bool => todo!(), Token::Bool => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Boolean(_) => ParseRule { Token::Boolean(_) => ParseRule {
prefix: Some(Parser::parse_boolean), prefix: Some(Parser::parse_boolean),
infix: None, infix: None,
@ -1311,13 +1384,21 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::None,
}, },
Token::Colon => todo!(), Token::Colon => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Comma => ParseRule { Token::Comma => ParseRule {
prefix: None, prefix: None,
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::None,
}, },
Token::Dot => todo!(), Token::Dot => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::DoubleAmpersand => ParseRule { Token::DoubleAmpersand => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_logical_binary), infix: Some(Parser::parse_logical_binary),
@ -1333,7 +1414,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: Some(Parser::parse_logical_binary), infix: Some(Parser::parse_logical_binary),
precedence: Precedence::LogicalOr, precedence: Precedence::LogicalOr,
}, },
Token::DoubleDot => todo!(), Token::DoubleDot => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Eof => ParseRule { Token::Eof => ParseRule {
prefix: None, prefix: None,
infix: None, infix: None,
@ -1354,7 +1439,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::None,
}, },
Token::FloatKeyword => todo!(), Token::FloatKeyword => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Fn => ParseRule { Token::Fn => ParseRule {
prefix: Some(Parser::parse_function), prefix: Some(Parser::parse_function),
infix: None, infix: None,
@ -1380,7 +1469,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::None,
}, },
Token::Int => todo!(), Token::Int => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::Integer(_) => ParseRule { Token::Integer(_) => ParseRule {
prefix: Some(Parser::parse_integer), prefix: Some(Parser::parse_integer),
infix: None, infix: None,
@ -1414,7 +1507,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
Token::Let => ParseRule { Token::Let => ParseRule {
prefix: Some(Parser::parse_let_statement), prefix: Some(Parser::parse_let_statement),
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::Assignment,
}, },
Token::Loop => todo!(), Token::Loop => todo!(),
Token::Map => todo!(), Token::Map => todo!(),
@ -1474,7 +1567,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
precedence: Precedence::None, precedence: Precedence::None,
}, },
Token::Semicolon => ParseRule { Token::Semicolon => ParseRule {
prefix: None, prefix: Some(Parser::expect_expression),
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::None,
}, },
@ -1498,7 +1591,11 @@ impl From<&Token<'_>> for ParseRule<'_> {
infix: Some(Parser::parse_math_binary), infix: Some(Parser::parse_math_binary),
precedence: Precedence::Assignment, precedence: Precedence::Assignment,
}, },
Token::Str => todo!(), Token::Str => ParseRule {
prefix: Some(Parser::expect_expression),
infix: None,
precedence: Precedence::None,
},
Token::String(_) => ParseRule { Token::String(_) => ParseRule {
prefix: Some(Parser::parse_string), prefix: Some(Parser::parse_string),
infix: None, infix: None,