Add math-assignment operators
This commit is contained in:
parent
d857f42434
commit
437a6bf164
@ -159,9 +159,15 @@ impl<'src> Lexer<'src> {
|
||||
}
|
||||
}
|
||||
'*' => {
|
||||
self.position += 1;
|
||||
if let Some('=') = self.peek_second_char() {
|
||||
self.position += 2;
|
||||
|
||||
(Token::Star, Span(self.position - 1, self.position))
|
||||
(Token::StarEqual, Span(self.position - 2, self.position))
|
||||
} else {
|
||||
self.position += 1;
|
||||
|
||||
(Token::Star, Span(self.position - 1, self.position))
|
||||
}
|
||||
}
|
||||
'(' => {
|
||||
self.position += 1;
|
||||
@ -261,9 +267,15 @@ impl<'src> Lexer<'src> {
|
||||
)
|
||||
}
|
||||
'/' => {
|
||||
self.position += 1;
|
||||
if let Some('=') = self.peek_second_char() {
|
||||
self.position += 2;
|
||||
|
||||
(Token::Slash, Span(self.position - 1, self.position))
|
||||
(Token::SlashEqual, Span(self.position - 2, self.position))
|
||||
} else {
|
||||
self.position += 1;
|
||||
|
||||
(Token::Slash, Span(self.position - 1, self.position))
|
||||
}
|
||||
}
|
||||
'%' => {
|
||||
self.position += 1;
|
||||
|
@ -348,12 +348,12 @@ impl<'src> Parser<'src> {
|
||||
) -> Result<(bool, bool, bool, u8), ParseError> {
|
||||
let mut push_back = false;
|
||||
let mut is_constant = false;
|
||||
let mut is_local = false;
|
||||
let mut is_mutable_local = false;
|
||||
let argument = match instruction.operation() {
|
||||
Operation::GetLocal => {
|
||||
is_local = true;
|
||||
let local_index = instruction.b();
|
||||
let local = self.chunk.get_local(local_index, self.current_position)?;
|
||||
is_mutable_local = local.is_mutable;
|
||||
|
||||
if let Some(index) = local.register_index {
|
||||
index
|
||||
@ -380,24 +380,44 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
};
|
||||
|
||||
Ok((push_back, is_constant, is_local, argument))
|
||||
Ok((push_back, is_constant, is_mutable_local, argument))
|
||||
}
|
||||
|
||||
fn parse_math_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_is_local, left) =
|
||||
let (push_back_left, left_is_constant, left_is_mutable_local, left) =
|
||||
self.handle_binary_argument(&left_instruction)?;
|
||||
|
||||
let operator = self.current_token;
|
||||
let operator_position = self.current_position;
|
||||
let rule = ParseRule::from(&operator.kind());
|
||||
|
||||
if let TokenKind::PlusEqual
|
||||
| TokenKind::MinusEqual
|
||||
| TokenKind::StarEqual
|
||||
| TokenKind::SlashEqual = operator.kind()
|
||||
{
|
||||
if !left_is_mutable_local {
|
||||
return Err(ParseError::ExpectedMutableVariable {
|
||||
found: self.previous_token.to_owned(),
|
||||
position: left_position,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
self.advance()?;
|
||||
self.parse(rule.precedence.increment())?;
|
||||
|
||||
let register = if left_is_local {
|
||||
let (right_instruction, right_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
let (push_back_right, right_is_constant, right_is_mutable_local, right) =
|
||||
self.handle_binary_argument(&right_instruction)?;
|
||||
|
||||
let register = if left_is_mutable_local {
|
||||
left
|
||||
} else if right_is_mutable_local {
|
||||
right
|
||||
} else {
|
||||
let current = self.current_register;
|
||||
|
||||
@ -406,18 +426,26 @@ impl<'src> Parser<'src> {
|
||||
current
|
||||
};
|
||||
let mut new_instruction = match operator.kind() {
|
||||
TokenKind::Plus => Instruction::add(register, left, 0),
|
||||
TokenKind::Minus => Instruction::subtract(register, left, 0),
|
||||
TokenKind::Star => Instruction::multiply(register, left, 0),
|
||||
TokenKind::Slash => Instruction::divide(register, left, 0),
|
||||
TokenKind::Percent => Instruction::modulo(register, left, 0),
|
||||
TokenKind::Plus => Instruction::add(register, left, right),
|
||||
TokenKind::PlusEqual => Instruction::add(register, left, right),
|
||||
TokenKind::Minus => Instruction::subtract(register, left, right),
|
||||
TokenKind::MinusEqual => Instruction::subtract(register, left, right),
|
||||
TokenKind::Star => Instruction::multiply(register, left, right),
|
||||
TokenKind::StarEqual => Instruction::multiply(register, left, right),
|
||||
TokenKind::Slash => Instruction::divide(register, left, right),
|
||||
TokenKind::SlashEqual => Instruction::divide(register, left, right),
|
||||
TokenKind::Percent => Instruction::modulo(register, left, right),
|
||||
_ => {
|
||||
return Err(ParseError::ExpectedTokenMultiple {
|
||||
expected: &[
|
||||
TokenKind::Plus,
|
||||
TokenKind::PlusEqual,
|
||||
TokenKind::Minus,
|
||||
TokenKind::MinusEqual,
|
||||
TokenKind::Star,
|
||||
TokenKind::StarEqual,
|
||||
TokenKind::Slash,
|
||||
TokenKind::SlashEqual,
|
||||
TokenKind::Percent,
|
||||
],
|
||||
found: operator.to_owned(),
|
||||
@ -426,13 +454,6 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
};
|
||||
|
||||
let (right_instruction, right_position) =
|
||||
self.chunk.pop_instruction(self.current_position)?;
|
||||
let (push_back_right, right_is_constant, right_is_local, right) =
|
||||
self.handle_binary_argument(&right_instruction)?;
|
||||
|
||||
new_instruction.set_c(right);
|
||||
|
||||
if left_is_constant {
|
||||
new_instruction.set_b_is_constant();
|
||||
}
|
||||
@ -1122,7 +1143,11 @@ impl From<&TokenKind> for ParseRule<'_> {
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Term,
|
||||
},
|
||||
TokenKind::MinusEqual => todo!(),
|
||||
TokenKind::MinusEqual => ParseRule {
|
||||
prefix: None,
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Assignment,
|
||||
},
|
||||
TokenKind::Mut => ParseRule {
|
||||
prefix: None,
|
||||
infix: None,
|
||||
@ -1138,7 +1163,11 @@ impl From<&TokenKind> for ParseRule<'_> {
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Term,
|
||||
},
|
||||
TokenKind::PlusEqual => todo!(),
|
||||
TokenKind::PlusEqual => ParseRule {
|
||||
prefix: None,
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Assignment,
|
||||
},
|
||||
TokenKind::RightCurlyBrace => ParseRule {
|
||||
prefix: None,
|
||||
infix: None,
|
||||
@ -1164,11 +1193,21 @@ impl From<&TokenKind> for ParseRule<'_> {
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Factor,
|
||||
},
|
||||
TokenKind::SlashEqual => ParseRule {
|
||||
prefix: None,
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Assignment,
|
||||
},
|
||||
TokenKind::Star => ParseRule {
|
||||
prefix: None,
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Factor,
|
||||
},
|
||||
TokenKind::StarEqual => ParseRule {
|
||||
prefix: None,
|
||||
infix: Some(Parser::parse_math_binary),
|
||||
precedence: Precedence::Assignment,
|
||||
},
|
||||
TokenKind::Str => todo!(),
|
||||
TokenKind::String => ParseRule {
|
||||
prefix: Some(Parser::parse_string),
|
||||
@ -1205,6 +1244,10 @@ pub enum ParseError {
|
||||
found: TokenOwned,
|
||||
position: Span,
|
||||
},
|
||||
ExpectedMutableVariable {
|
||||
found: TokenOwned,
|
||||
position: Span,
|
||||
},
|
||||
InvalidAssignmentTarget {
|
||||
found: TokenOwned,
|
||||
position: Span,
|
||||
@ -1250,6 +1293,7 @@ impl AnnotatedError for ParseError {
|
||||
Self::ExpectedExpression { .. } => "Expected an expression",
|
||||
Self::ExpectedToken { .. } => "Expected a specific token",
|
||||
Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens",
|
||||
Self::ExpectedMutableVariable { .. } => "Expected a mutable variable",
|
||||
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
|
||||
Self::UndefinedVariable { .. } => "Undefined variable",
|
||||
Self::RegisterOverflow { .. } => "Register overflow",
|
||||
@ -1291,6 +1335,9 @@ impl AnnotatedError for ParseError {
|
||||
|
||||
Some(details)
|
||||
}
|
||||
Self::ExpectedMutableVariable { found, .. } => {
|
||||
Some(format!("Expected mutable variable, found \"{found}\""))
|
||||
}
|
||||
Self::InvalidAssignmentTarget { found, .. } => {
|
||||
Some(format!("Invalid assignment target, found \"{found}\""))
|
||||
}
|
||||
@ -1312,6 +1359,7 @@ impl AnnotatedError for ParseError {
|
||||
Self::ExpectedExpression { position, .. } => *position,
|
||||
Self::ExpectedToken { position, .. } => *position,
|
||||
Self::ExpectedTokenMultiple { position, .. } => *position,
|
||||
Self::ExpectedMutableVariable { position, .. } => *position,
|
||||
Self::InvalidAssignmentTarget { position, .. } => *position,
|
||||
Self::UndefinedVariable { position, .. } => *position,
|
||||
Self::RegisterOverflow { position } => *position,
|
||||
|
@ -60,7 +60,9 @@ pub enum Token<'src> {
|
||||
RightSquareBrace,
|
||||
Semicolon,
|
||||
Slash,
|
||||
SlashEqual,
|
||||
Star,
|
||||
StarEqual,
|
||||
}
|
||||
|
||||
impl<'src> Token<'src> {
|
||||
@ -116,7 +118,9 @@ impl<'src> Token<'src> {
|
||||
Token::RightSquareBrace => 1,
|
||||
Token::Semicolon => 1,
|
||||
Token::Slash => 1,
|
||||
Token::SlashEqual => 2,
|
||||
Token::Star => 1,
|
||||
Token::StarEqual => 2,
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,7 +171,9 @@ impl<'src> Token<'src> {
|
||||
Token::RightSquareBrace => TokenOwned::RightSquareBrace,
|
||||
Token::Semicolon => TokenOwned::Semicolon,
|
||||
Token::Star => TokenOwned::Star,
|
||||
Token::StarEqual => TokenOwned::StarEqual,
|
||||
Token::Slash => TokenOwned::Slash,
|
||||
Token::SlashEqual => TokenOwned::SlashEqual,
|
||||
Token::String(text) => TokenOwned::String(text.to_string()),
|
||||
Token::Str => TokenOwned::Str,
|
||||
Token::Struct => TokenOwned::Struct,
|
||||
@ -222,7 +228,9 @@ impl<'src> Token<'src> {
|
||||
Token::RightSquareBrace => TokenKind::RightSquareBrace,
|
||||
Token::Semicolon => TokenKind::Semicolon,
|
||||
Token::Star => TokenKind::Star,
|
||||
Token::StarEqual => TokenKind::StarEqual,
|
||||
Token::Slash => TokenKind::Slash,
|
||||
Token::SlashEqual => TokenKind::SlashEqual,
|
||||
Token::Str => TokenKind::Str,
|
||||
Token::String(_) => TokenKind::String,
|
||||
Token::Struct => TokenKind::Struct,
|
||||
@ -279,7 +287,9 @@ impl<'src> Display for Token<'src> {
|
||||
Token::RightSquareBrace => write!(f, "]"),
|
||||
Token::Semicolon => write!(f, ";"),
|
||||
Token::Slash => write!(f, "/"),
|
||||
Token::SlashEqual => write!(f, "/="),
|
||||
Token::Star => write!(f, "*"),
|
||||
Token::StarEqual => write!(f, "*="),
|
||||
Token::Str => write!(f, "str"),
|
||||
Token::String(value) => write!(f, "{value}"),
|
||||
Token::Struct => write!(f, "struct"),
|
||||
@ -348,8 +358,10 @@ pub enum TokenOwned {
|
||||
RightSquareBrace,
|
||||
Semicolon,
|
||||
Star,
|
||||
StarEqual,
|
||||
Struct,
|
||||
Slash,
|
||||
SlashEqual,
|
||||
}
|
||||
|
||||
impl Display for TokenOwned {
|
||||
@ -400,7 +412,9 @@ impl Display for TokenOwned {
|
||||
TokenOwned::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
||||
TokenOwned::Semicolon => Token::Semicolon.fmt(f),
|
||||
TokenOwned::Star => Token::Star.fmt(f),
|
||||
TokenOwned::StarEqual => Token::StarEqual.fmt(f),
|
||||
TokenOwned::Slash => Token::Slash.fmt(f),
|
||||
TokenOwned::SlashEqual => Token::SlashEqual.fmt(f),
|
||||
TokenOwned::Str => Token::Str.fmt(f),
|
||||
TokenOwned::String(string) => Token::String(string).fmt(f),
|
||||
TokenOwned::Struct => Token::Struct.fmt(f),
|
||||
@ -467,8 +481,10 @@ pub enum TokenKind {
|
||||
RightSquareBrace,
|
||||
Semicolon,
|
||||
Star,
|
||||
StarEqual,
|
||||
Struct,
|
||||
Slash,
|
||||
SlashEqual,
|
||||
}
|
||||
|
||||
impl Display for TokenKind {
|
||||
@ -519,8 +535,10 @@ impl Display for TokenKind {
|
||||
TokenKind::RightSquareBrace => Token::RightSquareBrace.fmt(f),
|
||||
TokenKind::Semicolon => Token::Semicolon.fmt(f),
|
||||
TokenKind::Star => Token::Star.fmt(f),
|
||||
TokenKind::StarEqual => Token::StarEqual.fmt(f),
|
||||
TokenKind::Str => Token::Str.fmt(f),
|
||||
TokenKind::Slash => Token::Slash.fmt(f),
|
||||
TokenKind::SlashEqual => Token::SlashEqual.fmt(f),
|
||||
TokenKind::String => write!(f, "string value"),
|
||||
TokenKind::Struct => Token::Struct.fmt(f),
|
||||
TokenKind::While => Token::While.fmt(f),
|
||||
|
@ -1,4 +1,5 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn add() {
|
||||
let source = "1 + 2";
|
||||
@ -23,6 +24,28 @@ fn add() {
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_assign() {
|
||||
let source = "let mut a = 1; a += 2; a";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 13)),
|
||||
(Instruction::define_local(0, 0, true), Span(8, 9)),
|
||||
(*Instruction::add(0, 0, 1).set_c_is_constant(), Span(17, 19)),
|
||||
(Instruction::get_local(1, 0), Span(23, 24)),
|
||||
(Instruction::r#return(), Span(24, 24))
|
||||
],
|
||||
vec![Value::integer(1), Value::integer(2)],
|
||||
vec![Local::new(Identifier::new("a"), true, 0, Some(0))]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn and() {
|
||||
let source = "true && false";
|
||||
@ -97,6 +120,7 @@ fn block_scope() {
|
||||
#[test]
|
||||
fn constant() {
|
||||
let source = "42";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -115,6 +139,7 @@ fn constant() {
|
||||
#[test]
|
||||
fn define_local() {
|
||||
let source = "let x = 42;";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -133,6 +158,7 @@ fn define_local() {
|
||||
#[test]
|
||||
fn divide() {
|
||||
let source = "2 / 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -153,9 +179,35 @@ fn divide() {
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_assign() {
|
||||
let source = "let mut a = 2; a /= 2; a";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 13)),
|
||||
(Instruction::define_local(0, 0, true), Span(8, 9)),
|
||||
(
|
||||
*Instruction::divide(0, 0, 1).set_c_is_constant(),
|
||||
Span(17, 19)
|
||||
),
|
||||
(Instruction::get_local(1, 0), Span(23, 24)),
|
||||
(Instruction::r#return(), Span(24, 24))
|
||||
],
|
||||
vec![Value::integer(2), Value::integer(2)],
|
||||
vec![Local::new(Identifier::new("a"), true, 0, Some(0))]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let source = "";
|
||||
|
||||
assert_eq!(parse(source), Ok(Chunk::with_data(vec![], vec![], vec![])),);
|
||||
assert_eq!(run(source), Ok(None));
|
||||
}
|
||||
@ -554,6 +606,7 @@ fn list_with_simple_expression() {
|
||||
#[test]
|
||||
fn math_operator_precedence() {
|
||||
let source = "1 + 2 - 3 * 4 / 5";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -594,6 +647,7 @@ fn math_operator_precedence() {
|
||||
#[test]
|
||||
fn multiply() {
|
||||
let source = "1 * 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -614,6 +668,31 @@ fn multiply() {
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(2))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_assign() {
|
||||
let source = "let mut a = 2; a *= 3 a";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 13)),
|
||||
(Instruction::define_local(0, 0, true), Span(8, 9)),
|
||||
(
|
||||
*Instruction::multiply(0, 0, 1).set_c_is_constant(),
|
||||
Span(17, 19)
|
||||
),
|
||||
(Instruction::get_local(1, 0), Span(22, 23)),
|
||||
(Instruction::r#return(), Span(23, 23))
|
||||
],
|
||||
vec![Value::integer(2), Value::integer(3)],
|
||||
vec![Local::new(Identifier::new("a"), true, 0, Some(0)),]
|
||||
))
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(6))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn negate() {
|
||||
let source = "-(42)";
|
||||
@ -683,6 +762,7 @@ fn not_equal() {
|
||||
#[test]
|
||||
fn or() {
|
||||
let source = "true || false";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -704,6 +784,7 @@ fn or() {
|
||||
#[test]
|
||||
fn parentheses_precedence() {
|
||||
let source = "(1 + 2) * 3";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -731,6 +812,7 @@ fn parentheses_precedence() {
|
||||
#[test]
|
||||
fn set_local() {
|
||||
let source = "let mut x = 41; x = 42; x";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -753,6 +835,7 @@ fn set_local() {
|
||||
#[test]
|
||||
fn subtract() {
|
||||
let source = "1 - 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
@ -773,9 +856,35 @@ fn subtract() {
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(-1))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_assign() {
|
||||
let source = "let mut x = 42; x -= 2; x";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(12, 14)),
|
||||
(Instruction::define_local(0, 0, true), Span(8, 9)),
|
||||
(
|
||||
*Instruction::subtract(0, 0, 1).set_c_is_constant(),
|
||||
Span(18, 20)
|
||||
),
|
||||
(Instruction::get_local(1, 0), Span(24, 25)),
|
||||
(Instruction::r#return(), Span(25, 25)),
|
||||
],
|
||||
vec![Value::integer(42), Value::integer(2)],
|
||||
vec![Local::new(Identifier::new("x"), true, 0, Some(0)),]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(40))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn variable_and() {
|
||||
let source = "let a = true; let b = false; a && b";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
|
65
dust-lang/tests/parse_errors.rs
Normal file
65
dust-lang/tests/parse_errors.rs
Normal file
@ -0,0 +1,65 @@
|
||||
use dust_lang::*;
|
||||
|
||||
#[test]
|
||||
fn add_assign_expects_variable() {
|
||||
let source = "1 += 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Err(DustError::Parse {
|
||||
error: ParseError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide_assign_expects_variable() {
|
||||
let source = "1 -= 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Err(DustError::Parse {
|
||||
error: ParseError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiply_assign_expects_variable() {
|
||||
let source = "1 *= 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Err(DustError::Parse {
|
||||
error: ParseError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_assign_expects_variable() {
|
||||
let source = "1 -= 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Err(DustError::Parse {
|
||||
error: ParseError::ExpectedMutableVariable {
|
||||
found: Token::Integer("1").to_owned(),
|
||||
position: Span(0, 1)
|
||||
},
|
||||
source
|
||||
})
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user