| 51 | M: NodeMetadata, |
| 52 | { |
| 53 | fn parse<Iter>(p: &mut Parser<'a, Iter>) -> Result<Self> |
| 54 | where |
| 55 | Iter: Iterator<Item = crate::Cursor> + Clone, |
| 56 | { |
| 57 | let c = p.peek_n(1); |
| 58 | // Let rule be a new qualified rule with its prelude, declarations, and child rules all initially set to empty lists. |
| 59 | |
| 60 | // Process input: |
| 61 | |
| 62 | // <EOF-token> |
| 63 | // stop token (if passed) |
| 64 | // This is a parse error. Return nothing. |
| 65 | if p.at_end() { |
| 66 | Err(Diagnostic::new(p.peek_n(1), Diagnostic::unexpected_end))? |
| 67 | } |
| 68 | |
| 69 | // <}-token> |
| 70 | // This is a parse error. If nested is true, return nothing. Otherwise, consume a token and append the result to rule’s prelude. |
| 71 | if p.is(State::Nested) && <T!['}']>::peek(p, c) { |
| 72 | Err(Diagnostic::new(c, Diagnostic::unexpected_close_curly))?; |
| 73 | } |
| 74 | |
| 75 | // <{-token> |
| 76 | // If the first two non-<whitespace-token> values of rule’s prelude are an <ident-token> whose value starts with "--" followed by a <colon-token>, then: |
| 77 | let checkpoint = p.checkpoint(); |
| 78 | if <T![DashedIdent]>::peek(p, c) { |
| 79 | p.parse::<T![DashedIdent]>().ok(); |
| 80 | if <T![:]>::peek(p, p.peek_n(1)) { |
| 81 | // If nested is true, consume the remnants of a bad declaration from input, with nested set to true, and return nothing. |
| 82 | if p.is(State::Nested) { |
| 83 | p.rewind(checkpoint.clone()); |
| 84 | let start = p.peek_n(1); |
| 85 | p.parse::<BadDeclaration>()?; |
| 86 | let end = p.peek_n(1); |
| 87 | Err(Diagnostic::new(start, Diagnostic::bad_declaration).with_end_cursor(end))? |
| 88 | // If nested is false, consume a block from input, and return nothing. |
| 89 | } else { |
| 90 | // QualifiedRules must be able to consume a block from their input when encountering |
| 91 | // a custom property like declaration that doesn't end but opens a `{` block. This |
| 92 | // is implemented as parsing the existing block as that' simplifies downstream logic |
| 93 | // but consumers of this trait can instead opt to implement an optimised version of |
| 94 | // this which doesn't build up an AST and just throws away tokens. |
| 95 | p.parse::<Block<'a, D, R, M>>()?; |
| 96 | let start = p.peek_n(1); |
| 97 | p.parse::<BadDeclaration>()?; |
| 98 | let end = p.peek_n(1); |
| 99 | Err(Diagnostic::new(start, Diagnostic::bad_declaration).with_end_cursor(end))? |
| 100 | } |
| 101 | } |
| 102 | p.rewind(checkpoint); |
| 103 | } |
| 104 | |
| 105 | // Set the StopOn Curly to signify to prelude parsers that they shouldn't consume beyond the curly |
| 106 | let old_stop = p.set_stop(KindSet::new(&[Kind::LeftCurly])); |
| 107 | let prelude = p.parse::<P>(); |
| 108 | p.set_stop(old_stop); |
| 109 | let prelude = prelude?; |
| 110 | |