Skip to content

Add parse_whitespace_separated() #105

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

Closed
mitchhentges opened this issue May 26, 2016 · 1 comment
Closed

Add parse_whitespace_separated() #105

mitchhentges opened this issue May 26, 2016 · 1 comment

Comments

@mitchhentges
Copy link

For servo/servo#9283, Servo needs to be able to parse rect(...) values with values separated purely by spaces, for example: rect(0, 0, 5, 5).

However, cssparser only provides parse_comma_separated(). I looked into it a little, and it's a little challenging: parse_{x}_separated() will parse up to a Delimiter, of which all 8 slots of the byte are in use. It is not possible to have more than one true bit per byte, because some bitwise OR logic is used which depends on mutual exclusivity.

Additionally, three different Delimiters would need to be added: space, tab, newline.
So, I'd love to implement this, but I'll need some pointers :)

@SimonSapin
Copy link
Member

cssparser only provides parse_comma_separated()

It provides a lot more than that: https://servo.github.io/rust-cssparser/cssparser/struct.Parser.html

The most basic thing is calling the next method which gives the next token. next ignores whitespace, since it’s so rarely significant. (There’s next_including_whitespace for when it is.) Things like parse_comma_separated are helper methods to make common patterns easier, but you don’t have to use them.

In fact even comma-separated rect() shouldn’t use parse_comma_separated, which is designed for lists of arbitrary length like for example the font-family property. Since rect() expects exactly four arguments, allocating a Vec is not needed. Instead, an argument-parsing function could be called four times:

let top = try!(parse_rect_argument(input));
try!(input.expect_comma());
let right = try!(parse_rect_argument(input));
try!(input.expect_comma());
let bottom = try!(parse_rect_argument(input));
try!(input.expect_comma());
let left = try!(parse_rect_argument(input));

Now, in this case you want to allow rect() without commas, but note that it’s all or nothing:

https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect

Authors should separate offset values with commas. User agents must support separation with commas, but may also support separation without commas (but not a combination), because a previous revision of this specification was ambiguous in this respect.

(Emphasis added.)

To do this, you’ll need to parse the first argument, then see if there’s a comma. If so, require commas between the rest of the arguments. If not, require that there is no comma. Note that the expect_comma method consumes a token, so you’ll want to "go back" when that’s not a comma. The input.try method does this. The name is a bit confusing, sorry. It’s completely different from the try! macro.

let top = try!(parse_rect_argument(input));
let right;
let bottom;
let left;
if input.try(|input| input.expect_comma()) {
    right = try!(parse_rect_argument(input));
    try!(input.expect_comma());
    bottom = try!(parse_rect_argument(input));
    try!(input.expect_comma());
    left = try!(parse_rect_argument(input));
} else {
    right = try!(parse_rect_argument(input));
    bottom = try!(parse_rect_argument(input));
    left = try!(parse_rect_argument(input));
}

I’m closing this since I don’t think a change in rust-cssparser is needed, but feel free to ask more questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants