Continue passing tests and tweaking

This commit is contained in:
Jeff 2024-08-15 00:20:36 -04:00
parent 81b7888920
commit 486530610b
3 changed files with 320 additions and 191 deletions

View File

@ -16,27 +16,6 @@ pub enum Expression {
}
impl Expression {
pub fn range(range: Range, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Range(range)),
position,
))
}
pub fn call(call_expression: CallExpression, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Call(call_expression)),
position,
))
}
pub fn field_access(field_access: FieldAccess, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::FieldAccess(field_access)),
position,
))
}
pub fn operator(operator_expression: OperatorExpression, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(operator_expression)),
@ -44,9 +23,175 @@ impl Expression {
))
}
pub fn r#loop(r#loop: Loop, position: Span) -> Self {
pub fn range(start: Expression, end: Expression, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Range(Range { start, end })),
position,
))
}
pub fn call(invoker: Expression, arguments: Vec<Expression>, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Call(CallExpression {
invoker,
arguments,
})),
position,
))
}
pub fn field_access(container: Expression, field: Node<Identifier>, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::FieldAccess(FieldAccess {
container,
field,
})),
position,
))
}
pub fn tuple_access(tuple: Expression, index: Node<usize>, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::TupleAccess(TupleAccess {
tuple,
index,
})),
position,
))
}
pub fn assignment(assignee: Expression, value: Expression, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(
OperatorExpression::Assignment { assignee, value },
)),
position,
))
}
pub fn comparison(
left: Expression,
operator: Node<ComparisonOperator>,
right: Expression,
position: Span,
) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(
OperatorExpression::Comparison {
left,
operator,
right,
},
)),
position,
))
}
pub fn compound_assignment(
assignee: Expression,
operator: Node<MathOperator>,
modifier: Expression,
position: Span,
) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(
OperatorExpression::CompoundAssignment {
assignee,
operator,
modifier,
},
)),
position,
))
}
pub fn math(
left: Expression,
operator: Node<MathOperator>,
right: Expression,
position: Span,
) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(OperatorExpression::Math {
left,
operator,
right,
})),
position,
))
}
pub fn negation(expression: Expression, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(
OperatorExpression::Negation(expression),
)),
position,
))
}
pub fn not(expression: Expression, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(OperatorExpression::Not(
expression,
))),
position,
))
}
pub fn logic(
left: Expression,
operator: Node<LogicOperator>,
right: Expression,
position: Span,
) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(
OperatorExpression::Logic {
left,
operator,
right,
},
)),
position,
))
}
pub fn error_propagation(expression: Expression, position: Span) -> Self {
Expression::WithoutBlock(Node::new(
Box::new(ExpressionWithoutBlock::Operator(
OperatorExpression::ErrorPropagation(expression),
)),
position,
))
}
pub fn infinite_loop(block: Node<Block>, position: Span) -> Self {
Expression::WithBlock(Node::new(
Box::new(ExpressionWithBlock::Loop(r#loop)),
Box::new(ExpressionWithBlock::Loop(Loop::Infinite { block })),
position,
))
}
pub fn while_loop(condition: Expression, block: Node<Block>, position: Span) -> Self {
Expression::WithBlock(Node::new(
Box::new(ExpressionWithBlock::Loop(Loop::While { condition, block })),
position,
))
}
pub fn for_loop(
identifier: Node<Identifier>,
iterator: Expression,
block: Node<Block>,
position: Span,
) -> Self {
Expression::WithBlock(Node::new(
Box::new(ExpressionWithBlock::Loop(Loop::For {
identifier,
iterator,
block,
})),
position,
))
}
@ -168,6 +313,7 @@ pub enum ExpressionWithoutBlock {
FieldAccess(FieldAccess),
ListIndex(ListIndex),
Range(Range),
TupleAccess(TupleAccess),
}
impl Display for ExpressionWithoutBlock {
@ -183,10 +329,23 @@ impl Display for ExpressionWithoutBlock {
ExpressionWithoutBlock::FieldAccess(field_access) => write!(f, "{}", field_access),
ExpressionWithoutBlock::ListIndex(list_index) => write!(f, "{}", list_index),
ExpressionWithoutBlock::Range(range) => write!(f, "{}", range),
ExpressionWithoutBlock::TupleAccess(tuple_access) => write!(f, "{}", tuple_access),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TupleAccess {
pub tuple: Expression,
pub index: Node<usize>,
}
impl Display for TupleAccess {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}.{}", self.tuple, self.index)
}
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Range {
pub start: Expression,
@ -213,13 +372,13 @@ impl Display for ListIndex {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct CallExpression {
pub function: Expression,
pub invoker: Expression,
pub arguments: Vec<Expression>,
}
impl Display for CallExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}(", self.function)?;
write!(f, "{}(", self.invoker)?;
for (index, argument) in self.arguments.iter().enumerate() {
if index > 0 {
@ -342,7 +501,7 @@ pub enum OperatorExpression {
CompoundAssignment {
assignee: Expression,
operator: Node<MathOperator>,
value: Expression,
modifier: Expression,
},
ErrorPropagation(Expression),
Negation(Expression),
@ -375,7 +534,7 @@ impl Display for OperatorExpression {
OperatorExpression::CompoundAssignment {
assignee,
operator,
value,
modifier: value,
} => write!(f, "{} {}= {}", assignee, operator, value),
OperatorExpression::ErrorPropagation(expression) => write!(f, "{}?", expression),
OperatorExpression::Negation(expression) => write!(f, "-{}", expression),
@ -552,7 +711,9 @@ impl Display for Block {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum Loop {
Infinite(Block),
Infinite {
block: Node<Block>,
},
While {
condition: Expression,
block: Node<Block>,
@ -560,14 +721,14 @@ pub enum Loop {
For {
identifier: Node<Identifier>,
iterator: Expression,
block: Block,
block: Node<Block>,
},
}
impl Display for Loop {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Loop::Infinite(block) => write!(f, "loop {}", block),
Loop::Infinite { block } => write!(f, "loop {}", block),
Loop::While { condition, block } => write!(f, "while {} {}", condition, block),
Loop::For {
identifier,

View File

@ -298,10 +298,7 @@ impl<'src> Parser<'src> {
let operand = self.parse_expression(0)?;
let position = (operator_start, self.current_position.1);
Ok(Expression::operator(
OperatorExpression::Not(operand),
position,
))
Ok(Expression::not(operand, position))
}
Token::Minus => {
self.next_token()?;
@ -309,10 +306,7 @@ impl<'src> Parser<'src> {
let operand = self.parse_expression(0)?;
let position = (operator_start, self.current_position.1);
Ok(Expression::operator(
OperatorExpression::Negation(operand),
position,
))
Ok(Expression::negation(operand, position))
}
_ => Err(ParseError::UnexpectedToken {
actual: self.current_token.to_owned(),
@ -494,10 +488,7 @@ impl<'src> Parser<'src> {
let block = self.parse_block()?;
let position = (start_position.0, self.current_position.1);
Ok(Expression::r#loop(
Loop::While { condition, block },
position,
))
Ok(Expression::while_loop(condition, block, position))
}
_ => Err(ParseError::UnexpectedToken {
actual: self.current_token.to_owned(),
@ -523,13 +514,7 @@ impl<'src> Parser<'src> {
let value = self.parse_expression(operator_precedence)?;
let position = (left_start, value.position().1);
return Ok(Expression::operator(
OperatorExpression::Assignment {
assignee: left,
value,
},
position,
));
return Ok(Expression::assignment(left, value, position));
}
if let Token::PlusEqual | Token::MinusEqual = &self.current_token {
@ -549,22 +534,7 @@ impl<'src> Parser<'src> {
OperatorExpression::CompoundAssignment {
assignee: left,
operator,
value,
},
position,
));
}
if let Token::Dot = &self.current_token {
self.next_token()?;
let field = self.parse_identifier()?;
let position = (left_start, self.current_position.1);
return Ok(Expression::field_access(
FieldAccess {
container: left,
field,
modifier: value,
},
position,
));
@ -576,7 +546,7 @@ impl<'src> Parser<'src> {
let end = self.parse_expression(operator_precedence)?;
let position = (left_start, end.position().1);
return Ok(Expression::range(Range { start: left, end }, position));
return Ok(Expression::range(left, end, position));
}
if let Token::Minus | Token::Plus | Token::Star | Token::Slash | Token::Percent =
@ -673,6 +643,27 @@ impl<'src> Parser<'src> {
log::trace!("Parsing {} as postfix operator", self.current_token);
let expression = match &self.current_token {
Token::Dot => {
self.next_token()?;
if let Token::Integer(text) = &self.current_token {
let index = text.parse::<usize>().map_err(|error| ParseError::Integer {
error,
position: self.current_position,
})?;
let index_node = Node::new(index, self.current_position);
let position = (left.position().0, self.current_position.1);
self.next_token()?;
Expression::tuple_access(left, index_node, position)
} else {
let field = self.parse_identifier()?;
let position = (left.position().0, self.current_position.1);
Expression::field_access(left, field, position)
}
}
Token::LeftCurlyBrace => {
let identifier = if let Some(identifier) = left.as_identifier() {
identifier
@ -681,7 +672,6 @@ impl<'src> Parser<'src> {
};
let name = Node::new(identifier.clone(), left.position());
let start_left = self.current_position.0;
self.next_token()?;
@ -700,7 +690,7 @@ impl<'src> Parser<'src> {
self.next_token()?;
} else {
return Err(ParseError::ExpectedToken {
expected: TokenKind::Equal,
expected: TokenKind::Colon,
actual: self.current_token.to_owned(),
position: self.current_position,
});
@ -715,7 +705,7 @@ impl<'src> Parser<'src> {
}
}
let position = (start_left, self.current_position.1);
let position = (left.position().0, self.current_position.1);
Expression::r#struct(StructExpression::Fields { name, fields }, position)
}
@ -740,17 +730,9 @@ impl<'src> Parser<'src> {
let position = (left.position().0, self.current_position.1);
Expression::call(
CallExpression {
function: left,
arguments,
},
position,
)
Expression::call(left, arguments, position)
}
Token::LeftSquareBrace => {
let operator_start = self.current_position.0;
self.next_token()?;
let index = self.parse_expression(0)?;
@ -791,7 +773,7 @@ impl<'src> Parser<'src> {
fn parse_if(&mut self) -> Result<If, ParseError> {
// Assume that the "if" token has already been consumed
let condition = self.parse_expression(0)?;
let condition = self.parse_expression(10)?;
let if_block = self.parse_block()?;
if let Token::Else = self.current_token {
@ -1071,24 +1053,20 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::field_access(
FieldAccess {
container: Expression::call(
CallExpression {
function: Expression::identifier(Identifier::new("Foo"), (0, 0)),
arguments: vec![
Expression::literal(LiteralExpression::Integer(42), (0, 0)),
Statement::Expression(Expression::tuple_access(
Expression::call(
Expression::identifier(Identifier::new("Foo"), (0, 3)),
vec![
Expression::literal(LiteralExpression::Integer(42), (4, 6)),
Expression::literal(
LiteralExpression::String("bar".to_string()),
(0, 0)
(8, 13)
),
],
},
(0, 0)
(0, 15)
),
field: Node::new(Identifier::new("0"), (0, 0)),
},
(0, 0)
Node::new(0, (15, 16)),
(0, 16)
))
]))
);
@ -1096,7 +1074,12 @@ mod tests {
#[test]
fn fields_struct_instantiation() {
let source = "Foo { a = 42, b = 4.0 }";
let source = "Foo { a: 42, b: 4.0 }";
let mut tree = AbstractSyntaxTree::new();
if parse_into(source, &mut tree).is_err() {
println!("{:?}", tree);
}
assert_eq!(
parse(source),
@ -1130,19 +1113,19 @@ mod tests {
Ok(AbstractSyntaxTree::with_statements([
Statement::struct_definition(
StructDefinition::Fields {
name: Node::new(Identifier::new("Foo"), (0, 0)),
name: Node::new(Identifier::new("Foo"), (7, 10)),
fields: vec![
(
Node::new(Identifier::new("a"), (0, 0)),
Node::new(Type::Integer, (0, 0))
Node::new(Identifier::new("a"), (13, 14)),
Node::new(Type::Integer, (16, 19))
),
(
Node::new(Identifier::new("b"), (0, 0)),
Node::new(Type::Float, (0, 0))
Node::new(Identifier::new("b"), (21, 22)),
Node::new(Type::Float, (24, 29))
)
]
},
(0, 0)
(0, 31)
)
]))
);
@ -1166,13 +1149,11 @@ mod tests {
(0, 22)
),
Statement::Expression(Expression::call(
CallExpression {
function: Expression::identifier(Identifier::new("Foo"), (23, 26)),
arguments: vec![
Expression::identifier(Identifier::new("Foo"), (23, 26)),
vec![
Expression::literal(LiteralExpression::Integer(1), (27, 28)),
Expression::literal(LiteralExpression::Float(2.0), (30, 33))
]
},
],
(23, 34)
))
]))
@ -1230,25 +1211,25 @@ mod tests {
ListIndex {
list: Expression::list(
ListExpression::Ordered(vec![
Expression::literal(LiteralExpression::Integer(1), (0, 0)),
Expression::literal(LiteralExpression::Integer(1), (1, 2)),
Expression::list(
ListExpression::Ordered(vec![Expression::literal(
LiteralExpression::Integer(2),
(0, 0)
(5, 6)
)]),
(0, 0)
(4, 7)
),
Expression::literal(LiteralExpression::Integer(3), (0, 0)),
Expression::literal(LiteralExpression::Integer(3), (9, 10)),
]),
(0, 0)
(0, 11)
),
index: Expression::literal(LiteralExpression::Integer(1), (0, 0)),
index: Expression::literal(LiteralExpression::Integer(1), (12, 13)),
},
(0, 0)
(0, 14)
),
index: Expression::literal(LiteralExpression::Integer(0), (0, 0)),
index: Expression::literal(LiteralExpression::Integer(0), (15, 16)),
},
(0, 0)
(0, 17)
))
]))
);
@ -1262,10 +1243,8 @@ mod tests {
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::range(
Range {
start: Expression::literal(LiteralExpression::Integer(0), (0, 1)),
end: Expression::literal(LiteralExpression::Integer(42), (3, 5)),
},
Expression::literal(LiteralExpression::Integer(0), (0, 1)),
Expression::literal(LiteralExpression::Integer(42), (3, 5)),
(0, 5)
))
]))
@ -1478,28 +1457,21 @@ mod tests {
assert_eq!(
parse(source),
Ok(AbstractSyntaxTree::with_statements([
Statement::Expression(Expression::r#loop(
Loop::While {
condition: Expression::operator(
Statement::Expression(Expression::while_loop(
Expression::operator(
OperatorExpression::Comparison {
left: Expression::identifier(Identifier::new("x"), (6, 7)),
operator: Node::new(ComparisonOperator::LessThan, (8, 9)),
right: Expression::literal(
LiteralExpression::Integer(10),
(10, 12)
),
right: Expression::literal(LiteralExpression::Integer(10), (10, 12)),
},
(6, 12)
),
block: Node::new(
Node::new(
Block::Sync(vec![Statement::Expression(Expression::operator(
OperatorExpression::CompoundAssignment {
assignee: Expression::identifier(
Identifier::new("x"),
(15, 16)
),
assignee: Expression::identifier(Identifier::new("x"), (15, 16)),
operator: Node::new(MathOperator::Add, (17, 19)),
value: Expression::literal(
modifier: Expression::literal(
LiteralExpression::Integer(1),
(20, 21)
),
@ -1507,8 +1479,7 @@ mod tests {
(15, 21)
))]),
(13, 23)
)
},
),
(0, 23)
))
]))
@ -1523,18 +1494,12 @@ mod tests {
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)),
OperatorExpression::CompoundAssignment {
assignee: Expression::identifier(Identifier::new("a"), (0, 1)),
operator: Node::new(MathOperator::Add, (2, 4)),
modifier: Expression::literal(LiteralExpression::Integer(1), (5, 6)),
},
(0, 0)
),
},
(0, 0)
(0, 6)
))
]))
)
@ -1569,13 +1534,13 @@ mod tests {
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)),
left: Expression::literal(LiteralExpression::Integer(40), (2, 4)),
operator: Node::new(MathOperator::Add, (5, 6)),
right: Expression::literal(LiteralExpression::Integer(2), (7, 8)),
},
(0, 0)
(2, 8)
))]),
(0, 0)
(0, 10)
))
]))
)
@ -1649,10 +1614,10 @@ mod tests {
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)),
operator: Node::new(MathOperator::Divide, (3, 5)),
right: Expression::literal(LiteralExpression::Integer(2), (6, 8)),
},
(0, 6),
(0, 8),
))
]))
);
@ -1687,10 +1652,10 @@ mod tests {
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)),
operator: Node::new(ComparisonOperator::LessThanOrEqual, (2, 4)),
right: Expression::literal(LiteralExpression::Integer(2), (5, 6)),
},
(0, 5),
(0, 6),
))
]))
);
@ -1706,10 +1671,10 @@ mod tests {
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)),
operator: Node::new(ComparisonOperator::GreaterThanOrEqual, (2, 4)),
right: Expression::literal(LiteralExpression::Integer(2), (5, 6)),
},
(0, 5),
(0, 6),
))
]))
);
@ -1763,7 +1728,7 @@ mod tests {
Statement::Expression(Expression::operator(
OperatorExpression::Math {
left: Expression::literal(LiteralExpression::Integer(42), (0, 2)),
operator: Node::new(MathOperator::Divide, (3, 4)),
operator: Node::new(MathOperator::Modulo, (3, 4)),
right: Expression::literal(LiteralExpression::Integer(2), (5, 6)),
},
(0, 6),
@ -1879,10 +1844,8 @@ mod tests {
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)),
},
Expression::identifier(Identifier::new("a"), (0, 1)),
Node::new(Identifier::new("b"), (2, 3)),
(0, 3)
))
]))

