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