Add spans to all statements

This commit is contained in:
Jeff 2024-03-16 15:01:45 -04:00
parent 5b79af6e85
commit 15b1808741
12 changed files with 634 additions and 382 deletions

View File

@ -115,7 +115,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -138,7 +138,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::AddAssign, AssignmentOperator::AddAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(41))), Statement::expression(Expression::Value(ValueNode::Integer(41)), (0..0).into()),
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -161,7 +161,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::SubAssign, AssignmentOperator::SubAssign,
Statement::Expression(Expression::Value(ValueNode::Integer(1))), Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into()),
) )
.run(&context) .run(&context)
.unwrap(); .unwrap();
@ -178,7 +178,7 @@ mod tests {
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::Boolean), Some(Type::Boolean),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
) )
.validate(&Context::new()); .validate(&Context::new());

View File

@ -61,9 +61,9 @@ mod tests {
#[test] #[test]
fn run_returns_value_of_final_statement() { fn run_returns_value_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::Integer(1))), Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(2))), Statement::expression(Expression::Value(ValueNode::Integer(2)), (0..0).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
]); ]);
assert_eq!( assert_eq!(
@ -75,8 +75,11 @@ mod tests {
#[test] #[test]
fn expected_type_returns_type_of_final_statement() { fn expected_type_returns_type_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))), Statement::expression(
Statement::Expression(Expression::Value(ValueNode::Integer(42))), Expression::Value(ValueNode::String("42".to_string())),
(0..0).into(),
),
Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into()),
]); ]);
assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer)) assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))

View File

@ -62,8 +62,7 @@ impl AbstractTree for IfElse {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
abstract_tree::{Action, Statement, ValueNode}, abstract_tree::{Statement, ValueNode},
context::Context,
Value, Value,
}; };
@ -74,9 +73,10 @@ mod tests {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string())),
)),]), (0..0).into()
)]),
None None
) )
.run(&Context::new()), .run(&Context::new()),
@ -89,12 +89,14 @@ mod tests {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(false)), Expression::Value(ValueNode::Boolean(false)),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string())),
)),]), (0..0).into()
Some(Block::new(vec![Statement::Expression(Expression::Value( ),]),
ValueNode::String("bar".to_string()) Some(Block::new(vec![Statement::expression(
))])) Expression::Value(ValueNode::String("bar".to_string())),
(0..0).into()
)]))
) )
.run(&Context::new()), .run(&Context::new()),
Ok(Action::Return(Value::string("bar".to_string()))) Ok(Action::Return(Value::string("bar".to_string())))

View File

