Pass tests
This commit is contained in:
parent
71a4f863e3
commit
fd4ffeec7c
@ -498,7 +498,8 @@ impl AnnotatedError for ChunkError {
|
|||||||
ChunkError::IdentifierNotFound { identifier, .. } => {
|
ChunkError::IdentifierNotFound { identifier, .. } => {
|
||||||
Some(format!("Identifier: {}", identifier))
|
Some(format!("Identifier: {}", identifier))
|
||||||
}
|
}
|
||||||
_ => None,
|
ChunkError::IdentifierOverflow { .. } => Some("Identifier overflow".to_string()),
|
||||||
|
ChunkError::ConstantOverflow { .. } => Some("Constant overflow".to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,7 +509,10 @@ impl AnnotatedError for ChunkError {
|
|||||||
ChunkError::ConstantAlreadyUsed { position, .. } => *position,
|
ChunkError::ConstantAlreadyUsed { position, .. } => *position,
|
||||||
ChunkError::ConstantIndexOutOfBounds { position, .. } => *position,
|
ChunkError::ConstantIndexOutOfBounds { position, .. } => *position,
|
||||||
ChunkError::IdentifierNotFound { position, .. } => *position,
|
ChunkError::IdentifierNotFound { position, .. } => *position,
|
||||||
_ => todo!(),
|
ChunkError::InstructionUnderflow { position, .. } => *position,
|
||||||
|
ChunkError::LocalIndexOutOfBounds { position, .. } => *position,
|
||||||
|
ChunkError::IdentifierOverflow { position, .. } => *position,
|
||||||
|
ChunkError::ConstantOverflow { position, .. } => *position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,12 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
fn parse_grouped(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
|
fn parse_grouped(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
self.expect(TokenKind::RightParenthesis)
|
|
||||||
|
if self.previous_token == Token::RightParenthesis {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
self.expect(TokenKind::RightParenthesis)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
|
fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
|
||||||
@ -249,9 +254,41 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_binary(&mut self) -> Result<(), ParseError> {
|
fn parse_binary(&mut self) -> Result<(), ParseError> {
|
||||||
|
let operator_position = self.previous_position;
|
||||||
|
let operator = self.previous_token.kind();
|
||||||
|
let rule = ParseRule::from(&operator);
|
||||||
|
|
||||||
|
self.parse(rule.precedence.increment())?;
|
||||||
|
|
||||||
|
let (right_instruction, right_position) =
|
||||||
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
|
let mut push_back_right = false;
|
||||||
|
let mut right_is_constant = false;
|
||||||
|
let right = match right_instruction.operation() {
|
||||||
|
Operation::LoadConstant => {
|
||||||
|
right_is_constant = true;
|
||||||
|
|
||||||
|
self.decrement_register()?;
|
||||||
|
right_instruction.first_argument()
|
||||||
|
}
|
||||||
|
Operation::GetLocal => {
|
||||||
|
self.decrement_register()?;
|
||||||
|
right_instruction.first_argument()
|
||||||
|
}
|
||||||
|
operation if operation.is_binary() => {
|
||||||
|
push_back_right = true;
|
||||||
|
|
||||||
|
self.current_register - 2
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
push_back_right = true;
|
||||||
|
|
||||||
|
self.current_register - 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let (left_instruction, left_position) =
|
let (left_instruction, left_position) =
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
self.chunk.pop_instruction(self.current_position)?;
|
||||||
|
|
||||||
let mut push_back_left = false;
|
let mut push_back_left = false;
|
||||||
let mut left_is_constant = false;
|
let mut left_is_constant = false;
|
||||||
let left = match left_instruction.operation() {
|
let left = match left_instruction.operation() {
|
||||||
@ -272,48 +309,17 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if push_back_left {
|
let destination = if left_is_constant && right_is_constant {
|
||||||
self.emit_instruction(left_instruction, left_position);
|
self.current_register.saturating_sub(1)
|
||||||
}
|
} else {
|
||||||
|
self.current_register
|
||||||
let operator_position = self.previous_position;
|
|
||||||
let operator = self.previous_token.kind();
|
|
||||||
let rule = ParseRule::from(&operator);
|
|
||||||
|
|
||||||
self.parse(rule.precedence)?;
|
|
||||||
|
|
||||||
let (right_instruction, right_position) =
|
|
||||||
self.chunk.pop_instruction(self.current_position)?;
|
|
||||||
|
|
||||||
let mut push_back_right = false;
|
|
||||||
let mut right_is_constant = false;
|
|
||||||
let right = match right_instruction.operation() {
|
|
||||||
Operation::LoadConstant => {
|
|
||||||
right_is_constant = true;
|
|
||||||
|
|
||||||
self.decrement_register()?;
|
|
||||||
right_instruction.first_argument()
|
|
||||||
}
|
|
||||||
Operation::GetLocal => {
|
|
||||||
self.decrement_register()?;
|
|
||||||
right_instruction.first_argument()
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
push_back_right = true;
|
|
||||||
|
|
||||||
self.current_register - 1
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if push_back_right {
|
|
||||||
self.emit_instruction(right_instruction, right_position);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut instruction = match operator {
|
let mut instruction = match operator {
|
||||||
TokenKind::Plus => Instruction::add(self.current_register, left, right),
|
TokenKind::Plus => Instruction::add(destination, left, right),
|
||||||
TokenKind::Minus => Instruction::subtract(self.current_register, left, right),
|
TokenKind::Minus => Instruction::subtract(destination, left, right),
|
||||||
TokenKind::Star => Instruction::multiply(self.current_register, left, right),
|
TokenKind::Star => Instruction::multiply(destination, left, right),
|
||||||
TokenKind::Slash => Instruction::divide(self.current_register, left, right),
|
TokenKind::Slash => Instruction::divide(destination, left, right),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParseError::ExpectedTokenMultiple {
|
return Err(ParseError::ExpectedTokenMultiple {
|
||||||
expected: vec![
|
expected: vec![
|
||||||
@ -336,8 +342,16 @@ impl<'src> Parser<'src> {
|
|||||||
instruction.set_second_argument_to_constant();
|
instruction.set_second_argument_to_constant();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.increment_register()?;
|
if push_back_right {
|
||||||
|
self.emit_instruction(right_instruction, right_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
if push_back_left {
|
||||||
|
self.emit_instruction(left_instruction, left_position);
|
||||||
|
}
|
||||||
|
|
||||||
self.emit_instruction(instruction, operator_position);
|
self.emit_instruction(instruction, operator_position);
|
||||||
|
self.increment_register()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -457,7 +471,7 @@ impl<'src> Parser<'src> {
|
|||||||
(true, false)
|
(true, false)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let has_semicolon = self.allow(TokenKind::Semicolon)?;
|
let has_semicolon = self.previous_token == Token::Semicolon;
|
||||||
|
|
||||||
if is_expression_statement && !contains_block && !has_semicolon {
|
if is_expression_statement && !contains_block && !has_semicolon {
|
||||||
let end = self.previous_position.1;
|
let end = self.previous_position.1;
|
||||||
@ -524,8 +538,8 @@ impl<'src> Parser<'src> {
|
|||||||
prefix
|
prefix
|
||||||
} else {
|
} else {
|
||||||
return Err(ParseError::ExpectedExpression {
|
return Err(ParseError::ExpectedExpression {
|
||||||
found: self.previous_token.to_owned(),
|
found: self.current_token.to_owned(),
|
||||||
position: self.previous_position,
|
position: self.current_position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
let allow_assignment = precedence < Precedence::Assignment;
|
let allow_assignment = precedence < Precedence::Assignment;
|
||||||
@ -533,12 +547,10 @@ impl<'src> Parser<'src> {
|
|||||||
self.advance()?;
|
self.advance()?;
|
||||||
prefix_parser(self, allow_assignment)?;
|
prefix_parser(self, allow_assignment)?;
|
||||||
|
|
||||||
let mut infix_rule = ParseRule::from(&self.current_token.kind());
|
while precedence <= ParseRule::from(&self.current_token.kind()).precedence {
|
||||||
|
|
||||||
while precedence < infix_rule.precedence {
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
if let Some(infix_parser) = infix_rule.infix {
|
if let Some(infix_parser) = ParseRule::from(&self.previous_token.kind()).infix {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"Parsing {} as infix with precedence {precedence}",
|
"Parsing {} as infix with precedence {precedence}",
|
||||||
self.previous_token,
|
self.previous_token,
|
||||||
@ -555,8 +567,6 @@ impl<'src> Parser<'src> {
|
|||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
infix_rule = ParseRule::from(&self.current_token.kind());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -811,10 +821,10 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::UndefinedVariable { .. } => "Undefined variable",
|
Self::UndefinedVariable { .. } => "Undefined variable",
|
||||||
Self::RegisterOverflow { .. } => "Register overflow",
|
Self::RegisterOverflow { .. } => "Register overflow",
|
||||||
Self::RegisterUnderflow { .. } => "Register underflow",
|
Self::RegisterUnderflow { .. } => "Register underflow",
|
||||||
Self::Chunk { .. } => "Chunk error",
|
|
||||||
Self::Lex(_) => "Lex error",
|
|
||||||
Self::ParseFloatError { .. } => "Failed to parse float",
|
Self::ParseFloatError { .. } => "Failed to parse float",
|
||||||
Self::ParseIntError { .. } => "Failed to parse integer",
|
Self::ParseIntError { .. } => "Failed to parse integer",
|
||||||
|
Self::Chunk(error) => error.description(),
|
||||||
|
Self::Lex(error) => error.description(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,10 +845,10 @@ impl AnnotatedError for ParseError {
|
|||||||
}
|
}
|
||||||
Self::RegisterOverflow { .. } => None,
|
Self::RegisterOverflow { .. } => None,
|
||||||
Self::RegisterUnderflow { .. } => None,
|
Self::RegisterUnderflow { .. } => None,
|
||||||
Self::Chunk(error) => error.details(),
|
|
||||||
Self::Lex(error) => error.details(),
|
|
||||||
Self::ParseFloatError { error, .. } => Some(error.to_string()),
|
Self::ParseFloatError { error, .. } => Some(error.to_string()),
|
||||||
Self::ParseIntError { error, .. } => Some(error.to_string()),
|
Self::ParseIntError { error, .. } => Some(error.to_string()),
|
||||||
|
Self::Chunk(error) => error.details(),
|
||||||
|
Self::Lex(error) => error.details(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user