use super::Literal;
use crate::{
ast::{BinaryExpr, BinaryExprOp, Expr, Node, Value},
parser::{
Comment, CommentStyle, DefaultTracker, MetaTracker, Metadata, ParserInner, Result, Scanner,
},
};
fn parse_expr<'s, M: MetaTracker<'s> + Default>(
s: &'s str,
) -> Result<(Expr<'s, M::NodeId>, M::Metadata)> {
let mut p = ParserInner::new(Scanner::new(s), M::default());
p.parse_expr()
.and_then(|expr| p.finish().map(|meta| (expr, meta)))
}
#[test]
fn test_comments() {
let (expr, meta) = parse_expr::<DefaultTracker>(
r#"-- before everything else
( /* asdfqwer */ (1 -- blah blah
+ /* ej */ 2 /* hip */ /* hop */
* 3 / 4 /* almost */))"#,
)
.expect("invalid source");
assert_eq!(expr.literal().to_string(), "((1 + 2 * 3 / 4))");
let_expect!(Expr::Nested(Node(nested, id)) = expr);
assert_eq!(meta.location(id), (2, 1).into());
assert_eq!(
meta.comments(id),
(
&[Comment {
text: " before everything else",
style: CommentStyle::Line,
loc: (1, 1).into()
}][..],
&[][..]
)
);
let_expect!(Expr::Nested(Node(nested, id)) = *nested);
assert_eq!(meta.location(id), (2, 18).into());
assert_eq!(
meta.comments(id),
(
&[Comment {
text: " asdfqwer ",
style: CommentStyle::Block,
loc: (2, 3).into()
}][..],
&[][..]
)
);
let_expect!(Expr::Binary(binary_add) = *nested);
let BinaryExpr { left, op, right } = *binary_add;
assert_eq!(op.0, BinaryExprOp::Add);
assert_eq!(meta.location(op.1), (3, 1).into());
assert_eq!(
meta.comments(op.1),
(
&[Comment {
text: " blah blah",
style: CommentStyle::Line,
loc: (2, 21).into()
},][..],
&[Comment {
text: " ej ",
style: CommentStyle::Block,
loc: (3, 3).into()
}][..]
)
);
let_expect!(Expr::Value(Node(Value::Integer("1"), id)) = left);
assert_eq!(meta.location(id), (2, 19).into());
assert_eq!(
meta.comments(id),
(
&[][..],
&[Comment {
text: " blah blah",
style: CommentStyle::Line,
loc: (2, 21).into()
}][..]
)
);
let_expect!(Expr::Binary(binary_div) = right);
let BinaryExpr {
left: left_div,
op,
right: right_div,
} = *binary_div;
assert_eq!(op.0, BinaryExprOp::Div);
assert_eq!(meta.location(op.1), (4, 5).into());
assert_eq!(meta.comments(op.1), (&[][..], &[][..]));
let_expect!(Expr::Binary(binary_mul) = left_div);
let BinaryExpr {
left: left_mul,
op,
right: right_mul,
} = *binary_mul;
assert_eq!(op.0, BinaryExprOp::Mul);
assert_eq!(meta.location(op.1), (4, 1).into());
assert_eq!(
meta.comments(op.1),
(
&[
Comment {
text: " hip ",
style: CommentStyle::Block,
loc: (3, 14).into()
},
Comment {
text: " hop ",
style: CommentStyle::Block,
loc: (3, 24).into()
},
][..],
&[][..]
)
);
let_expect!(Expr::Value(Node(Value::Integer("2"), id)) = left_mul);
assert_eq!(meta.location(id), (3, 12).into());
assert_eq!(
meta.comments(id),
(
&[Comment {
text: " ej ",
style: CommentStyle::Block,
loc: (3, 3).into()
}][..],
&[
Comment {
text: " hip ",
style: CommentStyle::Block,
loc: (3, 14).into()
},
Comment {
text: " hop ",
style: CommentStyle::Block,
loc: (3, 24).into()
},
][..]
)
);
let_expect!(Expr::Value(Node(Value::Integer("3"), id)) = right_mul);
assert_eq!(meta.location(id), (4, 3).into());
assert_eq!(meta.comments(id), (&[][..], &[][..]));
let_expect!(Expr::Value(Node(Value::Integer("4"), id)) = right_div);
assert_eq!(meta.location(id), (4, 7).into());
assert_eq!(
meta.comments(id),
(
&[][..],
&[Comment {
text: " almost ",
style: CommentStyle::Block,
loc: (4, 9).into()
}][..]
)
);
}
#[test]
fn test_comments_trailing_on_nested_0() {
let (expr, meta) = parse_expr::<DefaultTracker>("/*a*/ (1) /*e*/").expect("invalid source");
assert_eq!(expr.literal().to_string(), "(1)");
let_expect!(Expr::Nested(Node(nested, id)) = &expr);
assert_eq!(
meta.comments(*id),
(
&[Comment {
text: "a",
style: CommentStyle::Block,
loc: (1, 1).into()
}][..],
&[Comment {
text: "e",
style: CommentStyle::Block,
loc: (1, 11).into()
}][..]
)
);
let_expect!(Expr::Value(Node(Value::Integer("1"), id)) = **nested);
assert_eq!(meta.comments(id), (&[][..], &[][..]));
}
#[test]
fn test_comments_trailing_on_nested_1() {
#[rustfmt::skip]
let (expr, meta) = parse_expr::<DefaultTracker>("/*a*/ (/*w*/ (/*x*/ 1 /*y*/) /*z*/) /*e*/ + 2 /*f*/")
.expect("invalid source");
assert_eq!(expr.literal().to_string(), "((1)) + 2");
assert_eq!(
expr.literal().with(&meta).to_string(),
"/*a*/ ( /*w*/ ( /*x*/ 1 /*y*/ ) /*z*/ ) /*e*/ + 2 /*f*/"
);
let_expect!(Expr::Binary(binary) = expr);
let_expect!(
BinaryExpr {
left,
op: Node(BinaryExprOp::Add, id),
right
} = *binary
);
assert_eq!(
meta.comments(id),
(
&[Comment {
text: "e",
style: CommentStyle::Block,
loc: (1, 37).into()
}][..],
&[][..]
)
);
let_expect!(Expr::Value(Node(Value::Integer("2"), id)) = right);
assert_eq!(
meta.comments(id),
(
&[][..],
&[Comment {
text: "f",
style: CommentStyle::Block,
loc: (1, 47).into()
}][..]
)
);
let_expect!(Expr::Nested(Node(nested, id)) = left);
assert_eq!(
meta.comments(id),
(
&[Comment {
text: "a",
style: CommentStyle::Block,
loc: (1, 1).into()
}][..],
&[Comment {
text: "e",
style: CommentStyle::Block,
loc: (1, 37).into()
}][..]
)
);
let_expect!(Expr::Nested(Node(nested, id)) = *nested);
assert_eq!(
meta.comments(id),
(
&[Comment {
text: "w",
style: CommentStyle::Block,
loc: (1, 8).into()
}][..],
&[Comment {
text: "z",
style: CommentStyle::Block,
loc: (1, 30).into()
}][..]
)
);
let_expect!(Expr::Value(Node(Value::Integer("1"), id)) = *nested);
assert_eq!(
meta.comments(id),
(
&[Comment {
text: "x",
style: CommentStyle::Block,
loc: (1, 15).into()
}][..],
&[Comment {
text: "y",
style: CommentStyle::Block,
loc: (1, 23).into()
}][..]
)
);
}
#[test]
#[rustfmt::skip]
fn test_comments_on_function_calls_0() {
let (expr, meta) = parse_expr::<DefaultTracker>("/*a*/ foo /*b*/ (/*c*/)/*e*/")
.expect("invalid source");
assert_eq!(expr.literal().to_string(), "foo()");
assert_eq!(expr.literal().with(&meta).to_string(), "/*a*/ foo /*b*/ ( /*c*/ ) /*e*/");
}
#[test]
#[rustfmt::skip]
fn test_comments_on_function_calls_1() {
let (expr, meta) = parse_expr::<DefaultTracker>("foo /*b*/ (1 /*c*/)/*e*/")
.expect("invalid source");
assert_eq!(expr.literal().to_string(), "foo(1)");
assert_eq!(expr.literal().with(&meta).to_string(), "foo /*b*/ (1 /*c*/ ) /*e*/");
}
#[test]
#[rustfmt::skip]
fn test_comments_on_function_calls_2() {
let (expr, meta) = parse_expr::<DefaultTracker>("foo /*b*/ (1 /*c*/, /*e*/ 2)")
.expect("invalid source");
assert_eq!(expr.literal().to_string(), "foo(1, 2)");
assert_eq!(expr.literal().with(&meta).to_string(), "foo /*b*/ (1 /*c*/ , /*e*/ 2)");
}
#[rustfmt::skip]
#[test]
fn test_comments_on_function_calls_3() {
assert_sql!(
expr("foo( /*b*/ bar /*x*/ (1 /*c*/, /*e*/ 2) /*f*/, /*g*/ /*h*/ 3 /*i*/, quux(/*j*/ /*k*/) /*l*/) /*m*/"),
"foo(bar(1, 2), 3, quux())"
);
assert_sql!(
expr("foo( /*b*/ bar /*x*/ (1 /*c*/, /*e*/ 2) /*f*/, /*g*/ /*h*/ 3 /*i*/, quux(/*j*/ /*k*/) /*l*/) /*m*/"),
with_meta("foo( /*b*/ bar /*x*/ (1 /*c*/ , /*e*/ 2) /*f*/ , /*g*/ /*h*/ 3 /*i*/ , quux( /*j*/ /*k*/ ) /*l*/ ) /*m*/")
);
}