Refactor parsing for better jumping and returns
This commit is contained in:
parent
1da61f0873
commit
648bbdbc4d
@ -25,6 +25,7 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
||||
implicit_return: true,
|
||||
})
|
||||
.map_err(|error| DustError::Parse { error, source })?;
|
||||
parser.commit_current_statement();
|
||||
}
|
||||
|
||||
Ok(parser.finish())
|
||||
@ -36,6 +37,7 @@ pub struct Parser<'src> {
|
||||
chunk: Chunk,
|
||||
|
||||
current_statement: Vec<(Instruction, Span)>,
|
||||
current_is_expression: bool,
|
||||
minimum_register: u8,
|
||||
|
||||
current_token: Token<'src>,
|
||||
@ -61,6 +63,7 @@ impl<'src> Parser<'src> {
|
||||
lexer,
|
||||
chunk: Chunk::new(None),
|
||||
current_statement: Vec::new(),
|
||||
current_is_expression: false,
|
||||
minimum_register: 0,
|
||||
current_token,
|
||||
current_position,
|
||||
@ -145,7 +148,9 @@ impl<'src> Parser<'src> {
|
||||
self.current_statement.push((instruction, position));
|
||||
}
|
||||
|
||||
fn commit_current_statement(&mut self) {
|
||||
fn commit_current_statement(&mut self) -> Result<(), ParseError> {
|
||||
self.parse_implicit_return()?;
|
||||
|
||||
let next_register = self.next_register();
|
||||
|
||||
for (instruction, position) in self.current_statement.drain(..) {
|
||||
@ -153,6 +158,9 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
|
||||
self.minimum_register = next_register;
|
||||
self.current_is_expression = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_statement_operations<const COUNT: usize>(&self) -> Option<[(Operation, Span); COUNT]> {
|
||||
@ -234,6 +242,8 @@ impl<'src> Parser<'src> {
|
||||
position,
|
||||
);
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ParseError::ExpectedToken {
|
||||
@ -256,6 +266,8 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ParseError::ExpectedToken {
|
||||
@ -276,6 +288,8 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ParseError::ExpectedToken {
|
||||
@ -302,6 +316,8 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ParseError::ExpectedToken {
|
||||
@ -328,6 +344,8 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ParseError::ExpectedToken {
|
||||
@ -348,6 +366,8 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.emit_constant(value, position)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ParseError::ExpectedToken {
|
||||
@ -363,6 +383,8 @@ impl<'src> Parser<'src> {
|
||||
self.parse_expression()?;
|
||||
self.expect(Token::RightParenthesis)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -419,6 +441,8 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.emit_instruction(instruction, operator_position);
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -559,7 +583,9 @@ impl<'src> Parser<'src> {
|
||||
| Token::SlashEqual
|
||||
| Token::PercentEqual = operator
|
||||
{
|
||||
self.commit_current_statement();
|
||||
self.current_is_expression = false;
|
||||
} else {
|
||||
self.current_is_expression = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -658,6 +684,8 @@ impl<'src> Parser<'src> {
|
||||
operator_position,
|
||||
);
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -695,6 +723,8 @@ impl<'src> Parser<'src> {
|
||||
self.emit_instruction(Instruction::jump(jump_to), operator_position);
|
||||
self.parse_sub_expression(&rule.precedence)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -721,6 +751,8 @@ impl<'src> Parser<'src> {
|
||||
start_position,
|
||||
)?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(ParseError::UndeclaredVariable {
|
||||
@ -792,6 +824,8 @@ impl<'src> Parser<'src> {
|
||||
Instruction::set_local(register, local_index),
|
||||
start_position,
|
||||
);
|
||||
|
||||
self.current_is_expression = false;
|
||||
} else {
|
||||
let register = self.next_register();
|
||||
|
||||
@ -799,6 +833,8 @@ impl<'src> Parser<'src> {
|
||||
Instruction::get_local(register, local_index),
|
||||
self.previous_position,
|
||||
);
|
||||
|
||||
self.current_is_expression = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -869,6 +905,8 @@ impl<'src> Parser<'src> {
|
||||
Span(start, end),
|
||||
);
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -892,33 +930,18 @@ impl<'src> Parser<'src> {
|
||||
|
||||
if let Token::LeftCurlyBrace = self.current_token {
|
||||
self.parse_block(block_allowed)?;
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::LeftCurlyBrace,
|
||||
found: self.current_token.to_owned(),
|
||||
position: self.current_position,
|
||||
});
|
||||
}
|
||||
|
||||
let if_end = self.chunk.len() + self.current_statement.len();
|
||||
let if_block_end = self.current_statement.len();
|
||||
|
||||
if let Some(if_jump) = self.get_last_jump_mut() {
|
||||
if_jump.set_b(if_end as u8);
|
||||
}
|
||||
|
||||
let last_operation = self
|
||||
.current_statement
|
||||
.last()
|
||||
.map(|(instruction, _)| instruction.operation());
|
||||
|
||||
if let (Some(Operation::LoadConstant) | Some(Operation::LoadBoolean), Token::Else) =
|
||||
(last_operation, self.current_token)
|
||||
{
|
||||
let (mut load_constant, load_constant_position) = self
|
||||
.current_statement
|
||||
.pop()
|
||||
.ok_or_else(|| ParseError::ExpectedExpression {
|
||||
found: self.previous_token.to_owned(),
|
||||
position: self.previous_position,
|
||||
})?;
|
||||
|
||||
load_constant.set_c_to_boolean(true);
|
||||
|
||||
self.emit_instruction(load_constant, load_constant_position);
|
||||
if_jump.set_b(if_block_end as u8);
|
||||
}
|
||||
|
||||
if self.allow(Token::Else)? {
|
||||
@ -928,23 +951,38 @@ impl<'src> Parser<'src> {
|
||||
|
||||
if let Token::LeftCurlyBrace = self.current_token {
|
||||
self.parse_block(block_allowed)?;
|
||||
self.commit_current_statement();
|
||||
|
||||
let else_end = (self.chunk.len() + self.current_statement.len()) as u8;
|
||||
let else_end = self.current_statement.len();
|
||||
|
||||
if let Operation::LoadBoolean | Operation::LoadConstant = self
|
||||
.chunk
|
||||
.get_instruction(if_end, self.current_position)
|
||||
.map(|(instruction, _)| instruction.operation())?
|
||||
{
|
||||
} else {
|
||||
self.chunk.insert_instruction(
|
||||
if_end,
|
||||
Instruction::jump(else_end + 1),
|
||||
if else_end - if_block_end > 1 {
|
||||
self.current_statement.insert(
|
||||
if_block_end,
|
||||
(
|
||||
Instruction::jump((else_end + 1) as u8),
|
||||
self.current_position,
|
||||
)?;
|
||||
),
|
||||
);
|
||||
} else {
|
||||
self.current_statement
|
||||
.iter_mut()
|
||||
.rev()
|
||||
.filter(|(instruction, _)| {
|
||||
matches!(
|
||||
instruction.operation(),
|
||||
Operation::LoadBoolean | Operation::LoadConstant
|
||||
)
|
||||
})
|
||||
.nth(1)
|
||||
.map(|(instruction, _)| instruction.set_c_to_boolean(true));
|
||||
}
|
||||
|
||||
self.current_is_expression = self
|
||||
.current_statement
|
||||
.last()
|
||||
.map_or(false, |(instruction, _)| instruction.yields_value());
|
||||
|
||||
self.commit_current_statement()?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -955,7 +993,10 @@ impl<'src> Parser<'src> {
|
||||
});
|
||||
}
|
||||
|
||||
self.commit_current_statement();
|
||||
self.current_is_expression = false;
|
||||
|
||||
self.commit_current_statement()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -989,47 +1030,15 @@ impl<'src> Parser<'src> {
|
||||
let jump_back = Instruction::jump(jump_start);
|
||||
|
||||
self.emit_instruction(jump_back, self.current_position);
|
||||
self.commit_current_statement();
|
||||
self.commit_current_statement()?;
|
||||
|
||||
self.current_is_expression = false;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||
self.parse(
|
||||
Precedence::None,
|
||||
Allowed {
|
||||
assignment: true,
|
||||
explicit_return: true,
|
||||
implicit_return: true,
|
||||
},
|
||||
)?;
|
||||
|
||||
let parsed_expression = self
|
||||
.current_statement
|
||||
.last()
|
||||
.or_else(|| self.chunk.instructions().last())
|
||||
.map(|(instruction, _)| instruction.yields_value())
|
||||
.unwrap_or(false);
|
||||
let end_of_statement = matches!(
|
||||
self.current_token,
|
||||
Token::Eof | Token::RightCurlyBrace | Token::Semicolon
|
||||
);
|
||||
let has_semicolon = self.allow(Token::Semicolon)?;
|
||||
let returned = self
|
||||
.current_statement
|
||||
.last()
|
||||
.map(|(instruction, _)| matches!(instruction.operation(), Operation::Return))
|
||||
.unwrap_or(false);
|
||||
|
||||
if allowed.implicit_return
|
||||
&& parsed_expression
|
||||
&& end_of_statement
|
||||
&& !has_semicolon
|
||||
&& !returned
|
||||
{
|
||||
self.emit_instruction(Instruction::r#return(true), self.current_position);
|
||||
self.commit_current_statement();
|
||||
}
|
||||
self.parse(Precedence::None, allowed)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1080,7 +1089,33 @@ impl<'src> Parser<'src> {
|
||||
let end = self.current_position.1;
|
||||
|
||||
self.emit_instruction(Instruction::r#return(has_return_value), Span(start, end));
|
||||
self.commit_current_statement();
|
||||
|
||||
self.current_is_expression = false;
|
||||
|
||||
self.commit_current_statement()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_implicit_return(&mut self) -> Result<(), ParseError> {
|
||||
if !self.current_is_expression {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let end_of_statement = matches!(
|
||||
self.current_token,
|
||||
Token::Eof | Token::RightCurlyBrace | Token::Semicolon
|
||||
);
|
||||
let has_semicolon = self.allow(Token::Semicolon)?;
|
||||
let returned = self
|
||||
.current_statement
|
||||
.last()
|
||||
.map(|(instruction, _)| matches!(instruction.operation(), Operation::Return))
|
||||
.unwrap_or(false);
|
||||
|
||||
if end_of_statement && !has_semicolon && !returned {
|
||||
self.emit_instruction(Instruction::r#return(true), self.current_position);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1131,7 +1166,10 @@ impl<'src> Parser<'src> {
|
||||
Instruction::define_local(register, local_index, is_mutable),
|
||||
position,
|
||||
);
|
||||
self.commit_current_statement();
|
||||
|
||||
self.current_is_expression = false;
|
||||
|
||||
self.commit_current_statement()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1230,6 +1268,7 @@ impl<'src> Parser<'src> {
|
||||
explicit_return: true,
|
||||
implicit_return: true,
|
||||
})?;
|
||||
function_parser.commit_current_statement()?;
|
||||
}
|
||||
|
||||
function_parser.advance()?;
|
||||
@ -1264,9 +1303,14 @@ impl<'src> Parser<'src> {
|
||||
Instruction::define_local(register, local_index, false),
|
||||
identifier_position,
|
||||
);
|
||||
self.commit_current_statement();
|
||||
|
||||
self.current_is_expression = false;
|
||||
|
||||
self.commit_current_statement()?;
|
||||
} else {
|
||||
self.emit_constant(function, Span(function_start, function_end))?;
|
||||
|
||||
self.current_is_expression = true;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -1318,9 +1362,17 @@ impl<'src> Parser<'src> {
|
||||
Span(start, end),
|
||||
);
|
||||
|
||||
self.current_is_expression = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn parse_semicolon(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||
self.current_is_expression = false;
|
||||
|
||||
self.advance()
|
||||
}
|
||||
|
||||
fn expect_expression(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||
if self.current_token.is_expression() {
|
||||
Ok(())
|
||||
@ -1657,7 +1709,7 @@ impl From<&Token<'_>> for ParseRule<'_> {
|
||||
precedence: Precedence::None,
|
||||
},
|
||||
Token::Semicolon => ParseRule {
|
||||
prefix: Some(Parser::expect_expression),
|
||||
prefix: Some(Parser::parse_semicolon),
|
||||
infix: None,
|
||||
precedence: Precedence::None,
|
||||
},
|
||||
|
@ -538,21 +538,23 @@ fn if_else_complex() {
|
||||
*Instruction::equal(true, 0, 1)
|
||||
.set_b_is_constant()
|
||||
.set_c_is_constant(),
|
||||
Span(9, 11)
|
||||
Span(14, 16)
|
||||
),
|
||||
(Instruction::jump(7), Span(9, 11)),
|
||||
(Instruction::load_constant(0, 0, false), Span(9, 11)),
|
||||
(Instruction::load_constant(1, 1, false), Span(9, 11)),
|
||||
(Instruction::load_constant(2, 2, false), Span(9, 11)),
|
||||
(Instruction::load_constant(3, 3, false), Span(9, 11)),
|
||||
(Instruction::jump(11), Span(9, 11)),
|
||||
(Instruction::load_constant(0, 0, false), Span(9, 11)),
|
||||
(Instruction::load_constant(1, 1, false), Span(9, 11)),
|
||||
(Instruction::load_constant(2, 2, false), Span(9, 11)),
|
||||
(Instruction::load_constant(3, 3, false), Span(9, 11)),
|
||||
(Instruction::r#return(true), Span(11, 11)),
|
||||
(Instruction::jump(7), Span(14, 16)),
|
||||
(Instruction::load_constant(0, 2, false), Span(33, 34)),
|
||||
(Instruction::load_constant(1, 3, false), Span(36, 37)),
|
||||
(Instruction::load_constant(2, 4, false), Span(39, 40)),
|
||||
(Instruction::load_constant(3, 5, false), Span(42, 43)),
|
||||
(Instruction::jump(11), Span(95, 95)),
|
||||
(Instruction::load_constant(4, 6, false), Span(74, 75)),
|
||||
(Instruction::load_constant(5, 7, false), Span(77, 78)),
|
||||
(Instruction::load_constant(6, 8, false), Span(80, 81)),
|
||||
(Instruction::load_constant(7, 9, false), Span(83, 84)),
|
||||
(Instruction::r#return(true), Span(95, 95)),
|
||||
],
|
||||
vec![
|
||||
Value::integer(1),
|
||||
Value::integer(1),
|
||||
Value::integer(1),
|
||||
Value::integer(2),
|
||||
Value::integer(3),
|
||||
|
Loading…
Reference in New Issue
Block a user