diff options
Diffstat (limited to 'src/syntax/test.rs')
| -rw-r--r-- | src/syntax/test.rs | 86 |
1 files changed, 80 insertions, 6 deletions
diff --git a/src/syntax/test.rs b/src/syntax/test.rs index df354768..6c89b4f5 100644 --- a/src/syntax/test.rs +++ b/src/syntax/test.rs @@ -1,8 +1,62 @@ +use std::fmt::Debug; + use super::func::FuncHeader; use super::expr::{Expr, Tuple, Object}; +use super::span::{Span, Spanned}; +use super::tokens::Token; use super::*; +/// Check whether the expected and found results for the given source code +/// match by the comparison function, and print them out otherwise. +pub fn check<T>(src: &str, exp: T, found: T, spans: bool) +where T: Debug + PartialEq + SpanlessEq { + let cmp = if spans { PartialEq::eq } else { SpanlessEq::spanless_eq }; + if !cmp(&exp, &found) { + println!("source: {:?}", src); + println!("expected: {:#?}", exp); + println!("found: {:#?}", found); + panic!("test failed"); + } +} + +/// Create a vector of optionally spanned expressions from a list description. +/// +/// # Examples +/// When you want to add span information to the items, the format is as +/// follows. +/// ``` +/// spanned![(0:0, 0:5, "hello"), (0:5, 0:3, "world")] +/// ``` +/// The span information can simply be omitted to create a vector with items +/// that are spanned with dummy zero spans. +macro_rules! spanned { + (item ($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)) => ({ + #[allow(unused_imports)] + use $crate::syntax::span::{Position, Span, Spanned}; + Spanned { + span: Span::new( + Position::new($sl, $sc), + Position::new($el, $ec) + ), + v: $v + } + }); + + (vec $(($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)),* $(,)?) => { + (vec![$(spanned![item ($sl:$sc, $el:$ec, $v)]),*], true) + }; + + (vec $($v:expr),* $(,)?) => { + (vec![$($crate::syntax::test::zspan($v)),*], false) + }; +} + +/// Span an element with a zero span. +pub fn zspan<T>(v: T) -> Spanned<T> { + Spanned { v, span: Span::ZERO } +} + function! { /// Most functions in the tests are parsed into the debug function for easy /// inspection of arguments and body. @@ -30,26 +84,31 @@ pub trait SpanlessEq<Rhs=Self> { fn spanless_eq(&self, other: &Rhs) -> bool; } -impl SpanlessEq for Vec<Spanned<Token<'_>>> { - fn spanless_eq(&self, other: &Vec<Spanned<Token>>) -> bool { +impl<T: SpanlessEq> SpanlessEq for Vec<Spanned<T>> { + fn spanless_eq(&self, other: &Vec<Spanned<T>>) -> bool { self.len() == other.len() - && self.iter().zip(other).all(|(x, y)| x.v == y.v) + && self.iter().zip(other).all(|(x, y)| x.v.spanless_eq(&y.v)) } } impl SpanlessEq for SyntaxModel { fn spanless_eq(&self, other: &SyntaxModel) -> bool { + self.nodes.spanless_eq(&other.nodes) + } +} + +impl SpanlessEq for Node { + fn spanless_eq(&self, other: &Node) -> bool { fn downcast<'a>(func: &'a (dyn Model + 'static)) -> &'a DebugFn { func.downcast::<DebugFn>().expect("not a debug fn") } - self.nodes.len() == other.nodes.len() - && self.nodes.iter().zip(&other.nodes).all(|(x, y)| match (&x.v, &y.v) { + match (self, other) { (Node::Model(a), Node::Model(b)) => { downcast(a.as_ref()).spanless_eq(downcast(b.as_ref())) } (a, b) => a == b, - }) + } } } @@ -86,3 +145,18 @@ impl SpanlessEq for Object { .all(|(x, y)| x.key.v == y.key.v && x.value.v.spanless_eq(&y.value.v)) } } + +/// Implement `SpanlessEq` by just forwarding to `PartialEq`. +macro_rules! forward { + ($type:ty) => { + impl SpanlessEq for $type { + fn spanless_eq(&self, other: &$type) -> bool { + self == other + } + } + }; +} + +forward!(String); +forward!(Token<'_>); +forward!(Decoration); |
