Skip to content

Commit 0bce2f6

Browse files
committed
Make the parser return iterators.
1 parent bff9dfc commit 0bce2f6

File tree

3 files changed

+180
-112
lines changed

3 files changed

+180
-112
lines changed

parser.rs

Lines changed: 121 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,15 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
// http://dev.w3.org/csswg/css-syntax/#parsing
6-
//
7-
// The input to the tree construction stage is a sequence of tokens
8-
// from the tokenization stage.
9-
// The output is a tree of items with a stylesheet at the root
10-
// and all other nodes being at-rules, style rules, or declarations.
6+
7+
/// The input to these functions needs to implement Iterator<(ComponentValue, SourceLocation)>.
8+
/// The input is consumed to avoid doing a lot of copying.
9+
/// A conforming input can be obtained:
10+
///
11+
/// * From a string in CSS syntax, with tokenize()
12+
/// * From a ~[(ComponentValue, SourceLocation)] vector
13+
/// (as found in "nested" component values such as CurlyBracketBlock),
14+
/// with v.consume_iter()
1115
1216

1317
use std::iterator::Iterator;
@@ -16,101 +20,67 @@ use std::ascii::eq_ignore_ascii_case;
1620
use ast::*;
1721

1822

19-
// Work around "error: cannot borrow `*iter` as mutable more than once at a time"
20-
// when using a normal for loop.
21-
macro_rules! for_iter(
22-
($iter: ident, $pattern: pat, $loop_body: expr) => (
23-
loop {
24-
match $iter.next() { None => break, Some($pattern) => $loop_body }
25-
}
26-
);
27-
)
23+
/// Parse top-level of a CSS stylesheet.
24+
/// Return a Iterator<Result<Rule, ErrorReason>>
25+
#[inline]
26+
pub fn parse_stylesheet<T: Iterator<Node>>(iter: T) -> StylesheetParser<T> {
27+
StylesheetParser(iter)
28+
}
2829

2930

30-
/// Call repeatedly for the top-level of a CSS stylesheet
31-
pub fn parse_stylesheet_rule<T: Iterator<Node>>(iter: &mut T) -> Option<Result<Rule, ErrorReason>> {
32-
for_iter!(iter, (component_value, location), {
33-
match component_value {
34-
WhiteSpace | CDO | CDC => (),
35-
AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
36-
_ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
37-
Ok(rule) => Ok(QualifiedRule(rule)),
38-
Err(reason) => Err(reason),
39-
}),
40-
}
41-
})
42-
None
31+
/// Parse a non-top level list of rules eg. the content of an @media rule.
32+
/// Return a Iterator<Result<Rule, ErrorReason>>
33+
#[inline]
34+
pub fn parse_rule_list<T: Iterator<Node>>(iter: T) -> RuleListParser<T> {
35+
RuleListParser(iter)
4336
}
4437

4538

46-
/// Call repeatedly for a non-top level list of rules eg. the content of an @media rule.
47-
/// Same as parse_stylesheet() except for the handling of top-level CDO and CDC
48-
pub fn parse_rule<T: Iterator<Node>>(iter: &mut T) -> Option<Result<Rule, ErrorReason>> {
49-
for_iter!(iter, (component_value, location), {
50-
match component_value {
51-
WhiteSpace => (),
52-
AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
53-
_ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
54-
Ok(rule) => Ok(QualifiedRule(rule)),
55-
Err(reason) => Err(reason),
56-
}),
57-
}
58-
})
59-
None
39+
/// Parse a list of declarations and at-rules,
40+
/// like @page in CSS 2.1, all declaration lists in level 3
41+
/// Return a Iterator<Result<DeclarationListItem, ErrorReason>>
42+
#[inline]
43+
pub fn parse_declaration_list<T: Iterator<Node>>(iter: T) -> DeclarationListParser<T> {
44+
DeclarationListParser(iter)
6045
}
6146

6247

