Extend parsing
This commit is contained in:
parent
57edf48e36
commit
23f733d8b2
@ -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!(),
|
||||||
|
@ -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![]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
@ -197,7 +197,7 @@ impl Vm {
|
|||||||
position,
|
position,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if boolean != test_value {
|
if boolean == test_value {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user