summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-08-15 15:01:55 +0200
committerLaurenz <laurmaedje@gmail.com>2020-08-15 15:01:55 +0200
commit84f30fb73518ca23cbc728b1bf414e80b344412a (patch)
tree64e313f540f0e174522c60b8d6ba4cde34d0c60e /src/syntax
parenteb9c4b1a49c90e687d70e7bd712848d78ffbd909 (diff)
Remove SpanlessEq 🎃
The new solution is slightly hacky, but way more flexible. All types that implement PartialEq can now be compared spanlessly in tests by manipulating a thread-local boolean that is read in Span's PartialEq implementation.
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/span.rs29
-rw-r--r--src/syntax/test.rs156
2 files changed, 36 insertions, 149 deletions
diff --git a/src/syntax/span.rs b/src/syntax/span.rs
index c93f5c1e..923d13c2 100644
--- a/src/syntax/span.rs
+++ b/src/syntax/span.rs
@@ -3,9 +3,23 @@
use std::fmt::{self, Debug, Formatter};
use std::ops::{Add, Sub};
+#[cfg(test)]
+use std::cell::Cell;
+
#[cfg(feature = "serialize")]
use serde::Serialize;
+#[cfg(test)]
+thread_local! {
+ static CMP_SPANS: Cell<bool> = Cell::new(true);
+}
+
+/// When set to `false` comparisons with `PartialEq` ignore spans.
+#[cfg(test)]
+pub(crate) fn set_cmp(cmp: bool) {
+ CMP_SPANS.with(|cell| cell.set(cmp));
+}
+
/// Span offsetting.
pub trait Offset {
/// Offset all spans contained in `Self` by the given position.
@@ -85,7 +99,7 @@ impl<T: Debug> Debug for Spanned<T> {
}
/// Locates a slice of source code.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+#[derive(Copy, Clone, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize))]
pub struct Span {
/// The inclusive start position.
@@ -131,6 +145,19 @@ impl Offset for Span {
}
}
+impl Eq for Span {}
+
+impl PartialEq for Span {
+ fn eq(&self, other: &Self) -> bool {
+ #[cfg(test)]
+ if !CMP_SPANS.with(Cell::get) {
+ return true;
+ }
+
+ self.start == other.start && self.end == other.end
+ }
+}
+
impl Debug for Span {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "<{:?}-{:?}>", self.start, self.end)
diff --git a/src/syntax/test.rs b/src/syntax/test.rs
index 97fecebc..aec54ded 100644
--- a/src/syntax/test.rs
+++ b/src/syntax/test.rs
@@ -1,19 +1,18 @@
use std::fmt::Debug;
use crate::func::prelude::*;
-use super::decoration::Decoration;
-use super::expr::{Expr, Ident, NamedTuple, Object, Pair, Tuple};
-use super::parsing::{FuncArg, FuncArgs};
-use super::span::Spanned;
-use super::tokens::Token;
-use super::tree::{DynamicNode, SyntaxNode};
+use super::tree::SyntaxNode;
+use super::span;
pub fn check<T>(src: &str, exp: T, found: T, cmp_spans: bool)
where
- T: Debug + PartialEq + SpanlessEq,
+ T: Debug + PartialEq,
{
- let cmp = if cmp_spans { PartialEq::eq } else { SpanlessEq::spanless_eq };
- if !cmp(&exp, &found) {
+ span::set_cmp(cmp_spans);
+ let equal = exp == found;
+ span::set_cmp(true);
+
+ if !equal {
println!("source: {:?}", src);
println!("expected: {:#?}", exp);
println!("found: {:#?}", found);
@@ -72,142 +71,3 @@ impl Layout for DebugNode {
unimplemented!()
}
}
-
-/// Compares elements by only looking at values and ignoring spans.
-pub trait SpanlessEq<Rhs = Self> {
- fn spanless_eq(&self, other: &Rhs) -> bool;
-}
-
-impl SpanlessEq for SyntaxNode {
- fn spanless_eq(&self, other: &Self) -> bool {
- fn downcast<'a>(func: &'a (dyn DynamicNode + 'static)) -> &'a DebugNode {
- func.downcast::<DebugNode>().expect("not a debug node")
- }
-
- match (self, other) {
- (Self::Dyn(a), Self::Dyn(b)) => {
- downcast(a.as_ref()).spanless_eq(downcast(b.as_ref()))
- }
- (Self::Par(a), Self::Par(b)) => a.spanless_eq(b),
- (a, b) => a == b,
- }
- }
-}
-
-impl SpanlessEq for DebugNode {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.0.spanless_eq(&other.0)
- && self.1.spanless_eq(&other.1)
- }
-}
-
-impl SpanlessEq for FuncCall {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.name.spanless_eq(&other.name)
- && self.args.spanless_eq(&other.args)
- }
-}
-
-impl SpanlessEq for FuncArgs {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.key.spanless_eq(&other.key)
- && self.pos.spanless_eq(&other.pos)
- }
-}
-
-impl SpanlessEq for FuncArg {
- fn spanless_eq(&self, other: &Self) -> bool {
- match (self, other) {
- (FuncArg::Pos(a), FuncArg::Pos(b)) => a.spanless_eq(b),
- (FuncArg::Key(a), FuncArg::Key(b)) => a.spanless_eq(b),
- _ => false,
- }
- }
-}
-
-impl SpanlessEq for Expr {
- fn spanless_eq(&self, other: &Self) -> bool {
- match (self, other) {
- (Expr::Tuple(a), Expr::Tuple(b)) => a.spanless_eq(b),
- (Expr::NamedTuple(a), Expr::NamedTuple(b)) => a.spanless_eq(b),
- (Expr::Object(a), Expr::Object(b)) => a.spanless_eq(b),
- (Expr::Neg(a), Expr::Neg(b)) => a.spanless_eq(&b),
- (Expr::Add(a1, a2), Expr::Add(b1, b2)) => a1.spanless_eq(&b1) && a2.spanless_eq(&b2),
- (Expr::Sub(a1, a2), Expr::Sub(b1, b2)) => a1.spanless_eq(&b1) && a2.spanless_eq(&b2),
- (Expr::Mul(a1, a2), Expr::Mul(b1, b2)) => a1.spanless_eq(&b1) && a2.spanless_eq(&b2),
- (Expr::Div(a1, a2), Expr::Div(b1, b2)) => a1.spanless_eq(&b1) && a2.spanless_eq(&b2),
- (a, b) => a == b,
- }
- }
-}
-
-impl SpanlessEq for Tuple {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.0.spanless_eq(&other.0)
- }
-}
-
-impl SpanlessEq for NamedTuple {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.name.v == other.name.v
- && self.tuple.v.spanless_eq(&other.tuple.v)
- }
-}
-
-impl SpanlessEq for Object {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.0.spanless_eq(&other.0)
- }
-}
-
-impl SpanlessEq for Pair {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.key.spanless_eq(&other.key) && self.value.spanless_eq(&other.value)
- }
-}
-
-impl<T: SpanlessEq> SpanlessEq for Vec<T> {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.len() == other.len()
- && self.iter().zip(other).all(|(x, y)| x.spanless_eq(&y))
- }
-}
-
-impl<T: SpanlessEq> SpanlessEq for Spanned<T> {
- fn spanless_eq(&self, other: &Self) -> bool {
- self.v.spanless_eq(&other.v)
- }
-}
-
-impl<T: SpanlessEq> SpanlessEq for Box<T> {
- fn spanless_eq(&self, other: &Self) -> bool {
- (&**self).spanless_eq(&**other)
- }
-}
-
-impl<T: SpanlessEq> SpanlessEq for Option<T> {
- fn spanless_eq(&self, other: &Self) -> bool {
- match (self, other) {
- (Some(a), Some(b)) => a.spanless_eq(b),
- (None, None) => true,
- _ => false,
- }
- }
-}
-
-macro_rules! impl_through_partial_eq {
- ($type:ty) => {
- impl SpanlessEq for $type {
- fn spanless_eq(&self, other: &$type) -> bool {
- self == other
- }
- }
- };
-}
-
-impl_through_partial_eq!(Token<'_>);
-impl_through_partial_eq!(Ident);
-
-// Implement for string and decoration to be able to compare feedback.
-impl_through_partial_eq!(String);
-impl_through_partial_eq!(Decoration);