Skip to content

Commit e4217f2

Browse files
authored
allow_any_combination_of_operators (#57)
* allow_any_combination_of_operators * restore formatting
1 parent f72f2ee commit e4217f2

File tree

2 files changed

+118
-27
lines changed

2 files changed

+118
-27
lines changed

src/lib.rs

+81
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,87 @@ mod tests {
17591759
and colb = 3"
17601760
);
17611761

1762+
assert_eq!(format(input, &QueryParams::None, &options), expected);
1763+
}
1764+
#[test]
1765+
fn it_correctly_parses_all_operators() {
1766+
let operators = [
1767+
"!!", "!~~*", "!~~", "!~*", "!~", "##", "#>>", "#>", "#-", "&<|", "&<", "&>", "&&",
1768+
"*<>", "*<=", "*>=", "*>", "*=", "*<", "<<|", "<<=", "<<", "<->", "<@", "<^", "<=",
1769+
"<>", "<", ">=", ">>=", ">>", ">^", "->>", "->", "-|-", "-", "+", "/", "=", "%", "?||",
1770+
"?|", "?-|", "?-", "?#", "?&", "?", "@@@", "@@", "@>", "@?", "@-@", "@", "^@", "^",
1771+
"|&>", "|>>", "|/", "|", "||/", "||", "~>=~", "~>~", "~<=~", "~<~", "~=", "~*", "~~*",
1772+
"~~", "~",
1773+
];
1774+
1775+
// Test each operator individually
1776+
for &operator in &operators {
1777+
let input = format!("left {} right", operator);
1778+
let expected = format!("left {} right", operator);
1779+
let options = FormatOptions {
1780+
uppercase: None,
1781+
..FormatOptions::default()
1782+
};
1783+
1784+
assert_eq!(
1785+
format(&input, &QueryParams::None, &options),
1786+
expected,
1787+
"Failed to parse operator: {}",
1788+
operator
1789+
);
1790+
}
1791+
}
1792+
#[test]
1793+
fn it_correctly_splits_operators() {
1794+
let input = "
1795+
SELECT
1796+
left <@ right,
1797+
left << right,
1798+
left >> right,
1799+
left &< right,
1800+
left &> right,
1801+
left -|- right,
1802+
@@ left,
1803+
@-@ left,
1804+
left <-> right,
1805+
left <<| right,
1806+
left |>> right,
1807+
left &<| right,
1808+
left |>& right,
1809+
left <^ right,
1810+
left >^ right,
1811+
?- left,
1812+
left ?-| right,
1813+
left ?|| right,
1814+
left ~= right";
1815+
let options = FormatOptions {
1816+
uppercase: None,
1817+
..FormatOptions::default()
1818+
};
1819+
let expected = indoc!(
1820+
"
1821+
SELECT
1822+
left <@ right,
1823+
left << right,
1824+
left >> right,
1825+
left &< right,
1826+
left &> right,
1827+
left -|- right,
1828+
@@ left,
1829+
@-@ left,
1830+
left <-> right,
1831+
left <<| right,
1832+
left |>> right,
1833+
left &<| right,
1834+
left |>& right,
1835+
left <^ right,
1836+
left >^ right,
1837+
?- left,
1838+
left ?-| right,
1839+
left ?|| right,
1840+
left ~= right"
1841+
);
1842+
17621843
assert_eq!(format(input, &QueryParams::None, &options), expected);
17631844
}
17641845
}

src/tokenizer.rs

+37-27
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
use nom::branch::alt;
22
use nom::bytes::complete::{tag, tag_no_case, take, take_until, take_while1};
33
use nom::character::complete::{anychar, char, digit0, digit1, not_line_ending};
4-
use nom::combinator::{eof, opt, peek, recognize, verify};
4+
use nom::combinator::{eof, map, opt, peek, recognize, verify};
55
use nom::error::ParseError;
66
use nom::error::{Error, ErrorKind};
7-
use nom::multi::many0;
7+
use nom::multi::{many0, many_m_n};
88
use nom::sequence::{terminated, tuple};
99
use nom::{AsChar, Err, IResult};
1010
use std::borrow::Cow;
@@ -107,9 +107,10 @@ fn get_next_token<'a>(
107107
last_reserved_top_level_token,
108108
)
109109
})
110+
.or_else(|_| get_operator_token(input))
110111
.or_else(|_| get_placeholder_token(input, named_placeholders))
111112
.or_else(|_| get_word_token(input))
112-
.or_else(|_| get_operator_token(input))
113+
.or_else(|_| get_any_other_char(input))
113114
}
114115

115116
fn get_whitespace_token(input: &str) -> IResult<&str, Token<'_>> {
@@ -998,30 +999,39 @@ fn get_word_token(input: &str) -> IResult<&str, Token<'_>> {
998999
}
9991000

10001001
fn get_operator_token(input: &str) -> IResult<&str, Token<'_>> {
1001-
alt((
1002-
tag("!="),
1003-
tag("<>"),
1004-
tag("=="),
1005-
tag("<="),
1006-
tag(">="),
1007-
tag("!<"),
1008-
tag("!>"),
1009-
tag("||"),
1010-
tag("::"),
1011-
tag("->>"),
1012-
tag("->"),
1013-
tag("~~*"),
1014-
tag("~~"),
1015-
tag("!~~*"),
1016-
tag("!~~"),
1017-
tag("~*"),
1018-
tag("!~*"),
1019-
tag("!~"),
1020-
tag(":="),
1021-
recognize(verify(take(1usize), |token: &str| {
1022-
token != "\n" && token != "\r"
1023-
})),
1024-
))(input)
1002+
// Define the allowed operator characters
1003+
let allowed_operators = alt((
1004+
tag("!"),
1005+
tag("<"),
1006+
tag(">"),
1007+
tag("="),
1008+
tag("|"),
1009+
tag(":"),
1010+
tag("-"),
1011+
tag("~"),
1012+
tag("*"),
1013+
tag("&"),
1014+
tag("@"),
1015+
tag("^"),
1016+
tag("?"),
1017+
tag("#"),
1018+
tag("/"),
1019+
));
1020+
1021+
map(
1022+
recognize(many_m_n(2, 5, allowed_operators)),
1023+
|token: &str| Token {
1024+
kind: TokenKind::Operator,
1025+
value: token,
1026+
key: None,
1027+
},
1028+
)(input)
1029+
}
1030+
fn get_any_other_char(input: &str) -> IResult<&str, Token<'_>> {
1031+
alt((recognize(verify(
1032+
nom::character::complete::anychar,
1033+
|&token: &char| token != '\n' && token != '\r',
1034+
)),))(input)
10251035
.map(|(input, token)| {
10261036
(
10271037
input,

0 commit comments

Comments
 (0)