Add spans to all statements
This commit is contained in:
parent
5b79af6e85
commit
15b1808741
@ -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());
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -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())))
|
||||||
|
@ -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::*;
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
60
src/error.rs
60
src/error.rs
@ -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()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
587
src/parser.rs
587
src/parser.rs
@ -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()
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}])
|
}])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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)
|
||||||
}])
|
}])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
)])
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user