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 rule = ParseRule::from(&operator.kind());
let (mut instruction, push_args_first) = match operator.kind() {
TokenKind::Plus => (Instruction::add(self.current_register, left, 0), true),
TokenKind::Minus => (Instruction::subtract(self.current_register, left, 0), true),
TokenKind::Star => (Instruction::multiply(self.current_register, left, 0), true),
TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), true),
TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), true),
TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), false),
let (mut instruction, is_comparison) = match operator.kind() {
TokenKind::Plus => (Instruction::add(self.current_register, left, 0), false),
TokenKind::Minus => (Instruction::subtract(self.current_register, left, 0), false),
TokenKind::Star => (Instruction::multiply(self.current_register, left, 0), false),
TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), false),
TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), false),
TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), true),
TokenKind::DoubleAmpersand => {
let and_test = Instruction::test(self.current_register, false);
(and_test, false)
(and_test, true)
}
_ => {
return Err(ParseError::ExpectedTokenMultiple {
@ -435,7 +435,7 @@ impl<'src> Parser<'src> {
instruction.set_second_argument_to_constant();
}
if push_args_first {
if !is_comparison {
if push_back_left {
self.emit_instruction(left_instruction, left_position);
}
@ -447,7 +447,7 @@ impl<'src> Parser<'src> {
self.emit_instruction(instruction, operator_position);
}
if !push_args_first {
if is_comparison {
let push_left_first = self.current_register.saturating_sub(1) == left;
if push_back_left && push_left_first {
@ -476,23 +476,19 @@ impl<'src> Parser<'src> {
allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
let token = self.current_token.to_owned();
let token = self.current_token;
let start_position = self.current_position;
let local_index = self.parse_identifier_from(token, start_position)?;
let is_mutable = self.chunk.get_local(local_index, start_position)?.mutable;
self.advance()?;
if !is_mutable {
return Err(ParseError::CannotMutateImmutableVariable {
identifier: self.chunk.get_identifier(local_index).cloned().unwrap(),
position: start_position,
});
}
if allow_assignment && self.allow(TokenKind::Equal)? {
if !is_mutable {
let identifier = self.chunk.get_identifier(local_index).cloned().unwrap();
return Err(ParseError::CannotMutateImmutableVariable {
identifier,
position: start_position,
});
}
self.parse_expression()?;
let (mut previous_instruction, previous_position) =
@ -530,12 +526,8 @@ impl<'src> Parser<'src> {
Ok(())
}
fn parse_identifier_from(
&mut self,
token: TokenOwned,
position: Span,
) -> Result<u8, ParseError> {
if let TokenOwned::Identifier(text) = token {
fn parse_identifier_from(&mut self, token: Token, position: Span) -> Result<u8, ParseError> {
if let Token::Identifier(text) = token {
let identifier = Identifier::new(text);
if let Ok(local_index) = self.chunk.get_local_index(&identifier, position) {
@ -616,20 +608,29 @@ impl<'src> Parser<'src> {
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.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::If)? {
self.parse_if(allow_assignment, false)?;
self.parse_if(allow_assignment, allow_return)?;
} 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(())
}
@ -650,53 +651,18 @@ impl<'src> Parser<'src> {
}
fn parse_statement(&mut self, allow_return: bool) -> Result<(), ParseError> {
let start = self.current_position.0;
let is_expression = match self.current_token {
match self.current_token {
Token::Let => {
self.parse_let_statement(true, allow_return)?;
false
}
Token::LeftCurlyBrace => {
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()?;
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(())
}
@ -712,7 +678,7 @@ impl<'src> Parser<'src> {
});
}
self.advance()?;
self.allow(TokenKind::Let)?;
let is_mutable = self.allow(TokenKind::Mut)?;
let position = self.current_position;

View File

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

View File

@ -292,9 +292,13 @@ impl Vm {
self.ip = new_ip;
}
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)?));
}
}
}
}