@ -122,7 +122,7 @@ impl AbstractTree for Logic {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::abstract_tree::{Expression, ValueNode}; use crate::abstract_tree::ValueNode;
use super::*; use super::*;

View File

@ -58,7 +58,7 @@ mod tests {
#[test] #[test]
fn basic_loop() { fn basic_loop() {
let result = Loop { let result = Loop {
statements: vec![Statement::Break], statements: vec![Statement::r#break((0..1).into())],
} }
.run(&Context::new()); .run(&Context::new());

View File

@ -1,3 +1,5 @@
use chumsky::span::{SimpleSpan, Span};
use crate::{ use crate::{
context::Context, context::Context,
error::{RuntimeError, ValidationError}, error::{RuntimeError, ValidationError},
@ -6,7 +8,72 @@ use crate::{
use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While}; use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement { pub struct Statement {
pub inner: StatementInner,
pub span: (usize, usize),
}
impl Statement {
pub fn assignment(assignment: Assignment, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Assignment(assignment),
span: (span.start(), span.end()),
}
}
pub fn block(block: Block, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Block(block),
span: (span.start(), span.end()),
}
}
pub fn r#break(span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Break,
span: (span.start(), span.end()),
}
}
pub fn expression(expression: Expression, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Expression(expression),
span: (span.start(), span.end()),
}
}
pub fn if_else(if_else: IfElse, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::IfElse(if_else),
span: (span.start(), span.end()),
}
}
pub fn r#loop(r#loop: Loop, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::Loop(r#loop),
span: (span.start(), span.end()),
}
}
pub fn r#while(r#while: While, span: SimpleSpan) -> Self {
Statement {
inner: StatementInner::While(r#while),
span: (span.start(), span.end()),
}
}
pub fn span(&self) -> (usize, usize) {
self.span
}
pub fn inner(&self) -> &StatementInner {
&self.inner
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum StatementInner {
Assignment(Assignment), Assignment(Assignment),
Block(Block), Block(Block),
Break, Break,
@ -18,38 +85,38 @@ pub enum Statement {
impl AbstractTree for Statement { impl AbstractTree for Statement {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> { fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
match self { match &self.inner {
Statement::Assignment(assignment) => assignment.expected_type(_context), StatementInner::Assignment(assignment) => assignment.expected_type(_context),
Statement::Block(block) => block.expected_type(_context), StatementInner::Block(block) => block.expected_type(_context),
Statement::Break => Ok(Type::None), StatementInner::Break => Ok(Type::None),
Statement::Expression(expression) => expression.expected_type(_context), StatementInner::Expression(expression) => expression.expected_type(_context),
Statement::IfElse(if_else) => if_else.expected_type(_context), StatementInner::IfElse(if_else) => if_else.expected_type(_context),
Statement::Loop(r#loop) => r#loop.expected_type(_context), StatementInner::Loop(r#loop) => r#loop.expected_type(_context),
Statement::While(r#while) => r#while.expected_type(_context), StatementInner::While(r#while) => r#while.expected_type(_context),
} }
} }
fn validate(&self, _context: &Context) -> Result<(), ValidationError> { fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
match self { match &self.inner {
Statement::Assignment(assignment) => assignment.validate(_context), StatementInner::Assignment(assignment) => assignment.validate(_context),
Statement::Block(block) => block.validate(_context), StatementInner::Block(block) => block.validate(_context),
Statement::Break => Ok(()), StatementInner::Break => Ok(()),
Statement::Expression(expression) => expression.validate(_context), StatementInner::Expression(expression) => expression.validate(_context),
Statement::IfElse(if_else) => if_else.validate(_context), StatementInner::IfElse(if_else) => if_else.validate(_context),
Statement::Loop(r#loop) => r#loop.validate(_context), StatementInner::Loop(r#loop) => r#loop.validate(_context),
Statement::While(r#while) => r#while.validate(_context), StatementInner::While(r#while) => r#while.validate(_context),
} }
} }
fn run(self, _context: &Context) -> Result<Action, RuntimeError> { fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
match self { match self.inner {
Statement::Assignment(assignment) => assignment.run(_context), StatementInner::Assignment(assignment) => assignment.run(_context),
Statement::Block(block) => block.run(_context), StatementInner::Block(block) => block.run(_context),
Statement::Break => Ok(Action::Break), StatementInner::Break => Ok(Action::Break),
Statement::Expression(expression) => expression.run(_context), StatementInner::Expression(expression) => expression.run(_context),
Statement::IfElse(if_else) => if_else.run(_context), StatementInner::IfElse(if_else) => if_else.run(_context),
Statement::Loop(r#loop) => r#loop.run(_context), StatementInner::Loop(r#loop) => r#loop.run(_context),
Statement::While(r#while) => r#while.run(_context), StatementInner::While(r#while) => r#while.run(_context),
} }
} }
} }

View File

@ -1,7 +1,7 @@
use std::sync::PoisonError; use std::sync::PoisonError;
use ariadne::{Color, Label, Report, ReportKind}; use ariadne::{Color, Label, Report, ReportKind};
use chumsky::{prelude::Rich, span::SimpleSpan}; use chumsky::{prelude::Rich, span::Span};
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Type},
@ -12,45 +12,40 @@ use crate::{
pub enum Error { pub enum Error {
Parse { Parse {
expected: String, expected: String,
span: SimpleSpan, span: (usize, usize),
}, },
Lex { Lex {
expected: String, expected: String,
span: SimpleSpan, span: (usize, usize),
}, },
Runtime(RuntimeError), Runtime(RuntimeError),
Validation { Validation {
error: ValidationError, error: ValidationError,
span: SimpleSpan, span: (usize, usize),
}, },
} }
impl Error { impl Error {
pub fn report(&self) -> Report { pub fn report(&self) -> Report {
match self { match self {
Error::Parse { expected, span } => Report::build( Error::Parse { expected, span } => {
ReportKind::Custom("Parsing Error", Color::White), let message = match expected.as_str() {
(), "" => "Invalid character.".to_string(),
span.start, expected => format!("Expected {expected}."),
)
.with_label(
Label::new(span.start..span.end).with_message(format!("Expected {expected}.")),
)
.finish(),
Error::Lex { expected, span } => {
let expected = match expected.as_str() {
"" => "something else",
expected => expected,
}; };
Report::build( Report::build(ReportKind::Custom("Lexing Error", Color::White), (), span.0)
ReportKind::Custom("Lexing Error", Color::White), .with_label(Label::new(span.0..span.1).with_message(message))
(), .finish()
span.start, }
) Error::Lex { expected, span } => {
.with_label( let message = match expected.as_str() {
Label::new(span.start..span.end).with_message(format!("Expected {expected}.")), "" => "Invalid character.".to_string(),
) expected => format!("Expected {expected}."),
};
Report::build(ReportKind::Custom("Lexing Error", Color::White), (), span.0)
.with_label(Label::new(span.0..span.1).with_message(message))
.finish() .finish()
} }
Error::Runtime(_) => todo!(), Error::Runtime(_) => todo!(),
@ -58,30 +53,29 @@ impl Error {
let mut report = Report::build( let mut report = Report::build(
ReportKind::Custom("Validation Error", Color::White), ReportKind::Custom("Validation Error", Color::White),
(), (),
span.start, span.0,
); );
match error { match error {
ValidationError::ExpectedBoolean => { ValidationError::ExpectedBoolean => {
report = report.with_label( report = report.with_label(
Label::new(span.start..span.end).with_message("Expected boolean."), Label::new(span.0..span.1).with_message("Expected boolean."),
); );
} }
ValidationError::ExpectedIntegerOrFloat => { ValidationError::ExpectedIntegerOrFloat => {
report = report.with_label( report = report.with_label(
Label::new(span.start..span.end) Label::new(span.0..span.1).with_message("Expected integer or float."),
.with_message("Expected integer or float."),
); );
} }
ValidationError::RwLockPoison(_) => todo!(), ValidationError::RwLockPoison(_) => todo!(),
ValidationError::TypeCheck(TypeCheckError { actual, expected }) => { ValidationError::TypeCheck(TypeCheckError { actual, expected }) => {
report = report.with_label(Label::new(span.start..span.end).with_message( report = report.with_label(Label::new(span.0..span.1).with_message(
format!("Type error. Expected {expected} but got {actual}."), format!("Type error. Expected {expected} but got {actual}."),
)); ));
} }
ValidationError::VariableNotFound(identifier) => { ValidationError::VariableNotFound(identifier) => {
report = report report = report
.with_label(Label::new(span.start..span.end).with_message(format!( .with_label(Label::new(span.0..span.1).with_message(format!(
"The variable {identifier} does not exist." "The variable {identifier} does not exist."
))); )));
} }
@ -102,7 +96,7 @@ impl From<Rich<'_, char>> for Error {
fn from(error: Rich<'_, char>) -> Self { fn from(error: Rich<'_, char>) -> Self {
Error::Lex { Error::Lex {
expected: error.expected().map(|error| error.to_string()).collect(), expected: error.expected().map(|error| error.to_string()).collect(),
span: error.span().clone(), span: (error.span().start(), error.span().end()),
} }
} }
} }
@ -111,7 +105,7 @@ impl<'src> From<Rich<'_, Token<'src>>> for Error {
fn from(error: Rich<'_, Token<'src>>) -> Self { fn from(error: Rich<'_, Token<'src>>) -> Self {
Error::Parse { Error::Parse {
expected: error.expected().map(|error| error.to_string()).collect(), expected: error.expected().map(|error| error.to_string()).collect(),
span: error.span().clone(), span: (error.span().start(), error.span().end()),
} }
} }
} }

View File

@ -33,12 +33,12 @@ impl Interpreter {
let statements = parse(&tokens)?; let statements = parse(&tokens)?;
let errors = statements let errors = statements
.iter() .iter()
.filter_map(|(statement, span)| { .filter_map(|statement| {
statement statement
.validate(&self.context) .validate(&self.context)
.map_err(|validation_error| Error::Validation { .map_err(|validation_error| Error::Validation {
error: validation_error, error: validation_error,
span: span.clone(), span: statement.span(),
}) })
.err() .err()
}) })
@ -50,7 +50,7 @@ impl Interpreter {
let mut value = None; let mut value = None;
for (statement, _span) in statements { for statement in statements {
value = match statement.run(&self.context) { value = match statement.run(&self.context) {
Ok(action) => match action { Ok(action) => match action {
Action::Break => None, Action::Break => None,

View File

@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed<
'src, 'src,
'src, 'src,
ParserInput<'src>, ParserInput<'src>,
Vec<(Statement, SimpleSpan)>, Vec<Statement>,
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>, extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
>; >;
@ -21,7 +21,7 @@ pub type ParserInput<'src> =
pub fn parse<'src>( pub fn parse<'src>(
tokens: &'src [(Token<'src>, SimpleSpan)], tokens: &'src [(Token<'src>, SimpleSpan)],
) -> Result<Vec<(Statement, SimpleSpan)>, Vec<Error>> { ) -> Result<Vec<Statement>, Vec<Error>> {
parser() parser()
.parse(tokens.spanned((tokens.len()..tokens.len()).into())) .parse(tokens.spanned((tokens.len()..tokens.len()).into()))
.into_result() .into_result()
@ -292,10 +292,11 @@ pub fn parser<'src>() -> DustParser<'src> {
let expression_statement = expression let expression_statement = expression
.clone() .clone()
.map(|expression| Statement::Expression(expression)) .map_with(|expression, state| Statement::expression(expression, state.span()))
.boxed(); .boxed();
let r#break = just(Token::Keyword("break")).to(Statement::Break); let r#break =
just(Token::Keyword("break")).map_with(|_, state| Statement::r#break(state.span()));
let assignment = identifier let assignment = identifier
.clone() .clone()
@ -306,12 +307,17 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign), just(Token::Operator(Operator::SubAssign)).to(AssignmentOperator::SubAssign),
))) )))
.then(statement.clone()) .then(statement.clone())
.map(|(((identifier, r#type), operator), statement)| { .map_with(|(((identifier, r#type), operator), statement), state| {
Statement::Assignment(Assignment::new(identifier, r#type, operator, statement)) Statement::assignment(
Assignment::new(identifier, r#type, operator, statement),
state.span(),
)
}) })
.boxed(); .boxed();
let block_statement = block.clone().map(|block| Statement::Block(block)); let block_statement = block
.clone()
.map_with(|block, state| Statement::block(block, state.span()));
let r#loop = statement let r#loop = statement
.clone() .clone()
@ -322,13 +328,15 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Keyword("loop")).then(just(Token::Control(Control::CurlyOpen))), just(Token::Keyword("loop")).then(just(Token::Control(Control::CurlyOpen))),
just(Token::Control(Control::CurlyClose)), just(Token::Control(Control::CurlyClose)),
) )
.map(|statements| Statement::Loop(Loop::new(statements))) .map_with(|statements, state| Statement::r#loop(Loop::new(statements), state.span()))
.boxed(); .boxed();
let r#while = just(Token::Keyword("while")) let r#while = just(Token::Keyword("while"))
.ignore_then(expression.clone()) .ignore_then(expression.clone())
.then(block.clone()) .then(block.clone())
.map(|(expression, block)| Statement::While(While::new(expression, block))); .map_with(|(expression, block), state| {
Statement::r#while(While::new(expression, block), state.span())
});
let if_else = just(Token::Keyword("if")) let if_else = just(Token::Keyword("if"))
.ignore_then(expression.clone()) .ignore_then(expression.clone())
@ -338,8 +346,11 @@ pub fn parser<'src>() -> DustParser<'src> {
.ignore_then(block.clone()) .ignore_then(block.clone())
.or_not(), .or_not(),
) )
.map(|((if_expression, if_block), else_block)| { .map_with(|((if_expression, if_block), else_block), state| {
Statement::IfElse(IfElse::new(if_expression, if_block, else_block)) Statement::if_else(
IfElse::new(if_expression, if_block, else_block),
state.span(),
)
}) })
.boxed(); .boxed();
@ -356,159 +367,205 @@ pub fn parser<'src>() -> DustParser<'src> {
.boxed() .boxed()
}); });
statement statement.repeated().collect().boxed()
.map_with(|item, state| (item, state.span()))
.repeated()
.collect()
.boxed()
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{abstract_tree::Logic, lexer::lex}; use tests::statement::StatementInner;
use crate::lexer::lex;
use super::*; use super::*;
#[test] #[test]
fn r#while() { fn r#while() {
assert_eq!( assert_eq!(
parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0].0, parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0],
Statement::While(While::new( Statement::r#while(
While::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Block::new(vec![Statement::Expression(Expression::FunctionCall( Block::new(vec![Statement::expression(
FunctionCall::new( Expression::FunctionCall(FunctionCall::new(
Expression::Identifier(Identifier::new("output")), Expression::Identifier(Identifier::new("output")),
vec![Expression::Value(ValueNode::String("hi".to_string()))] vec![Expression::Value(ValueNode::String("hi".to_string()))]
)),
(0..0).into()
)])
),
(0..0).into()
) )
))])
))
) )
} }
#[test] #[test]
fn types() { fn types() {
assert_eq!( assert_eq!(
parse(&lex("foobar : bool = true").unwrap()).unwrap()[0].0, parse(&lex("foobar : bool = true").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::Boolean), Some(Type::Boolean),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Boolean(true))) Statement::expression(
)) Expression::Value(ValueNode::Boolean(true)),
(0..0).into()
)
),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0].0, parse(&lex("foobar : list(bool) = [true]").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::ListOf(Box::new(Type::Boolean))), Some(Type::ListOf(Box::new(Type::Boolean))),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value( Statement::expression(
Expression::Value(ValueNode::List(vec![Expression::Value(
ValueNode::Boolean(true) ValueNode::Boolean(true)
)]))) )])),
)) (0..0).into()
)
),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0].0, parse(&lex("foobar : [bool, str] = [true, '42']").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::ListExact(vec![Type::Boolean, Type::String])), Some(Type::ListExact(vec![Type::Boolean, Type::String])),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![ Statement::expression(
Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Expression::Value(ValueNode::String("42".to_string())) Expression::Value(ValueNode::String("42".to_string()))
]))) ])),
)) (0..0).into()
)
),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("foobar : () -> any = some_function").unwrap()).unwrap()[0].0, parse(&lex("foobar : () -> any = some_function").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::Function { Some(Type::Function {
parameter_types: vec![], parameter_types: vec![],
return_type: Box::new(Type::Any) return_type: Box::new(Type::Any)
}), }),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Identifier(Identifier::new("some_function"))) Statement::expression(
)) Expression::Identifier(Identifier::new("some_function")),
(0..0).into()
)
),
(0..0).into()
)
); );
} }
#[test] #[test]
fn function_call() { fn function_call() {
assert_eq!( assert_eq!(
parse(&lex("output()").unwrap()).unwrap()[0].0, parse(&lex("output()").unwrap()).unwrap()[0],
Statement::Expression(Expression::FunctionCall(FunctionCall::new( Statement::expression(
Expression::FunctionCall(FunctionCall::new(
Expression::Identifier(Identifier::new("output")), Expression::Identifier(Identifier::new("output")),
Vec::with_capacity(0), Vec::with_capacity(0),
))) )),
(0..0).into()
)
) )
} }
#[test] #[test]
fn range() { fn range() {
assert_eq!( assert_eq!(
parse(&lex("1..10").unwrap()).unwrap()[0].0, parse(&lex("1..10").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Range(1..10))) Statement::expression(Expression::Value(ValueNode::Range(1..10)), (0..0).into())
) )
} }
#[test] #[test]
fn function() { fn function() {
assert_eq!( assert_eq!(
parse(&lex("(x: int): int { x }").unwrap()).unwrap()[0].0, parse(&lex("(x: int): int { x }").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Function { Statement::expression(
Expression::Value(ValueNode::Function {
parameters: vec![(Identifier::new("x"), Type::Integer)], parameters: vec![(Identifier::new("x"), Type::Integer)],
return_type: Type::Integer, return_type: Type::Integer,
body: Block::new(vec![Statement::Expression(Expression::Identifier( body: Block::new(vec![Statement::expression(
Identifier::new("x") Expression::Identifier(Identifier::new("x")),
))]) (0..0).into()
})) )])
}),
(0..0).into()
)
) )
} }
#[test] #[test]
fn r#if() { fn r#if() {
assert_eq!( assert_eq!(
parse(&lex("if true { 'foo' }").unwrap()).unwrap()[0].0, parse(&lex("if true { 'foo' }").unwrap()).unwrap()[0],
Statement::IfElse(IfElse::new( Statement::if_else(
IfElse::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string())),
))]), (0..0).into()
)]),
None None
)) ),
(0..0).into()
)
); );
} }
#[test] #[test]
fn if_else() { fn if_else() {
assert_eq!( assert_eq!(
parse(&lex("if true {'foo' } else { 'bar' }").unwrap()).unwrap()[0].0, parse(&lex("if true {'foo' } else { 'bar' }").unwrap()).unwrap()[0],
Statement::IfElse(IfElse::new( Statement::if_else(
IfElse::new(
Expression::Value(ValueNode::Boolean(true)), Expression::Value(ValueNode::Boolean(true)),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string())),
))]), (0..0).into()
Some(Block::new(vec![Statement::Expression(Expression::Value( )]),
ValueNode::String("bar".to_string()) Some(Block::new(vec![Statement::expression(
))])) Expression::Value(ValueNode::String("bar".to_string())),
)) (0..0).into()
)]))
),
(0..0).into()
)
) )
} }
#[test] #[test]
fn map() { fn map() {
assert_eq!( assert_eq!(
parse(&lex("{ foo = 'bar' }").unwrap()).unwrap()[0].0, parse(&lex("{ foo = 'bar' }").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Map(vec![( Statement::expression(
Expression::Value(ValueNode::Map(vec![(
Identifier::new("foo"), Identifier::new("foo"),
None, None,
Expression::Value(ValueNode::String("bar".to_string())) Expression::Value(ValueNode::String("bar".to_string()))
)]))) )])),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("{ x = 1, y = 2, }").unwrap()).unwrap()[0].0, parse(&lex("{ x = 1, y = 2, }").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Map(vec![ Statement::expression(
Expression::Value(ValueNode::Map(vec![
( (
Identifier::new("x"), Identifier::new("x"),
None, None,
@ -519,11 +576,14 @@ mod tests {
None, None,
Expression::Value(ValueNode::Integer(2)) Expression::Value(ValueNode::Integer(2))
), ),
]))) ])),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("{ x = 1 y = 2 }").unwrap()).unwrap()[0].0, parse(&lex("{ x = 1 y = 2 }").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Map(vec![ Statement::expression(
Expression::Value(ValueNode::Map(vec![
( (
Identifier::new("x"), Identifier::new("x"),
None, None,
@ -534,38 +594,51 @@ mod tests {
None, None,
Expression::Value(ValueNode::Integer(2)) Expression::Value(ValueNode::Integer(2))
), ),
]))) ])),
(0..0).into()
)
); );
} }
#[test] #[test]
fn math() { fn math() {
assert_eq!( assert_eq!(
parse(&lex("1 + 1").unwrap()).unwrap()[0].0, parse(&lex("1 + 1").unwrap()).unwrap()[0],
Statement::Expression(Expression::Math(Box::new(Math::Add( Statement::expression(
Expression::Math(Box::new(Math::Add(
Expression::Value(ValueNode::Integer(1)), Expression::Value(ValueNode::Integer(1)),
Expression::Value(ValueNode::Integer(1)) Expression::Value(ValueNode::Integer(1))
)))) ))),
(0..0).into()
)
); );
} }
#[test] #[test]
fn r#loop() { fn r#loop() {
assert_eq!( assert_eq!(
parse(&lex("loop { 42 }").unwrap()).unwrap()[0].0, parse(&lex("loop { 42 }").unwrap()).unwrap()[0],
Statement::Loop(Loop::new(vec![Statement::Expression(Expression::Value( Statement::r#loop(
ValueNode::Integer(42) Loop::new(vec![Statement::expression(
))])) Expression::Value(ValueNode::Integer(42)),
(0..0).into()
)]),
(0..0).into()
)
); );
} }
#[test] #[test]
fn block() { fn block() {
assert_eq!( assert_eq!(
parse(&lex("{ x }").unwrap()).unwrap()[0].0, parse(&lex("{ x }").unwrap()).unwrap()[0],
Statement::Block(Block::new(vec![Statement::Expression( Statement::block(
Expression::Identifier(Identifier::new("x")) Block::new(vec![Statement::expression(
),])) Expression::Identifier(Identifier::new("x")),
(0..0).into()
)],),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
@ -579,13 +652,24 @@ mod tests {
") ")
.unwrap() .unwrap()
) )
.unwrap()[0] .unwrap()[0],
.0, Statement::block(
Statement::Block(Block::new(vec![ Block::new(vec![
Statement::Expression(Expression::Identifier(Identifier::new("x"))), Statement::expression(
Statement::Expression(Expression::Identifier(Identifier::new("y"))), Expression::Identifier(Identifier::new("x")),
Statement::Expression(Expression::Identifier(Identifier::new("z"))), (0..0).into()
])) ),
Statement::expression(
Expression::Identifier(Identifier::new("y")),
(0..0).into()
),
Statement::expression(
Expression::Identifier(Identifier::new("z")),
(0..0).into()
),
]),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
@ -598,109 +682,151 @@ mod tests {
") ")
.unwrap() .unwrap()
) )
.unwrap()[0] .unwrap()[0],
.0, Statement::block(
Statement::Block(Block::new(vec![ Block::new(vec![
Statement::Expression(Expression::Logic(Box::new(Logic::Equal( Statement::expression(
Expression::Logic(Box::new(Logic::Equal(
Expression::Value(ValueNode::Integer(1)), Expression::Value(ValueNode::Integer(1)),
Expression::Value(ValueNode::Integer(1)) Expression::Value(ValueNode::Integer(1))
)))), ))),
Statement::Expression(Expression::Identifier(Identifier::new("z"))), (0..0).into()
])) ),
Statement::expression(
Expression::Identifier(Identifier::new("z")),
(0..0).into()
),
]),
(0..0).into()
)
); );
} }
#[test] #[test]
fn identifier() { fn identifier() {
assert_eq!( assert_eq!(
parse(&lex("x").unwrap()).unwrap()[0].0, parse(&lex("x").unwrap()).unwrap()[0],
Statement::Expression(Expression::Identifier(Identifier::new("x"))) Statement::expression(Expression::Identifier(Identifier::new("x")), (0..0).into())
); );
assert_eq!( assert_eq!(
parse(&lex("foobar").unwrap()).unwrap()[0].0, parse(&lex("foobar").unwrap()).unwrap()[0],
Statement::Expression(Expression::Identifier(Identifier::new("foobar"))) Statement::expression(
Expression::Identifier(Identifier::new("foobar")),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("HELLO").unwrap()).unwrap()[0].0, parse(&lex("HELLO").unwrap()).unwrap()[0],
Statement::Expression(Expression::Identifier(Identifier::new("HELLO"))) Statement::expression(
Expression::Identifier(Identifier::new("HELLO")),
(0..0).into()
)
); );
} }
#[test] #[test]
fn assignment() { fn assignment() {
assert_eq!( assert_eq!(
parse(&lex("foobar = 1").unwrap()).unwrap()[0].0, parse(&lex("foobar = 1").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
None, None,
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(1))) Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into())
)), ),
(0..0).into()
),
); );
} }
#[test] #[test]
fn assignment_with_basic_type() { fn assignment_with_basic_type() {
assert_eq!( assert_eq!(
parse(&lex("foobar: int = 1").unwrap()).unwrap()[0].0, parse(&lex("foobar: int = 1").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::Integer), Some(Type::Integer),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::Integer(1))) Statement::expression(Expression::Value(ValueNode::Integer(1)), (0..0).into())
)), ),
(0..0).into()
),
); );
} }
#[test] #[test]
fn assignment_with_list_types() { fn assignment_with_list_types() {
assert_eq!( assert_eq!(
parse(&lex("foobar: list = []").unwrap()).unwrap()[0].0, parse(&lex("foobar: list = []").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::List), Some(Type::List),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![]))) Statement::expression(
)), Expression::Value(ValueNode::List(vec![])),
(0..0).into()
)
),
(0..0).into()
),
); );
assert_eq!( assert_eq!(
parse(&lex("foobar: list(int) = []").unwrap()).unwrap()[0].0, parse(&lex("foobar: list(int) = []").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::ListOf(Box::new(Type::Integer))), Some(Type::ListOf(Box::new(Type::Integer))),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![]))) Statement::expression(
)), Expression::Value(ValueNode::List(vec![])),
(0..0).into()
)
),
(0..0).into()
),
); );
assert_eq!( assert_eq!(
parse(&lex("foobar: [int, str] = [ 42, 'foo' ]").unwrap()).unwrap()[0].0, parse(&lex("foobar: [int, str] = [ 42, 'foo' ]").unwrap()).unwrap()[0],
Statement::Assignment(Assignment::new( Statement::assignment(
Assignment::new(
Identifier::new("foobar"), Identifier::new("foobar"),
Some(Type::ListExact(vec![Type::Integer, Type::String])), Some(Type::ListExact(vec![Type::Integer, Type::String])),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Statement::Expression(Expression::Value(ValueNode::List(vec![ Statement::expression(
Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Integer(42)), Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::String("foo".to_string())) Expression::Value(ValueNode::String("foo".to_string()))
]))) ])),
)), (0..0).into()
)
),
(0..0).into()
),
); );
} }
#[test] #[test]
fn logic() { fn logic() {
assert_eq!( assert_eq!(
parse(&lex("x == 1").unwrap()).unwrap()[0].0, parse(&lex("x == 1").unwrap()).unwrap()[0],
Statement::Expression(Expression::Logic(Box::new(Logic::Equal( Statement::expression(
Expression::Logic(Box::new(Logic::Equal(
Expression::Identifier(Identifier::new("x")), Expression::Identifier(Identifier::new("x")),
Expression::Value(ValueNode::Integer(1)) Expression::Value(ValueNode::Integer(1))
)))) ))),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("(x == 1) && (y == 2)").unwrap()).unwrap()[0].0, parse(&lex("(x == 1) && (y == 2)").unwrap()).unwrap()[0],
Statement::Expression(Expression::Logic(Box::new(Logic::And( Statement::expression(
Expression::Logic(Box::new(Logic::And(
Expression::Logic(Box::new(Logic::Equal( Expression::Logic(Box::new(Logic::Equal(
Expression::Identifier(Identifier::new("x")), Expression::Identifier(Identifier::new("x")),
Expression::Value(ValueNode::Integer(1)) Expression::Value(ValueNode::Integer(1))
@ -709,12 +835,15 @@ mod tests {
Expression::Identifier(Identifier::new("y")), Expression::Identifier(Identifier::new("y")),
Expression::Value(ValueNode::Integer(2)) Expression::Value(ValueNode::Integer(2))
))), ))),
)))) ))),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("(x == 1) && (y == 2) && true").unwrap()).unwrap()[0].0, parse(&lex("(x == 1) && (y == 2) && true").unwrap()).unwrap()[0],
Statement::Expression(Expression::Logic(Box::new(Logic::And( Statement::expression(
Expression::Logic(Box::new(Logic::And(
Expression::Logic(Box::new(Logic::And( Expression::Logic(Box::new(Logic::And(
Expression::Logic(Box::new(Logic::Equal( Expression::Logic(Box::new(Logic::Equal(
Expression::Identifier(Identifier::new("x")), Expression::Identifier(Identifier::new("x")),
@ -726,25 +855,34 @@ mod tests {
))), ))),
))), ))),
Expression::Value(ValueNode::Boolean(true)) Expression::Value(ValueNode::Boolean(true))
)))) ))),
(0..0).into()
)
); );
} }
#[test] #[test]
fn list() { fn list() {
assert_eq!( assert_eq!(
parse(&lex("[]").unwrap()).unwrap()[0].0, parse(&lex("[]").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::List(Vec::with_capacity(0)))) Statement::expression(
Expression::Value(ValueNode::List(Vec::with_capacity(0))),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("[42]").unwrap()).unwrap()[0].0, parse(&lex("[42]").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::List(vec![Expression::Value( Statement::expression(
Expression::Value(ValueNode::List(vec![Expression::Value(
ValueNode::Integer(42) ValueNode::Integer(42)
)]))) )])),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0].0, parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::List(vec![ Statement::expression(
Expression::Value(ValueNode::List(vec![
Expression::Value(ValueNode::Integer(42)), Expression::Value(ValueNode::Integer(42)),
Expression::Value(ValueNode::String("foo".to_string())), Expression::Value(ValueNode::String("foo".to_string())),
Expression::Value(ValueNode::String("bar".to_string())), Expression::Value(ValueNode::String("bar".to_string())),
@ -753,91 +891,105 @@ mod tests {
Expression::Value(ValueNode::Integer(2)), Expression::Value(ValueNode::Integer(2)),
Expression::Value(ValueNode::Integer(3)), Expression::Value(ValueNode::Integer(3)),
])) ]))
])),) ])),
(0..0).into()
)
); );
} }
#[test] #[test]
fn r#true() { fn r#true() {
assert_eq!( assert_eq!(
parse(&lex("true").unwrap()).unwrap()[0].0, parse(&lex("true").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Boolean(true))) Statement::expression(Expression::Value(ValueNode::Boolean(true)), (0..0).into())
); );
} }
#[test] #[test]
fn r#false() { fn r#false() {
assert_eq!( assert_eq!(
parse(&lex("false").unwrap()).unwrap()[0].0, parse(&lex("false").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Boolean(false))) Statement::expression(Expression::Value(ValueNode::Boolean(false)), (0..0).into())
); );
} }
#[test] #[test]
fn positive_float() { fn positive_float() {
assert_eq!( assert_eq!(
parse(&lex("0.0").unwrap()).unwrap()[0].0, parse(&lex("0").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(0.0))) Statement::expression(Expression::Value(ValueNode::Float(0.0)), (0..0).into())
); );
assert_eq!( assert_eq!(
parse(&lex("42.0").unwrap()).unwrap()[0].0, parse(&lex("42").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(42.0))) Statement::expression(Expression::Value(ValueNode::Float(42.0)), (0..0).into())
); );
let max_float = f64::MAX.to_string() + ".0"; let max_float = f64::MAX.to_string() + ".0";
assert_eq!( assert_eq!(
parse(&lex(&max_float).unwrap()).unwrap()[0].0, parse(&lex(&max_float).unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(f64::MAX))) Statement::expression(Expression::Value(ValueNode::Float(f64::MAX)), (0..0).into())
); );
let min_positive_float = f64::MIN_POSITIVE.to_string(); let min_positive_float = f64::MIN_POSITIVE.to_string();
assert_eq!( assert_eq!(
parse(&lex(&min_positive_float).unwrap()).unwrap()[0].0, parse(&lex(&min_positive_float).unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(f64::MIN_POSITIVE))) Statement::expression(
Expression::Value(ValueNode::Float(f64::MIN_POSITIVE)),
(0..0).into()
)
); );
} }
#[test] #[test]
fn negative_float() { fn negative_float() {
assert_eq!( assert_eq!(
parse(&lex("-0.0").unwrap()).unwrap()[0].0, parse(&lex("-0.0").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(-0.0))) Statement::expression(Expression::Value(ValueNode::Float(-0.0)), (0..0).into())
); );
assert_eq!( assert_eq!(
parse(&lex("-42.0").unwrap()).unwrap()[0].0, parse(&lex("-42.0").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(-42.0))) Statement::expression(Expression::Value(ValueNode::Float(-42.0)), (0..0).into())
); );
let min_float = f64::MIN.to_string() + ".0"; let min_float = f64::MIN.to_string() + ".0";
assert_eq!( assert_eq!(
parse(&lex(&min_float).unwrap()).unwrap()[0].0, parse(&lex(&min_float).unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(f64::MIN))) Statement::expression(Expression::Value(ValueNode::Float(f64::MIN)), (0..0).into())
); );
let max_negative_float = format!("-{}", f64::MIN_POSITIVE); let max_negative_float = format!("-{}", f64::MIN_POSITIVE);
assert_eq!( assert_eq!(
parse(&lex(&max_negative_float).unwrap()).unwrap()[0].0, parse(&lex(&max_negative_float).unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(-f64::MIN_POSITIVE))) Statement::expression(
Expression::Value(ValueNode::Float(-f64::MIN_POSITIVE)),
(0..0).into()
)
); );
} }
#[test] #[test]
fn other_float() { fn other_float() {
assert_eq!( assert_eq!(
parse(&lex("Infinity").unwrap()).unwrap()[0].0, parse(&lex("Infinity").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(f64::INFINITY))) Statement::expression(
Expression::Value(ValueNode::Float(f64::INFINITY)),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("-Infinity").unwrap()).unwrap()[0].0, parse(&lex("-Infinity").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Float(f64::NEG_INFINITY))) Statement::expression(
Expression::Value(ValueNode::Float(f64::NEG_INFINITY)),
(0..0).into()
)
); );
if let Statement::Expression(Expression::Value(ValueNode::Float(float))) = if let StatementInner::Expression(Expression::Value(ValueNode::Float(float))) =
&parse(&lex("NaN").unwrap()).unwrap()[0].0 &parse(&lex("NaN").unwrap()).unwrap()[0].inner
{ {
assert!(float.is_nan()); assert!(float.is_nan());
} else { } else {
@ -853,21 +1005,24 @@ mod tests {
let statements = parse(&tokens).unwrap(); let statements = parse(&tokens).unwrap();
assert_eq!( assert_eq!(
statements[0].0, statements[0],
Statement::Expression(Expression::Value(ValueNode::Integer(i))) Statement::expression(Expression::Value(ValueNode::Integer(i)), (0..0).into())
) )
} }
assert_eq!( assert_eq!(
parse(&lex("42").unwrap()).unwrap()[0].0, parse(&lex("42").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Integer(42))) Statement::expression(Expression::Value(ValueNode::Integer(42)), (0..0).into())
); );
let maximum_integer = i64::MAX.to_string(); let maximum_integer = i64::MAX.to_string();
assert_eq!( assert_eq!(
parse(&lex(&maximum_integer).unwrap()).unwrap()[0].0, parse(&lex(&maximum_integer).unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Integer(i64::MAX))) Statement::expression(
Expression::Value(ValueNode::Integer(i64::MAX)),
(0..0).into()
)
); );
} }
@ -879,69 +1034,99 @@ mod tests {
let statements = parse(&tokens).unwrap(); let statements = parse(&tokens).unwrap();
assert_eq!( assert_eq!(
statements[0].0, statements[0],
Statement::Expression(Expression::Value(ValueNode::Integer(i))) Statement::expression(Expression::Value(ValueNode::Integer(i)), (0..0).into())
) )
} }
assert_eq!( assert_eq!(
parse(&lex("-42").unwrap()).unwrap()[0].0, parse(&lex("-42").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Integer(-42))) Statement::expression(Expression::Value(ValueNode::Integer(-42)), (0..0).into())
); );
let minimum_integer = i64::MIN.to_string(); let minimum_integer = i64::MIN.to_string();
assert_eq!( assert_eq!(
parse(&lex(&minimum_integer).unwrap()).unwrap()[0].0, parse(&lex(&minimum_integer).unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::Integer(i64::MIN))) Statement::expression(
Expression::Value(ValueNode::Integer(i64::MIN)),
(0..0).into()
)
); );
} }
#[test] #[test]
fn double_quoted_string() { fn double_quoted_string() {
assert_eq!( assert_eq!(
parse(&lex("\"\"").unwrap()).unwrap()[0].0, parse(&lex("\"\"").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("".to_string())),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("\"42\"").unwrap()).unwrap()[0].0, parse(&lex("\"42\"").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("42".to_string())),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("\"foobar\"").unwrap()).unwrap()[0].0, parse(&lex("\"foobar\"").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("foobar".to_string())),
(0..0).into()
)
); );
} }
#[test] #[test]
fn single_quoted_string() { fn single_quoted_string() {
assert_eq!( assert_eq!(
parse(&lex("''").unwrap()).unwrap()[0].0, parse(&lex("''").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("".to_string())),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("'42'").unwrap()).unwrap()[0].0, parse(&lex("'42'").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("42".to_string())),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("'foobar'").unwrap()).unwrap()[0].0, parse(&lex("'foobar'").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("foobar".to_string())),
(0..0).into()
)
); );
} }
#[test] #[test]
fn grave_quoted_string() { fn grave_quoted_string() {
assert_eq!( assert_eq!(
parse(&lex("``").unwrap()).unwrap()[0].0, parse(&lex("``").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("".to_string())),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("`42`").unwrap()).unwrap()[0].0, parse(&lex("`42`").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("42".to_string())),
(0..0).into()
)
); );
assert_eq!( assert_eq!(
parse(&lex("`foobar`").unwrap()).unwrap()[0].0, parse(&lex("`foobar`").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(ValueNode::String("foobar".to_string()))) Statement::expression(
Expression::Value(ValueNode::String("foobar".to_string())),
(0..0).into()
)
); );
} }
} }