48+
/// Parse a single rule.
6349
/// Used eg. for CSSRuleList.insertRule()
64-
pub fn parse_one_rule<T: Iterator<Node>>(iter: &mut T) -> Result<Rule, ErrorReason> {
65-
match parse_rule(iter) {
50+
pub fn parse_one_rule<T: Iterator<Node>>(iter: T) -> Result<Rule, ErrorReason> {
51+
let mut parser = RuleListParser(iter);
52+
match parser.next() {
6653
None => Err(ErrEmptyInput),
67-
Some(result) => if result.is_err() || next_non_whitespace(iter).is_none() { result }
68-
else { Err(ErrExtraInput) }
69-
}
70-
}
71-
72-
73-
/// Call repeatedly of a list of declarations.
74-
/// @page in CSS 2.1, all declaration lists in level 3
75-
pub fn parse_declaration_or_at_rule<T: Iterator<Node>>(iter: &mut T)
76-
-> Option<Result<DeclarationListItem, ErrorReason>> {
77-
for_iter!(iter, (component_value, location), {
78-
match component_value {
79-
WhiteSpace | Semicolon => (),
80-
AtKeyword(name) => return Some(Ok(Decl_AtRule(parse_at_rule(iter, name, location)))),
81-
_ => return Some(match parse_declaration(iter, (component_value, location)) {
82-
Ok(declaration) => Ok(Declaration(declaration)),
83-
Err(reason) => {
84-
// Find the end of the declaration
85-
for (v, _) in *iter { if v == Semicolon { break } }
86-
Err(reason)
87-
}
88-
}),
54+
Some(result) => {
55+
if result.is_err() || next_non_whitespace(&mut *parser).is_none() { result }
56+
else { Err(ErrExtraInput) }
8957
}
90-
})
91-
None
58+
}
9259
}
9360

9461

62+
/// Parse a single declaration (not an at-rule)
9563
/// Used eg. in @supports
96-
pub fn parse_one_declaration<T: Iterator<Node>>(iter: &mut T) -> Result<Declaration, ErrorReason> {
97-
match next_non_whitespace(iter) {
64+
pub fn parse_one_declaration<T: Iterator<Node>>(mut iter: T) -> Result<Declaration, ErrorReason> {
65+
match next_non_whitespace(&mut iter) {
9866
None => Err(ErrEmptyInput),
9967
Some(item) => {
100-
let result = parse_declaration(iter, item);
101-
if result.is_err() || next_non_whitespace(iter).is_none() { result }
68+
let result = parse_declaration(&mut iter, item);
69+
if result.is_err() || next_non_whitespace(&mut iter).is_none() { result }
10270
else { Err(ErrExtraInput) }
10371
}
10472
}
10573
}
10674

10775

76+
/// Parse a single component value.
10877
/// Used eg. in attr(foo, color)
109-
pub fn parse_one_component_value<T: Iterator<Node>>(iter: &mut T) -> Result<Node, ErrorReason> {
110-
match next_non_whitespace(iter) {
78+
pub fn parse_one_component_value<T: Iterator<Node>>(mut iter: T)
79+
-> Result<ComponentValue, ErrorReason> {
80+
match next_non_whitespace(&mut iter) {
11181
None => Err(ErrEmptyInput),
112-
Some(item) => {
113-
if next_non_whitespace(iter).is_none() { Ok(item) }
82+
Some((component_value, _location)) => {
83+
if next_non_whitespace(&mut iter).is_none() { Ok(component_value) }
11484
else { Err(ErrExtraInput) }
11585
}
11686
}
@@ -120,6 +90,82 @@ pub fn parse_one_component_value<T: Iterator<Node>>(iter: &mut T) -> Result<Node
12090
// *********** End of public API ***********
12191

12292

93+
struct StylesheetParser<T>(T);
94+
struct RuleListParser<T>(T);
95+
struct DeclarationListParser<T>(T);
96+
97+
98+
// Work around "error: cannot borrow `*iter` as mutable more than once at a time"
99+
// when using a normal for loop.
100+
macro_rules! for_iter(
101+
($iter: ident, $pattern: pat, $loop_body: expr) => (
102+
loop {
103+
match $iter.next() { None => break, Some($pattern) => $loop_body }
104+
}
105+
);
106+
)
107+
108+
109+
impl<T: Iterator<Node>> Iterator<Result<Rule, ErrorReason>> for StylesheetParser<T> {
110+
fn next(&mut self) -> Option<Result<Rule, ErrorReason>> {
111+
let iter = &mut **self;
112+
for_iter!(iter, (component_value, location), {
113+
match component_value {
114+
WhiteSpace | CDO | CDC => (),
115+
AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
116+
_ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
117+
Ok(rule) => Ok(QualifiedRule(rule)),
118+
Err(reason) => Err(reason),
119+
}),
120+
}
121+
})
122+
None
123+
}
124+
}
125+
126+
127+
impl<T: Iterator<Node>> Iterator<Result<Rule, ErrorReason>> for RuleListParser<T> {
128+
fn next(&mut self) -> Option<Result<Rule, ErrorReason>> {
129+
let iter = &mut **self;
130+
for_iter!(iter, (component_value, location), {
131+
match component_value {
132+
WhiteSpace => (),
133+
AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
134+
_ => return Some(match parse_qualified_rule(iter, (component_value, location)) {
135+
Ok(rule) => Ok(QualifiedRule(rule)),
136+
Err(reason) => Err(reason),
137+
}),
138+
}
139+
})
140+
None
141+
}
142+
}
143+
144+
145+
impl<T: Iterator<Node>> Iterator<Result<DeclarationListItem, ErrorReason>>
146+
for DeclarationListParser<T> {
147+
fn next(&mut self) -> Option<Result<DeclarationListItem, ErrorReason>> {
148+
let iter = &mut **self;
149+
for_iter!(iter, (component_value, location), {
150+
match component_value {
151+
WhiteSpace | Semicolon => (),
152+
AtKeyword(name)
153+
=> return Some(Ok(Decl_AtRule(parse_at_rule(iter, name, location)))),
154+
_ => return Some(match parse_declaration(iter, (component_value, location)) {
155+
Ok(declaration) => Ok(Declaration(declaration)),
156+
Err(reason) => {
157+
// Find the end of the declaration
158+
for (v, _) in *iter { if v == Semicolon { break } }
159+
Err(reason)
160+
}
161+
}),
162+
}
163+
})
164+
None
165+
}
166+
}
167+
168+
123169
fn parse_at_rule<T: Iterator<Node>>(iter: &mut T, name: ~str, location: SourceLocation)
124170
-> AtRule {
125171
let mut prelude = ~[];

0 commit comments

Comments
 (0)