diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 30d8e574..550eeb61 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -88,7 +88,7 @@ jobs: rust: - 1.70.0 - 1.68.2 - - 1.63.0 + - 1.65.0 steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f9a3bd4..663161ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ project adheres to This removes integration with `num-rational`, `num-bigint`, `num-integer` and `num-traits`. * Improved `@for` loop evaluation and error handling (#206). -* Msrv is now 1.63.0 for rsass (and 1.74 for rsass-cli). +* Msrv is now 1.65.0 for rsass (and 1.74 for rsass-cli). ### Other changes: @@ -36,6 +36,7 @@ project adheres to Also allow "loud" comments in more places. * Pure css `round()` may take an expression argument. * Minor changes in agrument syntax errors. +* Updated `nom` to 8.0.0 and added `nom-language` 0.1.0. * Updated sass-spec test suite to 2024-12-12. diff --git a/rsass-macros/Cargo.toml b/rsass-macros/Cargo.toml index f9c12992..0e68bbe0 100644 --- a/rsass-macros/Cargo.toml +++ b/rsass-macros/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/kaj/rsass" readme = "README.md" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.63.0" +rust-version = "1.65.0" [lib] proc-macro = true diff --git a/rsass/Cargo.toml b/rsass/Cargo.toml index 9d5931cc..2f93255d 100644 --- a/rsass/Cargo.toml +++ b/rsass/Cargo.toml @@ -10,13 +10,14 @@ repository = "https://github.com/kaj/rsass" readme = "README.md" license = "MIT OR Apache-2.0" edition = "2021" -rust-version = "1.63.0" +rust-version = "1.65.0" [dependencies] arc-swap = "1.5.0" fastrand = "2.0" lazy_static = "1.0" -nom = "7.0" +nom = "8.0" +nom-language = "0.1.0" tracing = "0.1.34" [badges] diff --git a/rsass/src/css/selectors/attribute.rs b/rsass/src/css/selectors/attribute.rs index d745c845..1d46864b 100644 --- a/rsass/src/css/selectors/attribute.rs +++ b/rsass/src/css/selectors/attribute.rs @@ -44,7 +44,8 @@ pub(super) mod parser { use nom::bytes::complete::tag; use nom::character::complete::one_of; use nom::combinator::{map, map_res, opt}; - use nom::sequence::{delimited, pair, tuple}; + use nom::sequence::{delimited, pair}; + use nom::Parser as _; pub(crate) fn attribute(input: Span) -> PResult { map( @@ -52,7 +53,7 @@ pub(super) mod parser { term_opt_space(tag("[")), pair( term_opt_space(name_opt_ns), - opt(tuple(( + opt(( term_opt_space(map_res( alt(( tag("*="), @@ -69,7 +70,7 @@ pub(super) mod parser { "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ abcdefghijklmnopqrstuvwxyz", ))), - ))), + )), ), tag("]"), ), @@ -90,6 +91,7 @@ pub(super) mod parser { } } }, - )(input) + ) + .parse(input) } } diff --git a/rsass/src/css/selectors/compound.rs b/rsass/src/css/selectors/compound.rs index 8b1459dc..709d0978 100644 --- a/rsass/src/css/selectors/compound.rs +++ b/rsass/src/css/selectors/compound.rs @@ -327,6 +327,7 @@ pub(crate) mod parser { use nom::bytes::complete::tag; use nom::combinator::{opt, value, verify}; use nom::sequence::preceded; + use nom::Parser as _; pub(crate) fn compound_selector( input: Span, @@ -336,25 +337,28 @@ pub(crate) mod parser { result.element = Some(stop); return Ok((rest, result)); } - let (rest, backref) = opt(value((), tag("&")))(input)?; + let (rest, backref) = opt(value((), tag("&"))).parse(input)?; result.backref = backref; - let (mut rest, elem) = opt(elem_name)(rest)?; + let (mut rest, elem) = opt(elem_name).parse(rest)?; result.element = elem; loop { rest = match rest.first() { Some(b'#') => { - let (r, id) = preceded(tag("#"), css_string)(rest)?; + let (r, id) = + preceded(tag("#"), css_string).parse(rest)?; result.id = Some(id); r } Some(b'%') => { - let (r, p) = preceded(tag("%"), css_string)(rest)?; + let (r, p) = + preceded(tag("%"), css_string).parse(rest)?; result.placeholders.push(p); r } Some(b'.') => { - let (r, c) = preceded(tag("."), css_string)(rest)?; + let (r, c) = + preceded(tag("."), css_string).parse(rest)?; result.classes.push(c); r } @@ -371,7 +375,7 @@ pub(crate) mod parser { _ => break, }; } - verify(tag(""), |_| !result.is_empty())(rest)?; + verify(tag(""), |_| !result.is_empty()).parse(rest)?; Ok((rest, result)) } } diff --git a/rsass/src/css/selectors/elemtype.rs b/rsass/src/css/selectors/elemtype.rs index b88f08e4..cdb1ac7f 100644 --- a/rsass/src/css/selectors/elemtype.rs +++ b/rsass/src/css/selectors/elemtype.rs @@ -78,10 +78,11 @@ pub(super) mod parser { use nom::branch::alt; use nom::bytes::complete::{is_a, tag}; use nom::combinator::{map, opt, recognize, value}; - use nom::sequence::{pair, preceded, tuple}; + use nom::sequence::{pair, preceded}; + use nom::Parser as _; pub(crate) fn elem_name(input: Span) -> PResult { - map(name_opt_ns, |s| ElemType { s })(input) + map(name_opt_ns, |s| ElemType { s }).parse(input) } /// Recognize a keyframe stop as an element selector. @@ -90,20 +91,21 @@ pub(super) mod parser { /// in the future. pub(crate) fn keyframe_stop(input: Span) -> PResult { map( - recognize(tuple(( + recognize(( is_a("0123456789."), - opt(tuple((is_a("eE"), opt(tag("-")), is_a("0123456789")))), + opt((is_a("eE"), opt(tag("-")), is_a("0123456789"))), tag("%"), - ))), + )), |stop: Span| ElemType { s: String::from_utf8_lossy(stop.fragment()).to_string(), }, - )(input) + ) + .parse(input) } pub(crate) fn name_opt_ns(input: Span) -> PResult { fn name_part(input: Span) -> PResult { - alt((value(String::from("*"), tag("*")), css_string))(input) + alt((value(String::from("*"), tag("*")), css_string)).parse(input) } alt(( map(preceded(tag("|"), name_part), |mut s| { @@ -120,6 +122,7 @@ pub(super) mod parser { } }, ), - ))(input) + )) + .parse(input) } } diff --git a/rsass/src/css/selectors/pseudo.rs b/rsass/src/css/selectors/pseudo.rs index 2ec342d4..bae46a28 100644 --- a/rsass/src/css/selectors/pseudo.rs +++ b/rsass/src/css/selectors/pseudo.rs @@ -208,11 +208,12 @@ pub(super) mod parser { use nom::branch::alt; use nom::bytes::complete::tag; use nom::combinator::{map, value}; - use nom::sequence::{delimited, tuple}; + use nom::sequence::delimited; + use nom::Parser as _; pub(crate) fn pseudo(input: Span) -> PResult { map( - tuple(( + ( alt((value(true, tag("::")), value(false, tag(":")))), css_string_nohash, // Note: The accepted type of selector should probably @@ -229,8 +230,9 @@ pub(super) mod parser { ), map(tag(""), |_| Arg::None), )), - )), + ), |(element, name, arg)| Pseudo { name, arg, element }, - )(input) + ) + .parse(input) } } diff --git a/rsass/src/css/selectors/selector.rs b/rsass/src/css/selectors/selector.rs index 4673ee44..3a0f0aa4 100644 --- a/rsass/src/css/selectors/selector.rs +++ b/rsass/src/css/selectors/selector.rs @@ -666,19 +666,20 @@ pub(crate) mod parser { use nom::combinator::{into, opt, value, verify}; use nom::multi::fold_many0; use nom::sequence::{delimited, pair, preceded, terminated}; + use nom::Parser as _; pub(crate) fn selector(input: Span) -> PResult { let (input, prerel) = - preceded(opt_spacelike, opt(explicit_rel_kind))(input)?; + preceded(opt_spacelike, opt(explicit_rel_kind)).parse(input)?; let (input, first) = if let Some(prerel) = prerel { - let (input, first) = opt(compound_selector)(input)?; + let (input, first) = opt(compound_selector).parse(input)?; let first = Selector { rel_of: Some(Box::new((prerel, Selector::default()))), compound: first.unwrap_or_default(), }; (input, first) } else { - into(compound_selector)(input)? + into(compound_selector).parse(input)? }; terminated( fold_many0( @@ -692,7 +693,8 @@ pub(crate) mod parser { }, ), opt_spacelike, - )(input) + ) + .parse(input) } fn explicit_rel_kind(input: Span) -> PResult { @@ -704,10 +706,12 @@ pub(crate) mod parser { value(RelKind::Parent, tag(">")), )), opt_spacelike, - )(input) + ) + .parse(input) } fn rel_kind(input: Span) -> PResult { - alt((explicit_rel_kind, value(RelKind::Ancestor, spacelike)))(input) + alt((explicit_rel_kind, value(RelKind::Ancestor, spacelike))) + .parse(input) } } diff --git a/rsass/src/css/selectors/selectorset.rs b/rsass/src/css/selectors/selectorset.rs index adb8357a..060040ed 100644 --- a/rsass/src/css/selectors/selectorset.rs +++ b/rsass/src/css/selectors/selectorset.rs @@ -173,6 +173,7 @@ pub(super) mod parser { use nom::combinator::map; use nom::multi::separated_list1; use nom::sequence::delimited; + use nom::Parser as _; pub(crate) fn selector_set(input: Span) -> PResult { map( @@ -181,6 +182,7 @@ pub(super) mod parser { super::super::parser::selector, ), |s| SelectorSet { s }, - )(input) + ) + .parse(input) } } diff --git a/rsass/src/input/sourcepos.rs b/rsass/src/input/sourcepos.rs index 5083c2c6..a0c57c56 100644 --- a/rsass/src/input/sourcepos.rs +++ b/rsass/src/input/sourcepos.rs @@ -207,8 +207,8 @@ impl SourcePos { /// If self is preceded (on same line) by `s`, include `s` in self. pub(crate) fn opt_back(mut self, s: &str) -> Self { - let len = s.as_bytes().len(); - if self.source.data().get(self.start - s.len()..self.start) + let len = s.len(); + if self.source.data().get(self.start - len..self.start) == Some(s.as_bytes()) { self.start -= len; @@ -276,7 +276,7 @@ impl SourcePos { ) -> Self { let line = format!("{kind} {name}{args} {{"); Self { - start: kind.as_bytes().len() + 1, + start: kind.len() + 1, end: line.len() - 2, source: SourceFile::scss_bytes(line, SourceName::root(module)), } diff --git a/rsass/src/parser/css/media.rs b/rsass/src/parser/css/media.rs index c0cb96a1..82410320 100644 --- a/rsass/src/parser/css/media.rs +++ b/rsass/src/parser/css/media.rs @@ -7,6 +7,7 @@ use nom::bytes::complete::{tag, tag_no_case}; use nom::combinator::{map, value}; use nom::multi::{fold_many0, fold_many1, separated_list1}; use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; use std::str::from_utf8; pub fn args(input: Span) -> PResult { @@ -22,7 +23,8 @@ pub fn args(input: Span) -> PResult { MediaArgs::Comma(v) } }, - )(input) + ) + .parse(input) } fn media_args_and(input: Span) -> PResult { map( @@ -37,7 +39,8 @@ fn media_args_and(input: Span) -> PResult { MediaArgs::And(v) } }, - )(input) + ) + .parse(input) } fn media_args_or(input: Span) -> PResult { @@ -53,7 +56,8 @@ fn media_args_or(input: Span) -> PResult { MediaArgs::Or(v) } }, - )(input) + ) + .parse(input) } fn media_args_one(input: Span) -> PResult { @@ -94,7 +98,8 @@ fn media_args_one(input: Span) -> PResult { map(media_args_one, |v| MediaArgs::Bracket(Box::new(v))), tag("]"), ), - ))(input) + )) + .parse(input) } fn media_relation(input: Span) -> PResult> { @@ -109,7 +114,8 @@ fn media_relation(input: Span) -> PResult> { acc.push(item); acc }, - )(rest) + ) + .parse(rest) } pub fn relational_operator(input: Span) -> PResult { @@ -121,7 +127,8 @@ pub fn relational_operator(input: Span) -> PResult { value(Operator::Greater, tag(">")), value(Operator::LesserE, tag("<=")), value(Operator::Lesser, tag("<")), - ))(input) + )) + .parse(input) } /// Any css value that is allowd in a media relation / range. @@ -133,7 +140,8 @@ fn media_value(input: Span) -> PResult { media_value, preceded(opt_spacelike, tag(")")), ), - ))(input) + )) + .parse(input) } pub fn media_slash_list_no_space(input: Span) -> PResult { let (input, first) = values::single(input)?; @@ -144,7 +152,8 @@ pub fn media_slash_list_no_space(input: Span) -> PResult { list.push(item); list }, - )(input)?; + ) + .parse(input)?; Ok(( input, if list.len() == 1 { diff --git a/rsass/src/parser/css/mod.rs b/rsass/src/parser/css/mod.rs index 0b63d09d..2fcf4ae8 100644 --- a/rsass/src/parser/css/mod.rs +++ b/rsass/src/parser/css/mod.rs @@ -11,17 +11,18 @@ use nom::character::complete::{multispace0, multispace1}; use nom::combinator::{ all_consuming, into, map, map_res, not, opt, peek, recognize, }; -use nom::error::{VerboseError, VerboseErrorKind}; use nom::multi::{fold_many0, many0, many_till}; use nom::sequence::{delimited, preceded, terminated}; +use nom::Parser as _; +use nom_language::error::{VerboseError, VerboseErrorKind}; use std::str::from_utf8; pub fn file(input: Span) -> PResult> { preceded( alt(( tag("\u{feff}".as_bytes()), - tag_no_case(b"@charset \"UTF-8\";\n"), - tag_no_case(b"@charset \"ASCII\";\n"), + tag_no_case(&b"@charset \"UTF-8\";\n"[..]), + tag_no_case(&b"@charset \"ASCII\";\n"[..]), tag(""), )), map( @@ -31,25 +32,28 @@ pub fn file(input: Span) -> PResult> { ), |(v, _eof)| v, ), - )(input) + ) + .parse(input) } fn top_level_item(input: Span) -> PResult { - let (rest, start) = alt((tag("@"), tag("/*"), tag("$"), tag("")))(input)?; + let (rest, start) = + alt((tag("@"), tag("/*"), tag("$"), tag(""))).parse(input)?; match start.fragment() { - b"/*" => into(comment)(input), + b"/*" => into(comment).parse(input), b"$" => { - let (end, _) = preceded(tag("$"), strings::css_string)(input)?; + let (end, _) = + preceded(tag("$"), strings::css_string).parse(input)?; let pos = input.up_to(&end); Err(nom_err("Sass variables aren't allowed in plain CSS.", pos)) } b"@" => { let (input, name) = strings::css_string(rest)?; match name.as_ref() { - "import" => into(import2)(input), + "import" => into(import2).parse(input), "media" => { let (input, args) = - preceded(spacelike, media::args)(input)?; + preceded(spacelike, media::args).parse(input)?; let (input, body) = preceded( opt_spacelike, delimited( @@ -60,13 +64,15 @@ fn top_level_item(input: Span) -> PResult { )), tag("}"), ), - )(input)?; + ) + .parse(input)?; Ok((input, MediaRule::new(args, body).into())) } _ => { let (input, args) = map_res(atrule_args, |s| { std::str::from_utf8(s.fragment()) - })(input)?; + }) + .parse(input)?; let (input, body) = preceded( opt_spacelike, alt(( @@ -91,7 +97,8 @@ fn top_level_item(input: Span) -> PResult { Some, ), )), - )(input)?; + ) + .parse(input)?; Ok(( input, AtRule::new(name, args.trim().into(), body).into(), @@ -99,7 +106,7 @@ fn top_level_item(input: Span) -> PResult { } } } - _ => into(rule::rule)(input), + _ => into(rule::rule).parse(input), } } @@ -112,7 +119,8 @@ fn import2(input: Span) -> PResult { opt(terminated(opt_spacelike, tag(";"))), ), |uri| Import::new(uri, Value::Null), - )(input) + ) + .parse(input) } // Arguments for unknwn at-rules. Should probably be more permitting. @@ -123,11 +131,12 @@ fn atrule_args(input: Span) -> PResult { delimited(tag("("), atrule_args, tag(")")), atrule_args, )), - )))(input) + ))) + .parse(input) } pub fn comment(input: Span) -> PResult { - into(preceded(tag("/*"), comment2))(input) + into(preceded(tag("/*"), comment2)).parse(input) } pub fn comment2(input: Span) -> PResult { @@ -150,15 +159,16 @@ pub fn comment2(input: Span) -> PResult { }, ), tag("*/"), - )(input) + ) + .parse(input) } pub fn spacelike(input: Span) -> PResult<()> { - map(multispace1, |_| ())(input) + map(multispace1, |_| ()).parse(input) } pub fn opt_spacelike(input: Span) -> PResult<()> { - map(multispace0, |_| ())(input) + map(multispace0, |_| ()).parse(input) } fn nom_err<'a>( diff --git a/rsass/src/parser/css/rule.rs b/rsass/src/parser/css/rule.rs index 59d66cdf..5c94fcc0 100644 --- a/rsass/src/parser/css/rule.rs +++ b/rsass/src/parser/css/rule.rs @@ -10,6 +10,7 @@ use nom::character::complete::one_of; use nom::combinator::{into, map, opt}; use nom::multi::many_till; use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; pub fn rule(input: Span) -> PResult { map( @@ -18,7 +19,8 @@ pub fn rule(input: Span) -> PResult { many_till(terminated(body_item, opt_spacelike), tag("}")), ), |(selectors, (body, _))| Rule { selectors, body }, - )(input) + ) + .parse(input) } fn body_item(input: Span) -> PResult { @@ -26,17 +28,20 @@ fn body_item(input: Span) -> PResult { into(comment), into(preceded(tag("@import"), import2)), property, - ))(input) + )) + .parse(input) } pub fn property(input: Span) -> PResult { - let (rest, name) = terminated(property_name, tag(":"))(input)?; + let (rest, name) = terminated(property_name, tag(":")).parse(input)?; if name.starts_with("--") { - let (rest, value) = terminated(custom_value, opt(tag(";")))(rest)?; + let (rest, value) = + terminated(custom_value, opt(tag(";"))).parse(rest)?; Ok((rest, CustomProperty::new(name, value).into())) } else { let (rest, value) = - delimited(opt_spacelike, values::any, opt(tag(";")))(rest)?; + delimited(opt_spacelike, values::any, opt(tag(";"))) + .parse(rest)?; Ok((rest, Property::new(name, value).into())) } } @@ -50,5 +55,6 @@ fn property_name(input: Span) -> PResult { } main }, - )(input) + ) + .parse(input) } diff --git a/rsass/src/parser/css/strings.rs b/rsass/src/parser/css/strings.rs index 3715ccfd..29589696 100644 --- a/rsass/src/parser/css/strings.rs +++ b/rsass/src/parser/css/strings.rs @@ -10,10 +10,11 @@ use nom::combinator::{ }; use nom::multi::{fold_many0, fold_many1, many0, many_m_n}; use nom::sequence::{delimited, preceded, terminated}; +use nom::Parser as _; use std::str::from_utf8; pub fn css_string_any(input: Span) -> PResult { - alt((css_string_dq, css_string_sq, into(css_string)))(input) + alt((css_string_dq, css_string_sq, into(css_string))).parse(input) } pub fn css_string(input: Span) -> PResult { @@ -21,7 +22,8 @@ pub fn css_string(input: Span) -> PResult { selector_plain_part, normalized_first_escaped_char, map(hash_no_interpolation, String::from), - ))(input)?; + )) + .parse(input)?; fold_many0( // Note: This could probably be a whole lot more efficient, // but try to get stuff correct before caring too much about that. @@ -35,12 +37,14 @@ pub fn css_string(input: Span) -> PResult { acc.push_str(&item); acc }, - )(input) + ) + .parse(input) } pub fn css_string_nohash(input: Span) -> PResult { let (input, first) = - alt((selector_plain_part, normalized_first_escaped_char))(input)?; + alt((selector_plain_part, normalized_first_escaped_char)) + .parse(input)?; fold_many0( // Note: This could probably be a whole lot more efficient, // but try to get stuff correct before caring too much about that. @@ -50,7 +54,8 @@ pub fn css_string_nohash(input: Span) -> PResult { acc.push_str(&item); acc }, - )(input) + ) + .parse(input) } pub fn css_string_dq(input: Span) -> PResult { @@ -62,7 +67,8 @@ pub fn css_string_dq(input: Span) -> PResult { normalized_escaped_char_q, ))), tag("\""), - )(input)?; + ) + .parse(input)?; Ok((input, CssString::new(parts.join(""), Quotes::Double))) } @@ -75,7 +81,8 @@ pub fn css_string_sq(input: Span) -> PResult { normalized_escaped_char_q, ))), tag("'"), - )(input)?; + ) + .parse(input)?; Ok((input, CssString::new(parts.join(""), Quotes::Single))) } @@ -126,7 +133,8 @@ fn selector_plain_part(input: Span) -> PResult { acc.push(chr); acc }, - )(input) + ) + .parse(input) } fn hash_no_interpolation(input: Span) -> PResult<&str> { @@ -141,14 +149,16 @@ fn hash_no_interpolation(input: Span) -> PResult<&str> { } } fn interpolation_block(input: Span) -> PResult { - terminated(char('{'), opt(terminated(is_not("{}"), char('}'))))(input) + terminated(char('{'), opt(terminated(is_not("{}"), char('}')))) + .parse(input) } fn escaped_char(input: Span) -> PResult { preceded( tag("\\"), alt((map_opt(hex_number, std::char::from_u32), take_char)), - )(input) + ) + .parse(input) } fn hex_number(input: Span) -> PResult { @@ -161,7 +171,8 @@ fn hex_number(input: Span) -> PResult { input_to_str, ), |s| u32::from_str_radix(s, 16), - )(input) + ) + .parse(input) } fn take_char(input: Span) -> PResult { @@ -171,7 +182,8 @@ fn take_char(input: Span) -> PResult { map_opt(take(3usize), single_char), map_opt(take(4usize), single_char), map_opt(take(5usize), single_char), - ))(input) + )) + .parse(input) } fn single_char(data: Span) -> Option { @@ -191,7 +203,8 @@ pub fn custom_value(input: Span) -> PResult { } CssString::new(raw, Quotes::None) }), - ))(input) + )) + .parse(input) } pub fn custom_value_inner(input: Span) -> PResult { fold_many1( @@ -212,7 +225,8 @@ pub fn custom_value_inner(input: Span) -> PResult { acc.push_str(&items); acc }, - )(input) + ) + .parse(input) } fn custom_value_paren<'a>( @@ -240,5 +254,6 @@ fn custom_value_paren<'a>( parts.push_str(end); parts }, - )(input) + ) + .parse(input) } diff --git a/rsass/src/parser/css/values.rs b/rsass/src/parser/css/values.rs index 951d1c64..faa4090c 100644 --- a/rsass/src/parser/css/values.rs +++ b/rsass/src/parser/css/values.rs @@ -12,25 +12,29 @@ use nom::combinator::{ }; use nom::error::context; use nom::multi::{fold_many0, many0, separated_list0, separated_list1}; -use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser; +use nom_language::error::VerboseError; pub fn any(input: Span) -> PResult { - let (input, list) = separated_list1(spaced(","), slash_list)(input)?; + let (input, list) = + separated_list1(spaced(","), slash_list).parse(input)?; Ok((input, list_or_single(list, ListSeparator::Comma))) } pub fn slash_list(input: Span) -> PResult { let (input, list) = - separated_list1(spaced("/"), slash_list_no_space)(input)?; + separated_list1(spaced("/"), slash_list_no_space).parse(input)?; Ok((input, list_or_single(list, ListSeparator::Slash))) } pub fn slash_list_no_space(input: Span) -> PResult { let (mut input, first) = space_list(input)?; let mut list = vec![first]; while let PResult::Ok((rest, _)) = - terminated(tag("/"), peek(not(tag("*"))))(input) + terminated(tag("/"), peek(not(tag("*")))).parse(input) { let (rest, value) = - alt((map(space_list, Some), value(None, opt_spacelike)))(rest)?; + alt((map(space_list, Some), value(None, opt_spacelike))) + .parse(rest)?; list.push(value.unwrap_or(Value::Literal("".into()))); input = rest; } @@ -45,7 +49,8 @@ pub fn space_list(input: Span) -> PResult { list.push(item); list }, - )(input)?; + ) + .parse(input)?; Ok((input, list_or_single(list, ListSeparator::Space))) } @@ -69,35 +74,39 @@ pub fn single(input: Span) -> PResult { Value::List(v, sep, false) => Value::List(v, sep, true), v => Value::List(vec![v], None, true), }, - )(input), - Some(c) if c.is_ascii_digit() => into(numeric)(input), + ) + .parse(input), + Some(c) if c.is_ascii_digit() => into(numeric).parse(input), Some(c) if *c == b'-' || *c == b'.' => { - alt((into(numeric), string_or_call))(input) + alt((into(numeric), string_or_call)).parse(input) } Some(b'(') => { - let (end, _) = - delimited(tag("("), none_of(")"), opt(tag(")")))(input)?; + let (end, _) = delimited(tag("("), none_of(")"), opt(tag(")"))) + .parse(input)?; let pos = input.up_to(&end); Err(nom_err("Parentheses aren't allowed in plain CSS.", pos)) } Some(b'$') => { - let (end, _) = preceded(tag("$"), strings::css_string)(input)?; + let (end, _) = + preceded(tag("$"), strings::css_string).parse(input)?; let pos = input.up_to(&end); Err(nom_err("Sass variables aren't allowed in plain CSS.", pos)) } _ => alt(( map(unicode_range_inner, Value::UnicodeRange), string_or_call, - ))(input), + )) + .parse(input), } } pub fn string_or_call(input: Span) -> PResult { let (rest, string) = strings::css_string_any(input)?; if string.quotes().is_none() { - if let Ok((rest, _)) = terminated(tag("("), opt_spacelike)(rest) { + if let Ok((rest, _)) = terminated(tag("("), opt_spacelike).parse(rest) + { fn endp(input: Span) -> PResult<()> { - terminated(opt_spacelike, char(')'))(input) + terminated(opt_spacelike, char(')')).parse(input) } let (rest, args) = if string.value() == "calc" { if let Ok((end, _)) = endp(rest) { @@ -106,12 +115,14 @@ pub fn string_or_call(input: Span) -> PResult { input.up_to(&end), )); } - map(terminated(calc_expr, endp), CallArgs::from_single)(rest)? + map(terminated(calc_expr, endp), CallArgs::from_single) + .parse(rest)? } else { - terminated(call_args, endp)(rest)? + terminated(call_args, endp).parse(rest)? }; return Ok((rest, Value::Call(string.take_value(), args))); - } else if let Ok((end, _)) = preceded(char('.'), string_or_call)(rest) + } else if let Ok((end, _)) = + preceded(char('.'), string_or_call).parse(rest) { return Err(nom_err( "Module namespaces aren't allowed in plain CSS.", @@ -125,7 +136,7 @@ pub fn string_or_call(input: Span) -> PResult { fn calc_expr(input: Span) -> PResult { let (rest, first) = single_factor(input)?; fold_many0( - tuple(( + ( delimited( opt_spacelike, alt(( @@ -136,16 +147,17 @@ fn calc_expr(input: Span) -> PResult { opt_spacelike, ), single_factor, - )), + ), move || first.clone(), |v, (op, v2)| BinOp::new(v, true, op, true, v2).into(), - )(rest) + ) + .parse(rest) } pub fn single_factor(input: Span) -> PResult { let (rest, first) = single_term(input)?; fold_many0( - tuple(( + ( delimited( opt_spacelike, alt(( @@ -155,10 +167,11 @@ pub fn single_factor(input: Span) -> PResult { opt_spacelike, ), single_term, - )), + ), move || first.clone(), |v, (op, v2)| BinOp::new(v, true, op, true, v2).into(), - )(rest) + ) + .parse(rest) } fn single_term(input: Span) -> PResult { @@ -167,13 +180,15 @@ fn single_term(input: Span) -> PResult { terminated(tag("("), opt_spacelike), calc_expr, preceded(opt_spacelike, tag(")")), - )(input), + ) + .parse(input), Some(b'$') => { - let (end, _) = preceded(tag("$"), strings::css_string)(input)?; + let (end, _) = + preceded(tag("$"), strings::css_string).parse(input)?; let pos = input.up_to(&end); Err(nom_err("Sass variables aren't allowed in plain CSS.", pos)) } - Some(c) if b'0' <= *c && *c <= b'9' => into(numeric)(input), + Some(c) if b'0' <= *c && *c <= b'9' => into(numeric).parse(input), _ => string_or_call(input), } } @@ -182,14 +197,16 @@ fn call_args(input: Span) -> PResult { let (rest, named) = many0(pair( terminated(strings::css_string, spaced("=")), terminated(single, alt((spaced(","), peek(tag(")"))))), - ))(input)?; + )) + .parse(input)?; let named = named .into_iter() .map(|(name, val)| (name.into(), val)) .collect(); - let (rest, positional) = separated_list0(spaced(","), single_arg)(rest)?; + let (rest, positional) = + separated_list0(spaced(","), single_arg).parse(rest)?; let (rest, trailing_comma) = - map(opt(spaced(",")), |c| c.is_some())(rest)?; + map(opt(spaced(",")), |c| c.is_some()).parse(rest)?; let (rest, _) = cond( trailing_comma, @@ -197,7 +214,8 @@ fn call_args(input: Span) -> PResult { peek(tag(")")), context("Expected expression.", recognize(single_arg)), )), - )(rest)?; + ) + .parse(rest)?; Ok(( rest, CallArgs { @@ -210,15 +228,13 @@ fn call_args(input: Span) -> PResult { fn single_arg(input: Span) -> PResult { fn end(input: Span) -> PResult<()> { - peek(preceded(opt_spacelike, map(one_of(",)."), |_| ())))(input) - } - match terminated(space_list, end)(input) { - Ok(ok) => Ok(ok), - Err(err) => match terminated(into(ext_arg_as_string), end)(input) { - Ok(ok) => Ok(ok), - Err(_) => Err(err), - }, + peek(preceded(opt_spacelike, map(one_of(",)."), |_| ()))).parse(input) } + terminated(space_list, end).parse(input).or_else(|err| { + terminated(into(ext_arg_as_string), end) + .parse(input) + .map_err(|_| err) + }) } fn ext_arg_as_string(input: Span) -> PResult { @@ -228,11 +244,13 @@ fn ext_arg_as_string(input: Span) -> PResult { } else { Some(input_to_str(s).ok()?.to_owned()) } - })(input) + }) + .parse(input) } fn spaced<'a>( the_tag: &'static str, -) -> impl FnMut(Span<'a>) -> PResult<'a, Span<'a>> { +) -> impl Parser, Output = Span<'a>, Error = VerboseError>> +{ delimited(opt_spacelike, tag(the_tag), opt_spacelike) } diff --git a/rsass/src/parser/css_function.rs b/rsass/src/parser/css_function.rs index d5c63f13..9da65ec2 100644 --- a/rsass/src/parser/css_function.rs +++ b/rsass/src/parser/css_function.rs @@ -14,14 +14,16 @@ use nom::branch::alt; use nom::bytes::complete::{tag, tag_no_case}; use nom::character::complete::multispace0; use nom::combinator::{into, map, not, peek, value}; -use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; pub fn css_function(input: Span) -> PResult { let (rest, arg) = delimited( terminated(tag_no_case("calc("), ignore_comments), one_arg, preceded(ignore_comments, tag(")")), - )(input)?; + ) + .parse(input)?; let pos = input.up_to(&rest).to_owned(); Ok(( rest, @@ -36,13 +38,14 @@ fn one_arg(input: Span) -> PResult { }), sum_expression, map(sass_string, Value::Literal), - ))(input) + )) + .parse(input) } fn sum_expression(input: Span) -> PResult { let (mut rest, mut v) = term(input)?; while let Ok((nrest, (s1, op, s2, v2, end))) = alt(( - tuple(( + ( value(false, tag("")), alt(( value(Operator::Plus, tag("+")), @@ -51,8 +54,8 @@ fn sum_expression(input: Span) -> PResult { ignore_comments, term, position, - )), - tuple(( + ), + ( value(true, spacelike2), alt(( value(Operator::Plus, tag("+")), @@ -61,8 +64,9 @@ fn sum_expression(input: Span) -> PResult { ignore_comments, term, position, - )), - ))(rest) + ), + )) + .parse(rest) { let pos = input.up_to(&end).to_owned(); v = BinOp::new(v, s1, op, s2, v2, pos).into(); @@ -73,7 +77,7 @@ fn sum_expression(input: Span) -> PResult { fn term(input: Span) -> PResult { let (mut rest, mut v) = single_value(input)?; - while let Ok((nrest, (s1, op, s2, v2, end))) = tuple(( + while let Ok((nrest, (s1, op, s2, v2, end))) = ( map(multispace0, |s: Span| !s.fragment().is_empty()), alt(( value(Operator::Multiply, tag("*")), @@ -83,7 +87,8 @@ fn term(input: Span) -> PResult { map(multispace0, |s: Span| !s.fragment().is_empty()), single_value, position, - ))(rest) + ) + .parse(rest) { let pos = input.up_to(&end).to_owned(); rest = nrest; @@ -103,7 +108,8 @@ fn single_value(input: Span) -> PResult { value(Value::Null, tag("null")), special_function, function_call, - ))(input) + )) + .parse(input) } fn paren(input: Span) -> PResult { @@ -114,11 +120,12 @@ fn paren(input: Span) -> PResult { preceded(opt_spacelike, tag(")")), ), |inner| Value::Paren(Box::new(inner), false), - )(input) + ) + .parse(input) } fn function_call(input: Span) -> PResult { - let (rest, (name, args)) = pair(sass_string, call_args)(input)?; + let (rest, (name, args)) = pair(sass_string, call_args).parse(input)?; let pos = input.up_to(&rest).to_owned(); Ok((rest, Value::Call(name, args, pos))) } diff --git a/rsass/src/parser/error.rs b/rsass/src/parser/error.rs index f0556ab7..7f2e0650 100644 --- a/rsass/src/parser/error.rs +++ b/rsass/src/parser/error.rs @@ -1,6 +1,7 @@ use super::{PResult, Span}; use crate::input::SourcePos; -use nom::{character::complete::one_of, error::VerboseErrorKind, Finish}; +use nom::{character::complete::one_of, Finish}; +use nom_language::error::{VerboseError, VerboseErrorKind}; use std::fmt; /// An error encountered when parsing sass. @@ -42,8 +43,8 @@ impl ParseError { } } -impl From>> for ParseError { - fn from(value: nom::error::VerboseError>) -> Self { +impl From>> for ParseError { + fn from(value: VerboseError>) -> Self { let (msg, pos) = value .errors .iter() diff --git a/rsass/src/parser/formalargs.rs b/rsass/src/parser/formalargs.rs index e17dbdf3..df4ee9bb 100644 --- a/rsass/src/parser/formalargs.rs +++ b/rsass/src/parser/formalargs.rs @@ -9,9 +9,10 @@ use nom::combinator::{cut, map, map_res, opt}; use nom::error::context; use nom::multi::separated_list0; use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; pub fn formal_args(input: Span) -> PResult { - let (input, _) = terminated(char('('), opt_spacelike)(input)?; + let (input, _) = terminated(char('('), opt_spacelike).parse(input)?; let (input, v) = separated_list0( preceded(tag(","), opt_spacelike), map( @@ -25,12 +26,14 @@ pub fn formal_args(input: Span) -> PResult { ), |(name, d)| (name.into(), d), ), - )(input)?; + ) + .parse(input)?; let (input, va) = if !v.is_empty() { terminated( opt(tag("...")), preceded(opt_spacelike, terminated(opt(tag(",")), opt_spacelike)), - )(input)? + ) + .parse(input)? } else { (input, None) }; @@ -67,9 +70,10 @@ pub fn call_args(input: Span) -> PResult { )), terminated(space_list, opt_spacelike), ), - )(input)?; + ) + .parse(input)?; let (input, trail) = if !args.is_empty() { - opt(terminated(char(','), opt_spacelike))(input)? + opt(terminated(char(','), opt_spacelike)).parse(input)? } else { (input, None) }; @@ -78,5 +82,6 @@ pub fn call_args(input: Span) -> PResult { |(args, trail)| CallArgs::new(args, trail.is_some()), ), cut(char(')')), - )(input) + ) + .parse(input) } diff --git a/rsass/src/parser/imports.rs b/rsass/src/parser/imports.rs index 70a3a35b..6f71fa4c 100644 --- a/rsass/src/parser/imports.rs +++ b/rsass/src/parser/imports.rs @@ -12,14 +12,15 @@ use nom::character::complete::char; use nom::combinator::{cut, map, opt, value}; use nom::error::context; use nom::multi::{separated_list0, separated_list1}; -use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; use std::collections::BTreeSet; /// What follows the `@import` tag. pub fn import2(input: Span) -> PResult { map( terminated( - tuple(( + ( separated_list0( comma, alt(( @@ -31,20 +32,21 @@ pub fn import2(input: Span) -> PResult { ), opt(media::args), position, - )), + ), semi_or_end, ), |(import, args, end)| { let pos = input.up_to(&end).to_owned(); Item::Import(import, args.unwrap_or(Value::Null), pos) }, - )(input) + ) + .parse(input) } pub fn use2<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { map( terminated( - tuple(( + ( context( "Expected string.", terminated(quoted_sass_string, ignore_comments), @@ -55,7 +57,7 @@ pub fn use2<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { )), opt(preceded(terminated(tag("as"), ignore_comments), as_arg)), position, - )), + ), semi_or_end, ), |(s, w, n, end)| { @@ -66,19 +68,21 @@ pub fn use2<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { start.up_to(&end).to_owned(), ) }, - )(input) + ) + .parse(input) } pub fn forward2<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { let (mut end, path) = context( "Expected string.", terminated(quoted_sass_string, opt_spacelike), - )(input)?; + ) + .parse(input)?; let mut found_as = None; let mut expose = Expose::All; let mut found_with = None; while let Ok((rest, arg)) = - delimited(ignore_comments, name, ignore_comments)(end) + delimited(ignore_comments, name, ignore_comments).parse(end) { end = match arg.as_ref() { "as" if found_as.is_none() && found_with.is_none() => { @@ -137,7 +141,8 @@ fn exposed_names(input: Span) -> PResult<(BTreeSet, BTreeSet)> { } (funs, vars) }, - )(input) + ) + .parse(input) } fn as_arg(input: Span) -> PResult { @@ -150,11 +155,12 @@ fn as_arg(input: Span) -> PResult { value(UseAs::Star, tag("*")), )), opt_spacelike, - )(input) + ) + .parse(input) } fn fwd_as_arg(input: Span) -> PResult { - map(terminated(identifier, char('*')), UseAs::Prefix)(input) + map(terminated(identifier, char('*')), UseAs::Prefix).parse(input) } fn with_arg(input: Span) -> PResult> { @@ -162,7 +168,7 @@ fn with_arg(input: Span) -> PResult> { terminated(char('('), ignore_comments), separated_list1( comma, - tuple(( + ( delimited( char('$'), map(identifier, Name::from), @@ -172,16 +178,18 @@ fn with_arg(input: Span) -> PResult> { map(opt(terminated(tag("!default"), opt_spacelike)), |o| { o.is_some() }), - )), + ), ), delimited(opt(comma), char(')'), opt_spacelike), - )(input) + ) + .parse(input) } fn quoted_sass_string(input: Span) -> PResult { - alt((sass_string_dq, sass_string_sq))(input) + alt((sass_string_dq, sass_string_sq)).parse(input) } fn comma(input: Span) -> PResult<()> { - delimited(ignore_comments, map(tag(","), |_| ()), ignore_comments)(input) + delimited(ignore_comments, map(tag(","), |_| ()), ignore_comments) + .parse(input) } diff --git a/rsass/src/parser/media.rs b/rsass/src/parser/media.rs index 46b9672b..c50d1a1f 100644 --- a/rsass/src/parser/media.rs +++ b/rsass/src/parser/media.rs @@ -13,18 +13,20 @@ use nom::branch::alt; use nom::bytes::complete::tag; use nom::combinator::{into, map, opt, value}; use nom::multi::{many0, separated_list0}; -use nom::sequence::{delimited, preceded, terminated, tuple}; +use nom::sequence::{delimited, preceded, terminated}; +use nom::Parser as _; #[cfg(test)] use super::check_parse; pub fn rule<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { let pos = start.up_to(&input).to_owned(); - let (input, args) = opt(terminated(args, opt_spacelike))(input)?; + let (input, args) = opt(terminated(args, opt_spacelike)).parse(input)?; let (input, body) = preceded( opt_spacelike, alt((map(body_block, Some), value(None, semi_or_end))), - )(input)?; + ) + .parse(input)?; Ok(( input, Item::AtMedia { @@ -73,16 +75,18 @@ pub fn args(input: Span) -> PResult { )), |args| list_or_single(args, ListSeparator::Space), ), - )(input)?; + ) + .parse(input)?; Ok((input, list_or_single(args, ListSeparator::Comma))) } fn media_relation(input: Span) -> PResult { let (rest, first) = media_additive_expr(input)?; - if let Ok((rest, (op, b))) = tuple(( + if let Ok((rest, (op, b))) = ( delimited(opt_spacelike, relational_operator, opt_spacelike), media_relation, - ))(rest) + ) + .parse(rest) { let pos = input.up_to(&rest).to_owned(); Ok(( diff --git a/rsass/src/parser/mod.rs b/rsass/src/parser/mod.rs index 9adea488..1d96633a 100644 --- a/rsass/src/parser/mod.rs +++ b/rsass/src/parser/mod.rs @@ -47,10 +47,11 @@ use nom::character::complete::{char, one_of}; use nom::combinator::{ all_consuming, into, map, map_res, not, opt, peek, value, verify, }; -use nom::error::{context, VerboseError}; +use nom::error::context; use nom::multi::{many0, many_till, separated_list0, separated_list1}; use nom::sequence::{delimited, pair, preceded, terminated}; -use nom::IResult; +use nom::{IResult, Parser as _}; +use nom_language::error::VerboseError; use std::str::{from_utf8, Utf8Error}; /// A Parsing Result; ok gives a span for the rest of the data and a parsed T. @@ -69,7 +70,7 @@ pub(crate) fn input_span(value: impl Into>) -> SourcePos { /// Returns a single value (or an error). pub fn parse_value_data(data: &[u8]) -> Result { let data = code_span(data); - let value = all_consuming(value_expression)(data.borrow()); + let value = all_consuming(value_expression).parse(data.borrow()); Ok(ParseError::check(value)?) } @@ -97,41 +98,44 @@ pub(crate) fn sassfile(input: Span) -> PResult> { ), |(v, _eof)| v, ), - )(input) + ) + .parse(input) } fn top_level_item(input: Span) -> PResult { - let (rest, tag) = alt((tag("$"), tag("/*"), tag("@"), tag("")))(input)?; + let (rest, tag) = + alt((tag("$"), tag("/*"), tag("@"), tag(""))).parse(input)?; match tag.fragment() { - b"$" => into(variable_declaration2)(rest), + b"$" => into(variable_declaration2).parse(rest), b"/*" => comment_item(rest), b"@" => at_rule2(input), - b"" => alt((into(variable_declaration_mod), rule))(input), + b"" => alt((into(variable_declaration_mod), rule)).parse(input), _ => unreachable!(), } } fn comment_item(input: Span) -> PResult { - map(comment2, Item::Comment)(input) + map(comment2, Item::Comment).parse(input) } fn rule(input: Span) -> PResult { map(pair(rule_start, body_block2), |(selectors, body)| { Item::Rule(selectors, body) - })(input) + }) + .parse(input) } fn rule_start(input: Span) -> PResult { - terminated(selectors, terminated(opt(is_a(", \t\r\n")), tag("{")))(input) + terminated(selectors, terminated(opt(is_a(", \t\r\n")), tag("{"))) + .parse(input) } fn body_item(input: Span) -> PResult { let (rest, tag) = - alt((tag("$"), tag("/*"), tag(";"), tag("@"), tag("--"), tag("")))( - input, - )?; + alt((tag("$"), tag("/*"), tag(";"), tag("@"), tag("--"), tag(""))) + .parse(input)?; match tag.fragment() { - b"$" => into(variable_declaration2)(rest), + b"$" => into(variable_declaration2).parse(rest), b"/*" => comment_item(rest), b";" => Ok((rest, Item::None)), b"@" => at_rule2(input), @@ -167,21 +171,25 @@ fn at_root2(input: Span) -> PResult { ), |(selectors, body)| Item::AtRoot(selectors, body), ), - )(input) + ) + .parse(input) } /// What follows the `@include` tag. fn mixin_call<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { - let (rest, n1) = terminated(name, opt_spacelike)(input)?; - let (rest, n2) = opt(preceded(tag("."), name))(rest)?; + let (rest, n1) = terminated(name, opt_spacelike).parse(input)?; + let (rest, n2) = opt(preceded(tag("."), name)).parse(rest)?; let name = n2.map(|n2| format!("{n1}.{n2}")).unwrap_or(n1); let (rest, _) = opt_spacelike(rest)?; - let (rest0, args) = terminated(opt(call_args), ignore_comments)(rest)?; - let (rest, t) = alt((tag("using"), tag("{"), tag("")))(rest0)?; + let (rest0, args) = + terminated(opt(call_args), ignore_comments).parse(rest)?; + let (rest, t) = alt((tag("using"), tag("{"), tag(""))).parse(rest0)?; let (end, body) = match t.fragment() { b"using" => { - let (end, args) = preceded(ignore_comments, formal_args)(rest)?; - let (rest, body) = preceded(ignore_comments, body_block)(end)?; + let (end, args) = + preceded(ignore_comments, formal_args).parse(rest)?; + let (rest, body) = + preceded(ignore_comments, body_block).parse(end)?; let decl = rest0.up_to(&end).to_owned(); (rest, Some(Callable::new(args, body, decl))) } @@ -190,7 +198,7 @@ fn mixin_call<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { let decl = rest0.up_to(&rest).to_owned(); (rest, Some(Callable::no_args(body, decl))) } - _ => map(semi_or_end, |_| None)(rest)?, + _ => map(semi_or_end, |_| None).parse(rest)?, }; let pos = start.up_to(&rest).to_owned(); Ok(( @@ -205,23 +213,25 @@ fn at_rule2(input0: Span) -> PResult { tag("@"), context("Expected identifier.", sass_string), ignore_comments, - )(input0)?; + ) + .parse(input0)?; match name.single_raw().unwrap_or("") { "at-root" => at_root2(input), "charset" => charset2(input), "content" => content_stmt2(input), - "debug" => map(expression_argument, Item::Debug)(input), + "debug" => map(expression_argument, Item::Debug).parse(input), "each" => each_loop2(input), "error" => { let (end, v) = value_expression(input)?; - let (rest, _) = opt(tag(";"))(end)?; + let (rest, _) = opt(tag(";")).parse(end)?; let pos = input0.up_to(&end).to_owned(); Ok((rest, Item::Error(v, pos))) } "extend" => map( delimited(opt_spacelike, selectors, semi_or_end), Item::Extend, - )(input), + ) + .parse(input), "for" => for_loop2(input), "forward" => forward2(input0, input), "function" => function_declaration2(input), @@ -232,7 +242,7 @@ fn at_rule2(input0: Span) -> PResult { "mixin" => mixin_declaration2(input), "return" => return_stmt2(input0, input), "use" => use2(input0, input), - "warn" => map(expression_argument, Item::Warn)(input), + "warn" => map(expression_argument, Item::Warn).parse(input), "while" => while_loop2(input), _ => unknown_atrule(name, input0, input), } @@ -243,7 +253,7 @@ fn unknown_atrule<'a>( input: Span<'a>, ) -> PResult<'a, Item> { let (input, args) = - terminated(opt(unknown_rule_args), opt(ignore_space))(input)?; + terminated(opt(unknown_rule_args), opt(ignore_space)).parse(input)?; fn x_args(value: Value) -> Value { match value { Value::Variable(name, _pos) => { @@ -258,9 +268,9 @@ fn unknown_atrule<'a>( } } let (rest, body) = if input.first() == Some(&b'{') { - map(body_block, Some)(input)? + map(body_block, Some).parse(input)? } else { - value(None, semi_or_end)(input)? + value(None, semi_or_end).parse(input)? }; Ok(( rest, @@ -274,7 +284,7 @@ fn unknown_atrule<'a>( } fn expression_argument(input: Span) -> PResult { - terminated(value_expression, opt(tag(";")))(input) + terminated(value_expression, opt(tag(";"))).parse(input) } fn charset2(input: Span) -> PResult { @@ -293,7 +303,8 @@ fn charset2(input: Span) -> PResult { } }) }, - )(input) + ) + .parse(input) } /// Arguments to an unkown at rule. @@ -330,7 +341,8 @@ fn unknown_rule_args(input: Span) -> PResult { )), |args| list_or_single(args, ListSeparator::Space), ), - )(input)?; + ) + .parse(input)?; Ok((input, list_or_single(args, ListSeparator::Comma))) } @@ -346,23 +358,25 @@ fn if_statement_inner(input: Span) -> PResult { preceded( terminated(verify(name, |n: &String| n == "if"), opt_spacelike), if_statement2, - )(input) + ) + .parse(input) } fn if_statement2(input: Span) -> PResult { - let (input, cond) = terminated(value_expression, opt_spacelike)(input)?; + let (input, cond) = + terminated(value_expression, opt_spacelike).parse(input)?; let (input, body) = body_block(input)?; let (input2, word) = opt(delimited( preceded(opt_spacelike, tag("@")), name, opt_spacelike, - ))(input)?; + )) + .parse(input)?; match word.as_ref().map(AsRef::as_ref) { Some("else") => { - let (input2, else_body) = alt(( - map(if_statement_inner, |s| vec![s]), - body_block, - ))(input2)?; + let (input2, else_body) = + alt((map(if_statement_inner, |s| vec![s]), body_block)) + .parse(input2)?; Ok((input2, Item::IfStatement(cond, body, else_body))) } Some("elseif") => { @@ -378,19 +392,22 @@ fn each_loop2(input: Span) -> PResult { let (input, names) = separated_list1( delimited(opt_spacelike, tag(","), opt_spacelike), map(preceded(tag("$"), name), Name::from), - )(input)?; + ) + .parse(input)?; let (input, values) = delimited( delimited(spacelike, tag("in"), spacelike), value_expression, opt_spacelike, - )(input)?; + ) + .parse(input)?; let (input, body) = body_block(input)?; Ok((input, Item::Each(names, values, body))) } /// A for loop after the initial `@for`. fn for_loop2(input: Span) -> PResult { - let (input, name) = delimited(tag("$"), name, ignore_comments)(input)?; + let (input, name) = + delimited(tag("$"), name, ignore_comments).parse(input)?; let (input, range) = src_range(input)?; let (input, body) = body_block(input)?; Ok((input, Item::For(name.into(), range, body))) @@ -406,7 +423,8 @@ pub fn single_value_p(input: Span) -> PResult { } fn while_loop2(input: Span) -> PResult { - let (input, cond) = terminated(value_expression, opt_spacelike)(input)?; + let (input, cond) = + terminated(value_expression, opt_spacelike).parse(input)?; let (input, body) = body_block(input)?; Ok((input, Item::While(cond, body))) } @@ -415,8 +433,9 @@ fn mixin_declaration2(input: Span) -> PResult { let (rest, (name, args)) = pair( terminated(name, ignore_comments), alt((value(None, peek(not(char('(')))), map(formal_args, Some))), - )(input)?; - let (end, body) = preceded(ignore_comments, body_block)(rest)?; + ) + .parse(input)?; + let (end, body) = preceded(ignore_comments, body_block).parse(rest)?; let args = args.unwrap_or_else(FormalArgs::none); let decl = input.up_to(&rest).to_owned(); Ok(( @@ -426,9 +445,9 @@ fn mixin_declaration2(input: Span) -> PResult { } fn function_declaration2(input: Span) -> PResult { - let (end, name) = terminated(name, ignore_comments)(input)?; + let (end, name) = terminated(name, ignore_comments).parse(input)?; let (end, args) = formal_args(end)?; - let (rest, body) = preceded(ignore_comments, body_block)(end)?; + let (rest, body) = preceded(ignore_comments, body_block).parse(end)?; let decl = input.up_to(&end).to_owned(); Ok(( rest, @@ -437,21 +456,23 @@ fn function_declaration2(input: Span) -> PResult { } fn return_stmt2<'a>(start: Span, input: Span<'a>) -> PResult<'a, Item> { - let (input, v) = terminated(value_expression, ignore_comments)(input)?; + let (input, v) = + terminated(value_expression, ignore_comments).parse(input)?; let pos = start.up_to(&input).to_owned(); - let (input, _) = opt(tag(";"))(input)?; + let (input, _) = opt(tag(";")).parse(input)?; Ok((input, Item::Return(v, pos))) } fn content_stmt2(input: Span) -> PResult { - let (rest, args) = terminated(opt(call_args), opt(tag(";")))(input)?; + let (rest, args) = + terminated(opt(call_args), opt(tag(";"))).parse(input)?; let pos = input.up_to(&rest).to_owned(); Ok((rest, Item::Content(args.unwrap_or_default(), pos))) } fn custom_property(input: Span) -> PResult { - let (rest, name) = terminated(sass_string, char(':'))(input)?; - let (rest, value) = terminated(custom_value, semi_or_end)(rest)?; + let (rest, name) = terminated(sass_string, char(':')).parse(input)?; + let (rest, value) = terminated(custom_value, semi_or_end).parse(rest)?; Ok((rest, Item::CustomProperty(name, value))) } @@ -465,19 +486,22 @@ fn property_or_namespace_rule(input: Span) -> PResult { sass_string, )), delimited(ignore_comments, char(':'), ignore_comments), - )(input)?; + ) + .parse(input)?; let (input, val) = alt(( map(peek(char('{')), |_| None), map(context("Expected expression.", value_expression), Some), - ))(start_val)?; + )) + .parse(start_val)?; let pos = start_val.up_to(&input); let (input, body) = preceded( ignore_comments, alt((map(semi_or_end, |_| None), map(body_block, Some))), - )(input)?; + ) + .parse(input)?; Ok((input, ns_or_prop_item(name, val, body, pos.to_owned()))) } @@ -498,7 +522,7 @@ fn ns_or_prop_item( } fn body_block(input: Span) -> PResult> { - preceded(char('{'), body_block2)(input) + preceded(char('{'), body_block2).parse(input) } fn body_block2(input: Span) -> PResult> { @@ -508,7 +532,8 @@ fn body_block2(input: Span) -> PResult> { terminated(body_item, opt_spacelike), terminated(terminated(tag("}"), opt_spacelike), opt(tag(";"))), ), - )(input)?; + ) + .parse(input)?; Ok((input, v)) } diff --git a/rsass/src/parser/selectors.rs b/rsass/src/parser/selectors.rs index dce7bd6c..7ee37929 100644 --- a/rsass/src/parser/selectors.rs +++ b/rsass/src/parser/selectors.rs @@ -9,7 +9,8 @@ use nom::bytes::complete::tag; use nom::character::complete::one_of; use nom::combinator::{map, map_opt, map_res, opt, value}; use nom::multi::{many1, separated_list1}; -use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; pub fn selectors(input: Span) -> PResult { map_opt( @@ -22,11 +23,12 @@ pub fn selectors(input: Span) -> PResult { Some(Selectors::new(v)) } }, - )(input) + ) + .parse(input) } pub fn selector(input: Span) -> PResult { - let (input, mut s) = many1(selector_part)(input)?; + let (input, mut s) = many1(selector_part).parse(input)?; if s.last() == Some(&SelectorPart::Descendant) { s.pop(); } @@ -38,7 +40,7 @@ fn selector_part(input: Span) -> PResult { map( // A single dash is allowed as a selector, because the parsing // of psedudo-element attributes don't handle expressions yet. - tuple((opt(tag("%")), sass_string_allow_dash, opt(tag("%")))), + (opt(tag("%")), sass_string_allow_dash, opt(tag("%"))), |(pre, mut s, post)| { if pre.is_some() { s.prepend("%"); @@ -73,7 +75,7 @@ fn selector_part(input: Span) -> PResult { map( delimited( terminated(tag("["), opt_spacelike), - tuple(( + ( terminated(sass_string, opt_spacelike), terminated( map_res( @@ -100,7 +102,7 @@ fn selector_part(input: Span) -> PResult { ), opt_spacelike, )), - )), + ), tag("]"), ), |(name, op, val, modifier)| SelectorPart::Attribute { @@ -135,7 +137,8 @@ fn selector_part(input: Span) -> PResult { opt_spacelike, ), value(SelectorPart::Descendant, spacelike2), - ))(input) + )) + .parse(input) } #[cfg(test)] diff --git a/rsass/src/parser/span.rs b/rsass/src/parser/span.rs index 42e4e0c4..5231e54f 100644 --- a/rsass/src/parser/span.rs +++ b/rsass/src/parser/span.rs @@ -1,10 +1,7 @@ use crate::input::{SourceFile, SourcePos}; -use nom::{ - Compare, CompareResult, InputIter, InputLength, InputTake, - InputTakeAtPosition, Needed, Offset, Slice, -}; +use nom::{Compare, CompareResult, Input, Needed, Offset}; use std::fmt::Write; -use std::ops::{Deref, Range, RangeFrom, RangeTo}; +use std::ops::{Deref, Range}; /// A specific piece of input data. #[derive(Clone, Copy)] @@ -92,38 +89,40 @@ where } } -impl InputLength for Span<'_> { - fn input_len(&self) -> usize { - self.range().len() - } -} +impl<'a> Input for Span<'a> { + type Item = u8; -impl<'a> Deref for Span<'a> { - type Target = [u8]; - fn deref(&self) -> &'a [u8] { - self.fragment() - } -} + type Iter = <&'a [u8] as Input>::Iter; -impl AsRef<[u8]> for Span<'_> { - fn as_ref(&self) -> &[u8] { - self.fragment() + type IterIndices = <&'a [u8] as Input>::IterIndices; + + fn input_len(&self) -> usize { + self.end - self.start } -} -impl InputTake for Span<'_> { - fn take(&self, count: usize) -> Self { - let end = self.start + count; - assert!(end <= self.end, "Tried to take {count} from {self:?}"); + fn take(&self, index: usize) -> Self { + let end = self.start + index; + assert!(end <= self.end, "Tried to take {index} from {self:?}"); Span { start: self.start, end, source: self.source, } } - fn take_split(&self, count: usize) -> (Self, Self) { - let mid = self.start + count; - assert!(mid <= self.end, "Tried to take_split {count} from {self:?}"); + + fn take_from(&self, index: usize) -> Self { + let mid = self.start + index; + assert!(mid <= self.end, "Tried to take_from {index} from {self:?}"); + Span { + start: mid, + end: self.end, + source: self.source, + } + } + + fn take_split(&self, index: usize) -> (Self, Self) { + let mid = self.start + index; + assert!(mid <= self.end, "Tried to take_split {index} from {self:?}"); ( Span { start: mid, @@ -137,65 +136,34 @@ impl InputTake for Span<'_> { }, ) } -} - -impl Slice> for Span<'_> { - fn slice(&self, range: Range) -> Self { - let start = self.start + range.start; - let end = self.start + range.end; - assert!(start <= self.end); - assert!(end <= self.end); - Span { - start, - end, - source: self.source, - } - } -} -impl Slice> for Span<'_> { - fn slice(&self, range: RangeFrom) -> Self { - let start = self.start + range.start; - assert!(start <= self.end); - Span { - start, - end: self.end, - source: self.source, - } - } -} -impl Slice> for Span<'_> { - fn slice(&self, range: RangeTo) -> Self { - let end = self.start + range.end; - assert!(end <= self.end); - Span { - start: self.start, - end, - source: self.source, - } - } -} -impl<'a> InputIter for Span<'a> { - type Item = <&'a [u8] as InputIter>::Item; - type Iter = <&'a [u8] as InputIter>::Iter; - type IterElem = <&'a [u8] as InputIter>::IterElem; - fn iter_indices(&self) -> Self::Iter { - self.fragment().iter_indices() - } - fn iter_elements(&self) -> Self::IterElem { - self.fragment().iter_elements() - } fn position

(&self, predicate: P) -> Option where P: Fn(Self::Item) -> bool, { self.fragment().position(predicate) } + + fn iter_elements(&self) -> Self::Iter { + self.fragment().iter_elements() + } + + fn iter_indices(&self) -> Self::IterIndices { + self.fragment().iter_indices() + } + fn slice_index(&self, count: usize) -> Result { self.fragment().slice_index(count) } } +impl<'a> Deref for Span<'a> { + type Target = [u8]; + fn deref(&self) -> &'a [u8] { + self.fragment() + } +} + impl Offset for Span<'_> { fn offset(&self, second: &Self) -> usize { assert!(std::ptr::eq(self.source, second.source)); @@ -208,73 +176,6 @@ pub fn position(s: Span) -> super::PResult { Ok((s, s)) } -impl InputTakeAtPosition for Span<'_> { - type Item = u8; - - fn split_at_position>( - &self, - predicate: P, - ) -> nom::IResult - where - P: Fn(Self::Item) -> bool, - { - match self.position(predicate) { - Some(n) => Ok(self.take_split(n)), - None => Err(nom::Err::Incomplete(Needed::new(1))), - } - } - - fn split_at_position1>( - &self, - predicate: P, - e: nom::error::ErrorKind, - ) -> nom::IResult - where - P: Fn(Self::Item) -> bool, - { - match self.position(predicate) { - Some(0) => Err(nom::Err::Error(E::from_error_kind(*self, e))), - Some(n) => Ok(self.take_split(n)), - None => Err(nom::Err::Incomplete(Needed::new(1))), - } - } - - fn split_at_position_complete>( - &self, - predicate: P, - ) -> nom::IResult - where - P: Fn(Self::Item) -> bool, - { - match self.split_at_position(predicate) { - Err(nom::Err::Incomplete(_)) => { - Ok(self.take_split(self.input_len())) - } - res => res, - } - } - - fn split_at_position1_complete>( - &self, - predicate: P, - e: nom::error::ErrorKind, - ) -> nom::IResult - where - P: Fn(Self::Item) -> bool, - { - match self.split_at_position1(predicate, e) { - Err(nom::Err::Incomplete(_)) => { - if self.input_len() == 0 { - Err(nom::Err::Error(E::from_error_kind(*self, e))) - } else { - Ok(self.take_split(self.input_len())) - } - } - res => res, - } - } -} - impl std::fmt::Debug for Span<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Span") diff --git a/rsass/src/parser/strings.rs b/rsass/src/parser/strings.rs index fa1f360f..fb3b755e 100644 --- a/rsass/src/parser/strings.rs +++ b/rsass/src/parser/strings.rs @@ -10,20 +10,21 @@ use nom::combinator::{ }; use nom::error::context; use nom::multi::{fold_many0, fold_many1, many0, many1, many_m_n}; -use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; use std::str::from_utf8; pub fn sass_string(input: Span) -> PResult { - verify(sass_string_allow_dash, |s| { - s.single_raw().map_or(true, |s| s != "-") - })(input) + verify(sass_string_allow_dash, |s| s.single_raw() != Some("-")) + .parse(input) } pub fn sass_string_allow_dash(input: Span) -> PResult { let (input, first) = alt(( string_part_interpolation, map(unquoted_first_part, StringPart::Raw), - ))(input)?; + )) + .parse(input)?; let (input, parts) = fold_many0( alt(( string_part_interpolation, @@ -34,7 +35,8 @@ pub fn sass_string_allow_dash(input: Span) -> PResult { acc.push(item); acc }, - )(input)?; + ) + .parse(input)?; Ok((input, SassString::new(parts, Quotes::None))) } @@ -50,7 +52,8 @@ pub fn custom_value(input: Span) -> PResult { } SassString::new(parts, Quotes::None) }, - )(input) + ) + .parse(input) } pub fn custom_value_inner(input: Span) -> PResult> { fold_many1( @@ -83,7 +86,8 @@ pub fn custom_value_inner(input: Span) -> PResult> { acc.extend(items); acc }, - )(input) + ) + .parse(input) } fn custom_value_paren( @@ -111,12 +115,14 @@ fn custom_value_paren( parts.push(StringPart::Raw(end.into())); parts }, - )(input) + ) + .parse(input) } pub fn sass_string_ext(input: Span) -> PResult { let (input, parts) = - many1(alt((string_part_interpolation, extended_part)))(input)?; + many1(alt((string_part_interpolation, extended_part))) + .parse(input)?; Ok((input, SassString::new(parts, Quotes::None))) } @@ -125,7 +131,8 @@ fn unquoted_first_part(input: Span) -> PResult { map(str_plain_part, String::from), normalized_first_escaped_char, map(hash_no_interpolation, String::from), - ))(input)?; + )) + .parse(input)?; fold_many0( // Note: This could probably be a whole lot more efficient, // but try to get stuff correct before caring too much about that. @@ -139,7 +146,8 @@ fn unquoted_first_part(input: Span) -> PResult { acc.push_str(&item); acc }, - )(input) + ) + .parse(input) } fn unquoted_part(input: Span) -> PResult { fold_many1( @@ -155,7 +163,8 @@ fn unquoted_part(input: Span) -> PResult { acc.push_str(&item); acc }, - )(input) + ) + .parse(input) } fn normalized_first_escaped_char(input: Span) -> PResult { @@ -188,11 +197,11 @@ fn normalized_escaped_char(input: Span) -> PResult { /// so that it can end up beeing parsed as a normal function call. pub fn special_function_misc(input: Span) -> PResult { let (input, (start, mut args, end)) = verify( - tuple(( + ( recognize(terminated( alt(( map( - tuple(( + ( opt(delimited(tag("-"), alphanumeric1, tag("-"))), alt(( tag("calc"), @@ -200,7 +209,7 @@ pub fn special_function_misc(input: Span) -> PResult { tag("env"), tag("expression"), )), - )), + ), |_| (), ), map( @@ -218,11 +227,12 @@ pub fn special_function_misc(input: Span) -> PResult { )), special_args, alt((tag(")"), tag(""))), - )), + ), |(start, args, _end)| { start.fragment() != b"calc(" || args.is_interpolated() }, - )(input)?; + ) + .parse(input)?; args.prepend(from_utf8(start.fragment()).unwrap()); args.append_str(from_utf8(end.fragment()).unwrap()); @@ -252,13 +262,14 @@ pub fn special_arg_parts(input: Span) -> PResult> { map(map_res(is_not("#()\"\\;\n "), input_to_str), |s| { vec![StringPart::from(s)] }), - )))(input)?; + ))) + .parse(input)?; Ok((input, parts.into_iter().flatten().collect())) } pub fn special_url(input: Span) -> PResult { - let (input, _start) = tag("url(")(input)?; - let (input, _trim) = many0(is_a(" "))(input)?; + let (input, _start) = tag("url(").parse(input)?; + let (input, _trim) = many0(is_a(" ")).parse(input)?; let (input, mut parts) = many1(alt(( string_part_interpolation, map(unquoted_part, StringPart::Raw), @@ -266,9 +277,10 @@ pub fn special_url(input: Span) -> PResult { map_res(is_a("\":.;,!+/="), input_to_string), StringPart::Raw, ), - )))(input)?; - let (input, _trim) = many0(is_a(" "))(input)?; - let (input, _end) = tag(")")(input)?; + ))) + .parse(input)?; + let (input, _trim) = many0(is_a(" ")).parse(input)?; + let (input, _end) = tag(")").parse(input)?; parts.insert(0, "url(".into()); parts.push(")".into()); Ok((input, SassString::new(parts, Quotes::None))) @@ -292,7 +304,8 @@ fn dq_parts(input: Span) -> PResult> { map(normalized_escaped_char_q, StringPart::Raw), ))), char('"'), - )(input) + ) + .parse(input) } pub fn sass_string_sq(input: Span) -> PResult { @@ -308,7 +321,8 @@ pub fn sass_string_sq(input: Span) -> PResult { map(normalized_escaped_char_q, StringPart::Raw), ))), char('\''), - )(input)?; + ) + .parse(input)?; cleanup_escape_ws(&mut parts); Ok((input, SassString::new(parts, Quotes::Single))) } @@ -352,13 +366,13 @@ fn normalized_escaped_char_q(input: Span) -> PResult { pub fn string_part_interpolation(input: Span) -> PResult { let (input, expr) = - delimited(tag("#{"), value_expression, tag("}"))(input)?; + delimited(tag("#{"), value_expression, tag("}")).parse(input)?; Ok((input, StringPart::Interpolation(expr))) } fn simple_qstring_part(input: Span) -> PResult { let (input, part) = - map_res(is_not("\\#'\"\n\r\u{c}"), input_to_string)(input)?; + map_res(is_not("\\#'\"\n\r\u{c}"), input_to_string).parse(input)?; Ok((input, StringPart::Raw(part))) } @@ -380,7 +394,8 @@ fn selector_string(input: Span) -> PResult { acc.push_str(&item); acc }, - )(input) + ) + .parse(input) } fn selector_plain_part(input: Span) -> PResult { @@ -393,16 +408,19 @@ fn selector_plain_part(input: Span) -> PResult { acc.push(chr); acc }, - )(input) + ) + .parse(input) } fn str_plain_part(input: Span) -> PResult<&str> { // TODO: This should probably be based on unicode alphanumeric. - map_res(is_not("\r\n\t %<>$\"'\\#+*/()[]{}:;,=!&@~"), input_to_str)(input) + map_res(is_not("\r\n\t %<>$\"'\\#+*/()[]{}:;,=!&@~"), input_to_str) + .parse(input) } fn hash_no_interpolation(input: Span) -> PResult<&str> { - map_res(terminated(tag("#"), peek(not(tag("{")))), input_to_str)(input) + map_res(terminated(tag("#"), peek(not(tag("{")))), input_to_str) + .parse(input) } pub fn extended_part(input: Span) -> PResult { @@ -412,7 +430,8 @@ pub fn extended_part(input: Span) -> PResult { many0(verify(take_char, is_ext_str_char)), )), input_to_string, - )(input)?; + ) + .parse(input)?; Ok((input, StringPart::Raw(part))) } @@ -447,7 +466,8 @@ fn is_ext_str_char(c: &char) -> bool { pub fn name(input: Span) -> PResult { let (input, first) = - verify(alt((escaped_char, take_char)), is_name_start_char)(input)?; + verify(alt((escaped_char, take_char)), is_name_start_char) + .parse(input)?; verify( fold_many0( alt((escaped_char, name_char)), @@ -458,12 +478,14 @@ pub fn name(input: Span) -> PResult { }, ), |s: &str| !s.is_empty() && s != "-", - )(input) + ) + .parse(input) } pub fn unitname(input: Span) -> PResult { let (input, first) = - verify(alt((escaped_char, name_char)), |c| c.is_alphabetic())(input)?; + verify(alt((escaped_char, name_char)), |c| c.is_alphabetic()) + .parse(input)?; fold_many0( verify(alt((escaped_char, name_char)), |c| c.is_alphanumeric()), move || first.to_string(), @@ -471,11 +493,12 @@ pub fn unitname(input: Span) -> PResult { s.push(c); s }, - )(input) + ) + .parse(input) } pub fn name_char(input: Span) -> PResult { - verify(take_char, is_name_char)(input) + verify(take_char, is_name_char).parse(input) } fn escaped_char(input: Span) -> PResult { @@ -512,7 +535,8 @@ fn escaped_char(input: Span) -> PResult { ), take_char, )), - )(input) + ) + .parse(input) } fn take_char(input: Span) -> PResult { @@ -522,7 +546,8 @@ fn take_char(input: Span) -> PResult { map_opt(take(3usize), single_char), map_opt(take(4usize), single_char), map_opt(take(5usize), single_char), - ))(input) + )) + .parse(input) } fn single_char(data: Span) -> Option { diff --git a/rsass/src/parser/unit.rs b/rsass/src/parser/unit.rs index e768ccee..06e71db3 100644 --- a/rsass/src/parser/unit.rs +++ b/rsass/src/parser/unit.rs @@ -2,6 +2,7 @@ use super::strings::unitname; use super::{PResult, Span}; use crate::value::Unit; use nom::combinator::{map, value}; +use nom::Parser as _; use nom::{branch::alt, bytes::complete::tag}; pub fn unit(input: Span) -> PResult { @@ -50,5 +51,6 @@ pub fn unit(input: Span) -> PResult { name => Unit::Unknown(name.to_string()), }), value(Unit::None, tag("")), - ))(input) + )) + .parse(input) } diff --git a/rsass/src/parser/util.rs b/rsass/src/parser/util.rs index 7b2d7e9b..9860bc1c 100644 --- a/rsass/src/parser/util.rs +++ b/rsass/src/parser/util.rs @@ -6,13 +6,15 @@ use nom::character::complete::{char, multispace1}; use nom::combinator::{eof, map, map_res, not, opt, peek}; use nom::multi::{fold_many0, fold_many1, many0}; use nom::sequence::{preceded, terminated}; +use nom::Parser; +use nom_language::error::VerboseError; use std::str::from_utf8; pub(crate) fn term_opt_space<'a, F, T>( f: F, -) -> impl FnMut(Span<'a>) -> PResult<'a, T> +) -> impl Parser, Output = T, Error = VerboseError>> where - F: FnMut(Span<'a>) -> PResult<'a, T>, + F: Parser, Output = T, Error = VerboseError>>, { terminated(f, opt_spacelike) } @@ -25,23 +27,23 @@ pub fn semi_or_end(input: Span) -> PResult<()> { map(peek(char('}')), |_| ()), map(char(';'), |_| ()), )), - )(input) + ) + .parse(input) } pub fn spacelike(input: Span) -> PResult<()> { - fold_many1(alt((ignore_space, ignore_lcomment)), || (), |(), ()| ())( - input, - ) + fold_many1(alt((ignore_space, ignore_lcomment)), || (), |(), ()| ()) + .parse(input) } pub fn spacelike2(input: Span) -> PResult<()> { - map_res(ignore_comments, |s| if s { Ok(()) } else { Err(()) })(input) + map_res(ignore_comments, |s| if s { Ok(()) } else { Err(()) }) + .parse(input) } pub fn opt_spacelike(input: Span) -> PResult<()> { - fold_many0(alt((ignore_space, ignore_lcomment)), || (), |(), ()| ())( - input, - ) + fold_many0(alt((ignore_space, ignore_lcomment)), || (), |(), ()| ()) + .parse(input) } pub fn ignore_comments(input: Span) -> PResult { @@ -53,11 +55,12 @@ pub fn ignore_comments(input: Span) -> PResult { )), || false, |a, b| a || b, - )(input) + ) + .parse(input) } pub fn comment(input: Span) -> PResult { - preceded(tag("/*"), comment2)(input) + preceded(tag("/*"), comment2).parse(input) } pub fn comment2(input: Span) -> PResult { @@ -88,15 +91,16 @@ pub fn comment2(input: Span) -> PResult { tag("*/"), ), |p| SassString::new(p, Quotes::None), - )(input) + ) + .parse(input) } pub fn ignore_space(input: Span) -> PResult<()> { - map(multispace1, |_| ())(input) + map(multispace1, |_| ()).parse(input) } fn ignore_lcomment(input: Span) -> PResult<()> { - map(terminated(tag("//"), opt(is_not("\n"))), |_| ())(input) + map(terminated(tag("//"), opt(is_not("\n"))), |_| ()).parse(input) } #[cfg(test)] diff --git a/rsass/src/parser/value.rs b/rsass/src/parser/value.rs index cf6f786f..6e7d018c 100644 --- a/rsass/src/parser/value.rs +++ b/rsass/src/parser/value.rs @@ -22,16 +22,19 @@ use nom::combinator::{ }; use nom::error::context; use nom::multi::{fold_many0, many0, many_m_n, separated_list1}; -use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use nom::sequence::{delimited, pair, preceded, terminated}; +use nom::Parser as _; use std::str::from_utf8; pub fn value_expression(input: Span) -> PResult { let (input, result) = separated_list1( preceded(tag(","), ignore_comments), terminated(space_list, ignore_comments), - )(input)?; + ) + .parse(input)?; let (input, trail) = - many0(delimited(opt_spacelike, tag(","), opt_spacelike))(input)?; + many0(delimited(opt_spacelike, tag(","), opt_spacelike)) + .parse(input)?; Ok(( input, if result.len() == 1 && trail.is_empty() { @@ -62,7 +65,8 @@ pub fn space_list(input: Span) -> PResult { } list }, - )(input)?; + ) + .parse(input)?; Ok((input, list_or_single(list, ListSeparator::Space))) } @@ -75,7 +79,8 @@ pub fn simple_space_list(input: Span) -> PResult { list.push(item); list }, - )(input)?; + ) + .parse(input)?; Ok((input, list_or_single(list, ListSeparator::Space))) } @@ -92,7 +97,7 @@ fn se_or_ext_string(input: Span) -> PResult { fn single_expression(input: Span) -> PResult { let (input1, a) = logic_expression(input)?; fold_many0( - tuple(( + ( delimited( multispace0, alt(( @@ -103,29 +108,31 @@ fn single_expression(input: Span) -> PResult { ), single_expression, position, - )), + ), move || a.clone(), |a, (op, b, end)| { let pos = input.up_to(&end).to_owned(); BinOp::new(a, false, op, false, b, pos).into() }, - )(input1) + ) + .parse(input1) } fn logic_expression(input: Span) -> PResult { let (input1, a) = sum_expression(input)?; fold_many0( - tuple(( + ( delimited(multispace0, relational_operator, multispace0), sum_expression, position, - )), + ), move || a.clone(), |a, (op, b, end)| { let pos = input.up_to(&end).to_owned(); BinOp::new(a, true, op, true, b, pos).into() }, - )(input1) + ) + .parse(input1) } fn relational_operator(input: Span) -> PResult { @@ -136,7 +143,8 @@ fn relational_operator(input: Span) -> PResult { value(Operator::Greater, tag(">")), value(Operator::LesserE, tag("<=")), value(Operator::Lesser, tag("<")), - ))(input) + )) + .parse(input) } fn sum_expression(input: Span) -> PResult { @@ -150,18 +158,18 @@ where let (rest, v) = term(input)?; fold_many0( verify( - tuple(( - tuple(( + ( + ( ignore_comments, alt(( value(Operator::Plus, tag("+")), value(Operator::Minus, tag("-")), )), ignore_comments, - )), + ), term, position, - )), + ), |((s1, op, s2), t2, _)| { use Value::*; *s2 || !*s1 @@ -174,7 +182,8 @@ where let pos = input.up_to(&end).to_owned(); BinOp::new(v, s1, op, s2, v2, pos).into() }, - )(rest) + ) + .parse(rest) } fn term_value(input: Span) -> PResult { @@ -187,7 +196,7 @@ where { let (rest, v) = factor(input)?; fold_many0( - tuple(( + ( ignore_comments, alt(( value(Operator::Multiply, tag("*")), @@ -200,21 +209,22 @@ where ignore_comments, factor, position, - )), + ), move || v.clone(), |v1, (s1, op, s2, v2, end)| { let pos = input.up_to(&end).to_owned(); BinOp::new(v1, s1, op, s2, v2, pos).into() }, - )(rest) + ) + .parse(rest) } pub fn single_value(input: Span) -> PResult { match input.first() { Some(b'!') => bang(input), - Some(b'&') => value(Value::HereSelector, tag("&"))(input), - Some(b'"') => map(sass_string_dq, Value::Literal)(input), - Some(b'\'') => map(sass_string_sq, Value::Literal)(input), + Some(b'&') => value(Value::HereSelector, tag("&")).parse(input), + Some(b'"') => map(sass_string_dq, Value::Literal).parse(input), + Some(b'\'') => map(sass_string_sq, Value::Literal).parse(input), Some(b'[') => bracket_list(input), Some(b'(') => value_in_parens(input), Some(b'$') => variable_nomod(input), @@ -230,7 +240,8 @@ pub fn single_value(input: Span) -> PResult { special_function, function_call_or_string, unary_op, - ))(input), + )) + .parse(input), } } @@ -244,25 +255,27 @@ fn bang(input: Span) -> PResult { input_to_string, ), Value::Bang, - )(input) + ) + .parse(input) } pub fn value_in_parens(input: Span) -> PResult { - let (input0, _p) = preceded(tag("("), opt_spacelike)(input)?; + let (input0, _p) = preceded(tag("("), opt_spacelike).parse(input)?; if let Ok((input, first_key)) = simple_space_list(input0) { let (input, value) = if let Ok((mut input, first_val)) = - preceded(colon, space_list)(input) + preceded(colon, space_list).parse(input) { let mut items = vec![(first_key, first_val)]; while let Ok((rest, (key, val))) = pair( preceded(comma, simple_space_list), preceded(colon, space_list), - )(input) + ) + .parse(input) { items.push((key, val)); input = rest; } - let (input, _) = opt(comma)(input)?; + let (input, _) = opt(comma).parse(input)?; (input, Value::Map(items)) } else { (input, Value::Paren(Box::new(first_key), false)) @@ -277,31 +290,34 @@ pub fn value_in_parens(input: Span) -> PResult { map(tag(""), |_| Value::List(vec![], None, false)), )), end_paren, - )(input0) + ) + .parse(input0) } fn comma(input: Span) -> PResult { - delimited(opt_spacelike, tag(","), opt_spacelike)(input) + delimited(opt_spacelike, tag(","), opt_spacelike).parse(input) } fn colon(input: Span) -> PResult { - delimited(opt_spacelike, tag(":"), opt_spacelike)(input) + delimited(opt_spacelike, tag(":"), opt_spacelike).parse(input) } fn end_paren(input: Span) -> PResult { - preceded(opt_spacelike, tag(")"))(input) + preceded(opt_spacelike, tag(")")).parse(input) } fn unicode_range(input: Span) -> PResult { - map(unicode_range_inner, Value::UnicodeRange)(input) + map(unicode_range_inner, Value::UnicodeRange).parse(input) } pub(crate) fn unicode_range_inner(input: Span) -> PResult { - let (rest, _) = tag_no_case("U+")(input)?; - let (rest, a) = many_m_n(0, 6, one_of("0123456789ABCDEFabcdef"))(rest)?; + let (rest, _) = tag_no_case("U+").parse(input)?; + let (rest, a) = + many_m_n(0, 6, one_of("0123456789ABCDEFabcdef")).parse(rest)?; let (rest, _) = alt(( preceded(tag("-"), many_m_n(1, 6, one_of("0123456789ABCDEFabcdef"))), many_m_n(0, 6 - a.len(), one_of("?")), - ))(rest)?; + )) + .parse(rest)?; let length = rest.location_offset() - input.location_offset(); let matched = &input.fragment()[0..length]; // The unwrap should be ok, as only ascii is matched. @@ -310,7 +326,8 @@ pub(crate) fn unicode_range_inner(input: Span) -> PResult { pub fn bracket_list(input: Span) -> PResult { let (input, content) = - delimited(char('['), opt(value_expression), char(']'))(input)?; + delimited(char('['), opt(value_expression), char(']')) + .parse(input)?; Ok(( input, match content { @@ -326,7 +343,8 @@ pub fn bracket_list(input: Span) -> PResult { pub fn numeric(input: Span) -> PResult { map(pair(number, unit), |(number, unit)| { Numeric::new(number, unit) - })(input) + }) + .parse(input) } pub fn number(input: Span) -> PResult { @@ -340,11 +358,12 @@ pub fn number(input: Span) -> PResult { opt(delimited(one_of("eE"), opt(one_of("+-")), digit1)), )), |s: Span| from_utf8(s.fragment()).ok()?.parse().ok(), - )(input) + ) + .parse(input) } pub fn variable_nomod(input: Span) -> PResult { - let (rest, name) = preceded(char('$'), identifier)(input)?; + let (rest, name) = preceded(char('$'), identifier).parse(input)?; let pos = input.up_to(&rest).to_owned(); Ok((rest, Value::Variable(name.into(), pos))) } @@ -353,7 +372,8 @@ pub fn variable(input: Span) -> PResult { let (rest, (modules, name)) = pair( many0(terminated(name, tag("."))), preceded(tag("$"), cut(identifier)), - )(input)?; + ) + .parse(input)?; let name = if modules.is_empty() { name } else { @@ -364,18 +384,19 @@ pub fn variable(input: Span) -> PResult { } pub fn identifier(input: Span) -> PResult { - context("Expected identifier.", name)(input) + context("Expected identifier.", name).parse(input) } fn hex_color(input: Span) -> PResult { let (rest, (r, g, b, a)) = delimited( tag("#"), alt(( - tuple((hexchar2, hexchar2, hexchar2, opt(hexchar2))), - tuple((hexchar1, hexchar1, hexchar1, opt(hexchar1))), + (hexchar2, hexchar2, hexchar2, opt(hexchar2)), + (hexchar1, hexchar1, hexchar1, opt(hexchar1)), )), peek(map(not(alphanumeric1), |_| ())), - )(input)?; + ) + .parse(input)?; if let Some(a) = a { let rgba = Rgba::from_rgba(r, g, b, a); @@ -392,7 +413,7 @@ fn hex_color(input: Span) -> PResult { pub fn unary_op(input: Span) -> PResult { map( - tuple(( + ( alt(( value(Operator::Plus, tag("+")), value(Operator::Minus, tag("-")), @@ -401,7 +422,7 @@ pub fn unary_op(input: Span) -> PResult { )), ignore_comments, single_value, - )), + ), |(op, s, v)| match (op, s, v) { ( Operator::Minus | Operator::Plus, @@ -413,12 +434,14 @@ pub fn unary_op(input: Span) -> PResult { } (op, _, v) => Value::UnaryOp(op, Box::new(v)), }, - )(input) + ) + .parse(input) } pub fn special_function(input: Span) -> PResult { // Either a nice semantic css function or a fallback with interpolation. - alt((css_function, map(special_function_misc, Value::Literal)))(input) + alt((css_function, map(special_function_misc, Value::Literal))) + .parse(input) } pub fn function_call_or_string(input: Span) -> PResult { @@ -437,7 +460,7 @@ fn function_call_or_string_real( match val { "not" if allow_not => { if let Ok((rest, arg)) = - preceded(ignore_comments, single_value)(rest) + preceded(ignore_comments, single_value).parse(rest) { return Ok(( rest, @@ -487,15 +510,17 @@ fn literal_or_color(s: SassString) -> Value { } fn hexchar1(input: Span) -> PResult { - map(hexchar_raw, |one| one * 0x11)(input) + map(hexchar_raw, |one| one * 0x11).parse(input) } fn hexchar2(input: Span) -> PResult { - map(pair(hexchar_raw, hexchar_raw), |(hi, lo)| hi * 0x10 + lo)(input) + map(pair(hexchar_raw, hexchar_raw), |(hi, lo)| hi * 0x10 + lo) + .parse(input) } fn hexchar_raw(input: Span) -> PResult { map(one_of("0123456789ABCDEFabcdef"), |ch| { ch.to_digit(16).unwrap() as u8 - })(input) + }) + .parse(input) } pub fn dictionary(input: Span) -> PResult { @@ -503,7 +528,8 @@ pub fn dictionary(input: Span) -> PResult { preceded(tag("("), opt_spacelike), dictionary_inner, terminated(opt_spacelike, tag(")")), - )(input) + ) + .parse(input) } pub fn dictionary_inner(input: Span) -> PResult { @@ -519,7 +545,8 @@ pub fn dictionary_inner(input: Span) -> PResult { ), ), opt(delimited(opt_spacelike, tag(","), opt_spacelike)), - )(input)?; + ) + .parse(input)?; Ok((input, Value::Map(items.into_iter().collect()))) } diff --git a/rsass/src/sass/functions/color/other.rs b/rsass/src/sass/functions/color/other.rs index 3a88e460..7dbd9c7e 100644 --- a/rsass/src/sass/functions/color/other.rs +++ b/rsass/src/sass/functions/color/other.rs @@ -308,9 +308,10 @@ fn ok_as_filterarg(v: &Value) -> bool { use crate::parser::strings::unitname; use crate::parser::{code_span, util::opt_spacelike}; use nom::bytes::complete::tag; - use nom::sequence::tuple; + use nom::Parser as _; let span = code_span(s.value().as_ref()); - let b = tuple((unitname, opt_spacelike, tag("=")))(span.borrow()) + let b = (unitname, opt_spacelike, tag("=")) + .parse(span.borrow()) .is_ok(); b } diff --git a/rsass/src/sass/srcrange.rs b/rsass/src/sass/srcrange.rs index fce17ff2..d6989f6a 100644 --- a/rsass/src/sass/srcrange.rs +++ b/rsass/src/sass/srcrange.rs @@ -56,18 +56,22 @@ pub mod parser { use nom::bytes::complete::tag; use nom::combinator::value; use nom::sequence::{delimited, terminated}; + use nom::Parser as _; pub fn src_range(input: Span) -> PResult { let (input, from) = delimited( terminated(tag("from"), ignore_comments), single_value_p, ignore_comments, - )(input)?; + ) + .parse(input)?; let (input, inclusive) = terminated( alt((value(true, tag("through")), value(false, tag("to")))), ignore_comments, - )(input)?; - let (input, to) = terminated(single_value_p, ignore_comments)(input)?; + ) + .parse(input)?; + let (input, to) = + terminated(single_value_p, ignore_comments).parse(input)?; Ok(( input, SrcRange { diff --git a/rsass/src/sass/variabledeclaration.rs b/rsass/src/sass/variabledeclaration.rs index 77bb7454..1b25a36b 100644 --- a/rsass/src/sass/variabledeclaration.rs +++ b/rsass/src/sass/variabledeclaration.rs @@ -39,6 +39,7 @@ pub(crate) mod parser { #[cfg(test)] use crate::value::ListSeparator; use nom::sequence::{delimited, pair, preceded, terminated}; + use nom::Parser as _; use nom::{ branch::alt, bytes::complete::tag, combinator::map, multi::fold_many0, }; @@ -46,7 +47,7 @@ pub(crate) mod parser { pub(crate) fn variable_declaration( input: Span, ) -> PResult { - preceded(tag("$"), variable_declaration2)(input) + preceded(tag("$"), variable_declaration2).parse(input) } pub(crate) fn variable_declaration_mod( @@ -59,7 +60,8 @@ pub(crate) mod parser { pos: decl.pos.opt_back(&format!("{module}.")), ..decl }, - )(input) + ) + .parse(input) } pub(crate) fn variable_declaration2( @@ -68,9 +70,10 @@ pub(crate) mod parser { let (input, name) = terminated( map(name, Name::from), delimited(opt_spacelike, tag(":"), opt_spacelike), - )(input0)?; + ) + .parse(input0)?; let (input, val) = - terminated(value_expression, opt_spacelike)(input)?; + terminated(value_expression, opt_spacelike).parse(input)?; let (input, (default, global)) = fold_many0( terminated( alt(( @@ -81,7 +84,8 @@ pub(crate) mod parser { ), || (false, false), |(default, global), (d, g)| (default || d, global || g), - )(input)?; + ) + .parse(input)?; let (trail, _) = semi_or_end(input)?; let pos = input0.up_to(&input).to_owned().opt_back("$"); Ok(( diff --git a/rsass/src/variablescope.rs b/rsass/src/variablescope.rs index f20018ab..525b4a3a 100644 --- a/rsass/src/variablescope.rs +++ b/rsass/src/variablescope.rs @@ -612,6 +612,8 @@ impl Scope { #[cfg(test)] pub mod test { + use nom::Parser as _; + macro_rules! assert_expr { ($context:expr, $input:expr, $expected:expr) => {{ assert_eq!( @@ -864,7 +866,8 @@ pub mod test { )?; } let span = code_span(expression); - let expr = terminated(value_expression, tag(";"))(span.borrow()); + let expr = + terminated(value_expression, tag(";")).parse(span.borrow()); Ok(ParseError::check(expr)? .evaluate(scope)? .format(f)