Skip to content

Add <An+B> parsing. #5

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

Merged
merged 19 commits into from
Aug 13, 2013
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add SourceLocation to syntax errors.
  • Loading branch information
SimonSapin committed Aug 8, 2013
commit a4b758745ae895e0d9600f98e3f14f2d5d5220f1
12 changes: 10 additions & 2 deletions ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ pub enum Rule {
AtRule(AtRule),
}

#[deriving(Eq)]
pub struct SyntaxError {
location: SourceLocation,
reason: ErrorReason,
}

#[deriving(Eq)]
pub enum ErrorReason {
ErrEmptyInput, // Parsing a single "thing", found only whitespace.
Expand All @@ -115,8 +121,10 @@ pub enum ErrorReason {
// This is meant to be extended
}

impl ToStr for ErrorReason {
fn to_str(&self) -> ~str { fmt!("%?", self) }
impl ToStr for SyntaxError {
fn to_str(&self) -> ~str {
fmt!("%u:%u %?", self.location.line, self.location.column, self.reason)
}
}


Expand Down
80 changes: 49 additions & 31 deletions parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ use ast::*;


/// Parse top-level of a CSS stylesheet.
/// Return a Iterator<Result<Rule, ErrorReason>>
/// Return a Iterator<Result<Rule, SyntaxError>>
#[inline]
pub fn parse_stylesheet_rules<T: Iterator<Node>>(iter: T) -> StylesheetParser<T> {
StylesheetParser(iter)
}


/// Parse a non-top level list of rules eg. the content of an @media rule.
/// Return a Iterator<Result<Rule, ErrorReason>>
/// Return a Iterator<Result<Rule, SyntaxError>>
#[inline]
pub fn parse_rule_list<T: Iterator<Node>>(iter: T) -> RuleListParser<T> {
RuleListParser(iter)
Expand All @@ -38,7 +38,7 @@ pub fn parse_rule_list<T: Iterator<Node>>(iter: T) -> RuleListParser<T> {

/// Parse a list of declarations and at-rules,
/// like @page in CSS 2.1, all declaration lists in level 3
/// Return a Iterator<Result<DeclarationListItem, ErrorReason>>
/// Return a Iterator<Result<DeclarationListItem, SyntaxError>>
#[inline]
pub fn parse_declaration_list<T: Iterator<Node>>(iter: T) -> DeclarationListParser<T> {
DeclarationListParser(iter)
Expand All @@ -47,27 +47,33 @@ pub fn parse_declaration_list<T: Iterator<Node>>(iter: T) -> DeclarationListPars

/// Parse a single rule.
/// Used eg. for CSSRuleList.insertRule()
pub fn parse_one_rule<T: Iterator<Node>>(iter: T) -> Result<Rule, ErrorReason> {
pub fn parse_one_rule<T: Iterator<Node>>(iter: T) -> Result<Rule, SyntaxError> {
let mut parser = RuleListParser(iter);
match parser.next() {
None => Err(ErrEmptyInput),
None => error(START_LOCATION, ErrEmptyInput),
Some(result) => {
if result.is_err() || next_non_whitespace(&mut *parser).is_none() { result }
else { Err(ErrExtraInput) }
if result.is_err() { result }
else { match next_non_whitespace(&mut *parser) {
None => result,
Some((_component_value, location)) => error(location, ErrExtraInput),
}}
}
}
}


/// Parse a single declaration (not an at-rule)
/// Used eg. in @supports
pub fn parse_one_declaration<T: Iterator<Node>>(mut iter: T) -> Result<Declaration, ErrorReason> {
pub fn parse_one_declaration<T: Iterator<Node>>(mut iter: T) -> Result<Declaration, SyntaxError> {
match next_non_whitespace(&mut iter) {
None => Err(ErrEmptyInput),
None => error(START_LOCATION, ErrEmptyInput),
Some((component_value, location)) => {
let result = parse_declaration(&mut iter, component_value, location);
if result.is_err() || next_non_whitespace(&mut iter).is_none() { result }
else { Err(ErrExtraInput) }
if result.is_err() { result }
else { match next_non_whitespace(&mut iter) {
None => result,
Some((_component_value, location)) => error(location, ErrExtraInput),
}}
}
}
}
Expand All @@ -76,12 +82,14 @@ pub fn parse_one_declaration<T: Iterator<Node>>(mut iter: T) -> Result<Declarati
/// Parse a single component value.
/// Used eg. in attr(foo, color)
pub fn parse_one_component_value<T: Iterator<Node>>(mut iter: T)
-> Result<ComponentValue, ErrorReason> {
-> Result<ComponentValue, SyntaxError> {
match next_non_whitespace(&mut iter) {
None => Err(ErrEmptyInput),
None => error(START_LOCATION, ErrEmptyInput),
Some((component_value, _location)) => {
if next_non_whitespace(&mut iter).is_none() { Ok(component_value) }
else { Err(ErrExtraInput) }
match next_non_whitespace(&mut iter) {
None => Ok(component_value),
Some((_component_value, location)) => error(location, ErrExtraInput),
}
}
}
}
Expand All @@ -106,16 +114,16 @@ macro_rules! for_iter(
)


impl<T: Iterator<Node>> Iterator<Result<Rule, ErrorReason>> for StylesheetParser<T> {
fn next(&mut self) -> Option<Result<Rule, ErrorReason>> {
impl<T: Iterator<Node>> Iterator<Result<Rule, SyntaxError>> for StylesheetParser<T> {
fn next(&mut self) -> Option<Result<Rule, SyntaxError>> {
let iter = &mut **self;
for_iter!(iter, (component_value, location), {
match component_value {
WhiteSpace | CDO | CDC => (),
AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
_ => return Some(match parse_qualified_rule(iter, component_value, location) {
Ok(rule) => Ok(QualifiedRule(rule)),
Err(reason) => Err(reason),
Err(e) => Err(e),
}),
}
})
Expand All @@ -124,16 +132,16 @@ impl<T: Iterator<Node>> Iterator<Result<Rule, ErrorReason>> for StylesheetParser
}


impl<T: Iterator<Node>> Iterator<Result<Rule, ErrorReason>> for RuleListParser<T> {
fn next(&mut self) -> Option<Result<Rule, ErrorReason>> {
impl<T: Iterator<Node>> Iterator<Result<Rule, SyntaxError>> for RuleListParser<T> {
fn next(&mut self) -> Option<Result<Rule, SyntaxError>> {
let iter = &mut **self;
for_iter!(iter, (component_value, location), {
match component_value {
WhiteSpace => (),
AtKeyword(name) => return Some(Ok(AtRule(parse_at_rule(iter, name, location)))),
_ => return Some(match parse_qualified_rule(iter, component_value, location) {
Ok(rule) => Ok(QualifiedRule(rule)),
Err(reason) => Err(reason),
Err(e) => Err(e),
}),
}
})
Expand All @@ -142,9 +150,9 @@ impl<T: Iterator<Node>> Iterator<Result<Rule, ErrorReason>> for RuleListParser<T
}


impl<T: Iterator<Node>> Iterator<Result<DeclarationListItem, ErrorReason>>
impl<T: Iterator<Node>> Iterator<Result<DeclarationListItem, SyntaxError>>
for DeclarationListParser<T> {
fn next(&mut self) -> Option<Result<DeclarationListItem, ErrorReason>> {
fn next(&mut self) -> Option<Result<DeclarationListItem, SyntaxError>> {
let iter = &mut **self;
for_iter!(iter, (component_value, location), {
match component_value {
Expand All @@ -153,10 +161,10 @@ for DeclarationListParser<T> {
=> return Some(Ok(Decl_AtRule(parse_at_rule(iter, name, location)))),
_ => return Some(match parse_declaration(iter, component_value, location) {
Ok(declaration) => Ok(Declaration(declaration)),
Err(reason) => {
Err(e) => {
// Find the end of the declaration
for (v, _) in *iter { if v == Semicolon { break } }
Err(reason)
Err(e)
}
}),
}
Expand All @@ -183,7 +191,7 @@ fn parse_at_rule<T: Iterator<Node>>(iter: &mut T, name: ~str, location: SourceLo

fn parse_qualified_rule<T: Iterator<Node>>(iter: &mut T, first: ComponentValue,
location: SourceLocation)
-> Result<QualifiedRule, ErrorReason> {
-> Result<QualifiedRule, SyntaxError> {
match first {
CurlyBracketBlock(content)
=> return Ok(QualifiedRule { location: location, prelude: ~[], block: content }),
Expand All @@ -197,20 +205,20 @@ fn parse_qualified_rule<T: Iterator<Node>>(iter: &mut T, first: ComponentValue,
component_value => prelude.push(component_value),
}
})
Err(ErrMissingQualifiedRuleBlock)
error(location, ErrMissingQualifiedRuleBlock)
}


fn parse_declaration<T: Iterator<Node>>(iter: &mut T, first: ComponentValue,
location: SourceLocation)
-> Result<Declaration, ErrorReason> {
-> Result<Declaration, SyntaxError> {
let name = match first {
Ident(name) => name,
_ => return Err(ErrInvalidDeclarationSyntax)
_ => return error(location, ErrInvalidDeclarationSyntax)
};
match next_non_whitespace(iter) {
Some((Colon, _)) => (),
_ => return Err(ErrInvalidDeclarationSyntax),
_ => return error(location, ErrInvalidDeclarationSyntax),
}
let mut value = ~[];
let mut important = false;
Expand All @@ -221,7 +229,7 @@ fn parse_declaration<T: Iterator<Node>>(iter: &mut T, first: ComponentValue,
important = true;
break
} else {
return Err(ErrInvalidBangImportantSyntax)
return error(location, ErrInvalidBangImportantSyntax)
},
component_value => value.push(component_value),
}
Expand Down Expand Up @@ -252,3 +260,13 @@ fn next_non_whitespace<T: Iterator<Node>>(iter: &mut T) -> Option<Node> {
}
None
}


#[inline]
fn error<T>(location: SourceLocation, reason: ErrorReason) -> Result<T, SyntaxError> {
Err(SyntaxError{location: location, reason: reason})
}


// When parsing one thing on an empty input
static START_LOCATION: SourceLocation = SourceLocation{ line: 1, column: 1 };
30 changes: 15 additions & 15 deletions tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ fn color3_keywords() {
}


impl ToJson for Result<Rule, ErrorReason> {
impl ToJson for Result<Rule, SyntaxError> {
fn to_json(&self) -> json::Json {
match *self {
Ok(ref a) => a.to_json(),
Expand All @@ -174,7 +174,7 @@ impl ToJson for Result<Rule, ErrorReason> {
}


impl ToJson for Result<DeclarationListItem, ErrorReason> {
impl ToJson for Result<DeclarationListItem, SyntaxError> {
fn to_json(&self) -> json::Json {
match *self {
Ok(ref a) => a.to_json(),
Expand All @@ -184,7 +184,7 @@ impl ToJson for Result<DeclarationListItem, ErrorReason> {
}


impl ToJson for Result<Declaration, ErrorReason> {
impl ToJson for Result<Declaration, SyntaxError> {
fn to_json(&self) -> json::Json {
match *self {
Ok(ref a) => a.to_json(),
Expand All @@ -194,7 +194,7 @@ impl ToJson for Result<Declaration, ErrorReason> {
}


impl ToJson for Result<ComponentValue, ErrorReason> {
impl ToJson for Result<ComponentValue, SyntaxError> {
fn to_json(&self) -> json::Json {
match *self {
Ok(ref a) => a.to_json(),
Expand All @@ -204,23 +204,23 @@ impl ToJson for Result<ComponentValue, ErrorReason> {
}


impl ToJson for Color {
impl ToJson for SyntaxError {
fn to_json(&self) -> json::Json {
match *self {
RGBA(r, g, b, a) => (~[r, g, b, a]).to_json(),
CurrentColor => json::String(~"currentColor"),
}
json::List(~[json::String(~"error"), json::String(match self.reason {
ErrEmptyInput => ~"empty",
ErrExtraInput => ~"extra-input",
_ => ~"invalid",
})])
}
}


impl ToJson for ErrorReason {
impl ToJson for Color {
fn to_json(&self) -> json::Json {
json::List(~[json::String(~"error"), json::String(match *self {
ErrEmptyInput => ~"empty",
ErrExtraInput => ~"extra-input",
_ => ~"invalid",
})])
match *self {
RGBA(r, g, b, a) => (~[r, g, b, a]).to_json(),
CurrentColor => json::String(~"currentColor"),
}
}
}

Expand Down