1
0

Extend parsing

This commit is contained in:
Jeff 2024-09-23 00:55:39 -04:00
parent 57edf48e36
commit 23f733d8b2
3 changed files with 149 additions and 127 deletions

View File

@ -332,6 +332,15 @@ impl<'src> Parser<'src> {
previous_instruction.first_argument(), previous_instruction.first_argument(),
) )
} }
Operation::LoadBoolean => {
self.decrement_register()?;
(
true,
previous_instruction.destination(),
previous_instruction.first_argument(),
)
}
_ => { _ => {
self.emit_instruction(previous_instruction, previous_position); self.emit_instruction(previous_instruction, previous_position);
@ -355,82 +364,66 @@ impl<'src> Parser<'src> {
instruction.set_first_argument_to_constant(); instruction.set_first_argument_to_constant();
} }
self.increment_register()?;
self.emit_instruction(instruction, operator_position); self.emit_instruction(instruction, operator_position);
Ok(()) Ok(())
} }
fn parse_binary(&mut self) -> Result<(), ParseError> { fn handle_binary_argument(
fn handle_argument( &mut self,
parser: &mut Parser, instruction: &Instruction,
instruction: &Instruction, ) -> Result<(bool, bool, u8), ParseError> {
) -> Result<(bool, bool, u8), ParseError> { let mut push_back = false;
let mut push_back = false; let mut is_constant = false;
let mut is_constant = false; let argument = match instruction.operation() {
let argument = match instruction.operation() { Operation::GetLocal => {
Operation::GetLocal => { self.decrement_register()?;
parser.decrement_register()?; instruction.destination()
instruction.destination() }
} Operation::LoadConstant => {
Operation::LoadConstant => { is_constant = true;
is_constant = true;
parser.decrement_register()?; self.decrement_register()?;
instruction.first_argument() instruction.first_argument()
} }
Operation::LoadBoolean => { Operation::LoadBoolean => {
is_constant = true; is_constant = true;
push_back = true; push_back = true;
instruction.destination() instruction.destination()
} }
Operation::Close => { Operation::Close => {
return Err(ParseError::ExpectedExpression { return Err(ParseError::ExpectedExpression {
found: parser.previous_token.to_owned(), found: self.previous_token.to_owned(),
position: parser.previous_position, position: self.previous_position,
}); });
} }
_ => { _ => {
push_back = true; push_back = true;
instruction.destination() instruction.destination()
} }
}; };
Ok((push_back, is_constant, argument)) Ok((push_back, is_constant, argument))
} }
fn parse_math_binary(&mut self) -> Result<(), ParseError> {
let (left_instruction, left_position) = let (left_instruction, left_position) =
self.chunk.pop_instruction(self.current_position)?; self.chunk.pop_instruction(self.current_position)?;
let (push_back_left, left_is_constant, left) = handle_argument(self, &left_instruction)?; let (push_back_left, left_is_constant, left) =
self.handle_binary_argument(&left_instruction)?;
let operator = self.current_token; let operator = self.current_token;
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, is_comparison) = match operator.kind() { let mut instruction = match operator.kind() {
TokenKind::Plus => (Instruction::add(self.current_register, left, 0), false), TokenKind::Plus => Instruction::add(self.current_register, left, 0),
TokenKind::Minus => (Instruction::subtract(self.current_register, left, 0), false), TokenKind::Minus => Instruction::subtract(self.current_register, left, 0),
TokenKind::Star => (Instruction::multiply(self.current_register, left, 0), false), TokenKind::Star => Instruction::multiply(self.current_register, left, 0),
TokenKind::Slash => (Instruction::divide(self.current_register, left, 0), false), TokenKind::Slash => Instruction::divide(self.current_register, left, 0),
TokenKind::Percent => (Instruction::modulo(self.current_register, left, 0), false), TokenKind::Percent => Instruction::modulo(self.current_register, left, 0),
TokenKind::DoubleEqual => (Instruction::equal(true, left, 0), true),
TokenKind::BangEqual => (Instruction::equal(false, left, 0), true),
TokenKind::Less => (Instruction::less(true, left, 0), true),
TokenKind::LessEqual => (Instruction::less_equal(true, left, 0), true),
TokenKind::Greater => (Instruction::less_equal(false, left, 0), true),
TokenKind::GreaterEqual => (Instruction::less(false, left, 0), true),
TokenKind::DoubleAmpersand => {
let and_test = Instruction::test(self.current_register, false);
(and_test, true)
}
TokenKind::DoublePipe => {
let or_test = Instruction::test(self.current_register, true);
(or_test, true)
}
_ => { _ => {
return Err(ParseError::ExpectedTokenMultiple { return Err(ParseError::ExpectedTokenMultiple {
expected: &[ expected: &[
@ -439,14 +432,6 @@ impl<'src> Parser<'src> {
TokenKind::Star, TokenKind::Star,
TokenKind::Slash, TokenKind::Slash,
TokenKind::Percent, TokenKind::Percent,
TokenKind::DoubleEqual,
TokenKind::BangEqual,
TokenKind::Less,
TokenKind::LessEqual,
TokenKind::Greater,
TokenKind::GreaterEqual,
TokenKind::DoubleAmpersand,
TokenKind::DoublePipe,
], ],
found: operator.to_owned(), found: operator.to_owned(),
position: operator_position, position: operator_position,
@ -454,17 +439,14 @@ impl<'src> Parser<'src> {
} }
}; };
if !(operator == Token::DoubleEqual) { self.increment_register()?;
self.increment_register()?;
}
self.advance()?; self.advance()?;
self.parse(rule.precedence.increment())?; self.parse(rule.precedence.increment())?;
let (right_instruction, right_position) = let (right_instruction, right_position) =
self.chunk.pop_instruction(self.current_position)?; self.chunk.pop_instruction(self.current_position)?;
let (push_back_right, right_is_constant, right) = let (push_back_right, right_is_constant, right) =
handle_argument(self, &right_instruction)?; self.handle_binary_argument(&right_instruction)?;
instruction.set_second_argument(right); instruction.set_second_argument(right);
@ -476,57 +458,97 @@ impl<'src> Parser<'src> {
instruction.set_second_argument_to_constant(); instruction.set_second_argument_to_constant();
} }
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);
}
if push_back_right {
self.emit_instruction(right_instruction, right_position);
}
self.emit_instruction(instruction, operator_position);
} }
if is_comparison { if push_back_right {
let push_left_first = self.current_register.saturating_sub(1) == left; self.emit_instruction(right_instruction, right_position);
}
if push_back_left && push_left_first { self.emit_instruction(instruction, operator_position);
self.emit_instruction(left_instruction, left_position);
Ok(())
}
fn parse_comparison_binary(&mut self) -> Result<(), ParseError> {
let (left_instruction, left_position) =
self.chunk.pop_instruction(self.current_position)?;
let (push_back_left, left_is_constant, left) =
self.handle_binary_argument(&left_instruction)?;
let operator = self.current_token;
let operator_position = self.current_position;
let rule = ParseRule::from(&operator.kind());
let mut instruction = match self.current_token.kind() {
TokenKind::DoubleEqual => Instruction::equal(true, left, 0),
TokenKind::BangEqual => Instruction::equal(false, left, 0),
TokenKind::Less => Instruction::less(true, left, 0),
TokenKind::LessEqual => Instruction::less_equal(true, left, 0),
TokenKind::Greater => Instruction::less_equal(false, left, 0),
TokenKind::GreaterEqual => Instruction::less(false, left, 0),
_ => {
return Err(ParseError::ExpectedTokenMultiple {
expected: &[
TokenKind::DoubleEqual,
TokenKind::BangEqual,
TokenKind::Less,
TokenKind::LessEqual,
TokenKind::Greater,
TokenKind::GreaterEqual,
],
found: self.current_token.to_owned(),
position: self.current_position,
})
} }
};
let jump_distance = if left_is_constant { 1 } else { 2 }; self.advance()?;
self.parse(rule.precedence.increment())?;
self.emit_instruction(instruction, operator_position); let (right_instruction, right_position) =
self.emit_instruction(Instruction::jump(jump_distance, true), operator_position); self.chunk.pop_instruction(self.current_position)?;
if push_back_left && !push_left_first { let (push_back_right, right_is_constant, right) =
self.emit_instruction(left_instruction, left_position); self.handle_binary_argument(&right_instruction)?;
}
if push_back_right { instruction.set_second_argument(right);
self.emit_instruction(right_instruction, right_position);
}
if !push_back_left && !push_back_right { if left_is_constant {
if self.current_register > 0 { instruction.set_first_argument_to_constant();
self.decrement_register()?; }
}
self.emit_instruction( if right_is_constant {
Instruction::load_boolean(self.current_register, true, true), instruction.set_second_argument_to_constant();
operator_position, }
);
self.emit_instruction( self.emit_instruction(instruction, operator_position);
Instruction::load_boolean(self.current_register, false, false), self.emit_instruction(Instruction::jump(1, true), operator_position);
operator_position, self.emit_instruction(
); Instruction::load_boolean(self.current_register, true, true),
} operator_position,
);
self.emit_instruction(
Instruction::load_boolean(self.current_register, false, false),
operator_position,
);
if push_back_left {
self.emit_instruction(left_instruction, left_position);
}
if push_back_right {
self.emit_instruction(right_instruction, right_position);
} }
Ok(()) Ok(())
} }
fn parse_logical_binary(&mut self) -> Result<(), ParseError> {
todo!()
}
fn parse_variable( fn parse_variable(
&mut self, &mut self,
allow_assignment: bool, allow_assignment: bool,
@ -920,7 +942,7 @@ impl From<&TokenKind> for ParseRule<'_> {
}, },
TokenKind::BangEqual => ParseRule { TokenKind::BangEqual => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Equality, precedence: Precedence::Equality,
}, },
TokenKind::Bool => todo!(), TokenKind::Bool => todo!(),
@ -949,17 +971,17 @@ impl From<&TokenKind> for ParseRule<'_> {
TokenKind::Dot => todo!(), TokenKind::Dot => todo!(),
TokenKind::DoubleAmpersand => ParseRule { TokenKind::DoubleAmpersand => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_logical_binary),
precedence: Precedence::LogicalAnd, precedence: Precedence::LogicalAnd,
}, },
TokenKind::DoubleEqual => ParseRule { TokenKind::DoubleEqual => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Equality, precedence: Precedence::Equality,
}, },
TokenKind::DoublePipe => ParseRule { TokenKind::DoublePipe => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_logical_binary),
precedence: Precedence::LogicalOr, precedence: Precedence::LogicalOr,
}, },
TokenKind::DoubleDot => todo!(), TokenKind::DoubleDot => todo!(),
@ -986,12 +1008,12 @@ impl From<&TokenKind> for ParseRule<'_> {
TokenKind::FloatKeyword => todo!(), TokenKind::FloatKeyword => todo!(),
TokenKind::Greater => ParseRule { TokenKind::Greater => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Comparison, precedence: Precedence::Comparison,
}, },
TokenKind::GreaterEqual => ParseRule { TokenKind::GreaterEqual => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Comparison, precedence: Precedence::Comparison,
}, },
TokenKind::Identifier => ParseRule { TokenKind::Identifier => ParseRule {
@ -1027,12 +1049,12 @@ impl From<&TokenKind> for ParseRule<'_> {
}, },
TokenKind::Less => ParseRule { TokenKind::Less => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Comparison, precedence: Precedence::Comparison,
}, },
TokenKind::LessEqual => ParseRule { TokenKind::LessEqual => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_comparison_binary),
precedence: Precedence::Comparison, precedence: Precedence::Comparison,
}, },
TokenKind::Let => ParseRule { TokenKind::Let => ParseRule {
@ -1044,7 +1066,7 @@ impl From<&TokenKind> for ParseRule<'_> {
TokenKind::Map => todo!(), TokenKind::Map => todo!(),
TokenKind::Minus => ParseRule { TokenKind::Minus => ParseRule {
prefix: Some(Parser::parse_unary), prefix: Some(Parser::parse_unary),
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_math_binary),
precedence: Precedence::Term, precedence: Precedence::Term,
}, },
TokenKind::MinusEqual => todo!(), TokenKind::MinusEqual => todo!(),
@ -1055,12 +1077,12 @@ impl From<&TokenKind> for ParseRule<'_> {
}, },
TokenKind::Percent => ParseRule { TokenKind::Percent => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_math_binary),
precedence: Precedence::Factor, precedence: Precedence::Factor,
}, },
TokenKind::Plus => ParseRule { TokenKind::Plus => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_math_binary),
precedence: Precedence::Term, precedence: Precedence::Term,
}, },
TokenKind::PlusEqual => todo!(), TokenKind::PlusEqual => todo!(),
@ -1086,12 +1108,12 @@ impl From<&TokenKind> for ParseRule<'_> {
}, },
TokenKind::Slash => ParseRule { TokenKind::Slash => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_math_binary),
precedence: Precedence::Factor, precedence: Precedence::Factor,
}, },
TokenKind::Star => ParseRule { TokenKind::Star => ParseRule {
prefix: None, prefix: None,
infix: Some(Parser::parse_binary), infix: Some(Parser::parse_math_binary),
precedence: Precedence::Factor, precedence: Precedence::Factor,
}, },
TokenKind::Str => todo!(), TokenKind::Str => todo!(),

View File

@ -26,11 +26,11 @@ fn negate() {
assert_eq!( assert_eq!(
parse(source), parse(source),
Ok(Chunk::with_data( Ok(Chunk::with_data(
vec![ vec![(
(Instruction::load_constant(0, 0), Span(2, 4)), *Instruction::negate(0, 0).set_first_argument_to_constant(),
(Instruction::negate(0, 0), Span(1, 5)), Span(0, 1)
], ),],
vec![Value::integer(42),], vec![Value::integer(42)],
vec![] vec![]
)), )),
); );

View File

@ -197,7 +197,7 @@ impl Vm {
position, position,
})?; })?;
if boolean != test_value { if boolean == test_value {
self.ip += 1; self.ip += 1;
} }
} }