View File

@ -238,9 +238,10 @@ impl<'src> Token<'src> {
pub fn precedence(&self) -> u8 {
match self {
Token::Dot => 10,
Token::LeftParenthesis | Token::LeftSquareBrace => 9,
Token::Star | Token::Slash | Token::Percent => 8,
Token::Identifier(_) => 10,
Token::Dot => 9,
Token::LeftCurlyBrace | Token::LeftParenthesis | Token::LeftSquareBrace => 8,
Token::Star | Token::Slash | Token::Percent => 7,
Token::Minus | Token::Plus => 6,
Token::DoubleEqual
| Token::Less
@ -249,8 +250,8 @@ impl<'src> Token<'src> {
| Token::GreaterEqual => 5,
Token::DoubleAmpersand => 4,
Token::DoublePipe => 3,
Token::Equal | Token::MinusEqual | Token::PlusEqual => 2,
Token::DoubleDot => 1,
Token::DoubleDot => 2,
Token::Equal | Token::MinusEqual | Token::PlusEqual => 1,
_ => 0,
}
}
@ -258,7 +259,8 @@ impl<'src> Token<'src> {
pub fn is_left_associative(&self) -> bool {
matches!(
self,
Token::DoubleAmpersand
Token::Dot
| Token::DoubleAmpersand
| Token::DoublePipe
| Token::Plus
| Token::Minus
@ -269,7 +271,7 @@ impl<'src> Token<'src> {
}
pub fn is_right_associative(&self) -> bool {
matches!(self, Token::Equal | Token::PlusEqual)
matches!(self, Token::Equal | Token::MinusEqual | Token::PlusEqual)
}
pub fn is_prefix(&self) -> bool {
@ -277,7 +279,10 @@ impl<'src> Token<'src> {
}
pub fn is_postfix(&self) -> bool {
matches!(self, Token::LeftParenthesis | Token::LeftSquareBrace)
matches!(
self,
Token::Dot | Token::LeftCurlyBrace | Token::LeftParenthesis | Token::LeftSquareBrace
)
}
}