2024-08-09 01:59:09 +00:00
|
|
|
//! Parsing tools.
|
|
|
|
//!
|
|
|
|
//! This module provides two parsing options:
|
|
|
|
//! - `parse` convenience function
|
|
|
|
//! - `Parser` struct, which parses the input a statement at a time
|
2024-08-09 00:58:56 +00:00
|
|
|
use std::{
|
2024-08-09 10:32:44 +00:00
|
|
|
collections::VecDeque,
|
2024-08-09 00:58:56 +00:00
|
|
|
error::Error,
|
|
|
|
fmt::{self, Display, Formatter},
|
2024-08-09 18:01:01 +00:00
|
|
|
num::{ParseFloatError, ParseIntError},
|
|
|
|
str::ParseBoolError,
|
2024-08-09 00:58:56 +00:00
|
|
|
};
|
2024-08-05 04:40:51 +00:00
|
|
|
|
2024-08-07 22:24:25 +00:00
|
|
|
use crate::{
|
2024-08-11 21:59:52 +00:00
|
|
|
AbstractSyntaxTree, BinaryOperator, BuiltInFunction, DustError, Identifier, LexError, Lexer,
|
2024-08-13 19:12:32 +00:00
|
|
|
Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type, UnaryOperator,
|
|
|
|
Value,
|
2024-08-07 22:24:25 +00:00
|
|
|
};
|
2024-08-04 00:23:52 +00:00
|
|
|
|
2024-08-07 16:32:18 +00:00
|
|
|
/// Parses the input into an abstract syntax tree.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// ```
|
|
|
|
/// # use dust_lang::*;
|
2024-08-10 08:29:46 +00:00
|
|
|
/// let tree = parse("x = 42").unwrap();
|
2024-08-07 16:32:18 +00:00
|
|
|
///
|
|
|
|
/// assert_eq!(
|
2024-08-10 08:29:46 +00:00
|
|
|
/// tree,
|
|
|
|
/// AbstractSyntaxTree {
|
2024-08-07 16:32:18 +00:00
|
|
|
/// nodes: [
|
2024-08-10 08:29:46 +00:00
|
|
|
/// Node::new(
|
|
|
|
/// Statement::BinaryOperation {
|
|
|
|
/// left: Box::new(Node::new(
|
|
|
|
/// Statement::Identifier(Identifier::new("x")),
|
|
|
|
/// (0, 1),
|
|
|
|
/// )),
|
|
|
|
/// operator: Node::new(
|
|
|
|
/// BinaryOperator::Assign,
|
|
|
|
/// (2, 3)
|
|
|
|
/// ),
|
|
|
|
/// right: Box::new(Node::new(
|
|
|
|
/// Statement::Constant(Value::integer(42)),
|
|
|
|
/// (4, 6),
|
|
|
|
/// ))
|
2024-08-09 09:18:39 +00:00
|
|
|
/// },
|
2024-08-10 08:29:46 +00:00
|
|
|
/// (0, 6),
|
|
|
|
/// )
|
2024-08-07 16:32:18 +00:00
|
|
|
/// ].into(),
|
2024-08-10 08:29:46 +00:00
|
|
|
/// },
|
2024-08-07 16:32:18 +00:00
|
|
|
/// );
|
|
|
|
/// ```
|
2024-08-11 21:59:52 +00:00
|
|
|
pub fn parse(source: &str) -> Result<AbstractSyntaxTree, DustError> {
|
2024-08-08 20:19:14 +00:00
|
|
|
let lexer = Lexer::new();
|
2024-08-11 21:59:52 +00:00
|
|
|
let mut parser = Parser::new(source, lexer);
|
2024-08-05 04:40:51 +00:00
|
|
|
let mut nodes = VecDeque::new();
|
2024-08-04 23:25:44 +00:00
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
loop {
|
2024-08-11 21:59:52 +00:00
|
|
|
let node = parser
|
|
|
|
.parse()
|
|
|
|
.map_err(|parse_error| DustError::ParseError {
|
|
|
|
parse_error,
|
|
|
|
source,
|
|
|
|
})?;
|
2024-08-04 23:25:44 +00:00
|
|
|
|
2024-08-05 04:40:51 +00:00
|
|
|
nodes.push_back(node);
|
2024-08-05 00:08:43 +00:00
|
|
|
|
2024-08-05 02:15:31 +00:00
|
|
|
if let Token::Eof = parser.current.0 {
|
|
|
|
break;
|
|
|
|
}
|
2024-08-05 00:08:43 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree { nodes })
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 16:32:18 +00:00
|
|
|
/// Low-level tool for parsing the input a statement at a time.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
/// ```
|
|
|
|
/// # use std::collections::VecDeque;
|
|
|
|
/// # use dust_lang::*;
|
|
|
|
/// let input = "x = 42";
|
2024-08-08 20:19:14 +00:00
|
|
|
/// let lexer = Lexer::new();
|
|
|
|
/// let mut parser = Parser::new(input, lexer);
|
2024-08-07 16:32:18 +00:00
|
|
|
/// let mut nodes = VecDeque::new();
|
|
|
|
///
|
|
|
|
/// loop {
|
|
|
|
/// let node = parser.parse().unwrap();
|
|
|
|
///
|
|
|
|
/// nodes.push_back(node);
|
|
|
|
///
|
|
|
|
/// if let Token::Eof = parser.current().0 {
|
|
|
|
/// break;
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// assert_eq!(
|
|
|
|
/// nodes,
|
2024-08-09 07:00:48 +00:00
|
|
|
/// Into::<VecDeque<Node<Statement>>>::into([
|
2024-08-10 08:29:46 +00:00
|
|
|
/// Node::new(
|
|
|
|
/// Statement::BinaryOperation {
|
|
|
|
/// left: Box::new(Node::new(
|
|
|
|
/// Statement::Identifier(Identifier::new("x")),
|
|
|
|
/// (0, 1),
|
|
|
|
/// )),
|
|
|
|
/// operator: Node::new(
|
|
|
|
/// BinaryOperator::Assign,
|
|
|
|
/// (2, 3),
|
|
|
|
/// ),
|
|
|
|
/// right: Box::new(Node::new(
|
|
|
|
/// Statement::Constant(Value::integer(42)),
|
|
|
|
/// (4, 6),
|
|
|
|
/// )),
|
2024-08-09 09:18:39 +00:00
|
|
|
/// },
|
2024-08-10 08:29:46 +00:00
|
|
|
/// (0, 6),
|
|
|
|
/// )
|
2024-08-07 16:32:18 +00:00
|
|
|
/// ]),
|
|
|
|
/// );
|
|
|
|
/// ```
|
2024-08-04 00:23:52 +00:00
|
|
|
pub struct Parser<'src> {
|
2024-08-08 20:19:14 +00:00
|
|
|
source: &'src str,
|
|
|
|
lexer: Lexer,
|
|
|
|
current: (Token<'src>, Span),
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'src> Parser<'src> {
|
2024-08-08 20:19:14 +00:00
|
|
|
pub fn new(source: &'src str, lexer: Lexer) -> Self {
|
2024-08-04 00:23:52 +00:00
|
|
|
let mut lexer = lexer;
|
2024-08-08 20:19:14 +00:00
|
|
|
let current = lexer.next_token(source).unwrap_or((Token::Eof, (0, 0)));
|
2024-08-05 00:08:43 +00:00
|
|
|
|
2024-08-08 20:19:14 +00:00
|
|
|
Parser {
|
|
|
|
source,
|
|
|
|
lexer,
|
|
|
|
current,
|
|
|
|
}
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-07 16:32:18 +00:00
|
|
|
pub fn current(&self) -> &(Token, Span) {
|
|
|
|
&self.current
|
|
|
|
}
|
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
pub fn parse(&mut self) -> Result<Node<Statement>, ParseError> {
|
|
|
|
self.parse_statement(0)
|
|
|
|
}
|
2024-08-09 05:43:58 +00:00
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
fn next_token(&mut self) -> Result<(), ParseError> {
|
|
|
|
self.current = self.lexer.next_token(self.source)?;
|
2024-08-04 00:23:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-08-12 12:35:08 +00:00
|
|
|
fn parse_statement(&mut self, mut precedence: u8) -> Result<Node<Statement>, ParseError> {
|
|
|
|
// Parse a statement starting from the current node.
|
2024-08-12 23:06:57 +00:00
|
|
|
let mut left = if self.current.0.is_prefix() {
|
|
|
|
self.parse_prefix()?
|
|
|
|
} else {
|
|
|
|
self.parse_primary()?
|
|
|
|
};
|
2024-08-04 00:23:52 +00:00
|
|
|
|
2024-08-12 12:35:08 +00:00
|
|
|
// While the current token has a higher precedence than the given precedence
|
2024-08-10 04:01:50 +00:00
|
|
|
while precedence < self.current.0.precedence() {
|
2024-08-12 12:35:08 +00:00
|
|
|
// Give precedence to postfix operations
|
2024-08-12 23:06:57 +00:00
|
|
|
left = if self.current.0.is_postfix() {
|
|
|
|
// Replace the left-hand side with the postfix operation
|
|
|
|
let statement = self.parse_postfix(left)?;
|
|
|
|
|
|
|
|
precedence = self.current.0.precedence();
|
|
|
|
|
|
|
|
statement
|
2024-08-10 04:01:50 +00:00
|
|
|
} else {
|
2024-08-12 12:35:08 +00:00
|
|
|
// Replace the left-hand side with the infix operation
|
2024-08-12 23:06:57 +00:00
|
|
|
self.parse_infix(left)?
|
|
|
|
};
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
2024-08-10 04:01:50 +00:00
|
|
|
|
|
|
|
Ok(left)
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 10:00:14 +00:00
|
|
|
fn parse_prefix(&mut self) -> Result<Node<Statement>, ParseError> {
|
2024-08-08 20:19:14 +00:00
|
|
|
match self.current {
|
2024-08-12 09:44:05 +00:00
|
|
|
(Token::Bang, position) => {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let operand = Box::new(self.parse_statement(0)?);
|
|
|
|
let operand_end = operand.position.1;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::UnaryOperation {
|
|
|
|
operator: Node::new(UnaryOperator::Not, position),
|
|
|
|
operand,
|
|
|
|
},
|
|
|
|
(position.0, operand_end),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
(Token::Minus, position) => {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let operand = Box::new(self.parse_statement(0)?);
|
|
|
|
let operand_end = operand.position.1;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::UnaryOperation {
|
|
|
|
operator: Node::new(UnaryOperator::Negate, position),
|
|
|
|
operand,
|
|
|
|
},
|
|
|
|
(position.0, operand_end),
|
|
|
|
))
|
|
|
|
}
|
2024-08-12 23:06:57 +00:00
|
|
|
_ => Err(ParseError::UnexpectedToken {
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_primary(&mut self) -> Result<Node<Statement>, ParseError> {
|
|
|
|
match self.current {
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::Boolean(text), position) => {
|
2024-08-07 14:50:19 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
let boolean = text
|
|
|
|
.parse()
|
|
|
|
.map_err(|error| ParseError::BooleanError { error, position })?;
|
|
|
|
|
2024-08-07 14:50:19 +00:00
|
|
|
Ok(Node::new(
|
|
|
|
Statement::Constant(Value::boolean(boolean)),
|
2024-08-09 18:01:01 +00:00
|
|
|
position,
|
2024-08-07 14:50:19 +00:00
|
|
|
))
|
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::Float(text), position) => {
|
2024-08-04 00:23:52 +00:00
|
|
|
self.next_token()?;
|
2024-08-05 00:08:43 +00:00
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
let float = text
|
|
|
|
.parse()
|
|
|
|
.map_err(|error| ParseError::FloatError { error, position })?;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::Constant(Value::float(float)),
|
|
|
|
position,
|
|
|
|
))
|
2024-08-05 00:08:43 +00:00
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::Integer(text), position) => {
|
2024-08-05 00:08:43 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
let integer = text
|
2024-08-12 14:08:34 +00:00
|
|
|
.parse::<i64>()
|
2024-08-09 18:01:01 +00:00
|
|
|
.map_err(|error| ParseError::IntegerError { error, position })?;
|
|
|
|
|
2024-08-12 14:08:34 +00:00
|
|
|
if let Token::DoubleDot = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
if let Token::Integer(range_end) = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let range_end = range_end
|
|
|
|
.parse::<i64>()
|
|
|
|
.map_err(|error| ParseError::IntegerError { error, position })?;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::Constant(Value::range(integer..range_end)),
|
|
|
|
(position.0, self.current.1 .1),
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Integer,
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: (position.0, self.current.1 .1),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::Constant(Value::integer(integer)),
|
|
|
|
position,
|
|
|
|
))
|
|
|
|
}
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::Identifier(text), position) => {
|
2024-08-04 00:23:52 +00:00
|
|
|
self.next_token()?;
|
2024-08-05 00:08:43 +00:00
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
Ok(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new(text)),
|
|
|
|
position,
|
|
|
|
))
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
2024-08-11 18:35:33 +00:00
|
|
|
(Token::If, position) => {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let condition = Box::new(self.parse_statement(0)?);
|
2024-08-12 13:06:42 +00:00
|
|
|
let if_body = Box::new(self.parse_block()?);
|
2024-08-11 18:35:33 +00:00
|
|
|
|
|
|
|
if let Token::Else = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
if let Token::If = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let first_else_if = (self.parse_statement(0)?, self.parse_statement(0)?);
|
|
|
|
let mut else_ifs = vec![first_else_if];
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if let Token::Else = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
} else {
|
|
|
|
return Ok(Node::new(
|
|
|
|
Statement::IfElseIf {
|
|
|
|
condition,
|
|
|
|
if_body,
|
|
|
|
else_ifs,
|
|
|
|
},
|
|
|
|
position,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Token::If = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let else_if = (self.parse_statement(0)?, self.parse_statement(0)?);
|
|
|
|
|
|
|
|
else_ifs.push(else_if);
|
|
|
|
} else {
|
2024-08-12 13:06:42 +00:00
|
|
|
let else_body = Box::new(self.parse_block()?);
|
2024-08-11 18:35:33 +00:00
|
|
|
let else_end = else_body.position.1;
|
|
|
|
|
|
|
|
return Ok(Node::new(
|
|
|
|
Statement::IfElseIfElse {
|
|
|
|
condition,
|
|
|
|
if_body,
|
|
|
|
else_ifs,
|
|
|
|
else_body,
|
|
|
|
},
|
|
|
|
(position.0, else_end),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2024-08-12 13:06:42 +00:00
|
|
|
let else_body = Box::new(self.parse_block()?);
|
2024-08-11 18:35:33 +00:00
|
|
|
let else_end = else_body.position.1;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::IfElse {
|
|
|
|
condition,
|
|
|
|
if_body,
|
|
|
|
else_body,
|
|
|
|
},
|
|
|
|
(position.0, else_end),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let if_end = if_body.position.1;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::If {
|
|
|
|
condition,
|
|
|
|
body: if_body,
|
|
|
|
},
|
|
|
|
(position.0, if_end),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::String(string), position) => {
|
2024-08-08 17:11:32 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
Ok(Node::new(
|
|
|
|
Statement::Constant(Value::string(string)),
|
|
|
|
position,
|
|
|
|
))
|
2024-08-08 17:11:32 +00:00
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::LeftCurlyBrace, left_position) => {
|
2024-08-09 10:09:59 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-09 15:41:23 +00:00
|
|
|
// If the next token is a right curly brace, this is an empty map
|
2024-08-09 18:01:01 +00:00
|
|
|
if let (Token::RightCurlyBrace, right_position) = self.current {
|
2024-08-09 15:41:23 +00:00
|
|
|
self.next_token()?;
|
2024-08-09 10:09:59 +00:00
|
|
|
|
2024-08-09 15:41:23 +00:00
|
|
|
return Ok(Node::new(
|
|
|
|
Statement::Map(Vec::new()),
|
2024-08-09 18:01:01 +00:00
|
|
|
(left_position.0, right_position.1),
|
2024-08-09 15:41:23 +00:00
|
|
|
));
|
|
|
|
}
|
2024-08-09 10:09:59 +00:00
|
|
|
|
2024-08-11 19:39:42 +00:00
|
|
|
let first_node = self.parse_statement(0)?;
|
|
|
|
|
|
|
|
// Determine whether the new statement is a block or a map
|
|
|
|
//
|
|
|
|
// If the first node is an assignment, this might be a map
|
|
|
|
let mut statement = if let Statement::BinaryOperation {
|
|
|
|
left,
|
|
|
|
operator:
|
|
|
|
Node {
|
|
|
|
inner: BinaryOperator::Assign,
|
|
|
|
..
|
|
|
|
},
|
|
|
|
right,
|
|
|
|
} = first_node.inner
|
|
|
|
{
|
|
|
|
// If the current token is a comma or closing brace
|
|
|
|
if self.current.0 == Token::Comma || self.current.0 == Token::RightCurlyBrace {
|
|
|
|
// Allow commas after properties
|
|
|
|
if let Token::Comma = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The new statement is a map
|
|
|
|
Statement::Map(vec![(*left, *right)])
|
|
|
|
} else {
|
|
|
|
// Otherwise, the new statement is a block
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left,
|
|
|
|
operator: Node::new(BinaryOperator::Assign, (0, 0)),
|
|
|
|
right,
|
|
|
|
},
|
|
|
|
first_node.position,
|
|
|
|
)])
|
|
|
|
}
|
|
|
|
// If the next node is not an assignment, the new statement is a block
|
|
|
|
} else {
|
|
|
|
Statement::Block(vec![first_node])
|
|
|
|
};
|
2024-08-09 10:09:59 +00:00
|
|
|
|
2024-08-09 15:41:23 +00:00
|
|
|
loop {
|
|
|
|
// If a closing brace is found, return the new statement
|
2024-08-09 18:01:01 +00:00
|
|
|
if let (Token::RightCurlyBrace, right_position) = self.current {
|
2024-08-09 10:09:59 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-11 19:39:42 +00:00
|
|
|
return Ok(Node::new(statement, (left_position.0, right_position.1)));
|
2024-08-09 10:09:59 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
let next_node = self.parse_statement(0)?;
|
2024-08-09 15:41:23 +00:00
|
|
|
|
2024-08-10 08:29:46 +00:00
|
|
|
// If the new statement is already a block, add the next node to it
|
2024-08-11 19:39:42 +00:00
|
|
|
if let Some(block_statements) = statement.block_statements_mut() {
|
|
|
|
block_statements.push(next_node);
|
2024-08-11 17:16:16 +00:00
|
|
|
|
2024-08-11 19:39:42 +00:00
|
|
|
continue;
|
2024-08-11 17:16:16 +00:00
|
|
|
}
|
|
|
|
|
2024-08-11 19:39:42 +00:00
|
|
|
// If the new statement is already a map
|
|
|
|
if let Some(map_properties) = statement.map_properties_mut() {
|
|
|
|
// Expect the next node to be an assignment
|
2024-08-11 17:16:16 +00:00
|
|
|
if let Statement::BinaryOperation {
|
|
|
|
left,
|
|
|
|
operator:
|
|
|
|
Node {
|
|
|
|
inner: BinaryOperator::Assign,
|
|
|
|
..
|
|
|
|
},
|
|
|
|
right,
|
|
|
|
} = next_node.inner
|
|
|
|
{
|
2024-08-11 19:39:42 +00:00
|
|
|
// Add the new property to the map
|
|
|
|
map_properties.push((*left, *right));
|
2024-08-11 17:16:16 +00:00
|
|
|
|
2024-08-11 19:39:42 +00:00
|
|
|
// Allow commas after properties
|
2024-08-11 17:16:16 +00:00
|
|
|
if let Token::Comma = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedAssignment { actual: next_node });
|
2024-08-10 08:29:46 +00:00
|
|
|
}
|
2024-08-11 17:16:16 +00:00
|
|
|
}
|
2024-08-09 10:09:59 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::LeftParenthesis, left_position) => {
|
2024-08-04 00:23:52 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
let node = self.parse_statement(0)?;
|
2024-08-04 00:23:52 +00:00
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
if let (Token::RightParenthesis, right_position) = self.current {
|
2024-08-04 00:23:52 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
Ok(Node::new(node.inner, (left_position.0, right_position.1)))
|
2024-08-04 00:23:52 +00:00
|
|
|
} else {
|
2024-08-09 10:09:59 +00:00
|
|
|
Err(ParseError::ExpectedToken {
|
2024-08-12 14:08:34 +00:00
|
|
|
expected: TokenKind::RightParenthesis,
|
2024-08-09 00:19:07 +00:00
|
|
|
actual: self.current.0.to_owned(),
|
2024-08-09 01:47:49 +00:00
|
|
|
position: self.current.1,
|
2024-08-05 01:31:18 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
(Token::LeftSquareBrace, left_position) => {
|
2024-08-05 01:31:18 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-07 22:24:25 +00:00
|
|
|
let mut nodes = Vec::new();
|
2024-08-05 01:31:18 +00:00
|
|
|
|
|
|
|
loop {
|
2024-08-09 18:01:01 +00:00
|
|
|
if let (Token::RightSquareBrace, right_position) = self.current {
|
2024-08-05 01:31:18 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-05 03:11:04 +00:00
|
|
|
return Ok(Node::new(
|
2024-08-07 22:24:25 +00:00
|
|
|
Statement::List(nodes),
|
2024-08-09 18:01:01 +00:00
|
|
|
(left_position.0, right_position.1),
|
2024-08-05 01:31:18 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let (Token::Comma, _) = self.current {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-08-12 20:57:10 +00:00
|
|
|
let statement = self.parse_statement(0)?;
|
|
|
|
|
|
|
|
nodes.push(statement);
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-08 17:49:40 +00:00
|
|
|
(
|
2024-08-11 19:12:19 +00:00
|
|
|
Token::IsEven
|
|
|
|
| Token::IsOdd
|
|
|
|
| Token::Length
|
|
|
|
| Token::ReadLine
|
|
|
|
| Token::ToString
|
|
|
|
| Token::WriteLine,
|
2024-08-09 18:01:01 +00:00
|
|
|
left_position,
|
2024-08-08 17:49:40 +00:00
|
|
|
) => {
|
|
|
|
let function = match self.current.0 {
|
|
|
|
Token::IsEven => BuiltInFunction::IsEven,
|
|
|
|
Token::IsOdd => BuiltInFunction::IsOdd,
|
|
|
|
Token::Length => BuiltInFunction::Length,
|
|
|
|
Token::ReadLine => BuiltInFunction::ReadLine,
|
2024-08-11 19:12:19 +00:00
|
|
|
Token::ToString => BuiltInFunction::ToString,
|
2024-08-08 17:49:40 +00:00
|
|
|
Token::WriteLine => BuiltInFunction::WriteLine,
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2024-08-07 22:24:25 +00:00
|
|
|
|
2024-08-07 22:43:24 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
if let (Token::LeftParenthesis, _) = self.current {
|
|
|
|
self.next_token()?;
|
|
|
|
} else {
|
2024-08-09 10:09:59 +00:00
|
|
|
return Err(ParseError::ExpectedToken {
|
2024-08-12 14:08:34 +00:00
|
|
|
expected: TokenKind::LeftParenthesis,
|
2024-08-09 00:19:07 +00:00
|
|
|
actual: self.current.0.to_owned(),
|
2024-08-09 01:47:49 +00:00
|
|
|
position: self.current.1,
|
2024-08-07 22:43:24 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-09 07:00:48 +00:00
|
|
|
let mut value_arguments: Option<Vec<Node<Statement>>> = None;
|
2024-08-07 22:43:24 +00:00
|
|
|
|
2024-08-08 17:49:40 +00:00
|
|
|
loop {
|
|
|
|
if let (Token::RightParenthesis, _) = self.current {
|
|
|
|
self.next_token()?;
|
|
|
|
break;
|
|
|
|
}
|
2024-08-07 22:43:24 +00:00
|
|
|
|
2024-08-08 17:49:40 +00:00
|
|
|
if let (Token::Comma, _) = self.current {
|
|
|
|
self.next_token()?;
|
|
|
|
continue;
|
|
|
|
}
|
2024-08-07 22:43:24 +00:00
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
if let Ok(node) = self.parse_statement(0) {
|
2024-08-08 17:49:40 +00:00
|
|
|
if let Some(ref mut arguments) = value_arguments {
|
|
|
|
arguments.push(node);
|
|
|
|
} else {
|
|
|
|
value_arguments = Some(vec![node]);
|
|
|
|
}
|
|
|
|
} else {
|
2024-08-09 10:09:59 +00:00
|
|
|
return Err(ParseError::ExpectedToken {
|
2024-08-12 14:08:34 +00:00
|
|
|
expected: TokenKind::RightParenthesis,
|
2024-08-09 00:19:07 +00:00
|
|
|
actual: self.current.0.to_owned(),
|
2024-08-09 01:47:49 +00:00
|
|
|
position: self.current.1,
|
2024-08-08 17:49:40 +00:00
|
|
|
});
|
|
|
|
}
|
2024-08-07 22:43:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::BuiltInFunctionCall {
|
2024-08-08 17:49:40 +00:00
|
|
|
function,
|
2024-08-07 22:43:24 +00:00
|
|
|
type_arguments: None,
|
2024-08-08 17:49:40 +00:00
|
|
|
value_arguments,
|
2024-08-07 22:43:24 +00:00
|
|
|
},
|
2024-08-09 18:01:01 +00:00
|
|
|
left_position,
|
2024-08-07 22:43:24 +00:00
|
|
|
))
|
|
|
|
}
|
2024-08-13 17:54:16 +00:00
|
|
|
(Token::Struct, left_position) => {
|
2024-08-10 09:23:43 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
let (name, name_end) = if let Token::Identifier(_) = self.current.0 {
|
|
|
|
let position = self.current.1 .1;
|
2024-08-10 09:23:43 +00:00
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
(self.parse_identifier()?, position)
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Identifier,
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Token::LeftParenthesis = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let mut types = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if let (Token::RightParenthesis, right_position) = self.current {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
return Ok(Node::new(
|
|
|
|
Statement::StructDefinition(StructDefinition::Tuple {
|
|
|
|
name,
|
|
|
|
fields: types,
|
|
|
|
}),
|
|
|
|
(left_position.0, right_position.1),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let (Token::Comma, _) = self.current {
|
|
|
|
self.next_token()?;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let type_node = self.parse_type()?;
|
|
|
|
|
|
|
|
types.push(type_node);
|
|
|
|
}
|
|
|
|
} else {
|
2024-08-13 17:54:16 +00:00
|
|
|
Ok(Node::new(
|
|
|
|
Statement::StructDefinition(StructDefinition::Unit { name }),
|
|
|
|
(left_position.0, name_end),
|
|
|
|
))
|
2024-08-10 09:23:43 +00:00
|
|
|
}
|
2024-08-13 17:54:16 +00:00
|
|
|
}
|
|
|
|
(Token::While, left_position) => {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let condition = self.parse_statement(0)?;
|
2024-08-10 09:23:43 +00:00
|
|
|
|
|
|
|
let body = self.parse_block()?;
|
|
|
|
let body_end = body.position.1;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::While {
|
|
|
|
condition: Box::new(condition),
|
|
|
|
body: Box::new(body),
|
|
|
|
},
|
|
|
|
(left_position.0, body_end),
|
|
|
|
))
|
|
|
|
}
|
2024-08-09 04:49:17 +00:00
|
|
|
_ => Err(ParseError::UnexpectedToken {
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
}),
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
fn parse_infix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
|
2024-08-12 15:24:24 +00:00
|
|
|
let operator_precedence = self.current.0.precedence()
|
|
|
|
- if self.current.0.is_right_associative() {
|
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
2024-08-12 23:06:57 +00:00
|
|
|
let left_start = left.position.0;
|
2024-08-09 18:01:01 +00:00
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
if let Token::Dot = &self.current.0 {
|
2024-08-12 19:02:04 +00:00
|
|
|
let operator_position = self.current.1;
|
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-12 15:24:24 +00:00
|
|
|
let right = self.parse_statement(operator_precedence)?;
|
2024-08-10 04:01:50 +00:00
|
|
|
let right_end = right.position.1;
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-12 01:37:44 +00:00
|
|
|
if let Statement::BuiltInFunctionCall {
|
|
|
|
function,
|
|
|
|
type_arguments,
|
|
|
|
value_arguments,
|
|
|
|
} = right.inner
|
|
|
|
{
|
|
|
|
let value_arguments = if let Some(mut arguments) = value_arguments {
|
|
|
|
arguments.insert(0, left);
|
|
|
|
|
|
|
|
Some(arguments)
|
|
|
|
} else {
|
|
|
|
Some(vec![left])
|
|
|
|
};
|
|
|
|
|
|
|
|
return Ok(Node::new(
|
|
|
|
Statement::BuiltInFunctionCall {
|
|
|
|
function,
|
|
|
|
type_arguments,
|
|
|
|
value_arguments,
|
|
|
|
},
|
|
|
|
(left_start, right_end),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Statement::FunctionCall {
|
|
|
|
function,
|
|
|
|
type_arguments,
|
|
|
|
value_arguments,
|
|
|
|
} = right.inner
|
|
|
|
{
|
|
|
|
let value_arguments = if let Some(mut arguments) = value_arguments {
|
|
|
|
arguments.insert(0, left);
|
|
|
|
|
|
|
|
Some(arguments)
|
|
|
|
} else {
|
|
|
|
Some(vec![left])
|
|
|
|
};
|
|
|
|
|
|
|
|
return Ok(Node::new(
|
|
|
|
Statement::FunctionCall {
|
|
|
|
function,
|
|
|
|
type_arguments,
|
|
|
|
value_arguments,
|
|
|
|
},
|
|
|
|
(left_start, right_end),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
return Ok(Node::new(
|
2024-08-12 19:02:04 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(left),
|
|
|
|
operator: Node::new(BinaryOperator::FieldAccess, operator_position),
|
|
|
|
right: Box::new(right),
|
|
|
|
},
|
2024-08-09 22:14:46 +00:00
|
|
|
(left_start, right_end),
|
|
|
|
));
|
2024-08-10 04:01:50 +00:00
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
let binary_operator = match &self.current.0 {
|
|
|
|
Token::DoubleAmpersand => Node::new(BinaryOperator::And, self.current.1),
|
|
|
|
Token::DoubleEqual => Node::new(BinaryOperator::Equal, self.current.1),
|
|
|
|
Token::DoublePipe => Node::new(BinaryOperator::Or, self.current.1),
|
|
|
|
Token::Equal => Node::new(BinaryOperator::Assign, self.current.1),
|
|
|
|
Token::Greater => Node::new(BinaryOperator::Greater, self.current.1),
|
|
|
|
Token::GreaterEqual => Node::new(BinaryOperator::GreaterOrEqual, self.current.1),
|
|
|
|
Token::Less => Node::new(BinaryOperator::Less, self.current.1),
|
|
|
|
Token::LessEqual => Node::new(BinaryOperator::LessOrEqual, self.current.1),
|
|
|
|
Token::Minus => Node::new(BinaryOperator::Subtract, self.current.1),
|
|
|
|
Token::Plus => Node::new(BinaryOperator::Add, self.current.1),
|
|
|
|
Token::PlusEqual => Node::new(BinaryOperator::AddAssign, self.current.1),
|
|
|
|
Token::Star => Node::new(BinaryOperator::Multiply, self.current.1),
|
|
|
|
Token::Slash => Node::new(BinaryOperator::Divide, self.current.1),
|
|
|
|
Token::Percent => Node::new(BinaryOperator::Modulo, self.current.1),
|
2024-08-09 18:01:01 +00:00
|
|
|
_ => {
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
let left_start = left.position.0;
|
2024-08-10 04:01:50 +00:00
|
|
|
let right = self.parse_statement(operator_precedence)?;
|
2024-08-09 18:01:01 +00:00
|
|
|
let right_end = right.position.1;
|
|
|
|
|
|
|
|
Ok(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(left),
|
|
|
|
operator: binary_operator,
|
|
|
|
right: Box::new(right),
|
|
|
|
},
|
|
|
|
(left_start, right_end),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2024-08-12 23:06:57 +00:00
|
|
|
fn parse_postfix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
|
|
|
|
let left_start = left.position.0;
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-12 23:06:57 +00:00
|
|
|
let statement = if let Token::LeftSquareBrace = &self.current.0 {
|
|
|
|
let operator_start = self.current.1 .0;
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-12 23:06:57 +00:00
|
|
|
self.next_token()?;
|
2024-08-12 20:57:10 +00:00
|
|
|
|
2024-08-12 23:06:57 +00:00
|
|
|
let index = self.parse_statement(0)?;
|
2024-08-12 20:57:10 +00:00
|
|
|
|
2024-08-12 23:06:57 +00:00
|
|
|
let operator_end = if let Token::RightSquareBrace = self.current.0 {
|
|
|
|
let end = self.current.1 .1;
|
2024-08-12 20:57:10 +00:00
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-12 23:06:57 +00:00
|
|
|
end
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::RightSquareBrace,
|
2024-08-12 20:57:10 +00:00
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
});
|
2024-08-12 23:06:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let right_end = self.current.1 .1;
|
|
|
|
|
|
|
|
Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(left),
|
|
|
|
operator: Node::new(BinaryOperator::ListIndex, (operator_start, operator_end)),
|
|
|
|
right: Box::new(index),
|
|
|
|
},
|
|
|
|
(left_start, right_end),
|
|
|
|
)
|
|
|
|
} else if let Token::Semicolon = &self.current.0 {
|
|
|
|
let operator_end = self.current.1 .1;
|
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
Node::new(Statement::Nil(Box::new(left)), (left_start, operator_end))
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
});
|
2024-08-12 13:06:42 +00:00
|
|
|
};
|
|
|
|
|
2024-08-12 23:06:57 +00:00
|
|
|
if self.current.0.is_postfix() {
|
|
|
|
self.parse_postfix(statement)
|
|
|
|
} else {
|
|
|
|
Ok(statement)
|
|
|
|
}
|
2024-08-09 22:14:46 +00:00
|
|
|
}
|
2024-08-10 09:23:43 +00:00
|
|
|
|
2024-08-13 17:54:16 +00:00
|
|
|
fn parse_identifier(&mut self) -> Result<Node<Identifier>, ParseError> {
|
|
|
|
let identifier = if let Token::Identifier(text) = &self.current.0 {
|
|
|
|
Node::new(Identifier::new(text), self.current.1)
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Identifier,
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
Ok(identifier)
|
|
|
|
}
|
|
|
|
|
2024-08-10 09:23:43 +00:00
|
|
|
fn parse_block(&mut self) -> Result<Node<Statement>, ParseError> {
|
|
|
|
let left_start = self.current.1 .0;
|
|
|
|
|
|
|
|
if let Token::LeftCurlyBrace = self.current.0 {
|
|
|
|
self.next_token()?;
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
2024-08-12 14:08:34 +00:00
|
|
|
expected: TokenKind::LeftCurlyBrace,
|
2024-08-10 09:23:43 +00:00
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut statements = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
|
|
|
if let Token::RightCurlyBrace = self.current.0 {
|
|
|
|
let right_end = self.current.1 .1;
|
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
return Ok(Node::new(
|
|
|
|
Statement::Block(statements),
|
|
|
|
(left_start, right_end),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let statement = self.parse_statement(0)?;
|
|
|
|
|
|
|
|
statements.push(statement);
|
|
|
|
}
|
|
|
|
}
|
2024-08-13 19:12:32 +00:00
|
|
|
|
|
|
|
fn parse_type(&mut self) -> Result<Node<Type>, ParseError> {
|
|
|
|
let r#type = match self.current.0 {
|
|
|
|
Token::Bool => Type::Boolean,
|
|
|
|
Token::FloatKeyword => Type::Float,
|
|
|
|
Token::Int => Type::Integer,
|
|
|
|
_ => {
|
|
|
|
return Err(ParseError::ExpectedTokenMultiple {
|
|
|
|
expected: vec![TokenKind::Bool, TokenKind::FloatKeyword, TokenKind::Int],
|
|
|
|
actual: self.current.0.to_owned(),
|
|
|
|
position: self.current.1,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let position = self.current.1;
|
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
Ok(Node::new(r#type, position))
|
|
|
|
}
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-04 23:25:44 +00:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum ParseError {
|
2024-08-09 18:01:01 +00:00
|
|
|
BooleanError {
|
|
|
|
error: ParseBoolError,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-10 04:01:50 +00:00
|
|
|
LexError(LexError),
|
2024-08-11 17:16:16 +00:00
|
|
|
ExpectedAssignment {
|
|
|
|
actual: Node<Statement>,
|
|
|
|
},
|
2024-08-09 08:23:02 +00:00
|
|
|
ExpectedIdentifier {
|
2024-08-09 10:09:59 +00:00
|
|
|
actual: TokenOwned,
|
2024-08-09 15:41:23 +00:00
|
|
|
position: Span,
|
2024-08-09 08:23:02 +00:00
|
|
|
},
|
2024-08-09 10:09:59 +00:00
|
|
|
ExpectedToken {
|
2024-08-12 14:08:34 +00:00
|
|
|
expected: TokenKind,
|
2024-08-09 08:23:02 +00:00
|
|
|
actual: TokenOwned,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-13 19:12:32 +00:00
|
|
|
ExpectedTokenMultiple {
|
|
|
|
expected: Vec<TokenKind>,
|
|
|
|
actual: TokenOwned,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-09 08:23:02 +00:00
|
|
|
UnexpectedToken {
|
|
|
|
actual: TokenOwned,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-09 18:01:01 +00:00
|
|
|
FloatError {
|
|
|
|
error: ParseFloatError,
|
|
|
|
position: Span,
|
|
|
|
},
|
|
|
|
IntegerError {
|
|
|
|
error: ParseIntError,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-09 04:49:17 +00:00
|
|
|
}
|
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
impl From<LexError> for ParseError {
|
|
|
|
fn from(v: LexError) -> Self {
|
|
|
|
Self::LexError(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-09 04:49:17 +00:00
|
|
|
impl ParseError {
|
|
|
|
pub fn position(&self) -> Span {
|
|
|
|
match self {
|
2024-08-09 18:01:01 +00:00
|
|
|
ParseError::BooleanError { position, .. } => *position,
|
2024-08-11 17:16:16 +00:00
|
|
|
ParseError::ExpectedAssignment { actual } => actual.position,
|
2024-08-09 18:01:01 +00:00
|
|
|
ParseError::ExpectedIdentifier { position, .. } => *position,
|
|
|
|
ParseError::ExpectedToken { position, .. } => *position,
|
2024-08-13 19:12:32 +00:00
|
|
|
ParseError::ExpectedTokenMultiple { position, .. } => *position,
|
2024-08-09 18:01:01 +00:00
|
|
|
ParseError::FloatError { position, .. } => *position,
|
|
|
|
ParseError::IntegerError { position, .. } => *position,
|
2024-08-10 04:01:50 +00:00
|
|
|
ParseError::LexError(error) => error.position(),
|
2024-08-09 18:01:01 +00:00
|
|
|
ParseError::UnexpectedToken { position, .. } => *position,
|
2024-08-09 04:49:17 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-04 23:25:44 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 00:58:56 +00:00
|
|
|
impl Error for ParseError {
|
|
|
|
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
|
|
|
match self {
|
2024-08-10 04:01:50 +00:00
|
|
|
Self::LexError(error) => Some(error),
|
2024-08-09 00:58:56 +00:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for ParseError {
|
|
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
|
|
match self {
|
2024-08-09 18:01:01 +00:00
|
|
|
Self::BooleanError { error, .. } => write!(f, "{}", error),
|
2024-08-11 17:16:16 +00:00
|
|
|
Self::ExpectedAssignment { .. } => write!(f, "Expected assignment"),
|
2024-08-09 08:23:02 +00:00
|
|
|
Self::ExpectedIdentifier { actual, .. } => {
|
|
|
|
write!(f, "Expected identifier, found {actual}")
|
|
|
|
}
|
2024-08-09 10:09:59 +00:00
|
|
|
Self::ExpectedToken {
|
|
|
|
expected, actual, ..
|
|
|
|
} => write!(f, "Expected token {expected}, found {actual}"),
|
2024-08-13 19:12:32 +00:00
|
|
|
Self::ExpectedTokenMultiple {
|
|
|
|
expected, actual, ..
|
|
|
|
} => {
|
|
|
|
write!(f, "Expected one of")?;
|
|
|
|
|
|
|
|
for (i, token_kind) in expected.iter().enumerate() {
|
|
|
|
if i == 0 {
|
|
|
|
write!(f, " {token_kind}")?;
|
|
|
|
} else if i == expected.len() - 1 {
|
|
|
|
write!(f, " or {token_kind}")?;
|
|
|
|
} else {
|
|
|
|
write!(f, ", {token_kind}")?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
write!(f, ", found {actual}")
|
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
Self::FloatError { error, .. } => write!(f, "{}", error),
|
|
|
|
Self::IntegerError { error, .. } => write!(f, "{}", error),
|
2024-08-10 04:01:50 +00:00
|
|
|
Self::LexError(error) => write!(f, "{}", error),
|
2024-08-09 04:49:17 +00:00
|
|
|
Self::UnexpectedToken { actual, .. } => write!(f, "Unexpected token {actual}"),
|
2024-08-09 00:58:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-04 00:23:52 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2024-08-13 19:12:32 +00:00
|
|
|
use crate::{BinaryOperator, Identifier, StructDefinition, Type, UnaryOperator};
|
2024-08-04 00:23:52 +00:00
|
|
|
|
2024-08-04 23:25:44 +00:00
|
|
|
use super::*;
|
2024-08-04 00:23:52 +00:00
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
#[test]
|
|
|
|
fn tuple_struct() {
|
|
|
|
let input = "struct Foo(int, float)";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::StructDefinition(StructDefinition::Tuple {
|
|
|
|
name: Node::new(Identifier::new("Foo"), (7, 10)),
|
|
|
|
fields: vec![
|
|
|
|
Node::new(Type::Integer, (11, 14)),
|
|
|
|
Node::new(Type::Float, (16, 21))
|
|
|
|
]
|
|
|
|
}),
|
|
|
|
(0, 22)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 17:54:16 +00:00
|
|
|
#[test]
|
|
|
|
fn unit_struct() {
|
|
|
|
let input = "struct Foo";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::StructDefinition(StructDefinition::Unit {
|
|
|
|
name: Node::new(Identifier::new("Foo"), (7, 10)),
|
|
|
|
}),
|
|
|
|
(0, 10)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 20:57:10 +00:00
|
|
|
#[test]
|
|
|
|
fn list_index_nested() {
|
|
|
|
let input = "[1, [2], 3][1][0]";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::List(vec![
|
|
|
|
Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
|
|
|
|
Node::new(
|
|
|
|
Statement::List(vec![Node::new(
|
|
|
|
Statement::Constant(Value::integer(2)),
|
|
|
|
(5, 6)
|
|
|
|
)]),
|
|
|
|
(4, 7)
|
|
|
|
),
|
|
|
|
Node::new(Statement::Constant(Value::integer(3)), (9, 10))
|
|
|
|
]),
|
|
|
|
(0, 11)
|
|
|
|
)),
|
2024-08-12 23:06:57 +00:00
|
|
|
operator: Node::new(BinaryOperator::ListIndex, (11, 14)),
|
2024-08-12 20:57:10 +00:00
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(12, 13)
|
|
|
|
))
|
|
|
|
},
|
2024-08-12 23:06:57 +00:00
|
|
|
(0, 15)
|
2024-08-12 20:57:10 +00:00
|
|
|
)),
|
2024-08-12 23:06:57 +00:00
|
|
|
operator: Node::new(BinaryOperator::ListIndex, (14, 17)),
|
2024-08-12 20:57:10 +00:00
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(0)),
|
|
|
|
(15, 16)
|
|
|
|
))
|
|
|
|
},
|
2024-08-12 23:06:57 +00:00
|
|
|
(0, 17)
|
2024-08-12 20:57:10 +00:00
|
|
|
),]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 15:24:24 +00:00
|
|
|
#[test]
|
|
|
|
fn map_property_nested() {
|
|
|
|
let input = "{ x = { y = 42 } }.x.y";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-12 19:02:04 +00:00
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Map(vec![(
|
|
|
|
Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("x")),
|
|
|
|
(2, 3)
|
|
|
|
),
|
|
|
|
Node::new(
|
|
|
|
Statement::Map(vec![(
|
|
|
|
Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("y")),
|
|
|
|
(8, 9)
|
|
|
|
),
|
|
|
|
Node::new(
|
|
|
|
Statement::Constant(Value::integer(42)),
|
|
|
|
(12, 14)
|
|
|
|
)
|
|
|
|
)]),
|
|
|
|
(6, 16)
|
|
|
|
)
|
2024-08-12 15:24:24 +00:00
|
|
|
)]),
|
2024-08-12 19:02:04 +00:00
|
|
|
(0, 18)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::FieldAccess, (18, 19)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("x")),
|
|
|
|
(19, 20)
|
|
|
|
))
|
|
|
|
},
|
|
|
|
(0, 20)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::FieldAccess, (20, 21)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("y")),
|
|
|
|
(21, 22)
|
|
|
|
))
|
|
|
|
},
|
|
|
|
(0, 22)
|
|
|
|
)]
|
2024-08-12 15:24:24 +00:00
|
|
|
.into()
|
|
|
|
})
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2024-08-12 14:08:34 +00:00
|
|
|
#[test]
|
|
|
|
fn range() {
|
|
|
|
let input = "0..42";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(Statement::Constant(Value::range(0..42)), (0, 5))].into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 09:44:05 +00:00
|
|
|
#[test]
|
|
|
|
fn negate_variable() {
|
|
|
|
let input = "a = 1; -a";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [
|
|
|
|
Node::new(
|
2024-08-12 12:35:08 +00:00
|
|
|
Statement::Nil(Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("a")),
|
|
|
|
(0, 1)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Assign, (2, 3)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(4, 5)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 5)
|
|
|
|
))),
|
2024-08-12 20:57:10 +00:00
|
|
|
(0, 6)
|
2024-08-12 09:44:05 +00:00
|
|
|
),
|
|
|
|
Node::new(
|
|
|
|
Statement::UnaryOperation {
|
2024-08-12 12:35:08 +00:00
|
|
|
operator: Node::new(UnaryOperator::Negate, (7, 8)),
|
2024-08-12 09:44:05 +00:00
|
|
|
operand: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("a")),
|
2024-08-12 12:35:08 +00:00
|
|
|
(8, 9)
|
2024-08-12 09:44:05 +00:00
|
|
|
)),
|
|
|
|
},
|
2024-08-12 12:35:08 +00:00
|
|
|
(7, 9)
|
2024-08-12 09:44:05 +00:00
|
|
|
)
|
|
|
|
]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn negate_expression() {
|
|
|
|
let input = "-(1 + 1)";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::UnaryOperation {
|
|
|
|
operator: Node::new(UnaryOperator::Negate, (0, 1)),
|
|
|
|
operand: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(2, 3)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Add, (4, 5)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(6, 7)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(1, 8)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 8)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 10:00:14 +00:00
|
|
|
#[test]
|
|
|
|
fn not_expression() {
|
|
|
|
let input = "!(1 > 42)";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::UnaryOperation {
|
|
|
|
operator: Node::new(UnaryOperator::Not, (0, 1)),
|
|
|
|
operand: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(2, 3)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Greater, (4, 5)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(42)),
|
|
|
|
(6, 8)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(1, 9)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 9)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn not_variable() {
|
|
|
|
let input = "a = false; !a";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [
|
|
|
|
Node::new(
|
|
|
|
Statement::Nil(Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("a")),
|
|
|
|
(0, 1)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Assign, (2, 3)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::boolean(false)),
|
|
|
|
(4, 9)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 9)
|
|
|
|
))),
|
2024-08-12 20:57:10 +00:00
|
|
|
(0, 10)
|
2024-08-12 10:00:14 +00:00
|
|
|
),
|
|
|
|
Node::new(
|
|
|
|
Statement::UnaryOperation {
|
|
|
|
operator: Node::new(UnaryOperator::Not, (11, 12)),
|
|
|
|
operand: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("a")),
|
|
|
|
(12, 13)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(11, 13)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-11 18:35:33 +00:00
|
|
|
#[test]
|
|
|
|
fn r#if() {
|
|
|
|
let input = "if x { y }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::If {
|
|
|
|
condition: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("x")),
|
|
|
|
(3, 4)
|
|
|
|
)),
|
|
|
|
body: Box::new(Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("y")),
|
|
|
|
(7, 8)
|
|
|
|
)]),
|
|
|
|
(5, 10)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 10)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn if_else() {
|
|
|
|
let input = "if x { y } else { z }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::IfElse {
|
|
|
|
condition: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("x")),
|
|
|
|
(3, 4)
|
|
|
|
)),
|
|
|
|
if_body: Box::new(Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("y")),
|
|
|
|
(7, 8)
|
|
|
|
)]),
|
|
|
|
(5, 10)
|
|
|
|
)),
|
|
|
|
else_body: Box::new(Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("z")),
|
|
|
|
(18, 19)
|
|
|
|
)]),
|
|
|
|
(16, 21)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 21)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn if_else_if_else() {
|
|
|
|
let input = "if x { y } else if z { a } else { b }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::IfElseIfElse {
|
|
|
|
condition: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("x")),
|
|
|
|
(3, 4)
|
|
|
|
)),
|
|
|
|
if_body: Box::new(Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("y")),
|
|
|
|
(7, 8)
|
|
|
|
)]),
|
|
|
|
(5, 10)
|
|
|
|
)),
|
|
|
|
else_ifs: vec![(
|
|
|
|
Node::new(Statement::Identifier(Identifier::new("z")), (19, 20)),
|
|
|
|
Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("a")),
|
|
|
|
(23, 24)
|
|
|
|
)]),
|
|
|
|
(21, 26)
|
|
|
|
),
|
|
|
|
)],
|
|
|
|
else_body: Box::new(Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("b")),
|
|
|
|
(34, 35)
|
|
|
|
)]),
|
|
|
|
(32, 37)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 37)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-11 17:16:16 +00:00
|
|
|
#[test]
|
|
|
|
fn malformed_map() {
|
|
|
|
let input = "{ x = 1, y = 2, z = 3; }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-11 21:59:52 +00:00
|
|
|
Err(DustError::ParseError {
|
|
|
|
source: input,
|
|
|
|
parse_error: ParseError::ExpectedAssignment {
|
|
|
|
actual: Node::new(
|
|
|
|
Statement::Nil(Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("z")),
|
|
|
|
(16, 17)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Assign, (18, 19)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(3)),
|
|
|
|
(20, 21)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(16, 21)
|
|
|
|
))),
|
2024-08-12 20:57:10 +00:00
|
|
|
(16, 22)
|
2024-08-11 21:59:52 +00:00
|
|
|
),
|
|
|
|
}
|
2024-08-11 17:16:16 +00:00
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-10 09:23:43 +00:00
|
|
|
#[test]
|
|
|
|
fn while_loop() {
|
|
|
|
let input = "while x < 10 { x += 1 }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::While {
|
|
|
|
condition: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("x")),
|
|
|
|
(6, 7)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Less, (8, 9)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(10)),
|
|
|
|
(10, 12)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(6, 12)
|
|
|
|
)),
|
|
|
|
body: Box::new(Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("x")),
|
|
|
|
(15, 16)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::AddAssign, (17, 19)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(20, 21)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(15, 21)
|
|
|
|
)]),
|
|
|
|
(13, 23)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 23)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
#[test]
|
|
|
|
fn add_assign() {
|
|
|
|
let input = "a += 1";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("a")),
|
|
|
|
(0, 1)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::AddAssign, (2, 4)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))),
|
|
|
|
},
|
|
|
|
(0, 6)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
#[test]
|
|
|
|
fn or() {
|
|
|
|
let input = "true || false";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::boolean(true)),
|
|
|
|
(0, 4)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Or, (5, 7)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::boolean(false)),
|
|
|
|
(8, 13)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(0, 13)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 15:41:23 +00:00
|
|
|
#[test]
|
|
|
|
fn misplaced_semicolon() {
|
|
|
|
let input = ";";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-11 21:59:52 +00:00
|
|
|
Err(DustError::ParseError {
|
|
|
|
source: input,
|
|
|
|
parse_error: ParseError::UnexpectedToken {
|
|
|
|
actual: TokenOwned::Semicolon,
|
|
|
|
position: (0, 1)
|
|
|
|
}
|
2024-08-09 15:41:23 +00:00
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn block_with_one_statement() {
|
|
|
|
let input = "{ 40 + 2 }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::Block(vec![Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(40)),
|
|
|
|
(2, 4)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Add, (5, 6)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(2)),
|
|
|
|
(7, 8)
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
(2, 8)
|
|
|
|
)]),
|
|
|
|
(0, 10)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn block_with_assignment() {
|
|
|
|
let input = "{ foo = 42; bar = 42; baz = '42' }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::Block(vec![
|
|
|
|
Node::new(
|
|
|
|
Statement::Nil(Box::new(Node::new(
|
2024-08-09 22:14:46 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("foo")),
|
|
|
|
(2, 5)
|
|
|
|
)),
|
2024-08-10 08:29:46 +00:00
|
|
|
operator: Node::new(BinaryOperator::Assign, (6, 7)),
|
2024-08-09 22:14:46 +00:00
|
|
|
right: Box::new(Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Constant(Value::integer(42)),
|
2024-08-10 08:29:46 +00:00
|
|
|
(8, 10)
|
2024-08-09 22:14:46 +00:00
|
|
|
)),
|
2024-08-09 15:41:23 +00:00
|
|
|
},
|
2024-08-10 08:29:46 +00:00
|
|
|
(2, 10)
|
2024-08-09 15:41:23 +00:00
|
|
|
),)),
|
2024-08-12 20:57:10 +00:00
|
|
|
(2, 11)
|
2024-08-09 15:41:23 +00:00
|
|
|
),
|
|
|
|
Node::new(
|
|
|
|
Statement::Nil(Box::new(Node::new(
|
2024-08-09 22:14:46 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("bar")),
|
2024-08-10 08:29:46 +00:00
|
|
|
(12, 15)
|
2024-08-09 22:14:46 +00:00
|
|
|
)),
|
2024-08-10 08:29:46 +00:00
|
|
|
operator: Node::new(BinaryOperator::Assign, (16, 17)),
|
2024-08-09 22:14:46 +00:00
|
|
|
right: Box::new(Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Constant(Value::integer(42)),
|
2024-08-10 08:29:46 +00:00
|
|
|
(18, 20)
|
2024-08-09 22:14:46 +00:00
|
|
|
)),
|
2024-08-09 15:41:23 +00:00
|
|
|
},
|
|
|
|
(12, 20)
|
|
|
|
),)),
|
2024-08-12 20:57:10 +00:00
|
|
|
(12, 21)
|
2024-08-09 15:41:23 +00:00
|
|
|
),
|
|
|
|
Node::new(
|
2024-08-09 22:14:46 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("baz")),
|
2024-08-10 08:29:46 +00:00
|
|
|
(22, 25)
|
2024-08-09 22:14:46 +00:00
|
|
|
)),
|
2024-08-10 08:29:46 +00:00
|
|
|
operator: Node::new(BinaryOperator::Assign, (26, 27)),
|
2024-08-09 22:14:46 +00:00
|
|
|
right: Box::new(Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Constant(Value::string("42")),
|
2024-08-10 08:29:46 +00:00
|
|
|
(28, 32)
|
2024-08-09 22:14:46 +00:00
|
|
|
)),
|
2024-08-09 15:41:23 +00:00
|
|
|
},
|
|
|
|
(22, 32)
|
|
|
|
)
|
|
|
|
]),
|
|
|
|
(0, 34)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn empty_map() {
|
|
|
|
let input = "{}";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(Statement::Map(vec![]), (0, 2))].into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_with_trailing_comma() {
|
|
|
|
let input = "{ foo = 42, bar = 42, baz = '42', }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::Map(vec![
|
|
|
|
(
|
2024-08-09 22:14:46 +00:00
|
|
|
Node::new(Statement::Identifier(Identifier::new("foo")), (2, 5)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (8, 10))
|
|
|
|
),
|
|
|
|
(
|
2024-08-09 22:14:46 +00:00
|
|
|
Node::new(Statement::Identifier(Identifier::new("bar")), (12, 15)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (18, 20))
|
|
|
|
),
|
|
|
|
(
|
2024-08-09 22:14:46 +00:00
|
|
|
Node::new(Statement::Identifier(Identifier::new("baz")), (22, 25)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::string("42")), (28, 32))
|
|
|
|
),
|
|
|
|
]),
|
|
|
|
(0, 35)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-08-12 19:02:04 +00:00
|
|
|
fn map_with_two_fields() {
|
2024-08-09 15:41:23 +00:00
|
|
|
let input = "{ x = 42, y = 'foobar' }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::Map(vec![
|
|
|
|
(
|
2024-08-09 22:14:46 +00:00
|
|
|
Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (6, 8))
|
|
|
|
),
|
|
|
|
(
|
2024-08-09 22:14:46 +00:00
|
|
|
Node::new(Statement::Identifier(Identifier::new("y")), (10, 11)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::string("foobar")), (14, 22))
|
|
|
|
)
|
|
|
|
]),
|
|
|
|
(0, 24)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-08-12 19:02:04 +00:00
|
|
|
fn map_with_one_field() {
|
|
|
|
let input = "{ x = 42 }";
|
2024-08-09 15:41:23 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::Map(vec![(
|
2024-08-09 22:14:46 +00:00
|
|
|
Node::new(Statement::Identifier(Identifier::new("x")), (2, 3)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (6, 8))
|
|
|
|
)]),
|
2024-08-12 19:02:04 +00:00
|
|
|
(0, 10)
|
2024-08-09 15:41:23 +00:00
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 11:15:09 +00:00
|
|
|
#[test]
|
|
|
|
fn equal() {
|
|
|
|
let input = "42 == 42";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(42)), (0, 2))),
|
|
|
|
operator: Node::new(BinaryOperator::Equal, (3, 5)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(42)), (6, 8)))
|
|
|
|
},
|
|
|
|
(0, 8)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 11:02:55 +00:00
|
|
|
#[test]
|
|
|
|
fn modulo() {
|
|
|
|
let input = "42 % 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(42)), (0, 2))),
|
|
|
|
operator: Node::new(BinaryOperator::Modulo, (3, 4)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6)))
|
|
|
|
},
|
|
|
|
(0, 6)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 10:46:24 +00:00
|
|
|
#[test]
|
|
|
|
fn divide() {
|
|
|
|
let input = "42 / 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(42)), (0, 2))),
|
|
|
|
operator: Node::new(BinaryOperator::Divide, (3, 4)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6)))
|
|
|
|
},
|
|
|
|
(0, 6)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 07:00:48 +00:00
|
|
|
#[test]
|
|
|
|
fn less_than() {
|
|
|
|
let input = "1 < 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
|
|
|
operator: Node::new(BinaryOperator::Less, (2, 3)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
|
|
|
|
},
|
2024-08-09 07:00:48 +00:00
|
|
|
(0, 5)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn less_than_or_equal() {
|
|
|
|
let input = "1 <= 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
2024-08-09 08:56:24 +00:00
|
|
|
operator: Node::new(BinaryOperator::LessOrEqual, (2, 4)),
|
2024-08-09 08:23:02 +00:00
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6))),
|
|
|
|
},
|
2024-08-09 07:00:48 +00:00
|
|
|
(0, 6)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn greater_than_or_equal() {
|
|
|
|
let input = "1 >= 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
2024-08-09 08:56:24 +00:00
|
|
|
operator: Node::new(BinaryOperator::GreaterOrEqual, (2, 4)),
|
2024-08-09 08:23:02 +00:00
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (5, 6))),
|
|
|
|
},
|
2024-08-09 07:00:48 +00:00
|
|
|
(0, 6)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn greater_than() {
|
|
|
|
let input = "1 > 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
|
|
|
operator: Node::new(BinaryOperator::Greater, (2, 3)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5))),
|
|
|
|
},
|
2024-08-09 07:00:48 +00:00
|
|
|
(0, 5)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-08 17:11:32 +00:00
|
|
|
#[test]
|
2024-08-09 03:28:47 +00:00
|
|
|
fn subtract_negative_integers() {
|
|
|
|
let input = "-1 - -2";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
2024-08-09 08:56:24 +00:00
|
|
|
left: Node::new(Statement::Constant(Value::integer(-1)), (0, 2)).into(),
|
2024-08-09 08:23:02 +00:00
|
|
|
operator: Node::new(BinaryOperator::Subtract, (3, 4)),
|
2024-08-09 08:56:24 +00:00
|
|
|
right: Node::new(Statement::Constant(Value::integer(-2)), (5, 7)).into()
|
2024-08-09 08:23:02 +00:00
|
|
|
},
|
2024-08-09 03:28:47 +00:00
|
|
|
(0, 7)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2024-08-08 17:11:32 +00:00
|
|
|
fn string_concatenation() {
|
|
|
|
let input = "\"Hello, \" + \"World!\"";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
2024-08-08 17:11:32 +00:00
|
|
|
Statement::Constant(Value::string("Hello, ")),
|
2024-08-09 08:56:24 +00:00
|
|
|
(0, 9)
|
2024-08-08 17:11:32 +00:00
|
|
|
)),
|
2024-08-09 08:56:24 +00:00
|
|
|
operator: Node::new(BinaryOperator::Add, (10, 11)),
|
2024-08-09 08:23:02 +00:00
|
|
|
right: Box::new(Node::new(
|
2024-08-08 17:11:32 +00:00
|
|
|
Statement::Constant(Value::string("World!")),
|
2024-08-09 08:56:24 +00:00
|
|
|
(12, 20)
|
2024-08-08 17:11:32 +00:00
|
|
|
))
|
2024-08-09 08:23:02 +00:00
|
|
|
},
|
2024-08-09 08:56:24 +00:00
|
|
|
(0, 20)
|
2024-08-08 17:11:32 +00:00
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn string() {
|
|
|
|
let input = "\"Hello, World!\"";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::Constant(Value::string("Hello, World!")),
|
|
|
|
(0, 15)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-07 14:50:19 +00:00
|
|
|
#[test]
|
|
|
|
fn boolean() {
|
|
|
|
let input = "true";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(Statement::Constant(Value::boolean(true)), (0, 4))].into()
|
|
|
|
})
|
2024-08-07 14:50:19 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-07 22:24:25 +00:00
|
|
|
#[test]
|
|
|
|
fn property_access_function_call() {
|
|
|
|
let input = "42.is_even()";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-12 01:37:44 +00:00
|
|
|
Statement::BuiltInFunctionCall {
|
|
|
|
function: BuiltInFunction::IsEven,
|
|
|
|
type_arguments: None,
|
|
|
|
value_arguments: Some(vec![Node::new(
|
|
|
|
Statement::Constant(Value::integer(42)),
|
|
|
|
(0, 2)
|
|
|
|
)])
|
|
|
|
},
|
2024-08-07 22:24:25 +00:00
|
|
|
(0, 10),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-05 18:58:58 +00:00
|
|
|
#[test]
|
2024-08-12 20:57:10 +00:00
|
|
|
fn list_index() {
|
|
|
|
let input = "[1, 2, 3][0]";
|
2024-08-05 18:58:58 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-12 19:02:04 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::List(vec![
|
|
|
|
Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
|
|
|
|
Node::new(Statement::Constant(Value::integer(2)), (4, 5)),
|
|
|
|
Node::new(Statement::Constant(Value::integer(3)), (7, 8)),
|
|
|
|
]),
|
|
|
|
(0, 9)
|
|
|
|
)),
|
2024-08-12 23:06:57 +00:00
|
|
|
operator: Node::new(BinaryOperator::ListIndex, (9, 12)),
|
2024-08-12 19:02:04 +00:00
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(0)),
|
|
|
|
(10, 11)
|
|
|
|
)),
|
|
|
|
},
|
2024-08-12 20:57:10 +00:00
|
|
|
(0, 12),
|
2024-08-07 15:38:08 +00:00
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-05 18:58:58 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-05 18:31:08 +00:00
|
|
|
#[test]
|
|
|
|
fn property_access() {
|
|
|
|
let input = "a.b";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-12 19:02:04 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::Identifier(Identifier::new("a")),
|
|
|
|
(0, 1)
|
|
|
|
)),
|
2024-08-12 19:02:04 +00:00
|
|
|
operator: Node::new(BinaryOperator::FieldAccess, (1, 2)),
|
|
|
|
right: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::Identifier(Identifier::new("b")),
|
|
|
|
(2, 3)
|
|
|
|
)),
|
2024-08-12 19:02:04 +00:00
|
|
|
},
|
2024-08-07 15:38:08 +00:00
|
|
|
(0, 3),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-05 18:31:08 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-05 01:39:57 +00:00
|
|
|
#[test]
|
|
|
|
fn complex_list() {
|
|
|
|
let input = "[1, 1 + 1, 2 + (4 * 10)]";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::List(vec![
|
|
|
|
Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
|
|
|
|
Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(4, 5)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Add, (6, 7)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(8, 9)
|
|
|
|
))
|
|
|
|
},
|
|
|
|
(4, 9)
|
2024-08-05 04:40:51 +00:00
|
|
|
),
|
2024-08-07 15:38:08 +00:00
|
|
|
Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::Constant(Value::integer(2)),
|
|
|
|
(11, 12)
|
|
|
|
)),
|
2024-08-09 08:23:02 +00:00
|
|
|
operator: Node::new(BinaryOperator::Add, (13, 14)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::Constant(Value::integer(4)),
|
|
|
|
(16, 17)
|
|
|
|
)),
|
2024-08-09 08:23:02 +00:00
|
|
|
operator: Node::new(BinaryOperator::Multiply, (18, 19)),
|
|
|
|
right: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::Constant(Value::integer(10)),
|
|
|
|
(20, 22)
|
2024-08-09 08:23:02 +00:00
|
|
|
))
|
|
|
|
},
|
|
|
|
(15, 23)
|
|
|
|
))
|
|
|
|
},
|
|
|
|
(11, 23)
|
2024-08-05 04:40:51 +00:00
|
|
|
),
|
2024-08-07 15:38:08 +00:00
|
|
|
]),
|
|
|
|
(0, 24),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-05 01:39:57 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-05 01:31:18 +00:00
|
|
|
#[test]
|
|
|
|
fn list() {
|
|
|
|
let input = "[1, 2]";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
|
|
|
Statement::List(vec![
|
|
|
|
Node::new(Statement::Constant(Value::integer(1)), (1, 2)),
|
|
|
|
Node::new(Statement::Constant(Value::integer(2)), (4, 5)),
|
|
|
|
]),
|
|
|
|
(0, 6),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-05 01:31:18 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn empty_list() {
|
|
|
|
let input = "[]";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(Statement::List(vec![]), (0, 2))].into()
|
|
|
|
})
|
2024-08-05 01:31:18 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-05 00:08:43 +00:00
|
|
|
#[test]
|
|
|
|
fn float() {
|
|
|
|
let input = "42.0";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(Statement::Constant(Value::float(42.0)), (0, 4))].into()
|
|
|
|
})
|
2024-08-05 00:08:43 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-04 00:23:52 +00:00
|
|
|
#[test]
|
|
|
|
fn add() {
|
|
|
|
let input = "1 + 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
2024-08-04 23:25:44 +00:00
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
|
|
|
operator: Node::new(BinaryOperator::Add, (2, 3)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5)),)
|
|
|
|
},
|
2024-08-07 15:38:08 +00:00
|
|
|
(0, 5),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-04 00:23:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiply() {
|
|
|
|
let input = "1 * 2";
|
|
|
|
|
|
|
|
assert_eq!(
|
2024-08-04 23:25:44 +00:00
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
|
|
|
operator: Node::new(BinaryOperator::Multiply, (2, 3)),
|
|
|
|
right: Box::new(Node::new(Statement::Constant(Value::integer(2)), (4, 5)),)
|
|
|
|
},
|
2024-08-07 15:38:08 +00:00
|
|
|
(0, 5),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-04 00:23:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn add_and_multiply() {
|
|
|
|
let input = "1 + 2 * 3";
|
|
|
|
|
|
|
|
assert_eq!(
|
2024-08-04 23:25:44 +00:00
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(Statement::Constant(Value::integer(1)), (0, 1))),
|
|
|
|
operator: Node::new(BinaryOperator::Add, (2, 3)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(2)),
|
|
|
|
(4, 5)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Multiply, (6, 7)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(3)),
|
|
|
|
(8, 9)
|
|
|
|
),)
|
|
|
|
},
|
|
|
|
(4, 9)
|
|
|
|
),)
|
|
|
|
},
|
2024-08-07 15:38:08 +00:00
|
|
|
(0, 9),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-04 00:23:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn assignment() {
|
|
|
|
let input = "a = 1 + 2 * 3";
|
|
|
|
|
|
|
|
assert_eq!(
|
2024-08-04 23:25:44 +00:00
|
|
|
parse(input),
|
2024-08-07 15:38:08 +00:00
|
|
|
Ok(AbstractSyntaxTree {
|
|
|
|
nodes: [Node::new(
|
2024-08-09 22:14:46 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("a")),
|
|
|
|
(0, 1)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Assign, (2, 3)),
|
|
|
|
right: Box::new(Node::new(
|
2024-08-09 08:23:02 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(1)),
|
|
|
|
(4, 5)
|
|
|
|
)),
|
|
|
|
operator: Node::new(BinaryOperator::Add, (6, 7)),
|
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::Constant(Value::integer(2)),
|
|
|
|
(8, 9)
|
|
|
|
)),
|
2024-08-09 08:23:02 +00:00
|
|
|
operator: Node::new(BinaryOperator::Multiply, (10, 11)),
|
|
|
|
right: Box::new(Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
Statement::Constant(Value::integer(3)),
|
|
|
|
(12, 13)
|
2024-08-09 08:23:02 +00:00
|
|
|
),)
|
|
|
|
},
|
|
|
|
(8, 13)
|
|
|
|
),)
|
|
|
|
},
|
|
|
|
(4, 13)
|
|
|
|
),)
|
|
|
|
},
|
2024-08-07 15:38:08 +00:00
|
|
|
(0, 13),
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
2024-08-04 00:23:52 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|