Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign upadd parsing/serialisation of 'grid-auto-flow', fixing issue #15313 #15364
Conversation
highfive
commented
Feb 3, 2017
|
Thanks for the pull request, and welcome! The Servo team is excited to review your changes, and you should hear from @Manishearth (or someone else) soon. |
highfive
commented
Feb 3, 2017
highfive
commented
Feb 3, 2017
| #[derive(PartialEq, Clone, Eq, Copy, Debug)] | ||
| #[cfg_attr(feature = "servo", derive(HeapSizeOf))] | ||
| pub struct T { | ||
| pub row_or_column: Option<RowOrColumn>, |
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 3, 2017
Member
Gecko uses bit fields to check whether dense exists along with row/column. Let's achieve this simply with a bool.
pub struct T {
is_row: bool,
dense: bool,
}This will reduce a lot of unwanted complexity in the code :)
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 3, 2017
Member
@emilio You okay with this? I don't think we need an enum to represent whether it's a row or column.
This comment has been minimized.
This comment has been minimized.
emilio
Feb 3, 2017
Member
Sure, as long as we serialize the same way, that's fine. (We could also use bitflags!)
This comment has been minimized.
This comment has been minimized.
Manishearth
Feb 3, 2017
Member
Enums are fine IMO. It's more Rusty to use an enum (whereas they get used less in C++)
But yeah, for the computed value the Option isn't necessary.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 4, 2017
Member
Fair enough. Then, let's have AutoFlow::{Row, Column} in that case without the Option.
| #[derive(PartialEq, Clone, Eq, Copy, Debug)] | ||
| #[cfg_attr(feature = "servo", derive(HeapSizeOf))] | ||
| pub struct T { | ||
| pub row_or_column: Option<RowOrColumn>, |
This comment has been minimized.
This comment has been minimized.
emilio
Feb 3, 2017
Member
Sure, as long as we serialize the same way, that's fine. (We could also use bitflags!)
| } | ||
| }).is_ok() {} | ||
|
|
||
| if row_or_column | dense { Ok(value) } else { Err(()) } |
This comment has been minimized.
This comment has been minimized.
| let mut dense = false; | ||
| let mut value = SpecifiedValue { row_or_column: None, dense: false }; | ||
| while input.try(|input| { | ||
| if let Ok(ident) = input.expect_ident() { |
This comment has been minimized.
This comment has been minimized.
emilio
Feb 3, 2017
Member
nit: match_ignore_ascii_case! { input.expect_ident()?,, so you don't need to indent this more than necessary.
| let mut row_or_column = false; | ||
| let mut dense = false; | ||
| let mut value = SpecifiedValue { row_or_column: None, dense: false }; | ||
| while input.try(|input| { |
This comment has been minimized.
This comment has been minimized.
emilio
Feb 3, 2017
Member
why not just loop? We're not trying multiple things, so this try is doing just nothing.
| /// [ row | column ] || dense | ||
| pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { | ||
| let mut row_or_column = false; | ||
| let mut dense = false; |
This comment has been minimized.
This comment has been minimized.
| else { value.dense = true; continue }, | ||
| _ => break | ||
| } | ||
| } |
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 5, 2017
Member
We don't parse more than 2 keywords here. I don't think there's much need for a loop at all. We could have something like,
if input.try(|i| i.expect_ident_matching("row")) {
// row thing
} else if ... {
// column thing
}
// finally check dense
This comment has been minimized.
This comment has been minimized.
emilio
Feb 6, 2017
Member
That'd be wrong, dense row is also a valid value for this property, the loop is required.
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 6, 2017
Member
I didn't realize that until now. I thought the order actually mattered
This comment has been minimized.
This comment has been minimized.
galexite
Feb 8, 2017
Author
Contributor
Yes, I did wonder how that could work out! Sorry for delay: busy since.
|
Everything looks good (except the parsing code). Once that's fixed, we'll land this :) |
| let mut value = get_initial_value(); | ||
| loop { | ||
| match_ignore_ascii_case! { input.expect_ident()?, | ||
| "row" => if autoflow { break } |
This comment has been minimized.
This comment has been minimized.
emilio
Feb 6, 2017
•
Member
This should return an error right? otherwise we'd be parsing things like "row column".
| else { value.dense = true; continue }, | ||
| _ => break | ||
| } | ||
| } |
This comment has been minimized.
This comment has been minimized.
emilio
Feb 6, 2017
Member
That'd be wrong, dense row is also a valid value for this property, the loop is required.
| }, | ||
| "dense" => if value.dense { break } | ||
| else { value.dense = true; continue }, | ||
| _ => break |
This comment has been minimized.
This comment has been minimized.
| value.autoflow = computed_value::AutoFlow::Row; | ||
| continue | ||
| }, | ||
| "column" => if autoflow { break } |
This comment has been minimized.
This comment has been minimized.
| value.autoflow = computed_value::AutoFlow::Column; | ||
| continue | ||
| }, | ||
| "dense" => if value.dense { break } |
This comment has been minimized.
This comment has been minimized.
emilio
Feb 6, 2017
Member
Similarly, this would parse dense dense correctly. Please fix and add a test case. You may need to change the loop to while !input.is_exhausted().
Please add tests for all the test cases I've mentioned.
|
|
|
@galexite Are you planning to address the review comments? |
|
I never got notified of this. Next time, feel free to ping us whenever you want something to be landed :) |
| let mut value = get_initial_value(); | ||
| loop { | ||
| match_ignore_ascii_case! { input.expect_ident()?, | ||
| "row" => if autoflow { Err(()) } |
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 24, 2017
Member
I don't think this works as expected. Shouldn't all these be return Err(())?
| _ => Err(()) | ||
| } | ||
| } | ||
|
|
This comment has been minimized.
This comment has been minimized.
|
Like @emilio said, tests could help you with seeing what the code really serializes into. Please consider adding unit tests for this :) |
|
@wafflespeanut @emilio Working on adding unit tests! |
|
|
@jdm yes, I haven't uploaded my updated code, I just resynched my fork with upstream! Is it OK to replace the loop with |
|
I think we can loop as long as we get an identifier from the parser. |
|
@wafflespeanut but what happens if an integer or string is encountered? The loop breaks and there will be no error. |
|
If I looped until the semicolon, then if an integer or string appeared, |
|
Why wouldn't there be an error? Once the loop ends, we should check that one of |
|
@wafflespeanut then how do I break the loop when the statement ends? i.e. grid-auto-flow: row dense;
/* ^ what happens here? */Because of
If I were to replace |
|
Note that the parser has already looked for the semicolon so in your example you'll only be parsing Also, the parser looks for exhaustion, so if you return |
|
@emilio I couldn't grasp that from the http://docs.rs/ documentation. Great, thank you. |
|
ready @wafflespeanut @emilio |
|
Thanks! I've got some comments. |
| pub fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> { | ||
| let mut autoflow = false; | ||
| let mut value = get_initial_value(); | ||
| while !input.is_exhausted() { |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
| let mut value = get_initial_value(); | ||
| while !input.is_exhausted() { | ||
| match_ignore_ascii_case! { &try!(input.expect_ident()), | ||
| "row" => if autoflow { return Err(()) } |
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 27, 2017
Member
Since they're Copy, everything could be handled with pattern guards like so,
"row" if !autoflow => { }and everything else will be matched with the wildcard pattern, returning Err(())
This comment has been minimized.
This comment has been minimized.
emilio
Feb 27, 2017
Member
I don't think that match_ignore_ascii_case! supports guards, so this is fine IMO.
| else { | ||
| autoflow = true; | ||
| value.autoflow = computed_value::AutoFlow::Row; | ||
| continue |
This comment has been minimized.
This comment has been minimized.
| let mut autoflow = false; | ||
| let mut value = get_initial_value(); | ||
| while !input.is_exhausted() { | ||
| match_ignore_ascii_case! { &try!(input.expect_ident()), |
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 27, 2017
Member
This should be input.try(|input| input.expect_ident()) so that once we find an error, we can break out of the loop. Here's a similar case that may be of help (it makes use of bit fields, but the essential idea is the same).
This comment has been minimized.
This comment has been minimized.
emilio
Feb 27, 2017
Member
I think the code as written before worked fine? What's the advantage of that? This function only parses idents.
This comment has been minimized.
This comment has been minimized.
wafflespeanut
Feb 27, 2017
Member
It's just that I've never seen using input.is_exhausted anywhere in our parsing code. Mostly, we just loop, input.try(...) and break on getting an error. Here, the loop doesn't break at all.
|
Also, please don't specify our names in the commit message |
|
For the record, servo/rust-cssparser#123 adds support for |
|
@galexite FYI, the cssparser bump landed a few days back. You can now add pattern guards to the macro. You planning on finishing this off? I think the code needs changes (it's not what I or emilio suggested). |
|
OK, thank you! |
|
Updated and reopened in #16024 |
Add parsing/serialisation for 'grid-auto-flow' Didn't want the work (and review comments) in #15364 to go wasted. Fixes #15313 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16024) <!-- Reviewable:end -->
galexite commentedFeb 3, 2017
•
edited
This pull request adds the parsing and serialisation code for 'grid-auto-flow', as part of issue #15313.
./mach build -ddoes not report any errors./mach test-tidydoes not report any errorsThis change is