mod ast;
mod bifs;
mod closure;
mod context;
mod expr;
macro_rules! scope {
() => {{
use crate::tests::ParsingScope;
ParsingScope::default()
}};
}
macro_rules! s {
($l:literal) => {
$l.to_string()
};
() => {
"".to_string()
};
}
macro_rules! _num {
($a:expr, $b:expr) => {
AstNode::Numeric($a.to_string(), $b.to_string(), '+', "".to_string())
};
($a:expr) => {
AstNode::Numeric($a.to_string(), "".to_string(), '+', "".to_string())
};
}
macro_rules! b_num {
($a:expr, $b:expr) => {
Box::new(AstNode::Numeric($a.to_string(), $b.to_string(), '+', "".to_string()))
};
($a:expr) => {
Box::new(AstNode::Numeric($a.to_string(), "".to_string(), '+', "".to_string()))
};
}
macro_rules! __name {
($a:tt) => {
stringify!($a).into()
};
}
macro_rules! _name {
($a:tt) => {
AstNode::Name(stringify!($a).into())
};
}
macro_rules! b_name {
($a:tt) => {
Box::new(AstNode::Name(stringify!($a).into()))
};
}
macro_rules! b_bool {
($a:literal) => {
Box::new(AstNode::Boolean($a))
};
}
use crate::lalr::TokenType;
use crate::lalr::TokenType::StartExpression;
use crate::parser::Parser;
use crate::{AstNode, ParsingScope};
use difference::Changeset;
use dsntk_feel::Name;
pub(crate) use {__name, _name, _num, b_bool, b_name, b_num, s, scope};
fn accept(scope: &ParsingScope, start_token_type: TokenType, input: &str, expected: &str, trace: bool) {
let node = Parser::new(scope, start_token_type, input, trace).parse().unwrap();
let actual = node.trace();
if actual != expected {
println!("EXPECTED:\n------------------------------------------------------------{expected}\n");
println!("ACTUAL:\n------------------------------------------------------------{actual}\n");
println!(
"DIFF:\n------------------------------------------------------------{}\n",
Changeset::new(expected, &actual, "")
);
}
assert_eq!(expected, actual);
}
fn eqd(expected: &str, node: &AstNode) {
assert_eq!(expected, format!("{node:?}"));
}
fn eqs(expected: &str, node: &AstNode) {
assert_eq!(expected, node.trace());
}
#[test]
fn test_parse_textual_expression() {
let scope = dsntk_feel::FeelScope::default();
let node = crate::parse_textual_expression(&scope, "1+2", false).unwrap();
eqs(
r#"
Add
├─ Numeric
│ └─ `1`
└─ Numeric
└─ `2`
"#,
&node,
);
}
#[test]
fn test_parse_textual_expressions() {
let scope = dsntk_feel::FeelScope::default();
let node = crate::parse_textual_expressions(&scope, "1+2,2+3,3*4", false).unwrap();
eqs(
r#"
ExpressionList
├─ Add
│ ├─ Numeric
│ │ └─ `1`
│ └─ Numeric
│ └─ `2`
├─ Add
│ ├─ Numeric
│ │ └─ `2`
│ └─ Numeric
│ └─ `3`
└─ Mul
├─ Numeric
│ └─ `3`
└─ Numeric
└─ `4`
"#,
&node,
);
}
#[test]
fn test_parse_unary_tests() {
let scope = dsntk_feel::FeelScope::default();
let node = crate::parse_unary_tests(&scope, "1,2,3,4", false).unwrap();
eqs(
r#"
ExpressionList
├─ Numeric
│ └─ `1`
├─ Numeric
│ └─ `2`
├─ Numeric
│ └─ `3`
└─ Numeric
└─ `4`
"#,
&node,
);
}
#[test]
fn test_parse_boxed_expression() {
let scope = dsntk_feel::FeelScope::default();
let node = crate::parse_boxed_expression(&scope, "[1,2,3,4]", false).unwrap();
eqs(
r#"
List
├─ Numeric
│ └─ `1`
├─ Numeric
│ └─ `2`
├─ Numeric
│ └─ `3`
└─ Numeric
└─ `4`
"#,
&node,
);
}
#[test]
fn test_parse_context() {
let scope = dsntk_feel::FeelScope::default();
let node = crate::parse_context(&scope, "{age: 50}", false).unwrap();
eqs(
r#"
Context
└─ ContextEntry
├─ ContextEntryKey
│ └─ `age`
└─ Numeric
└─ `50`
"#,
&node,
);
}
#[test]
fn test_parse_name() {
let name_a: Name = Name::new(&["Full", "House"]);
let scope = dsntk_feel::FeelScope::default();
assert_eq!(name_a, crate::parse_name(&scope, "Full House", false).unwrap());
}
#[test]
fn test_parse_longest_name() {
let name_a: Name = Name::new(&["Full", "House", "With", "A", "Cat"]);
assert_eq!(name_a, crate::parse_longest_name(" Full House With \t A \n\n Cat ").unwrap());
}
#[test]
#[should_panic]
fn test_not_accept() {
let scope = scope!();
accept(
&scope,
StartExpression,
"1+2",
r#"
Add
Numeric 1.
Numeric 3.
"#,
false,
);
}