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-14 18:28:39 +00:00
|
|
|
marker::PhantomData,
|
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-14 18:28:39 +00:00
|
|
|
abstract_tree::*, AbstractSyntaxTree, BuiltInFunction, DustError, Identifier, LexError, Lexer,
|
|
|
|
Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type, 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-13 21:34:45 +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(
|
2024-08-13 21:34:45 +00:00
|
|
|
/// BinaryOperator::Add,
|
2024-08-10 08:29:46 +00:00
|
|
|
/// (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-14 18:28:39 +00:00
|
|
|
let mut parser = Parser::<Statement>::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-14 18:28:39 +00:00
|
|
|
if let Token::Eof = parser.current_token {
|
2024-08-05 02:15:31 +00:00
|
|
|
break;
|
|
|
|
}
|
2024-08-05 00:08:43 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(AbstractSyntaxTree { statements: nodes })
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 01:24:56 +00:00
|
|
|
pub fn parse_into<'src>(
|
|
|
|
source: &'src str,
|
|
|
|
tree: &mut AbstractSyntaxTree,
|
|
|
|
) -> Result<(), DustError<'src>> {
|
|
|
|
let lexer = Lexer::new();
|
2024-08-14 18:28:39 +00:00
|
|
|
let mut parser = Parser::<Statement>::new(source, lexer);
|
2024-08-14 01:24:56 +00:00
|
|
|
|
|
|
|
loop {
|
|
|
|
let node = parser
|
|
|
|
.parse()
|
|
|
|
.map_err(|parse_error| DustError::ParseError {
|
|
|
|
parse_error,
|
|
|
|
source,
|
|
|
|
})?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
tree.statements.push_back(node);
|
2024-08-14 01:24:56 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Eof = parser.current_token {
|
2024-08-14 01:24:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
///
|
2024-08-13 21:34:45 +00:00
|
|
|
/// let tree = AbstractSyntaxTree { nodes };
|
|
|
|
///
|
2024-08-07 16:32:18 +00:00
|
|
|
/// ```
|
2024-08-14 18:28:39 +00:00
|
|
|
pub struct Parser<'src, T> {
|
2024-08-08 20:19:14 +00:00
|
|
|
source: &'src str,
|
|
|
|
lexer: Lexer,
|
2024-08-14 18:28:39 +00:00
|
|
|
current_token: Token<'src>,
|
|
|
|
current_position: Span,
|
|
|
|
product: PhantomData<T>,
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
impl<'src, T> Parser<'src, T> {
|
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-14 18:28:39 +00:00
|
|
|
let (current_token, current_position) =
|
|
|
|
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,
|
2024-08-14 18:28:39 +00:00
|
|
|
current_token,
|
|
|
|
current_position,
|
|
|
|
product: PhantomData,
|
2024-08-08 20:19:14 +00:00
|
|
|
}
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
pub fn parse(&mut self) -> Result<Statement, ParseError> {
|
|
|
|
self.parse_next(0)
|
2024-08-10 04:01:50 +00:00
|
|
|
}
|
2024-08-09 05:43:58 +00:00
|
|
|
|
2024-08-10 04:01:50 +00:00
|
|
|
fn next_token(&mut self) -> Result<(), ParseError> {
|
2024-08-14 18:28:39 +00:00
|
|
|
let (token, position) = self.lexer.next_token(self.source)?;
|
|
|
|
|
|
|
|
self.current_token = token;
|
|
|
|
self.current_position = position;
|
2024-08-04 00:23:52 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
fn parse_next(&mut self, mut precedence: u8) -> Result<Statement, ParseError> {
|
2024-08-12 12:35:08 +00:00
|
|
|
// Parse a statement starting from the current node.
|
2024-08-14 18:28:39 +00:00
|
|
|
let mut left = if self.current_token.is_prefix() {
|
2024-08-12 23:06:57 +00:00
|
|
|
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-14 18:28:39 +00:00
|
|
|
while precedence < self.current_token.precedence() {
|
2024-08-12 12:35:08 +00:00
|
|
|
// Give precedence to postfix operations
|
2024-08-14 18:28:39 +00:00
|
|
|
left = if self.current_token.is_postfix() {
|
2024-08-12 23:06:57 +00:00
|
|
|
let statement = self.parse_postfix(left)?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
precedence = self.current_token.precedence();
|
2024-08-12 23:06:57 +00:00
|
|
|
|
2024-08-14 07:53:15 +00:00
|
|
|
// Replace the left-hand side with the postfix operation
|
2024-08-12 23:06:57 +00:00
|
|
|
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-14 18:28:39 +00:00
|
|
|
fn parse_prefix(&mut self) -> Result<Statement, ParseError> {
|
|
|
|
log::trace!("Parsing {} as prefix operator", self.current_token);
|
2024-08-14 07:53:15 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let operator_start = self.current_position.0;
|
2024-08-14 07:53:15 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
match self.current_token {
|
|
|
|
Token::Bang => {
|
2024-08-12 09:44:05 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let operand = self.parse_expression(0)?;
|
|
|
|
let position = (operator_start, self.current_position.1);
|
2024-08-12 09:44:05 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::Expression(Expression::operator_expression(
|
|
|
|
OperatorExpression::Not(operand),
|
|
|
|
position,
|
|
|
|
)))
|
2024-08-12 09:44:05 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::Minus => {
|
2024-08-12 09:44:05 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let operand = self.parse_expression(0)?;
|
|
|
|
let position = (operator_start, self.current_position.1);
|
2024-08-12 09:44:05 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::Expression(Expression::operator_expression(
|
|
|
|
OperatorExpression::Negation(operand),
|
|
|
|
position,
|
|
|
|
)))
|
2024-08-12 09:44:05 +00:00
|
|
|
}
|
2024-08-12 23:06:57 +00:00
|
|
|
_ => Err(ParseError::UnexpectedToken {
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-12 23:06:57 +00:00
|
|
|
}),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
fn parse_primary(&mut self) -> Result<Statement, ParseError> {
|
|
|
|
log::trace!("Parsing {} as primary", self.current_token);
|
2024-08-14 07:53:15 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let start_position = self.current_position;
|
2024-08-14 03:45:17 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
match self.current_token {
|
|
|
|
Token::Async => {
|
|
|
|
let block = self.parse_block()?;
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
2024-08-14 03:45:17 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::block(block.inner, position));
|
2024-08-14 03:45:17 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::Boolean(text) => {
|
2024-08-07 14:50:19 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let boolean = text.parse().map_err(|error| ParseError::Boolean {
|
|
|
|
error,
|
|
|
|
position: start_position,
|
|
|
|
})?;
|
|
|
|
let right_end = self.current_position.1;
|
|
|
|
let statement = Statement::literal(
|
|
|
|
LiteralExpression::Boolean(boolean),
|
|
|
|
(start_position.0, right_end),
|
|
|
|
);
|
|
|
|
|
|
|
|
return Ok(statement);
|
2024-08-07 14:50:19 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::Float(text) => {
|
2024-08-04 00:23:52 +00:00
|
|
|
self.next_token()?;
|
2024-08-05 00:08:43 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let float = text.parse().map_err(|error| ParseError::Float {
|
|
|
|
error,
|
|
|
|
position: start_position,
|
|
|
|
})?;
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
2024-08-09 18:01:01 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::literal(
|
|
|
|
LiteralExpression::Float(float),
|
2024-08-09 18:01:01 +00:00
|
|
|
position,
|
2024-08-14 18:28:39 +00:00
|
|
|
));
|
2024-08-05 00:08:43 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::Identifier(text) => {
|
|
|
|
let identifier = Identifier::new(text);
|
|
|
|
let identifier_position = self.current_position;
|
2024-08-13 23:41:36 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
self.next_token()?;
|
2024-08-13 23:41:36 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::LeftCurlyBrace = self.current_token {
|
2024-08-13 23:41:36 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let mut fields = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::RightCurlyBrace = self.current_token {
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
2024-08-13 23:41:36 +00:00
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::struct_expression(
|
|
|
|
StructExpression::Fields {
|
|
|
|
name: Node::new(identifier, identifier_position),
|
2024-08-13 23:41:36 +00:00
|
|
|
fields,
|
|
|
|
},
|
2024-08-14 18:28:39 +00:00
|
|
|
position,
|
2024-08-13 23:41:36 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let field_name = self.parse_identifier()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Colon = self.current_token {
|
2024-08-13 23:41:36 +00:00
|
|
|
self.next_token()?;
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Equal,
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-13 23:41:36 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let field_value = self.parse_expression(0)?;
|
2024-08-13 23:41:36 +00:00
|
|
|
|
|
|
|
fields.push((field_name, field_value));
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Comma = self.current_token {
|
2024-08-13 23:41:36 +00:00
|
|
|
self.next_token()?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::identifier_expression(
|
|
|
|
identifier,
|
|
|
|
identifier_position,
|
2024-08-13 23:41:36 +00:00
|
|
|
))
|
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::Integer(text) => {
|
2024-08-05 00:08:43 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let integer = text.parse::<i64>().map_err(|error| ParseError::Integer {
|
|
|
|
error,
|
|
|
|
position: start_position,
|
|
|
|
})?;
|
2024-08-09 18:01:01 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::DoubleDot = self.current_token {
|
2024-08-12 14:08:34 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Integer(range_end) = self.current_token {
|
|
|
|
let end_position = self.current_position;
|
2024-08-12 14:08:34 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
self.next_token()?;
|
2024-08-12 14:08:34 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let range_end =
|
|
|
|
range_end
|
|
|
|
.parse::<i64>()
|
|
|
|
.map_err(|error| ParseError::Integer {
|
|
|
|
error,
|
|
|
|
position: end_position,
|
|
|
|
})?;
|
|
|
|
|
|
|
|
Ok(Statement::literal(
|
|
|
|
LiteralExpression::Range(integer, range_end),
|
|
|
|
(start_position.0, end_position.1),
|
2024-08-12 14:08:34 +00:00
|
|
|
))
|
|
|
|
} else {
|
|
|
|
Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Integer,
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: (start_position.0, self.current_position.1),
|
2024-08-12 14:08:34 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
} else {
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::literal(
|
|
|
|
LiteralExpression::Integer(integer),
|
|
|
|
start_position,
|
2024-08-12 14:08:34 +00:00
|
|
|
))
|
|
|
|
}
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::If => {
|
2024-08-11 18:35:33 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let condition = self.parse_expression(0)?;
|
|
|
|
let if_block = self.parse_block()?;
|
|
|
|
let else_block = if let Token::Else = self.current_token {
|
2024-08-11 18:35:33 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Some(self.parse_block()?)
|
2024-08-11 18:35:33 +00:00
|
|
|
} else {
|
2024-08-14 18:28:39 +00:00
|
|
|
None
|
|
|
|
};
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
2024-08-13 23:41:36 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::r#if(
|
|
|
|
If {
|
|
|
|
condition,
|
|
|
|
if_block,
|
|
|
|
else_block,
|
|
|
|
},
|
|
|
|
position,
|
|
|
|
))
|
2024-08-11 18:35:33 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::String(text) => {
|
2024-08-08 17:11:32 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::literal(
|
|
|
|
LiteralExpression::String(text.to_string()),
|
|
|
|
start_position,
|
|
|
|
))
|
2024-08-08 17:11:32 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::LeftCurlyBrace => {
|
|
|
|
let block_node = self.parse_block()?;
|
2024-08-11 17:16:16 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::block(block_node.inner, block_node.position))
|
2024-08-09 10:09:59 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::LeftParenthesis => {
|
2024-08-04 00:23:52 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let node = self.parse_expression(0)?;
|
|
|
|
|
|
|
|
if let Token::RightParenthesis = self.current_token {
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
2024-08-04 00:23:52 +00:00
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::grouped(node, position))
|
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-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-05 01:31:18 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::LeftSquareBrace => {
|
2024-08-05 01:31:18 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let first_expression = self.parse_expression(0)?;
|
2024-08-05 01:31:18 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Semicolon = self.current_token {
|
|
|
|
self.next_token()?;
|
2024-08-05 01:31:18 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let repeat_operand = self.parse_expression(0)?;
|
|
|
|
|
|
|
|
if let Token::RightSquareBrace = self.current_token {
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
2024-08-05 01:31:18 +00:00
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::list(
|
|
|
|
ListExpression::AutoFill {
|
|
|
|
length_operand: first_expression,
|
|
|
|
repeat_operand,
|
|
|
|
},
|
|
|
|
position,
|
|
|
|
));
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::RightSquareBrace,
|
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
|
|
|
});
|
2024-08-05 01:31:18 +00:00
|
|
|
}
|
2024-08-07 22:43:24 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let mut expressions = vec![first_expression];
|
2024-08-07 22:43:24 +00:00
|
|
|
|
2024-08-08 17:49:40 +00:00
|
|
|
loop {
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::RightSquareBrace = self.current_token {
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
|
|
|
|
2024-08-08 17:49:40 +00:00
|
|
|
self.next_token()?;
|
2024-08-14 18:28:39 +00:00
|
|
|
|
|
|
|
return Ok(Statement::list(
|
|
|
|
ListExpression::Ordered(expressions),
|
|
|
|
position,
|
|
|
|
));
|
2024-08-08 17:49:40 +00:00
|
|
|
}
|
2024-08-07 22:43:24 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Comma = self.current_token {
|
2024-08-08 17:49:40 +00:00
|
|
|
self.next_token()?;
|
2024-08-14 18:28:39 +00:00
|
|
|
|
2024-08-08 17:49:40 +00:00
|
|
|
continue;
|
|
|
|
}
|
2024-08-07 22:43:24 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let expression = self.parse_expression(0)?;
|
2024-08-07 22:43:24 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
expressions.push(expression);
|
2024-08-14 07:53:15 +00:00
|
|
|
}
|
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::Struct => {
|
2024-08-10 09:23:43 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let (name, name_end) = if let Token::Identifier(_) = self.current_token {
|
|
|
|
let end = self.current_position.1;
|
2024-08-10 09:23:43 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
(self.parse_identifier()?, end)
|
2024-08-13 19:12:32 +00:00
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Identifier,
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-13 19:12:32 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::LeftParenthesis = self.current_token {
|
2024-08-13 19:12:32 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let mut types = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::RightParenthesis = self.current_token {
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::struct_definition(
|
|
|
|
StructDefinition::Tuple { name, items: types },
|
|
|
|
position,
|
2024-08-13 19:12:32 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Comma = self.current_token {
|
2024-08-13 19:12:32 +00:00
|
|
|
self.next_token()?;
|
2024-08-14 18:28:39 +00:00
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let type_node = self.parse_type()?;
|
|
|
|
|
|
|
|
types.push(type_node);
|
|
|
|
}
|
2024-08-10 09:23:43 +00:00
|
|
|
}
|
2024-08-13 22:48:02 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::LeftCurlyBrace = self.current_token {
|
2024-08-13 22:48:02 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
let mut fields = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::RightCurlyBrace = self.current_token {
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
|
|
|
|
2024-08-13 22:48:02 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::struct_definition(
|
|
|
|
StructDefinition::Fields { name, fields },
|
|
|
|
position,
|
2024-08-13 22:48:02 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Comma = self.current_token {
|
2024-08-13 22:48:02 +00:00
|
|
|
self.next_token()?;
|
2024-08-14 18:28:39 +00:00
|
|
|
|
2024-08-13 22:48:02 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let field_name = self.parse_identifier()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Colon = self.current_token {
|
2024-08-13 22:48:02 +00:00
|
|
|
self.next_token()?;
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Colon,
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-13 22:48:02 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let field_type = self.parse_type()?;
|
|
|
|
|
|
|
|
fields.push((field_name, field_type));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::struct_definition(
|
|
|
|
StructDefinition::Unit { name },
|
|
|
|
(start_position.0, name_end),
|
2024-08-13 22:48:02 +00:00
|
|
|
))
|
2024-08-13 17:54:16 +00:00
|
|
|
}
|
2024-08-14 18:28:39 +00:00
|
|
|
Token::While => {
|
2024-08-13 17:54:16 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let condition = self.parse_expression(0)?;
|
|
|
|
let block = self.parse_block()?;
|
|
|
|
let position = (start_position.0, self.current_position.1);
|
2024-08-10 09:23:43 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::r#loop(
|
|
|
|
Loop::While { condition, block },
|
|
|
|
position,
|
2024-08-10 09:23:43 +00:00
|
|
|
))
|
|
|
|
}
|
2024-08-09 04:49:17 +00:00
|
|
|
_ => Err(ParseError::UnexpectedToken {
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-09 04:49:17 +00:00
|
|
|
}),
|
2024-08-04 00:23:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
fn parse_infix(&mut self, left: Statement) -> Result<Statement, ParseError> {
|
|
|
|
log::trace!("Parsing {} as infix operator", self.current_token);
|
2024-08-14 07:53:15 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let left = if let Statement::Expression(expression) = left {
|
|
|
|
expression
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedExpression { actual: left });
|
|
|
|
};
|
|
|
|
let operator_precedence = self.current_token.precedence()
|
|
|
|
- if self.current_token.is_right_associative() {
|
2024-08-12 15:24:24 +00:00
|
|
|
1
|
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
2024-08-14 18:28:39 +00:00
|
|
|
let left_start = left.position().0;
|
2024-08-13 21:34:45 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Equal = &self.current_token {
|
2024-08-13 21:34:45 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let value = self.parse_expression(operator_precedence)?;
|
|
|
|
let position = (left_start, value.position().1);
|
2024-08-13 21:34:45 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::operator_expression(
|
|
|
|
OperatorExpression::Assignment {
|
|
|
|
assignee: left,
|
|
|
|
value,
|
2024-08-13 21:34:45 +00:00
|
|
|
},
|
2024-08-14 18:28:39 +00:00
|
|
|
position,
|
2024-08-13 21:34:45 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::PlusEqual | Token::MinusEqual = &self.current_token {
|
|
|
|
let math_operator = match self.current_token {
|
|
|
|
Token::PlusEqual => MathOperator::Add,
|
|
|
|
Token::MinusEqual => MathOperator::Subtract,
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
|
|
|
let operator = Node::new(math_operator, self.current_position);
|
2024-08-12 19:02:04 +00:00
|
|
|
|
2024-08-09 22:14:46 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let value = self.parse_expression(operator_precedence)?;
|
|
|
|
let position = (left_start, value.position().1);
|
2024-08-12 01:37:44 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::operator_expression(
|
|
|
|
OperatorExpression::CompoundAssignment {
|
|
|
|
assignee: left,
|
|
|
|
operator,
|
|
|
|
value,
|
|
|
|
},
|
|
|
|
position,
|
|
|
|
));
|
|
|
|
}
|
2024-08-12 01:37:44 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Dot = &self.current_token {
|
|
|
|
self.next_token()?;
|
2024-08-12 01:37:44 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let field = self.parse_identifier()?;
|
|
|
|
let position = (left_start, self.current_position.1);
|
2024-08-12 01:37:44 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return Ok(Statement::field_access(
|
|
|
|
FieldAccess {
|
|
|
|
container: left,
|
|
|
|
field,
|
2024-08-12 19:02:04 +00:00
|
|
|
},
|
2024-08-14 18:28:39 +00:00
|
|
|
position,
|
2024-08-09 22:14:46 +00:00
|
|
|
));
|
2024-08-10 04:01:50 +00:00
|
|
|
}
|
2024-08-09 18:01:01 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let math_operator = match &self.current_token {
|
|
|
|
Token::Minus => Node::new(MathOperator::Subtract, self.current_position),
|
|
|
|
Token::Plus => Node::new(MathOperator::Add, self.current_position),
|
|
|
|
Token::Star => Node::new(MathOperator::Multiply, self.current_position),
|
|
|
|
Token::Slash => Node::new(MathOperator::Divide, self.current_position),
|
|
|
|
Token::Percent => Node::new(MathOperator::Modulo, self.current_position),
|
2024-08-09 18:01:01 +00:00
|
|
|
_ => {
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-09 18:01:01 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let right = self.parse_expression(operator_precedence)?;
|
|
|
|
let position = (left_start, right.position().1);
|
2024-08-09 18:01:01 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Statement::operator_expression(
|
|
|
|
OperatorExpression::Math {
|
|
|
|
left,
|
|
|
|
operator: math_operator,
|
|
|
|
right,
|
2024-08-09 18:01:01 +00:00
|
|
|
},
|
2024-08-14 18:28:39 +00:00
|
|
|
position,
|
2024-08-09 18:01:01 +00:00
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
fn parse_postfix(&mut self, left: Statement) -> Result<Statement, ParseError> {
|
|
|
|
log::trace!("Parsing {} as postfix operator", self.current_token);
|
2024-08-14 07:53:15 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let left = if let Statement::Expression(expression) = left {
|
|
|
|
expression
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedExpression { actual: left });
|
|
|
|
};
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let statement = match &self.current_token {
|
2024-08-13 20:21:44 +00:00
|
|
|
Token::LeftParenthesis => {
|
|
|
|
self.next_token()?;
|
2024-08-09 22:14:46 +00:00
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
let mut arguments = Vec::new();
|
2024-08-12 20:57:10 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
while self.current_token != Token::RightParenthesis {
|
|
|
|
let argument = self.parse_expression(0)?;
|
2024-08-12 20:57:10 +00:00
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
arguments.push(argument);
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::Comma = self.current_token {
|
2024-08-13 20:21:44 +00:00
|
|
|
self.next_token()?;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-12 20:57:10 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let position = (left.position().0, self.current_position.1);
|
2024-08-14 01:24:56 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Statement::call_expression(
|
|
|
|
CallExpression {
|
|
|
|
function: left,
|
|
|
|
arguments,
|
2024-08-13 20:21:44 +00:00
|
|
|
},
|
2024-08-14 18:28:39 +00:00
|
|
|
position,
|
2024-08-13 20:21:44 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
Token::LeftSquareBrace => {
|
2024-08-14 18:28:39 +00:00
|
|
|
let operator_start = self.current_position.0;
|
2024-08-12 23:06:57 +00:00
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
self.next_token()?;
|
2024-08-12 23:06:57 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let index = self.parse_expression(0)?;
|
2024-08-12 23:06:57 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let operator_end = if let Token::RightSquareBrace = self.current_token {
|
|
|
|
let end = self.current_position.1;
|
2024-08-12 23:06:57 +00:00
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
end
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::RightSquareBrace,
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-13 20:21:44 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let position = (left.position().0, operator_end);
|
2024-08-13 20:21:44 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Statement::list_index(ListIndex { list: left, index }, position)
|
2024-08-13 20:21:44 +00:00
|
|
|
}
|
|
|
|
Token::Semicolon => {
|
2024-08-14 18:28:39 +00:00
|
|
|
let position = (left.position().0, self.current_position.1);
|
2024-08-13 20:21:44 +00:00
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Statement::ExpressionNullified(Node::new(left, position))
|
2024-08-13 20:21:44 +00:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
return Err(ParseError::UnexpectedToken {
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-13 20:21:44 +00:00
|
|
|
});
|
|
|
|
}
|
2024-08-12 13:06:42 +00:00
|
|
|
};
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if self.current_token.is_postfix() {
|
2024-08-12 23:06:57 +00:00
|
|
|
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-14 18:28:39 +00:00
|
|
|
fn parse_expression(&mut self, precedence: u8) -> Result<Expression, ParseError> {
|
|
|
|
log::trace!("Parsing expression");
|
|
|
|
|
|
|
|
let statement = self.parse_next(precedence)?;
|
|
|
|
|
|
|
|
if let Statement::Expression(expression) = statement {
|
|
|
|
Ok(expression)
|
2024-08-13 17:54:16 +00:00
|
|
|
} else {
|
2024-08-14 18:28:39 +00:00
|
|
|
Err(ParseError::ExpectedExpression { actual: statement })
|
|
|
|
}
|
|
|
|
}
|
2024-08-13 17:54:16 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
fn parse_identifier(&mut self) -> Result<Node<Identifier>, ParseError> {
|
|
|
|
if let Token::Identifier(text) = self.current_token {
|
|
|
|
self.next_token()?;
|
2024-08-13 17:54:16 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
Ok(Node::new(Identifier::new(text), self.current_position))
|
|
|
|
} else {
|
|
|
|
Err(ParseError::ExpectedToken {
|
|
|
|
expected: TokenKind::Identifier,
|
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
|
|
|
})
|
|
|
|
}
|
2024-08-13 17:54:16 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
fn parse_block(&mut self) -> Result<Node<Block>, ParseError> {
|
|
|
|
let left_start = self.current_position.0;
|
|
|
|
let is_async = if let Token::Async = self.current_token {
|
|
|
|
self.next_token()?;
|
|
|
|
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
2024-08-10 09:23:43 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::LeftCurlyBrace = self.current_token {
|
2024-08-10 09:23:43 +00:00
|
|
|
self.next_token()?;
|
|
|
|
} else {
|
|
|
|
return Err(ParseError::ExpectedToken {
|
2024-08-12 14:08:34 +00:00
|
|
|
expected: TokenKind::LeftCurlyBrace,
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-10 09:23:43 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut statements = Vec::new();
|
|
|
|
|
|
|
|
loop {
|
2024-08-14 18:28:39 +00:00
|
|
|
if let Token::RightCurlyBrace = self.current_token {
|
|
|
|
let position = (left_start, self.current_position.1);
|
2024-08-10 09:23:43 +00:00
|
|
|
|
|
|
|
self.next_token()?;
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
return if is_async {
|
|
|
|
Ok(Node::new(Block::Async(statements), position))
|
|
|
|
} else {
|
|
|
|
Ok(Node::new(Block::Sync(statements), position))
|
|
|
|
};
|
2024-08-10 09:23:43 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
let statement = self.parse_next(0)?;
|
2024-08-10 09:23:43 +00:00
|
|
|
|
|
|
|
statements.push(statement);
|
|
|
|
}
|
|
|
|
}
|
2024-08-13 19:12:32 +00:00
|
|
|
|
|
|
|
fn parse_type(&mut self) -> Result<Node<Type>, ParseError> {
|
2024-08-14 18:28:39 +00:00
|
|
|
let r#type = match self.current_token {
|
2024-08-13 19:12:32 +00:00
|
|
|
Token::Bool => Type::Boolean,
|
|
|
|
Token::FloatKeyword => Type::Float,
|
|
|
|
Token::Int => Type::Integer,
|
|
|
|
_ => {
|
|
|
|
return Err(ParseError::ExpectedTokenMultiple {
|
|
|
|
expected: vec![TokenKind::Bool, TokenKind::FloatKeyword, TokenKind::Int],
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: self.current_token.to_owned(),
|
|
|
|
position: self.current_position,
|
2024-08-13 19:12:32 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
2024-08-14 18:28:39 +00:00
|
|
|
let position = self.current_position;
|
2024-08-13 19:12:32 +00:00
|
|
|
|
|
|
|
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-14 18:28:39 +00:00
|
|
|
Boolean {
|
2024-08-09 18:01:01 +00:00
|
|
|
error: ParseBoolError,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-14 18:28:39 +00:00
|
|
|
Lex(LexError),
|
2024-08-11 17:16:16 +00:00
|
|
|
ExpectedAssignment {
|
2024-08-14 18:28:39 +00:00
|
|
|
actual: Statement,
|
|
|
|
},
|
|
|
|
ExpectedExpression {
|
|
|
|
actual: Statement,
|
2024-08-11 17:16:16 +00:00
|
|
|
},
|
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-14 18:28:39 +00:00
|
|
|
Float {
|
2024-08-09 18:01:01 +00:00
|
|
|
error: ParseFloatError,
|
|
|
|
position: Span,
|
|
|
|
},
|
2024-08-14 18:28:39 +00:00
|
|
|
Integer {
|
2024-08-09 18:01:01 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
Self::Lex(v)
|
2024-08-10 04:01:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-09 04:49:17 +00:00
|
|
|
impl ParseError {
|
|
|
|
pub fn position(&self) -> Span {
|
|
|
|
match self {
|
2024-08-14 18:28:39 +00:00
|
|
|
ParseError::Boolean { position, .. } => *position,
|
|
|
|
ParseError::ExpectedAssignment { actual } => actual.position(),
|
|
|
|
ParseError::ExpectedExpression { 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-14 18:28:39 +00:00
|
|
|
ParseError::Float { position, .. } => *position,
|
|
|
|
ParseError::Integer { position, .. } => *position,
|
|
|
|
ParseError::Lex(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-14 18:28:39 +00:00
|
|
|
Self::Lex(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-14 18:28:39 +00:00
|
|
|
Self::Boolean { error, .. } => write!(f, "{}", error),
|
2024-08-11 17:16:16 +00:00
|
|
|
Self::ExpectedAssignment { .. } => write!(f, "Expected assignment"),
|
2024-08-14 18:28:39 +00:00
|
|
|
Self::ExpectedExpression { .. } => write!(f, "Expected expression"),
|
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-14 18:28:39 +00:00
|
|
|
Self::Float { error, .. } => write!(f, "{}", error),
|
|
|
|
Self::Integer { error, .. } => write!(f, "{}", error),
|
|
|
|
Self::Lex(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-14 18:28:39 +00:00
|
|
|
use crate::{Identifier, StructDefinition, Type};
|
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-14 05:13:43 +00:00
|
|
|
#[test]
|
|
|
|
fn mutable_variable() {
|
2024-08-14 08:59:27 +00:00
|
|
|
let input = "mut x = false";
|
2024-08-14 05:13:43 +00:00
|
|
|
|
2024-08-14 18:28:39 +00:00
|
|
|
assert_eq!(parse(input), todo!());
|
2024-08-14 05:13:43 +00:00
|
|
|
}
|
|
|
|
|
2024-08-14 03:45:17 +00:00
|
|
|
#[test]
|
|
|
|
fn async_block() {
|
|
|
|
let input = "async { x = 42; y = 4.0 }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Statement::block(
|
|
|
|
Block::Async(vec![Statement::operator_expression(
|
|
|
|
OperatorExpression::Assignment {
|
|
|
|
assignee: Expression::WithoutBlock(()),
|
|
|
|
value: ()
|
|
|
|
},
|
|
|
|
position
|
|
|
|
)]),
|
|
|
|
position
|
2024-08-14 03:45:17 +00:00
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-14 01:24:56 +00:00
|
|
|
#[test]
|
|
|
|
fn tuple_struct_access() {
|
2024-08-14 07:53:15 +00:00
|
|
|
let input = "(Foo(42, 'bar')).0";
|
|
|
|
let mut tree = AbstractSyntaxTree::new();
|
|
|
|
|
|
|
|
if parse_into(input, &mut tree).is_err() {
|
|
|
|
println!("{tree:?}")
|
|
|
|
}
|
2024-08-14 01:24:56 +00:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-14 01:24:56 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Invokation {
|
|
|
|
invokee: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("Foo")),
|
2024-08-14 07:53:15 +00:00
|
|
|
(1, 4)
|
2024-08-14 01:24:56 +00:00
|
|
|
)),
|
|
|
|
type_arguments: None,
|
|
|
|
value_arguments: Some(vec![
|
2024-08-14 07:53:15 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (5, 7)),
|
|
|
|
Node::new(Statement::Constant(Value::string("bar")), (9, 14))
|
2024-08-14 01:24:56 +00:00
|
|
|
]),
|
|
|
|
},
|
2024-08-14 07:53:15 +00:00
|
|
|
(0, 16)
|
2024-08-14 01:24:56 +00:00
|
|
|
)),
|
2024-08-14 07:53:15 +00:00
|
|
|
operator: Node::new(BinaryOperator::FieldAccess, (16, 17)),
|
2024-08-14 01:24:56 +00:00
|
|
|
right: Box::new(Node::new(
|
|
|
|
Statement::Constant(Value::integer(0)),
|
2024-08-14 07:53:15 +00:00
|
|
|
(17, 18)
|
2024-08-14 01:24:56 +00:00
|
|
|
))
|
|
|
|
},
|
2024-08-14 07:53:15 +00:00
|
|
|
(0, 18)
|
2024-08-14 01:24:56 +00:00
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 23:41:36 +00:00
|
|
|
#[test]
|
|
|
|
fn fields_struct_instantiation() {
|
|
|
|
let input = "Foo { a = 42, b = 4.0 }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-13 23:41:36 +00:00
|
|
|
Statement::FieldsStructInstantiation {
|
|
|
|
name: Node::new(Identifier::new("Foo"), (0, 3)),
|
|
|
|
fields: vec![
|
|
|
|
(
|
|
|
|
Node::new(Identifier::new("a"), (6, 7)),
|
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (10, 12))
|
|
|
|
),
|
|
|
|
(
|
|
|
|
Node::new(Identifier::new("b"), (14, 15)),
|
|
|
|
Node::new(Statement::Constant(Value::float(4.0)), (18, 21))
|
|
|
|
)
|
|
|
|
]
|
|
|
|
},
|
|
|
|
(0, 23)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 22:48:02 +00:00
|
|
|
#[test]
|
|
|
|
fn fields_struct() {
|
|
|
|
let input = "struct Foo { a: int, b: float }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-13 22:48:02 +00:00
|
|
|
Statement::StructDefinition(StructDefinition::Fields {
|
|
|
|
name: Node::new(Identifier::new("Foo"), (7, 10)),
|
|
|
|
fields: vec![
|
|
|
|
(
|
|
|
|
Node::new(Identifier::new("a"), (13, 14)),
|
|
|
|
Node::new(Type::Integer, (16, 19))
|
|
|
|
),
|
|
|
|
(
|
|
|
|
Node::new(Identifier::new("b"), (21, 22)),
|
|
|
|
Node::new(Type::Float, (24, 29))
|
|
|
|
)
|
|
|
|
]
|
|
|
|
}),
|
|
|
|
(0, 31)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 20:21:44 +00:00
|
|
|
#[test]
|
|
|
|
fn tuple_struct_instantiation() {
|
|
|
|
let input = "struct Foo(int, float) Foo(1, 2.0)";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [
|
2024-08-13 20:21:44 +00:00
|
|
|
Node::new(
|
|
|
|
Statement::StructDefinition(StructDefinition::Tuple {
|
|
|
|
name: Node::new(Identifier::new("Foo"), (7, 10)),
|
2024-08-13 22:48:02 +00:00
|
|
|
items: vec![
|
2024-08-13 20:21:44 +00:00
|
|
|
Node::new(Type::Integer, (11, 14)),
|
|
|
|
Node::new(Type::Float, (16, 21))
|
|
|
|
]
|
|
|
|
}),
|
|
|
|
(0, 22)
|
|
|
|
),
|
|
|
|
Node::new(
|
|
|
|
Statement::Invokation {
|
|
|
|
invokee: Box::new(Node::new(
|
|
|
|
Statement::Identifier(Identifier::new("Foo")),
|
|
|
|
(23, 26)
|
|
|
|
)),
|
|
|
|
type_arguments: None,
|
|
|
|
value_arguments: Some(vec![
|
|
|
|
Node::new(Statement::Constant(Value::integer(1)), (27, 28)),
|
|
|
|
Node::new(Statement::Constant(Value::float(2.0)), (30, 33))
|
|
|
|
])
|
|
|
|
},
|
|
|
|
(23, 34)
|
|
|
|
)
|
|
|
|
]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-13 19:12:32 +00:00
|
|
|
#[test]
|
|
|
|
fn tuple_struct() {
|
|
|
|
let input = "struct Foo(int, float)";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-13 19:12:32 +00:00
|
|
|
Statement::StructDefinition(StructDefinition::Tuple {
|
|
|
|
name: Node::new(Identifier::new("Foo"), (7, 10)),
|
2024-08-13 22:48:02 +00:00
|
|
|
items: vec![
|
2024-08-13 19:12:32 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-13 17:54:16 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-12 20:57:10 +00:00
|
|
|
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-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-12 19:02:04 +00:00
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::BinaryOperation {
|
|
|
|
left: Box::new(Node::new(
|
|
|
|
Statement::Map(vec![(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(Identifier::new("x"), (2, 3)),
|
2024-08-12 19:02:04 +00:00
|
|
|
Node::new(
|
|
|
|
Statement::Map(vec![(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(Identifier::new("y"), (8, 9)),
|
2024-08-12 19:02:04 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(Statement::Constant(Value::range(0..42)), (0, 5))].into()
|
2024-08-12 14:08:34 +00:00
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-12 09:44:05 +00:00
|
|
|
#[test]
|
|
|
|
fn negate_variable() {
|
|
|
|
let input = "a = 1; -a";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [
|
2024-08-12 09:44:05 +00:00
|
|
|
Node::new(
|
2024-08-12 12:35:08 +00:00
|
|
|
Statement::Nil(Box::new(Node::new(
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
|
|
|
operator: Node::new(AssignmentOperator::Assign, (2, 3)),
|
|
|
|
value: Box::new(Node::new(
|
2024-08-12 12:35:08 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-12 09:44:05 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-12 10:00:14 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [
|
2024-08-12 10:00:14 +00:00
|
|
|
Node::new(
|
|
|
|
Statement::Nil(Box::new(Node::new(
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
|
|
|
operator: Node::new(AssignmentOperator::Assign, (2, 3)),
|
|
|
|
value: Box::new(Node::new(
|
2024-08-12 10:00:14 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-11 18:35:33 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-11 18:35:33 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-11 18:35:33 +00:00
|
|
|
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(
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("z"), (16, 17)),
|
|
|
|
operator: Node::new(AssignmentOperator::Assign, (18, 19)),
|
|
|
|
value: Box::new(Node::new(
|
2024-08-11 21:59:52 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-10 09:23:43 +00:00
|
|
|
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(
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("x"), (15, 16)),
|
|
|
|
operator: Node::new(AssignmentOperator::AddAssign, (17, 19)),
|
|
|
|
value: Box::new(Node::new(
|
2024-08-10 09:23:43 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
|
|
|
operator: Node::new(AssignmentOperator::AddAssign, (2, 4)),
|
|
|
|
value: Box::new(Node::new(Statement::Constant(Value::integer(1)), (5, 6))),
|
2024-08-09 22:14:46 +00:00
|
|
|
},
|
|
|
|
(0, 6)
|
|
|
|
)]
|
|
|
|
.into()
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 18:01:01 +00:00
|
|
|
#[test]
|
|
|
|
fn or() {
|
|
|
|
let input = "true || false";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 18:01:01 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Block(vec![
|
|
|
|
Node::new(
|
|
|
|
Statement::Nil(Box::new(Node::new(
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("foo"), (2, 5)),
|
|
|
|
operator: Node::new(AssignmentOperator::Assign, (6, 7)),
|
|
|
|
value: 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-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("bar"), (12, 15)),
|
|
|
|
operator: Node::new(AssignmentOperator::Assign, (16, 17)),
|
|
|
|
value: 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-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("baz"), (22, 25)),
|
|
|
|
operator: Node::new(AssignmentOperator::Assign, (26, 27)),
|
|
|
|
value: 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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(Statement::Map(vec![]), (0, 2))].into()
|
2024-08-09 15:41:23 +00:00
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn map_with_trailing_comma() {
|
|
|
|
let input = "{ foo = 42, bar = 42, baz = '42', }";
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
parse(input),
|
|
|
|
Ok(AbstractSyntaxTree {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Map(vec![
|
|
|
|
(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(Identifier::new("foo"), (2, 5)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (8, 10))
|
|
|
|
),
|
|
|
|
(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(Identifier::new("bar"), (12, 15)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (18, 20))
|
|
|
|
),
|
|
|
|
(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Map(vec![
|
|
|
|
(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(Identifier::new("x"), (2, 3)),
|
2024-08-09 15:41:23 +00:00
|
|
|
Node::new(Statement::Constant(Value::integer(42)), (6, 8))
|
|
|
|
),
|
|
|
|
(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 15:41:23 +00:00
|
|
|
Statement::Map(vec![(
|
2024-08-13 21:34:45 +00:00
|
|
|
Node::new(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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 11:15:09 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 11:02:55 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-09 10:46:24 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-08 17:11:32 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(Statement::Constant(Value::boolean(true)), (0, 4))].into()
|
2024-08-07 15:38:08 +00:00
|
|
|
})
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-07 15:38:08 +00:00
|
|
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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)),
|
|
|
|
]),
|
|
|
|
(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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(Statement::List(vec![]), (0, 2))].into()
|
2024-08-07 15:38:08 +00:00
|
|
|
})
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(Statement::Constant(Value::float(42.0)), (0, 4))].into()
|
2024-08-07 15:38:08 +00:00
|
|
|
})
|
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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [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 {
|
2024-08-14 18:28:39 +00:00
|
|
|
statements: [Node::new(
|
2024-08-13 21:34:45 +00:00
|
|
|
Statement::Assignment {
|
|
|
|
identifier: Node::new(Identifier::new("a"), (0, 1)),
|
|
|
|
operator: Node::new(AssignmentOperator::Assign, (2, 3)),
|
|
|
|
value: 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
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|