1
0

Pass tests

This commit is contained in:
Jeff 2024-10-24 22:37:18 -04:00
parent c0f74f1e09
commit 004cf73959
3 changed files with 193 additions and 160 deletions

View File

@ -6,6 +6,10 @@ use crate::{Chunk, Operation};
pub struct Instruction(u32); pub struct Instruction(u32);
impl Instruction { impl Instruction {
pub fn with_operation(operation: Operation) -> Instruction {
Instruction(operation as u32)
}
pub fn r#move(to_register: u8, from_register: u8) -> Instruction { pub fn r#move(to_register: u8, from_register: u8) -> Instruction {
let mut instruction = Instruction(Operation::Move as u32); let mut instruction = Instruction(Operation::Move as u32);

View File

@ -22,11 +22,9 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
.parse_statement(Allowed { .parse_statement(Allowed {
assignment: true, assignment: true,
explicit_return: false, explicit_return: false,
implicit_return: true,
}) })
.map_err(|error| DustError::Parse { error, source })?; .map_err(|error| DustError::Parse { error, source })?;
parser
.commit_staged()
.map_err(|error| DustError::Parse { error, source })?;
} }
Ok(parser.finish()) Ok(parser.finish())
@ -37,7 +35,7 @@ pub struct Parser<'src> {
lexer: Lexer<'src>, lexer: Lexer<'src>,
chunk: Chunk, chunk: Chunk,
staged_instructions: Vec<(Instruction, Span)>, current_statement_length: usize,
current_is_expression: bool, current_is_expression: bool,
minimum_register: u8, minimum_register: u8,
@ -63,7 +61,7 @@ impl<'src> Parser<'src> {
Ok(Parser { Ok(Parser {
lexer, lexer,
chunk: Chunk::new(None), chunk: Chunk::new(None),
staged_instructions: Vec::new(), current_statement_length: 0,
current_is_expression: false, current_is_expression: false,
minimum_register: 0, minimum_register: 0,
current_token, current_token,
@ -85,7 +83,8 @@ impl<'src> Parser<'src> {
} }
fn next_register(&mut self) -> u8 { fn next_register(&mut self) -> u8 {
self.staged_instructions self.chunk
.instructions()
.iter() .iter()
.rev() .rev()
.find_map(|(instruction, _)| { .find_map(|(instruction, _)| {
@ -146,63 +145,98 @@ impl<'src> Parser<'src> {
position.to_string() position.to_string()
); );
self.staged_instructions.push((instruction, position)); self.current_statement_length += 1;
self.chunk.push_instruction(instruction, position);
} }
fn commit_staged(&mut self) -> Result<(), ParseError> { fn end_statement(&mut self) {
if self.staged_instructions.len() == 4 if let Some(
&& self.staged_instructions[0].0.operation().is_comparison() [Operation::LoadBoolean | Operation::LoadConstant, Operation::LoadBoolean | Operation::LoadConstant, Operation::Jump, Operation::Equal | Operation::Less | Operation::LessEqual],
&& matches!(self.staged_instructions[1].0.operation(), Operation::Jump) ) = self.get_end_of_statement()
&& matches!(
self.staged_instructions[2].0.operation(),
Operation::LoadBoolean | Operation::LoadConstant
)
&& matches!(
self.staged_instructions[3].0.operation(),
Operation::LoadBoolean | Operation::LoadConstant
)
{ {
self.staged_instructions[2].0.set_c_to_boolean(true); log::trace!("Optimizing boolean comparison");
let mut instructions = self
.chunk
.instructions_mut()
.iter_mut()
.rev()
.map(|(instruction, _)| instruction);
let second_loader = instructions.next().unwrap();
let first_loader = instructions.next().unwrap();
first_loader.set_c_to_boolean(true);
let mut second_loader_new = Instruction::with_operation(second_loader.operation());
second_loader_new.set_a(first_loader.a());
second_loader_new.set_b(second_loader.b());
second_loader_new.set_c(second_loader.c());
if second_loader.b_is_constant() {
second_loader_new.set_b_is_constant();
}
if second_loader.c_is_constant() {
second_loader_new.set_c_is_constant();
}
*second_loader = second_loader_new;
} }
self.parse_implicit_return()?; self.current_statement_length = 0;
let next_register = self.next_register();
for (instruction, position) in self.staged_instructions.drain(..) {
self.chunk.push_instruction(instruction, position);
}
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_instructions(&self) -> impl Iterator<Item = &Instruction> {
if self.staged_instructions.len() < COUNT { self.chunk
.instructions()
.iter()
.rev()
.take(self.current_statement_length)
.map(|(instruction, _)| instruction)
}
fn get_last_value_operation(&self) -> Option<Operation> {
self.chunk
.instructions()
.iter()
.rev()
.take(self.current_statement_length)
.find_map(|(instruction, _)| {
if instruction.yields_value() {
Some(instruction.operation())
} else {
None
}
})
}
fn get_end_of_statement<const COUNT: usize>(&self) -> Option<[Operation; COUNT]> {
if self.current_statement_length < COUNT {
return None; return None;
} }
let mut operations = [(Operation::Return, Span(0, 0)); COUNT]; let mut operations = [Operation::Return; COUNT];
for (index, (instruction, position)) in self for (index, (instruction, _)) in self
.staged_instructions .chunk
.instructions()
.iter() .iter()
.rev() .rev()
.enumerate()
.take(COUNT) .take(COUNT)
.enumerate()
{ {
operations[index] = (instruction.operation(), *position); operations[index] = instruction.operation();
} }
Some(operations) Some(operations)
} }
fn get_last_jump_mut(&mut self) -> Option<&mut Instruction> { fn get_last_jump_mut(&mut self) -> Option<&mut Instruction> {
self.staged_instructions self.chunk
.instructions_mut()
.iter_mut() .iter_mut()
.rev()
.find_map(|(instruction, _)| { .find_map(|(instruction, _)| {
if let Operation::Jump = instruction.operation() { if let Operation::Jump = instruction.operation() {
Some(instruction) Some(instruction)
@ -210,18 +244,6 @@ impl<'src> Parser<'src> {
None None
} }
}) })
.or_else(|| {
self.chunk
.instructions_mut()
.iter_mut()
.find_map(|(instruction, _)| {
if let Operation::Jump = instruction.operation() {
Some(instruction)
} else {
None
}
})
})
} }
fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> { fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> {
@ -243,19 +265,7 @@ impl<'src> Parser<'src> {
self.advance()?; self.advance()?;
let boolean = text.parse::<bool>().unwrap(); let boolean = text.parse::<bool>().unwrap();
let register = if let Some(instruction) = self let register = self.next_register();
.staged_instructions
.last()
.map(|(instruction, _)| instruction)
{
if let Operation::LoadBoolean = instruction.operation() {
instruction.a()
} else {
self.next_register()
}
} else {
self.next_register()
};
self.emit_instruction( self.emit_instruction(
Instruction::load_boolean(register, boolean, false), Instruction::load_boolean(register, boolean, false),
@ -415,13 +425,14 @@ impl<'src> Parser<'src> {
self.advance()?; self.advance()?;
self.parse_expression()?; self.parse_expression()?;
let (previous_instruction, previous_position) = let (previous_instruction, previous_position) = self
self.staged_instructions .chunk
.pop() .instructions_mut()
.ok_or_else(|| ParseError::ExpectedExpression { .pop()
found: self.previous_token.to_owned(), .ok_or_else(|| ParseError::ExpectedExpression {
position: self.previous_position, found: self.previous_token.to_owned(),
})?; position: self.previous_position,
})?;
let (push_back, is_constant, argument) = { let (push_back, is_constant, argument) = {
match previous_instruction.operation() { match previous_instruction.operation() {
@ -505,7 +516,8 @@ impl<'src> Parser<'src> {
fn parse_math_binary(&mut self) -> Result<(), ParseError> { fn parse_math_binary(&mut self) -> Result<(), ParseError> {
let (left_instruction, left_position) = let (left_instruction, left_position) =
self.staged_instructions self.chunk
.instructions_mut()
.pop() .pop()
.ok_or_else(|| ParseError::ExpectedExpression { .ok_or_else(|| ParseError::ExpectedExpression {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
@ -537,7 +549,8 @@ impl<'src> Parser<'src> {
self.parse_sub_expression(&rule.precedence)?; self.parse_sub_expression(&rule.precedence)?;
let (right_instruction, right_position) = let (right_instruction, right_position) =
self.staged_instructions self.chunk
.instructions_mut()
.pop() .pop()
.ok_or_else(|| ParseError::ExpectedExpression { .ok_or_else(|| ParseError::ExpectedExpression {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
@ -612,9 +625,8 @@ impl<'src> Parser<'src> {
} }
fn parse_comparison_binary(&mut self) -> Result<(), ParseError> { fn parse_comparison_binary(&mut self) -> Result<(), ParseError> {
if let Some( if let Some(Operation::Equal | Operation::Less | Operation::LessEqual) =
[(Operation::Jump, _), (Operation::Equal, _) | (Operation::Less, _) | (Operation::LessEqual, _)], self.get_last_value_operation()
) = self.get_statement_operations()
{ {
return Err(ParseError::CannotChainComparison { return Err(ParseError::CannotChainComparison {
position: self.current_position, position: self.current_position,
@ -622,7 +634,8 @@ impl<'src> Parser<'src> {
} }
let (left_instruction, left_position) = let (left_instruction, left_position) =
self.staged_instructions self.chunk
.instructions_mut()
.pop() .pop()
.ok_or_else(|| ParseError::ExpectedExpression { .ok_or_else(|| ParseError::ExpectedExpression {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
@ -639,7 +652,8 @@ impl<'src> Parser<'src> {
self.parse_sub_expression(&rule.precedence)?; self.parse_sub_expression(&rule.precedence)?;
let (right_instruction, right_position) = let (right_instruction, right_position) =
self.staged_instructions self.chunk
.instructions_mut()
.pop() .pop()
.ok_or_else(|| ParseError::ExpectedExpression { .ok_or_else(|| ParseError::ExpectedExpression {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
@ -692,7 +706,7 @@ impl<'src> Parser<'src> {
self.emit_instruction(instruction, operator_position); self.emit_instruction(instruction, operator_position);
let jump_to = (self.chunk.len() + self.staged_instructions.len() + 2) as u8; let jump_to = (self.chunk.len() + 2) as u8;
self.emit_instruction(Instruction::jump(jump_to), operator_position); self.emit_instruction(Instruction::jump(jump_to), operator_position);
self.emit_instruction( self.emit_instruction(
@ -711,7 +725,8 @@ impl<'src> Parser<'src> {
fn parse_logical_binary(&mut self) -> Result<(), ParseError> { fn parse_logical_binary(&mut self) -> Result<(), ParseError> {
let (left_instruction, left_position) = let (left_instruction, left_position) =
self.staged_instructions self.chunk
.instructions_mut()
.pop() .pop()
.ok_or_else(|| ParseError::ExpectedExpression { .ok_or_else(|| ParseError::ExpectedExpression {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
@ -738,7 +753,7 @@ impl<'src> Parser<'src> {
self.emit_instruction(left_instruction, left_position); self.emit_instruction(left_instruction, left_position);
self.emit_instruction(instruction, operator_position); self.emit_instruction(instruction, operator_position);
let jump_to = (self.chunk.len() + self.staged_instructions.len() + 2) as u8; let jump_to = (self.chunk.len() + 2) as u8;
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)?;
@ -815,12 +830,12 @@ impl<'src> Parser<'src> {
self.parse_expression()?; self.parse_expression()?;
let (mut previous_instruction, previous_position) = self let (mut previous_instruction, previous_position) =
.staged_instructions self.chunk.instructions_mut().pop().ok_or_else(|| {
.pop() ParseError::ExpectedExpression {
.ok_or_else(|| ParseError::ExpectedExpression { found: self.previous_token.to_owned(),
found: self.previous_token.to_owned(), position: self.previous_position,
position: self.previous_position, }
})?; })?;
if previous_instruction.operation().is_math() { if previous_instruction.operation().is_math() {
@ -844,6 +859,7 @@ impl<'src> Parser<'src> {
Instruction::set_local(register, local_index), Instruction::set_local(register, local_index),
start_position, start_position,
); );
self.end_statement();
self.current_is_expression = false; self.current_is_expression = false;
} else { } else {
@ -935,16 +951,17 @@ impl<'src> Parser<'src> {
self.parse_expression()?; self.parse_expression()?;
if let Some( if let Some(
[(Operation::LoadBoolean, _), (Operation::LoadBoolean, _), (Operation::Jump, _), (Operation::Equal | Operation::Less | Operation::LessEqual, _)], [Operation::LoadBoolean, Operation::LoadBoolean, Operation::Jump, Operation::Equal | Operation::Less | Operation::LessEqual],
) = self.get_statement_operations() ) = self.get_end_of_statement()
{ {
self.staged_instructions.pop(); self.chunk.instructions_mut().pop();
self.staged_instructions.pop(); self.chunk.instructions_mut().pop();
} }
let block_allowed = Allowed { let block_allowed = Allowed {
assignment: allowed.assignment, assignment: allowed.assignment,
explicit_return: allowed.explicit_return, explicit_return: allowed.explicit_return,
implicit_return: false,
}; };
if let Token::LeftCurlyBrace = self.current_token { if let Token::LeftCurlyBrace = self.current_token {
@ -957,61 +974,67 @@ impl<'src> Parser<'src> {
}); });
} }
let if_block_index = self.staged_instructions.len(); let if_block_end = self.chunk.len();
let if_block_end = (self.chunk.len() + if_block_index) as u8;
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_block_end); if_jump.set_b(if_block_end as u8);
} }
if self.allow(Token::Else)? { if let Token::Else = self.current_token {
if let Token::If = self.current_token { self.parse_else(allowed, block_allowed)?;
self.parse_if(allowed)?;
let if_block_index = self.staged_instructions.len();
let if_block_end = (self.chunk.len() + if_block_index) as u8;
if let Some(if_jump) = self.get_last_jump_mut() {
if_jump.set_b(if_block_end + 1);
}
} else if let Token::LeftCurlyBrace = self.current_token {
self.parse_block(block_allowed)?;
let else_end = self.chunk.len() + self.staged_instructions.len();
if else_end - if_block_index > 1 {
self.staged_instructions.insert(
if_block_index,
(
Instruction::jump((else_end + 1) as u8),
self.current_position,
),
);
}
self.current_is_expression = self
.staged_instructions
.last()
.map_or(false, |(instruction, _)| instruction.yields_value());
self.commit_staged()?;
} else {
return Err(ParseError::ExpectedTokenMultiple {
expected: &[TokenKind::If, TokenKind::LeftCurlyBrace],
found: self.current_token.to_owned(),
position: self.current_position,
});
}
self.current_is_expression = self
.staged_instructions
.last()
.map_or(false, |(instruction, _)| instruction.yields_value());
} else { } else {
self.current_is_expression = false; self.current_is_expression = false;
} }
self.commit_staged()?; Ok(())
}
fn parse_else(&mut self, allowed: Allowed, block_allowed: Allowed) -> Result<(), ParseError> {
self.advance()?;
let if_block_end = self.chunk.len();
if let Token::If = self.current_token {
self.parse_if(allowed)?;
let if_block_end = self.chunk.len() as u8;
if let Some(if_jump) = self.get_last_jump_mut() {
if_jump.set_b(if_block_end + 1);
}
} else if let Token::LeftCurlyBrace = self.current_token {
self.parse_block(block_allowed)?;
let else_end = self.chunk.len();
if else_end - if_block_end > 1 {
self.chunk.insert_instruction(
if_block_end,
Instruction::jump((else_end + 1) as u8),
self.current_position,
)?;
}
self.current_is_expression = self
.chunk
.instructions()
.last()
.map_or(false, |(instruction, _)| instruction.yields_value());
} else {
return Err(ParseError::ExpectedTokenMultiple {
expected: &[TokenKind::If, TokenKind::LeftCurlyBrace],
found: self.current_token.to_owned(),
position: self.current_position,
});
}
self.current_is_expression = self
.chunk
.instructions()
.last()
.map_or(false, |(instruction, _)| instruction.yields_value());
self.end_statement();
Ok(()) Ok(())
} }
@ -1019,24 +1042,25 @@ impl<'src> Parser<'src> {
fn parse_while(&mut self, allowed: Allowed) -> Result<(), ParseError> { fn parse_while(&mut self, allowed: Allowed) -> Result<(), ParseError> {
self.advance()?; self.advance()?;
let jump_start = (self.chunk.len() + self.staged_instructions.len()) as u8; let jump_start = self.chunk.len() as u8;
self.parse_expression()?; self.parse_expression()?;
if let Some( if let Some(
[(Operation::LoadBoolean, _), (Operation::LoadBoolean, _), (Operation::Jump, _), (Operation::Equal | Operation::Less | Operation::LessEqual, _)], [Operation::LoadBoolean, Operation::LoadBoolean, Operation::Jump, Operation::Equal | Operation::Less | Operation::LessEqual],
) = self.get_statement_operations() ) = self.get_end_of_statement()
{ {
self.staged_instructions.pop(); self.chunk.instructions_mut().pop();
self.staged_instructions.pop(); self.chunk.instructions_mut().pop();
} }
self.parse_block(Allowed { self.parse_block(Allowed {
assignment: true, assignment: true,
explicit_return: allowed.explicit_return, explicit_return: allowed.explicit_return,
implicit_return: false,
})?; })?;
let jump_end = (self.chunk.len() + self.staged_instructions.len()) as u8; let jump_end = self.chunk.len() as u8;
if let Some(jump) = self.get_last_jump_mut() { if let Some(jump) = self.get_last_jump_mut() {
jump.set_b(jump_end + 1); jump.set_b(jump_end + 1);
@ -1045,7 +1069,7 @@ 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_staged()?; self.end_statement();
self.current_is_expression = false; self.current_is_expression = false;
@ -1055,6 +1079,10 @@ impl<'src> Parser<'src> {
fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> { fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
self.parse(Precedence::None, allowed)?; self.parse(Precedence::None, allowed)?;
if allowed.implicit_return {
self.parse_implicit_return()?;
}
Ok(()) Ok(())
} }
@ -1064,6 +1092,7 @@ impl<'src> Parser<'src> {
Allowed { Allowed {
assignment: false, assignment: false,
explicit_return: false, explicit_return: false,
implicit_return: false,
}, },
) )
} }
@ -1074,6 +1103,7 @@ impl<'src> Parser<'src> {
Allowed { Allowed {
assignment: false, assignment: false,
explicit_return: false, explicit_return: false,
implicit_return: false,
}, },
) )
} }
@ -1102,11 +1132,10 @@ 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.end_statement();
self.current_is_expression = false; self.current_is_expression = false;
self.commit_staged()?;
Ok(()) Ok(())
} }
@ -1121,7 +1150,8 @@ impl<'src> Parser<'src> {
); );
let has_semicolon = self.allow(Token::Semicolon)?; let has_semicolon = self.allow(Token::Semicolon)?;
let returned = self let returned = self
.staged_instructions .chunk
.instructions()
.last() .last()
.map(|(instruction, _)| matches!(instruction.operation(), Operation::Return)) .map(|(instruction, _)| matches!(instruction.operation(), Operation::Return))
.unwrap_or(false); .unwrap_or(false);
@ -1179,11 +1209,10 @@ impl<'src> Parser<'src> {
Instruction::define_local(register, local_index, is_mutable), Instruction::define_local(register, local_index, is_mutable),
position, position,
); );
self.end_statement();
self.current_is_expression = false; self.current_is_expression = false;
self.commit_staged()?;
Ok(()) Ok(())
} }
@ -1251,9 +1280,7 @@ impl<'src> Parser<'src> {
Span(start, end), Span(start, end),
)?; )?;
if let Some(values) = &value_parameters { function_parser.minimum_register += 1;
function_parser.minimum_register = values.len() as u8;
}
function_parser.allow(Token::Comma)?; function_parser.allow(Token::Comma)?;
} }
@ -1279,8 +1306,8 @@ impl<'src> Parser<'src> {
function_parser.parse_statement(Allowed { function_parser.parse_statement(Allowed {
assignment: true, assignment: true,
explicit_return: true, explicit_return: true,
implicit_return: true,
})?; })?;
function_parser.commit_staged()?;
} }
function_parser.advance()?; function_parser.advance()?;
@ -1315,12 +1342,12 @@ impl<'src> Parser<'src> {
Instruction::define_local(register, local_index, false), Instruction::define_local(register, local_index, false),
identifier_position, identifier_position,
); );
self.end_statement();
self.current_is_expression = false; self.current_is_expression = false;
self.commit_staged()?;
} else { } else {
self.emit_constant(function, Span(function_start, function_end))?; self.emit_constant(function, Span(function_start, function_end))?;
self.end_statement();
self.current_is_expression = true; self.current_is_expression = true;
} }
@ -1329,7 +1356,7 @@ impl<'src> Parser<'src> {
} }
fn parse_call(&mut self) -> Result<(), ParseError> { fn parse_call(&mut self) -> Result<(), ParseError> {
let (last_instruction, _) = self.staged_instructions.last().copied().ok_or_else(|| { let (last_instruction, _) = self.chunk.instructions().last().copied().ok_or_else(|| {
ParseError::ExpectedExpression { ParseError::ExpectedExpression {
found: self.previous_token.to_owned(), found: self.previous_token.to_owned(),
position: self.previous_position, position: self.previous_position,
@ -1382,6 +1409,7 @@ impl<'src> Parser<'src> {
fn parse_semicolon(&mut self, _: Allowed) -> Result<(), ParseError> { fn parse_semicolon(&mut self, _: Allowed) -> Result<(), ParseError> {
self.current_is_expression = false; self.current_is_expression = false;
self.end_statement();
self.advance() self.advance()
} }
@ -1485,6 +1513,7 @@ pub enum Context {
struct Allowed { struct Allowed {
pub assignment: bool, pub assignment: bool,
pub explicit_return: bool, pub explicit_return: bool,
pub implicit_return: bool,
} }
type PrefixFunction<'a> = fn(&mut Parser<'a>, Allowed) -> Result<(), ParseError>; type PrefixFunction<'a> = fn(&mut Parser<'a>, Allowed) -> Result<(), ParseError>;

View File

@ -586,7 +586,7 @@ fn if_else_simple() {
), ),
(Instruction::jump(3), Span(5, 7)), (Instruction::jump(3), Span(5, 7)),
(Instruction::load_constant(0, 2, true), Span(12, 13)), (Instruction::load_constant(0, 2, true), Span(12, 13)),
(Instruction::load_constant(1, 3, false), Span(23, 24)), (Instruction::load_constant(0, 3, false), Span(23, 24)),
(Instruction::r#return(true), Span(26, 26)), (Instruction::r#return(true), Span(26, 26)),
], ],
vec![ vec![