Continue passing tests
This commit is contained in:
parent
f4d29eca38
commit
441df54a44
@ -97,6 +97,24 @@ impl Expression {
|
||||
))
|
||||
}
|
||||
|
||||
pub fn as_identifier(&self) -> Option<&Identifier> {
|
||||
if let Expression::WithoutBlock(Node {
|
||||
inner: expression_without_block,
|
||||
..
|
||||
}) = self
|
||||
{
|
||||
if let ExpressionWithoutBlock::Identifier(identifier) =
|
||||
expression_without_block.as_ref()
|
||||
{
|
||||
Some(identifier)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn position(&self) -> Span {
|
||||
match self {
|
||||
Expression::WithBlock(expression_node) => expression_node.position,
|
||||
@ -297,6 +315,11 @@ pub enum OperatorExpression {
|
||||
assignee: Expression,
|
||||
value: Expression,
|
||||
},
|
||||
Comparison {
|
||||
left: Expression,
|
||||
operator: Node<ComparisonOperator>,
|
||||
right: Expression,
|
||||
},
|
||||
CompoundAssignment {
|
||||
assignee: Expression,
|
||||
operator: Node<MathOperator>,
|
||||
@ -312,7 +335,7 @@ pub enum OperatorExpression {
|
||||
},
|
||||
Logic {
|
||||
left: Expression,
|
||||
operator: LogicOperator,
|
||||
operator: Node<LogicOperator>,
|
||||
right: Expression,
|
||||
},
|
||||
}
|
||||
@ -323,6 +346,13 @@ impl Display for OperatorExpression {
|
||||
OperatorExpression::Assignment { assignee, value } => {
|
||||
write!(f, "{} = {}", assignee, value)
|
||||
}
|
||||
OperatorExpression::Comparison {
|
||||
left,
|
||||
operator,
|
||||
right,
|
||||
} => {
|
||||
write!(f, "{} {} {}", left, operator, right)
|
||||
}
|
||||
OperatorExpression::CompoundAssignment {
|
||||
assignee,
|
||||
operator,
|
||||
@ -349,6 +379,31 @@ impl Display for OperatorExpression {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum ComparisonOperator {
|
||||
Equal,
|
||||
NotEqual,
|
||||
GreaterThan,
|
||||
GreaterThanOrEqual,
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
}
|
||||
|
||||
impl Display for ComparisonOperator {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let operator = match self {
|
||||
ComparisonOperator::Equal => "==",
|
||||
ComparisonOperator::NotEqual => "!=",
|
||||
ComparisonOperator::GreaterThan => ">",
|
||||
ComparisonOperator::GreaterThanOrEqual => ">=",
|
||||
ComparisonOperator::LessThan => "<",
|
||||
ComparisonOperator::LessThanOrEqual => "<=",
|
||||
};
|
||||
|
||||
write!(f, "{}", operator)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum MathOperator {
|
||||
Add,
|
||||
@ -390,21 +445,50 @@ impl Display for LogicOperator {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct If {
|
||||
pub condition: Expression,
|
||||
pub if_block: Node<Block>,
|
||||
pub else_block: Option<Node<Block>>,
|
||||
pub enum If {
|
||||
If {
|
||||
condition: Expression,
|
||||
if_block: Node<Block>,
|
||||
},
|
||||
IfElse {
|
||||
condition: Expression,
|
||||
if_block: Node<Block>,
|
||||
r#else: ElseExpression,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum ElseExpression {
|
||||
Block(Node<Block>),
|
||||
If(Box<If>),
|
||||
}
|
||||
|
||||
impl Display for ElseExpression {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
ElseExpression::Block(block) => write!(f, "{}", block),
|
||||
ElseExpression::If(r#if) => write!(f, "{}", r#if),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for If {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "if {} {}", self.condition, self.if_block)?;
|
||||
|
||||
if let Some(else_block) = &self.else_block {
|
||||
write!(f, " else {}", else_block)?;
|
||||
match self {
|
||||
If::If {
|
||||
condition,
|
||||
if_block,
|
||||
} => {
|
||||
write!(f, "if {} {}", condition, if_block)
|
||||
}
|
||||
If::IfElse {
|
||||
condition,
|
||||
if_block,
|
||||
r#else,
|
||||
} => {
|
||||
write!(f, "if {} {} else {}", condition, if_block, r#else)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,48 +358,6 @@ impl<'src> Parser<'src> {
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
if let Token::LeftCurlyBrace = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
let mut fields = Vec::new();
|
||||
|
||||
loop {
|
||||
if let Token::RightCurlyBrace = self.current_token {
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
return Ok(Expression::r#struct(
|
||||
StructExpression::Fields {
|
||||
name: Node::new(identifier, identifier_position),
|
||||
fields,
|
||||
},
|
||||
position,
|
||||
));
|
||||
}
|
||||
|
||||
let field_name = self.parse_identifier()?;
|
||||
|
||||
if let Token::Colon = self.current_token {
|
||||
self.next_token()?;
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::Equal,
|
||||
actual: self.current_token.to_owned(),
|
||||
position: self.current_position,
|
||||
});
|
||||
}
|
||||
|
||||
let field_value = self.parse_expression(0)?;
|
||||
|
||||
fields.push((field_name, field_value));
|
||||
|
||||
if let Token::Comma = self.current_token {
|
||||
self.next_token()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Expression::identifier(identifier, identifier_position))
|
||||
}
|
||||
Token::Integer(text) => {
|
||||
@ -445,27 +403,11 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
Token::If => {
|
||||
self.next_token()?;
|
||||
let start = self.current_position.0;
|
||||
let r#if = self.parse_if()?;
|
||||
let position = (start, self.current_position.1);
|
||||
|
||||
let condition = self.parse_expression(0)?;
|
||||
let if_block = self.parse_block()?;
|
||||
let else_block = if let Token::Else = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
Some(self.parse_block()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
|
||||
Ok(Expression::r#if(
|
||||
If {
|
||||
condition,
|
||||
if_block,
|
||||
else_block,
|
||||
},
|
||||
position,
|
||||
))
|
||||
Ok(Expression::r#if(r#if, position))
|
||||
}
|
||||
Token::String(text) => {
|
||||
self.next_token()?;
|
||||
@ -682,6 +624,53 @@ impl<'src> Parser<'src> {
|
||||
log::trace!("Parsing {} as postfix operator", self.current_token);
|
||||
|
||||
let statement = match &self.current_token {
|
||||
Token::LeftCurlyBrace => {
|
||||
let identifier = if let Some(identifier) = left.as_identifier() {
|
||||
identifier
|
||||
} else {
|
||||
return Err(ParseError::ExpectedIdentifierNode { actual: left });
|
||||
};
|
||||
|
||||
let name = Node::new(identifier.clone(), left.position());
|
||||
let start_left = self.current_position.0;
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
let mut fields = Vec::new();
|
||||
|
||||
loop {
|
||||
if let Token::RightCurlyBrace = self.current_token {
|
||||
let position = (start_left, self.current_position.1);
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
return Ok(Expression::r#struct(
|
||||
StructExpression::Fields { name, fields },
|
||||
position,
|
||||
));
|
||||
}
|
||||
|
||||
let field_name = self.parse_identifier()?;
|
||||
|
||||
if let Token::Colon = self.current_token {
|
||||
self.next_token()?;
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::Equal,
|
||||
actual: self.current_token.to_owned(),
|
||||
position: self.current_position,
|
||||
});
|
||||
}
|
||||
|
||||
let field_value = self.parse_expression(0)?;
|
||||
|
||||
fields.push((field_name, field_value));
|
||||
|
||||
if let Token::Comma = self.current_token {
|
||||
self.next_token()?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Token::LeftParenthesis => {
|
||||
self.next_token()?;
|
||||
|
||||
@ -751,6 +740,46 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_if(&mut self) -> Result<If, ParseError> {
|
||||
if let Token::If = self.current_token {
|
||||
self.next_token()?;
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::If,
|
||||
actual: self.current_token.to_owned(),
|
||||
position: self.current_position,
|
||||
});
|
||||
}
|
||||
|
||||
let condition = self.parse_expression(0)?;
|
||||
let if_block = self.parse_block()?;
|
||||
|
||||
if let Token::Else = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
if let Ok(else_if) = self.parse_if() {
|
||||
Ok(If::IfElse {
|
||||
condition,
|
||||
if_block,
|
||||
r#else: ElseExpression::If(Box::new(else_if)),
|
||||
})
|
||||
} else {
|
||||
let else_block = self.parse_block()?;
|
||||
|
||||
Ok(If::IfElse {
|
||||
condition,
|
||||
if_block,
|
||||
r#else: ElseExpression::Block(else_block),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Ok(If::If {
|
||||
condition,
|
||||
if_block,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_identifier(&mut self) -> Result<Node<Identifier>, ParseError> {
|
||||
if let Token::Identifier(text) = self.current_token {
|
||||
self.next_token()?;
|
||||
@ -840,7 +869,10 @@ pub enum ParseError {
|
||||
ExpectedExpression {
|
||||
actual: Statement,
|
||||
},
|
||||
ExpectedIdentifier {
|
||||
ExpectedIdentifierNode {
|
||||
actual: Expression,
|
||||
},
|
||||
ExpectedIdentifierToken {
|
||||
actual: TokenOwned,
|
||||
position: Span,
|
||||
},
|
||||
@ -880,7 +912,8 @@ impl ParseError {
|
||||
ParseError::Boolean { position, .. } => *position,
|
||||
ParseError::ExpectedAssignment { actual } => actual.position(),
|
||||
ParseError::ExpectedExpression { actual } => actual.position(),
|
||||
ParseError::ExpectedIdentifier { position, .. } => *position,
|
||||
ParseError::ExpectedIdentifierNode { actual } => actual.position(),
|
||||
ParseError::ExpectedIdentifierToken { position, .. } => *position,
|
||||
ParseError::ExpectedToken { position, .. } => *position,
|
||||
ParseError::ExpectedTokenMultiple { position, .. } => *position,
|
||||
ParseError::Float { position, .. } => *position,
|
||||
@ -906,7 +939,10 @@ impl Display for ParseError {
|
||||
Self::Boolean { error, .. } => write!(f, "{}", error),
|
||||
Self::ExpectedAssignment { .. } => write!(f, "Expected assignment"),
|
||||
Self::ExpectedExpression { .. } => write!(f, "Expected expression"),
|
||||
Self::ExpectedIdentifier { actual, .. } => {
|
||||
Self::ExpectedIdentifierNode { actual } => {
|
||||
write!(f, "Expected identifier, found {actual}")
|
||||
}
|
||||
Self::ExpectedIdentifierToken { actual, .. } => {
|
||||
write!(f, "Expected identifier, found {actual}")
|
||||
}
|
||||
Self::ExpectedToken {
|
||||
@ -1083,14 +1119,72 @@ mod tests {
|
||||
fn if_else() {
|
||||
let source = "if x { y } else { z }";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::r#if(
|
||||
If::IfElse {
|
||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||
if_block: Node::new(
|
||||
Block::Sync(vec![Statement::Expression(Expression::identifier(
|
||||
Identifier::new("y"),
|
||||
(7, 8)
|
||||
))]),
|
||||
(5, 10)
|
||||
),
|
||||
r#else: ElseExpression::Block(Node::new(
|
||||
Block::Sync(vec![Statement::Expression(Expression::identifier(
|
||||
Identifier::new("z"),
|
||||
(18, 19)
|
||||
))]),
|
||||
(16, 21)
|
||||
))
|
||||
},
|
||||
(0, 21)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn if_else_if_else() {
|
||||
let source = "if x { y } else if z { a } else { b }";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::r#if(
|
||||
If::IfElse {
|
||||
condition: Expression::identifier(Identifier::new("x"), (3, 4)),
|
||||
if_block: Node::new(
|
||||
Block::Sync(vec![Statement::Expression(Expression::identifier(
|
||||
Identifier::new("y"),
|
||||
(7, 8)
|
||||
))]),
|
||||
(5, 10)
|
||||
),
|
||||
r#else: ElseExpression::If(Box::new(If::IfElse {
|
||||
condition: Expression::identifier(Identifier::new("z"), (19, 20)),
|
||||
if_block: Node::new(
|
||||
Block::Sync(vec![Statement::Expression(Expression::identifier(
|
||||
Identifier::new("a"),
|
||||
(23, 24)
|
||||
))]),
|
||||
(21, 26)
|
||||
),
|
||||
r#else: ElseExpression::Block(Node::new(
|
||||
Block::Sync(vec![Statement::Expression(Expression::identifier(
|
||||
Identifier::new("b"),
|
||||
(34, 35)
|
||||
))]),
|
||||
(32, 37)
|
||||
)),
|
||||
})),
|
||||
},
|
||||
(0, 37)
|
||||
))
|
||||
]))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1104,42 +1198,162 @@ mod tests {
|
||||
fn while_loop() {
|
||||
let source = "while x < 10 { x += 1 }";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::r#loop(
|
||||
Loop::While {
|
||||
condition: Expression::operator(
|
||||
OperatorExpression::Comparison {
|
||||
left: Expression::identifier(Identifier::new("x"), (0, 0)),
|
||||
operator: Node::new(ComparisonOperator::LessThan, (0, 0)),
|
||||
right: Expression::literal(LiteralExpression::Integer(10), (0, 0)),
|
||||
},
|
||||
(0, 0)
|
||||
),
|
||||
block: Node::new(
|
||||
Block::Sync(vec![Statement::Expression(Expression::operator(
|
||||
OperatorExpression::CompoundAssignment {
|
||||
assignee: Expression::identifier(Identifier::new("x"), (0, 0)),
|
||||
operator: Node::new(MathOperator::Add, (0, 0)),
|
||||
value: Expression::literal(
|
||||
LiteralExpression::Integer(1),
|
||||
(0, 0)
|
||||
),
|
||||
},
|
||||
(0, 0)
|
||||
))]),
|
||||
(0, 0)
|
||||
)
|
||||
},
|
||||
(0, 0)
|
||||
))
|
||||
]))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_assign() {
|
||||
let source = "a += 1";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Assignment {
|
||||
assignee: Expression::identifier(Identifier::new("a"), (0, 0)),
|
||||
value: Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::identifier(Identifier::new("a"), (0, 0)),
|
||||
operator: Node::new(MathOperator::Add, (0, 0)),
|
||||
right: Expression::literal(LiteralExpression::Integer(1), (0, 0)),
|
||||
},
|
||||
(0, 0)
|
||||
),
|
||||
},
|
||||
(0, 0)
|
||||
))
|
||||
]))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn or() {
|
||||
let source = "true || false";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn misplaced_semicolon() {
|
||||
let source = ";";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Logic {
|
||||
left: Expression::literal(LiteralExpression::Boolean(true), (0, 0)),
|
||||
operator: Node::new(LogicOperator::Or, (0, 0)),
|
||||
right: Expression::literal(LiteralExpression::Boolean(false), (0, 0)),
|
||||
},
|
||||
(0, 0)
|
||||
))
|
||||
]))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_with_one_statement() {
|
||||
let source = "{ 40 + 2 }";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::block(
|
||||
Block::Sync(vec![Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(LiteralExpression::Integer(40), (0, 0)),
|
||||
operator: Node::new(MathOperator::Add, (0, 0)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (0, 0)),
|
||||
},
|
||||
(0, 0)
|
||||
))]),
|
||||
(0, 0)
|
||||
))
|
||||
]))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn block_with_assignment() {
|
||||
let source = "{ foo = 42; bar = 42; baz = '42' }";
|
||||
|
||||
assert_eq!(parse(source), todo!())
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::block(
|
||||
Block::Sync(vec![
|
||||
Statement::ExpressionNullified(Node::new(
|
||||
Expression::operator(
|
||||
OperatorExpression::Assignment {
|
||||
assignee: Expression::identifier(
|
||||
Identifier::new("foo"),
|
||||
(0, 0)
|
||||
),
|
||||
value: Expression::literal(
|
||||
LiteralExpression::Integer(42),
|
||||
(0, 0)
|
||||
),
|
||||
},
|
||||
(0, 0)
|
||||
),
|
||||
(0, 0)
|
||||
)),
|
||||
Statement::ExpressionNullified(Node::new(
|
||||
Expression::operator(
|
||||
OperatorExpression::Assignment {
|
||||
assignee: Expression::identifier(
|
||||
Identifier::new("bar"),
|
||||
(0, 0)
|
||||
),
|
||||
value: Expression::literal(
|
||||
LiteralExpression::Integer(42),
|
||||
(0, 0)
|
||||
),
|
||||
},
|
||||
(0, 0)
|
||||
),
|
||||
(0, 0)
|
||||
)),
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Assignment {
|
||||
assignee: Expression::identifier(Identifier::new("baz"), (0, 0)),
|
||||
value: Expression::literal(
|
||||
LiteralExpression::String("42".to_string()),
|
||||
(0, 0)
|
||||
),
|
||||
},
|
||||
(0, 0)
|
||||
)),
|
||||
]),
|
||||
(0, 0)
|
||||
))
|
||||
]))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1174,112 +1388,317 @@ mod tests {
|
||||
fn equal() {
|
||||
let source = "42 == 42";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modulo() {
|
||||
let source = "42 % 2";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide() {
|
||||
let source = "42 / 2";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(LiteralExpression::Integer(42), (0, 2)),
|
||||
operator: Node::new(MathOperator::Divide, (3, 4)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (5, 6)),
|
||||
},
|
||||
(0, 6),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than() {
|
||||
let source = "1 < 2";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Comparison {
|
||||
left: Expression::literal(LiteralExpression::Integer(1), (0, 1)),
|
||||
operator: Node::new(ComparisonOperator::LessThan, (2, 3)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (4, 5)),
|
||||
},
|
||||
(0, 5),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn less_than_or_equal() {
|
||||
let source = "1 <= 2";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Comparison {
|
||||
left: Expression::literal(LiteralExpression::Integer(1), (0, 1)),
|
||||
operator: Node::new(ComparisonOperator::LessThanOrEqual, (2, 3)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (4, 5)),
|
||||
},
|
||||
(0, 5),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than_or_equal() {
|
||||
let source = "1 >= 2";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Comparison {
|
||||
left: Expression::literal(LiteralExpression::Integer(1), (0, 1)),
|
||||
operator: Node::new(ComparisonOperator::GreaterThanOrEqual, (2, 3)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (4, 5)),
|
||||
},
|
||||
(0, 5),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater_than() {
|
||||
let source = "1 > 2";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Comparison {
|
||||
left: Expression::literal(LiteralExpression::Integer(1), (0, 1)),
|
||||
operator: Node::new(ComparisonOperator::GreaterThan, (2, 3)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (4, 5)),
|
||||
},
|
||||
(0, 5),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtract_negative_integers() {
|
||||
let source = "-1 - -2";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(LiteralExpression::Integer(-1), (0, 2)),
|
||||
operator: Node::new(MathOperator::Subtract, (2, 3)),
|
||||
right: Expression::literal(LiteralExpression::Integer(-2), (5, 7)),
|
||||
},
|
||||
(0, 7),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modulo() {
|
||||
let source = "42 % 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(LiteralExpression::Integer(42), (0, 2)),
|
||||
operator: Node::new(MathOperator::Divide, (3, 4)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (5, 6)),
|
||||
},
|
||||
(0, 6),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn divide() {
|
||||
let source = "42 / 2";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(LiteralExpression::Integer(42), (0, 2)),
|
||||
operator: Node::new(MathOperator::Divide, (3, 4)),
|
||||
right: Expression::literal(LiteralExpression::Integer(2), (5, 6)),
|
||||
},
|
||||
(0, 6),
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_concatenation() {
|
||||
let source = "\"Hello, \" + \"World!\"";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(
|
||||
LiteralExpression::String("Hello, ".to_string()),
|
||||
(0, 9)
|
||||
),
|
||||
operator: Node::new(MathOperator::Add, (9, 10)),
|
||||
right: Expression::literal(
|
||||
LiteralExpression::String("World!".to_string()),
|
||||
(10, 18)
|
||||
)
|
||||
},
|
||||
(0, 18)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string() {
|
||||
let source = "\"Hello, World!\"";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::literal(
|
||||
LiteralExpression::String("Hello, World!".to_string()),
|
||||
(0, 15)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boolean() {
|
||||
let source = "true";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn property_access_function_call() {
|
||||
let source = "42.is_even()";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::literal(
|
||||
LiteralExpression::Boolean(true),
|
||||
(0, 4)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list_index() {
|
||||
let source = "[1, 2, 3][0]";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::list_index(
|
||||
ListIndex {
|
||||
list: Expression::list(
|
||||
ListExpression::Ordered(vec![
|
||||
Expression::literal(LiteralExpression::Integer(1), (1, 2)),
|
||||
Expression::literal(LiteralExpression::Integer(2), (4, 5)),
|
||||
Expression::literal(LiteralExpression::Integer(3), (7, 8)),
|
||||
]),
|
||||
(0, 9)
|
||||
),
|
||||
index: Expression::literal(LiteralExpression::Integer(0), (10, 11)),
|
||||
},
|
||||
(0, 12)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn property_access() {
|
||||
let source = "a.b";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::field_access(
|
||||
FieldAccess {
|
||||
container: Expression::identifier(Identifier::new("a"), (0, 1)),
|
||||
field: Node::new(Identifier::new("b"), (2, 3)),
|
||||
},
|
||||
(0, 3)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complex_list() {
|
||||
let source = "[1, 1 + 1, 2 + (4 * 10)]";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::list(
|
||||
ListExpression::Ordered(vec![
|
||||
Expression::literal(LiteralExpression::Integer(1), (1, 2)),
|
||||
Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(LiteralExpression::Integer(1), (4, 5)),
|
||||
operator: Node::new(MathOperator::Add, (6, 7)),
|
||||
right: Expression::literal(LiteralExpression::Integer(1), (8, 9)),
|
||||
},
|
||||
(4, 9)
|
||||
),
|
||||
Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(LiteralExpression::Integer(2), (11, 12)),
|
||||
operator: Node::new(MathOperator::Add, (13, 14)),
|
||||
right: Expression::grouped(
|
||||
Expression::operator(
|
||||
OperatorExpression::Math {
|
||||
left: Expression::literal(
|
||||
LiteralExpression::Integer(4),
|
||||
(16, 17)
|
||||
),
|
||||
operator: Node::new(MathOperator::Multiply, (18, 19)),
|
||||
right: Expression::literal(
|
||||
LiteralExpression::Integer(10),
|
||||
(20, 22)
|
||||
),
|
||||
},
|
||||
(16, 22)
|
||||
),
|
||||
(15, 23)
|
||||
),
|
||||
},
|
||||
(11, 23)
|
||||
)
|
||||
]),
|
||||
(0, 24)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn list() {
|
||||
let source = "[1, 2]";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree::with_statements([
|
||||
Statement::Expression(Expression::list(
|
||||
ListExpression::Ordered(vec![
|
||||
Expression::literal(LiteralExpression::Integer(1), (1, 2)),
|
||||
Expression::literal(LiteralExpression::Integer(2), (4, 5))
|
||||
]),
|
||||
(0, 6)
|
||||
))
|
||||
]))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user