Continue passing tests

This commit is contained in:
Jeff 2024-08-14 18:30:36 -04:00
parent f4d29eca38
commit 441df54a44
2 changed files with 627 additions and 124 deletions

View File

@ -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(())
}
}

View File

@ -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]