View File

@ -62,7 +62,7 @@ fn function_context_does_not_capture_values() {
), ),
Err(vec![Error::Validation { Err(vec![Error::Validation {
error: ValidationError::VariableNotFound(Identifier::new("x")), error: ValidationError::VariableNotFound(Identifier::new("x")),
span: (32..66).into() span: (32, 66)
}]) }])
); );

View File

@ -140,7 +140,7 @@ fn map_type_errors() {
actual: Type::String, actual: Type::String,
expected: Type::Boolean expected: Type::Boolean
}), }),
span: (0..22).into() span: (0, 22)
}]) }])
); );
} }

View File

@ -29,7 +29,7 @@ fn set_variable_with_type_error() {
actual: Type::Boolean, actual: Type::Boolean,
expected: Type::String expected: Type::String
}), }),
span: (0..18).into() span: (0, 18)
}]) }])
); );
} }
@ -41,9 +41,10 @@ fn function_variable() {
Ok(Some(Value::function( Ok(Some(Value::function(
vec![(Identifier::new("x"), Type::Integer)], vec![(Identifier::new("x"), Type::Integer)],
Type::Integer, Type::Integer,
Block::new(vec![Statement::Expression(Expression::Identifier( Block::new(vec![Statement::expression(
Identifier::new("x") Expression::Identifier(Identifier::new("x")),
))]) (0..0).into()
)])
))) )))
); );
} }