Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to impove string parsing/escaping. #51

Merged
merged 1 commit into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/parser/formalargs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::util::{ignore_comments, name, opt_spacelike};
use super::strings::name;
use super::util::{ignore_comments, opt_spacelike};
use super::value::space_list;
use crate::sass::{CallArgs, FormalArgs, Value};
use nom::types::CompleteByteSlice as Input;
Expand Down
4 changes: 2 additions & 2 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ pub mod value;

use self::formalargs::{call_args, formal_args};
use self::selectors::selectors;
use self::strings::{sass_string, sass_string_dq, sass_string_sq};
use self::util::{comment2, ignore_space, name, opt_spacelike, spacelike};
use self::strings::{name, sass_string, sass_string_dq, sass_string_sq};
use self::util::{comment2, ignore_space, opt_spacelike, spacelike};
use self::value::{
dictionary, function_call, single_value, value_expression,
};
Expand Down
2 changes: 1 addition & 1 deletion src/parser/selectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ mod test {
selector(Input(b"\\E9m ")),
Ok((
Input(b""),
Selector(vec![SelectorPart::Simple("\\E9m".into())])
Selector(vec![SelectorPart::Simple("ém".into())])
))
)
}
Expand Down
89 changes: 70 additions & 19 deletions src/parser/strings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use super::util::{is_name_char, take_char};
use super::value::value_expression;
use super::{input_to_str, input_to_string};
use crate::sass::{SassString, StringPart};
Expand Down Expand Up @@ -42,10 +41,10 @@ named!(pub sass_string_sq<Input, SassString>,
simple_qstring_part |
string_part_interpolation |
map!(hash_no_interpolation,
|s| StringPart::Raw(s.to_string())) |
value!(StringPart::Raw("'".to_string()),
StringPart::from) |
value!(StringPart::from("'"),
tag!("\\'")) |
value!(StringPart::Raw("\"".to_string()),
value!(StringPart::from("\""),
tag!("\"")) |
extra_escape
)),
Expand All @@ -68,14 +67,20 @@ named!(
named!(
selector_string<Input, String>,
fold_many1!(
// Note: This could probably be a whole lot more efficient,
// but try to get stuff correct before caring too much about that.
alt_complete!(
selector_plain_part
| selector_escaped_part
| hash_no_interpolation
map!(selector_plain_part, String::from) |
map!(tag!("\\ "), |_| "\\ ".to_string()) |
map!(tag!("\\\""), |_| "\\\"".to_string()) |
map!(tag!("\\\'"), |_| "\\\'".to_string()) |
map!(tag!("\\\\"), |_| "\\\\".to_string()) |
map!(escaped_char, |c| format!("{}", c)) |
map!(hash_no_interpolation, String::from)
),
String::new(),
|mut acc: String, item: &str| {
acc.push_str(item);
|mut acc: String, item: String| {
acc.push_str(&item);
acc
}
)
Expand All @@ -85,16 +90,6 @@ named!(
map_res!(is_not!("\n\t >$\"'\\#+*/()[]{}:;,=!&@"), input_to_str)
);

named!(
selector_escaped_part<Input, &str>,
map_res!(
recognize!(preceded!(
tag!("\\"),
alt!(value!((), many_m_n!(1, 3, hexpair)) | value!((), take!(1)))
)),
input_to_str
)
);
named!(
hexpair<Input, Input>,
recognize!(do_parse!(
Expand Down Expand Up @@ -165,3 +160,59 @@ fn is_ext_str_char(c: char) -> bool {
|| c == '?'
|| c == '|'
}

named!(
pub name<Input, String>,
map_opt!(
fold_many0!(
alt!(
escaped_char |
verify!(take_char, is_name_char)
),
String::new(),
|mut s: String, c: char| { s.push(c); s }
),
|s| if s != "" && s != "-" { Some(s) } else { None }
)
);

named!(
escaped_char<Input, char>,
preceded!(
tag!("\\"),
alt!(
value!('\\', tag!("\\")) |
map!(
terminated!(
recognize!(many_m_n!(1, 6, one_of!("0123456789ABCDEFabcdef"))),
opt!(tag!(" "))
),
|hp| {
use std::char::from_u32;
from_u32(u32::from_str_radix(input_to_str(hp).unwrap(), 16).unwrap()).unwrap()
}
) |
take_char
)
)
);

named!(
take_char<Input, char>,
alt!(
map_opt!(take!(1), single_char) |
map_opt!(take!(2), single_char) |
map_opt!(take!(3), single_char) |
map_opt!(take!(4), single_char) |
map_opt!(take!(5), single_char)
)
);

fn single_char(data: Input) -> Option<char> {
use std::str::from_utf8;
from_utf8(&data).ok().and_then(|s| s.chars().next())
}

fn is_name_char(c: char) -> bool {
c.is_alphanumeric() || c == '_' || c == '-'
}
36 changes: 0 additions & 36 deletions src/parser/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use super::input_to_string;
use nom::multispace;
use nom::types::CompleteByteSlice as Input;
use nom::*;
Expand All @@ -23,41 +22,6 @@ named!(pub ignore_comments<Input, ()>,
(),
|(), ()| ()));

named!(pub name<Input, String>,
map_res!(
verify!(
recognize!(
fold_many0!(
verify!(take_char, is_name_char),
(),
|_, _| ()
)
),
|n| n != Input(b"") && n != Input(b"-")),
input_to_string
)
);

named!(
pub take_char<Input, char>,
alt!(
map_opt!(take!(1), single_char) |
map_opt!(take!(2), single_char) |
map_opt!(take!(3), single_char) |
map_opt!(take!(4), single_char) |
map_opt!(take!(5), single_char)
)
);

fn single_char(data: Input) -> Option<char> {
use std::str::from_utf8;
from_utf8(&data).ok().and_then(|s| s.chars().next())
}

pub fn is_name_char(c: char) -> bool {
c.is_alphanumeric() || c == '_' || c == '-'
}

named!(pub comment<Input, Input>,
preceded!(tag!("/*"), comment2)
);
Expand Down
4 changes: 2 additions & 2 deletions src/parser/value.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::formalargs::call_args;
use super::strings::{sass_string_dq, sass_string_ext, sass_string_sq};
use super::strings::{name, sass_string_dq, sass_string_ext, sass_string_sq};
use super::unit::unit;
use super::util::{name, opt_spacelike, spacelike2};
use super::util::{opt_spacelike, spacelike2};
use super::{input_to_string, sass_string};
use crate::sass::{SassString, Value};
use crate::value::{ListSeparator, Number, Operator, Rgba};
Expand Down
18 changes: 16 additions & 2 deletions src/sass/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,15 @@ impl SassString {
}
result.push_str(&v)
}
StringPart::Raw(ref s) => result.push_str(s),
StringPart::Raw(ref s) => {
for c in s.chars() {
if c.is_control() {
result.push_str(&format!("\\{:x} ", c as usize))
} else {
result.push(c)
}
}
}
}
}
if interpolated
Expand Down Expand Up @@ -138,10 +146,16 @@ impl fmt::Display for SassString {
}
}

impl From<&str> for StringPart {
fn from(s: &str) -> Self {
StringPart::Raw(s.to_string())
}
}

impl<'a> From<&'a str> for SassString {
fn from(s: &'a str) -> Self {
SassString {
parts: vec![StringPart::Raw(s.to_string())],
parts: vec![StringPart::from(s)],
quotes: Quotes::None,
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/sass/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ impl Value {
Value::Bang(ref s) => Ok(css::Value::Bang(s.clone())),
Value::Literal(ref s) => {
let (s, q) = s.evaluate(scope)?;
if s == "" && q == Quotes::None {
if s.is_empty() && q == Quotes::None {
Ok(css::Value::Null)
} else {
Ok(css::Value::Literal(s, q))
Expand Down
1 change: 0 additions & 1 deletion tests/basic/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,6 @@ fn t52_interchangeable_hyphens_underscores() {

// From "sass-spec/spec/basic/53_escaped_quotes"
#[test]
#[ignore] // failing
fn t53_escaped_quotes() {
assert_eq!(
rsass(
Expand Down
1 change: 1 addition & 0 deletions tests/css/unknown_directive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ fn name_interpolation() {

// From "sass-spec/spec/css/unknown_directive/plain.hrx"
#[test]
#[ignore] // failing
fn plain() {
assert_eq!(
rsass(
Expand Down
5 changes: 0 additions & 5 deletions tests/parser/interpolate/t11_escaped_literal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use rsass::set_precision;

// From "sass-spec/spec/parser/interpolate/11_escaped_literal/01_inline.hrx"
#[test]
#[ignore] // failing
fn t01_inline() {
assert_eq!(
rsass(
Expand All @@ -19,7 +18,6 @@ fn t01_inline() {

// From "sass-spec/spec/parser/interpolate/11_escaped_literal/02_variable.hrx"
#[test]
#[ignore] // failing
fn t02_variable() {
assert_eq!(
rsass(
Expand All @@ -32,7 +30,6 @@ fn t02_variable() {

// From "sass-spec/spec/parser/interpolate/11_escaped_literal/03_inline_double.hrx"
#[test]
#[ignore] // failing
fn t03_inline_double() {
assert_eq!(
rsass(
Expand All @@ -45,7 +42,6 @@ fn t03_inline_double() {

// From "sass-spec/spec/parser/interpolate/11_escaped_literal/04_variable_double.hrx"
#[test]
#[ignore] // failing
fn t04_variable_double() {
assert_eq!(
rsass(
Expand All @@ -58,7 +54,6 @@ fn t04_variable_double() {

// From "sass-spec/spec/parser/interpolate/11_escaped_literal/05_variable_quoted_double.hrx"
#[test]
#[ignore] // failing
fn t05_variable_quoted_double() {
assert_eq!(
rsass(
Expand Down
1 change: 0 additions & 1 deletion tests/parser/interpolate/t12_escaped_double_quoted/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ fn t05_variable_quoted_double() {

// From "sass-spec/spec/parser/interpolate/12_escaped_double_quoted/06_escape_interpolation.hrx"
#[test]
#[ignore] // failing
fn t06_escape_interpolation() {
assert_eq!(
rsass(
Expand Down
1 change: 0 additions & 1 deletion tests/parser/interpolate/t13_escaped_single_quoted/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ fn t05_variable_quoted_double() {

// From "sass-spec/spec/parser/interpolate/13_escaped_single_quoted/06_escape_interpolation.hrx"
#[test]
#[ignore] // failing
fn t06_escape_interpolation() {
assert_eq!(
rsass(
Expand Down
5 changes: 0 additions & 5 deletions tests/parser/interpolate/t14_escapes_literal_numbers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use rsass::set_precision;

// From "sass-spec/spec/parser/interpolate/14_escapes_literal_numbers/01_inline.hrx"
#[test]
#[ignore] // failing
fn t01_inline() {
assert_eq!(
rsass(
Expand All @@ -19,7 +18,6 @@ fn t01_inline() {

// From "sass-spec/spec/parser/interpolate/14_escapes_literal_numbers/02_variable.hrx"
#[test]
#[ignore] // failing
fn t02_variable() {
assert_eq!(
rsass(
Expand All @@ -32,7 +30,6 @@ fn t02_variable() {

// From "sass-spec/spec/parser/interpolate/14_escapes_literal_numbers/03_inline_double.hrx"
#[test]
#[ignore] // failing
fn t03_inline_double() {
assert_eq!(
rsass(
Expand All @@ -45,7 +42,6 @@ fn t03_inline_double() {

// From "sass-spec/spec/parser/interpolate/14_escapes_literal_numbers/04_variable_double.hrx"
#[test]
#[ignore] // failing
fn t04_variable_double() {
assert_eq!(
rsass(
Expand All @@ -58,7 +54,6 @@ fn t04_variable_double() {

// From "sass-spec/spec/parser/interpolate/14_escapes_literal_numbers/05_variable_quoted_double.hrx"
#[test]
#[ignore] // failing
fn t05_variable_quoted_double() {
assert_eq!(
rsass(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ fn t05_variable_quoted_double() {

// From "sass-spec/spec/parser/interpolate/15_escapes_double_quoted_numbers/06_escape_interpolation.hrx"
#[test]
#[ignore] // failing
fn t06_escape_interpolation() {
assert_eq!(
rsass(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ fn t05_variable_quoted_double() {

// From "sass-spec/spec/parser/interpolate/16_escapes_single_quoted_numbers/06_escape_interpolation.hrx"
#[test]
#[ignore] // failing
fn t06_escape_interpolation() {
assert_eq!(
rsass(
Expand Down
Loading