1
0

Pass tests

This commit is contained in:
Jeff 2024-09-19 13:54:28 -04:00
parent dee09d3583
commit d4a8a65096
3 changed files with 73 additions and 117 deletions

View File

@ -383,17 +383,17 @@ impl<'src> Parser<'src> {
let operator_position = self.current_position; let operator_position = self.current_position;
let rule = ParseRule::from(&operator.kind()); let rule = ParseRule::from(&operator.kind());
let (mut instruction, push_args_first) = match operator.kind() { let (mut instruction, is_comparison) = match operator.kind() {
TokenKind::Plus => (Instruction::add(self.current_register, left, 0), true), TokenKind::Plus => (Instruction::add(self.current_register, left, 0), false),
TokenKind::Minus => (Instruction::subtract(self.current_register, left, 0), true), TokenKind::Minus => (Instruction::subtract(self.current_register, left, 0), false),
TokenKind::Star => (Instruction::multiply(self.current_register, left, 0), true), TokenKind::Star => (Instruction::multiply(self.current_register, left, 0), false),
TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), true), TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), false),
TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), true), TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), false),
TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), false), TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), true),
TokenKind::DoubleAmpersand => { TokenKind::DoubleAmpersand => {
let and_test = Instruction::test(self.current_register, false); let and_test = Instruction::test(self.current_register, false);
(and_test, false) (and_test, true)
} }
_ => { _ => {
return Err(ParseError::ExpectedTokenMultiple { return Err(ParseError::ExpectedTokenMultiple {
@ -435,7 +435,7 @@ impl<'src> Parser<'src> {
instruction.set_second_argument_to_constant(); instruction.set_second_argument_to_constant();
} }
if push_args_first { if !is_comparison {
if push_back_left { if push_back_left {
self.emit_instruction(left_instruction, left_position); self.emit_instruction(left_instruction, left_position);
} }
@ -447,7 +447,7 @@ impl<'src> Parser<'src> {
self.emit_instruction(instruction, operator_position); self.emit_instruction(instruction, operator_position);
} }
if !push_args_first { if is_comparison {
let push_left_first = self.current_register.saturating_sub(1) == left; let push_left_first = self.current_register.saturating_sub(1) == left;
if push_back_left && push_left_first { if push_back_left && push_left_first {
@ -476,23 +476,19 @@ impl<'src> Parser<'src> {
allow_assignment: bool, allow_assignment: bool,
_allow_return: bool, _allow_return: bool,
) -> Result<(), ParseError> { ) -> Result<(), ParseError> {
let token = self.current_token.to_owned(); let token = self.current_token;
let start_position = self.current_position; let start_position = self.current_position;
let local_index = self.parse_identifier_from(token, start_position)?; let local_index = self.parse_identifier_from(token, start_position)?;
let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable; let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable;
self.advance()?;
if allow_assignment && self.allow(TokenKind::Equal)? {
if !is_mutable { if !is_mutable {
let identifier = self.chunk.get_identifier(local_index).cloned().unwrap();
return Err(ParseError::CannotMutateImmutableVariable { return Err(ParseError::CannotMutateImmutableVariable {
identifier, identifier: self.chunk.get_identifier(local_index).cloned().unwrap(),
position: start_position, position: start_position,
}); });
} }
if allow_assignment && self.allow(TokenKind::Equal)? {
self.parse_expression()?; self.parse_expression()?;
let (mut previous_instruction, previous_position) = let (mut previous_instruction, previous_position) =
@ -530,12 +526,8 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_identifier_from( fn parse_identifier_from(&mut self, token: Token, position: Span) -> Result<u8, ParseError> {
&mut self, if let Token::Identifier(text) = token {
token: TokenOwned,
position: Span,
) -> Result<u8, ParseError> {
if let TokenOwned::Identifier(text) = token {
let identifier = Identifier::new(text); let identifier = Identifier::new(text);
if let Ok(local_index) = self.chunk.get_local_index(&identifier, position) { if let Ok(local_index) = self.chunk.get_local_index(&identifier, position) {
@ -616,20 +608,29 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_if(&mut self, allow_assignment: bool, _allow_return: bool) -> Result<(), ParseError> { fn parse_if(&mut self, allow_assignment: bool, allow_return: bool) -> Result<(), ParseError> {
self.advance()?; self.advance()?;
self.parse_expression()?; self.parse_expression()?;
self.parse_block(allow_assignment, allow_return)?;
self.parse_block(allow_assignment, false)?; let jump_start = self.current_register;
let jump_index = self.chunk.len();
if self.allow(TokenKind::Else)? { if self.allow(TokenKind::Else)? {
if self.allow(TokenKind::If)? { if self.allow(TokenKind::If)? {
self.parse_if(allow_assignment, false)?; self.parse_if(allow_assignment, allow_return)?;
} else { } else {
self.parse_block(allow_assignment, false)?; self.parse_block(allow_assignment, allow_return)?;
} }
} }
let jump_end = self.current_register;
let jump_distance = (jump_end - jump_start).max(1);
let jump = Instruction::jump(jump_distance, true);
self.chunk
.insert_instruction(jump_index, jump, self.current_position);
Ok(()) Ok(())
} }
@ -650,53 +651,18 @@ impl<'src> Parser<'src> {
} }
fn parse_statement(&mut self, allow_return: bool) -> Result<(), ParseError> { fn parse_statement(&mut self, allow_return: bool) -> Result<(), ParseError> {
let start = self.current_position.0; match self.current_token {
let is_expression = match self.current_token {
Token::Let => { Token::Let => {
self.parse_let_statement(true, allow_return)?; self.parse_let_statement(true, allow_return)?;
false
} }
Token::LeftCurlyBrace => { Token::LeftCurlyBrace => {
self.parse_block(true, true)?; self.parse_block(true, true)?;
let last_operation = self.chunk.get_last_operation(self.current_position)?;
let ends_in_return = last_operation == Operation::Return;
if ends_in_return {
self.chunk.pop_instruction(self.current_position)?;
}
ends_in_return
} }
_ => { _ => {
self.parse_expression()?; self.parse_expression()?;
true
} }
}; };
if !allow_return || !is_expression {
return Ok(());
}
let (last_instruction, _) = *self.chunk.get_previous(self.current_position)?;
let ends_in_assignment = matches!(
last_instruction.operation(),
Operation::DefineLocal | Operation::SetLocal
);
let has_semicolon = self.allow(TokenKind::Semicolon)?;
if !ends_in_assignment && !has_semicolon {
let end = self.previous_position.1;
let return_register = last_instruction.destination();
self.emit_instruction(
Instruction::r#return(return_register, return_register),
Span(start, end),
);
}
Ok(()) Ok(())
} }
@ -712,7 +678,7 @@ impl<'src> Parser<'src> {
}); });
} }
self.advance()?; self.allow(TokenKind::Let)?;
let is_mutable = self.allow(TokenKind::Mut)?; let is_mutable = self.allow(TokenKind::Mut)?;
let position = self.current_position; let position = self.current_position;

View File

@ -18,6 +18,7 @@ fn equality_assignment_long() {
), ),
(Instruction::jump(1, true), Span(13, 15)), (Instruction::jump(1, true), Span(13, 15)),
(Instruction::load_boolean(0, true, true), Span(20, 24)), (Instruction::load_boolean(0, true, true), Span(20, 24)),
(Instruction::jump(1, true), Span(41, 42)),
(Instruction::load_boolean(0, false, false), Span(34, 39)), (Instruction::load_boolean(0, false, false), Span(34, 39)),
(Instruction::define_local(0, 0, false), Span(4, 5)), (Instruction::define_local(0, 0, false), Span(4, 5)),
], ],
@ -68,8 +69,8 @@ fn if_else_expression() {
), ),
(Instruction::jump(1, true), Span(5, 7)), (Instruction::jump(1, true), Span(5, 7)),
(Instruction::load_constant(0, 2), Span(12, 13)), (Instruction::load_constant(0, 2), Span(12, 13)),
(Instruction::jump(1, true), Span(26, 26)),
(Instruction::load_constant(1, 3), Span(23, 24)), (Instruction::load_constant(1, 3), Span(23, 24)),
(Instruction::r#return(1, 1), Span(0, 26)),
], ],
vec![ vec![
Value::integer(1), Value::integer(1),
@ -99,7 +100,6 @@ fn list_with_expression() {
), ),
(Instruction::load_constant(2, 3), Span(11, 12)), (Instruction::load_constant(2, 3), Span(11, 12)),
(Instruction::load_list(3, 0, 3), Span(0, 13)), (Instruction::load_list(3, 0, 3), Span(0, 13)),
(Instruction::r#return(3, 3), Span(0, 13)),
], ],
vec![ vec![
Value::integer(1), Value::integer(1),
@ -124,7 +124,6 @@ fn list() {
(Instruction::load_constant(1, 1), Span(4, 5)), (Instruction::load_constant(1, 1), Span(4, 5)),
(Instruction::load_constant(2, 2), Span(7, 8)), (Instruction::load_constant(2, 2), Span(7, 8)),
(Instruction::load_list(3, 0, 3), Span(0, 9)), (Instruction::load_list(3, 0, 3), Span(0, 9)),
(Instruction::r#return(3, 3), Span(0, 9)),
], ],
vec![Value::integer(1), Value::integer(2), Value::integer(3),], vec![Value::integer(1), Value::integer(2), Value::integer(3),],
vec![] vec![]
@ -217,7 +216,6 @@ fn parentheses_precedence() {
*Instruction::multiply(1, 0, 2).set_second_argument_to_constant(), *Instruction::multiply(1, 0, 2).set_second_argument_to_constant(),
Span(8, 9) Span(8, 9)
), ),
(Instruction::r#return(1, 1), Span(0, 11)),
], ],
vec![Value::integer(1), Value::integer(2), Value::integer(3)], vec![Value::integer(1), Value::integer(2), Value::integer(3)],
vec![] vec![]
@ -248,7 +246,6 @@ fn math_operator_precedence() {
Span(14, 15) Span(14, 15)
), ),
(Instruction::subtract(1, 0, 3), Span(6, 7)), (Instruction::subtract(1, 0, 3), Span(6, 7)),
(Instruction::r#return(1, 1), Span(0, 17)),
], ],
vec![ vec![
Value::integer(1), Value::integer(1),
@ -284,10 +281,14 @@ fn and() {
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![
(Instruction::load_boolean(0, true, false), Span(0, 4)), (Instruction::load_boolean(0, true, false), Span(0, 4)),
(Instruction::test(0, true), Span(5, 7)), (
*Instruction::test(0, true)
.set_second_argument_to_constant()
.set_first_argument_to_constant(),
Span(5, 7)
),
(Instruction::jump(1, true), Span(5, 7)), (Instruction::jump(1, true), Span(5, 7)),
(Instruction::load_boolean(1, false, false), Span(8, 13)), (Instruction::load_boolean(1, false, false), Span(8, 13)),
(Instruction::r#return(1, 1), Span(0, 13)),
], ],
vec![], vec![],
vec![] vec![]
@ -300,15 +301,12 @@ fn divide() {
assert_eq!( assert_eq!(
parse("1 / 2"), parse("1 / 2"),
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![(
(
*Instruction::divide(0, 0, 1) *Instruction::divide(0, 0, 1)
.set_first_argument_to_constant() .set_first_argument_to_constant()
.set_second_argument_to_constant(), .set_second_argument_to_constant(),
Span(2, 3) Span(2, 3)
), ),],
(Instruction::r#return(0, 0), Span(0, 5)),
],
vec![Value::integer(1), Value::integer(2)], vec![Value::integer(1), Value::integer(2)],
vec![] vec![]
)) ))
@ -320,15 +318,12 @@ fn multiply() {
assert_eq!( assert_eq!(
parse("1 * 2"), parse("1 * 2"),
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![(
(
*Instruction::multiply(0, 0, 1) *Instruction::multiply(0, 0, 1)
.set_first_argument_to_constant() .set_first_argument_to_constant()
.set_second_argument_to_constant(), .set_second_argument_to_constant(),
Span(2, 3) Span(2, 3)
), ),],
(Instruction::r#return(0, 0), Span(0, 5)),
],
vec![Value::integer(1), Value::integer(2)], vec![Value::integer(1), Value::integer(2)],
vec![] vec![]
)) ))
@ -340,15 +335,12 @@ fn add() {
assert_eq!( assert_eq!(
parse("1 + 2"), parse("1 + 2"),
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![(
(
*Instruction::add(0, 0, 1) *Instruction::add(0, 0, 1)
.set_first_argument_to_constant() .set_first_argument_to_constant()
.set_second_argument_to_constant(), .set_second_argument_to_constant(),
Span(2, 3) Span(2, 3)
), ),],
(Instruction::r#return(0, 0), Span(0, 5)),
],
vec![Value::integer(1), Value::integer(2)], vec![Value::integer(1), Value::integer(2)],
vec![] vec![]
)) ))
@ -360,15 +352,12 @@ fn subtract() {
assert_eq!( assert_eq!(
parse("1 - 2"), parse("1 - 2"),
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![(
(
*Instruction::subtract(0, 0, 1) *Instruction::subtract(0, 0, 1)
.set_first_argument_to_constant() .set_first_argument_to_constant()
.set_second_argument_to_constant(), .set_second_argument_to_constant(),
Span(2, 3) Span(2, 3)
), ),],
(Instruction::r#return(0, 0), Span(0, 5)),
],
vec![Value::integer(1), Value::integer(2)], vec![Value::integer(1), Value::integer(2)],
vec![] vec![]
)) ))
@ -380,10 +369,7 @@ fn constant() {
assert_eq!( assert_eq!(
parse("42"), parse("42"),
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![(Instruction::load_constant(0, 0), Span(0, 2)),],
(Instruction::load_constant(0, 0), Span(0, 2)),
(Instruction::r#return(0, 0), Span(0, 2)),
],
vec![Value::integer(42)], vec![Value::integer(42)],
vec![] vec![]
)) ))

View File

@ -292,9 +292,13 @@ impl Vm {
self.ip = new_ip; self.ip = new_ip;
} }
Operation::Return => { Operation::Return => {
let return_value = self.pop(position)?; let start_register = instruction.destination();
let end_register = instruction.first_argument();
let return_value_count = end_register - start_register;
return Ok(Some(return_value)); if return_value_count == 1 {
return Ok(Some(self.take(start_register, position)?));
}
} }
} }
} }