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 all commits
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
2 changes: 1 addition & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ RUST_SRC=$(shell find $(VPATH)/. -type f -name '*.rs') $(COLOR_DATA_RS)
all: libcssparser.dummy

libcssparser.dummy: cssparser.rc $(RUST_SRC)
$(RUSTC) $(RUSTFLAGS) $< -o $@
$(RUSTC) $(RUSTFLAGS) $<
touch $@

cssparser-test: cssparser.rc $(RUST_SRC)
Expand Down
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
rust-cssparser
==============

WIP rust implementation of the 2013 version of
Rust implementation of the 2013 version of
[css3-syntax](http://dev.w3.org/csswg/css3-syntax/)


TODO
----

* [x] Tokenization
* [x] Declaration and rule parsing
* [ ] Detect character encoding & decode from bytes
* [ ] Track line/column number for tokens.
* [ ] Figure out float and integer overflow
* [ ] Make it fast!
* Detect character encoding & decode from bytes
* Figure out float and integer overflow
* Serialize tokens back to CSS
* Make it fast!
88 changes: 74 additions & 14 deletions ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str::ToStr;
use std::vec;


#[deriving(Eq)]
Expand All @@ -20,13 +21,16 @@ pub struct SourceLocation {
}


pub type Node = (ComponentValue, SourceLocation); // TODO this is not a good name


#[deriving(Eq)]
pub enum ComponentValue {
// Preserved tokens. Same as in the tokenizer.
// Preserved tokens.
Ident(~str),
AtKeyword(~str),
Hash(~str),
IDHash(~str), // Hash token that is a valid ID selector.
IDHash(~str), // Hash that is a valid ID selector.
String(~str),
URL(~str),
Delim(char),
Expand All @@ -39,7 +43,7 @@ pub enum ComponentValue {
Colon, // :
Semicolon, // ;
Comma, // ,
IncludeMath, // ~=
IncludeMatch, // ~=
DashMatch, // |=
PrefixMatch, // ^=
SuffixMatch, // $=
Expand All @@ -49,12 +53,12 @@ pub enum ComponentValue {
CDC, // -->

// Function
Function(~str, ~[(ComponentValue, SourceLocation)]), // name, arguments
Function(~str, ~[ComponentValue]), // name, arguments

// Simple block
ParenthesisBlock(~[(ComponentValue, SourceLocation)]), // (…)
SquareBracketBlock(~[(ComponentValue, SourceLocation)]), // […]
CurlyBracketBlock(~[(ComponentValue, SourceLocation)]), // {…}
ParenthesisBlock(~[ComponentValue]), // (…)
SquareBracketBlock(~[ComponentValue]), // […]
CurlyBracketBlock(~[Node]), // {…}

// These are always invalid
BadURL,
Expand All @@ -69,23 +73,23 @@ pub enum ComponentValue {
pub struct Declaration {
location: SourceLocation,
name: ~str,
value: ~[(ComponentValue, SourceLocation)],
value: ~[ComponentValue],
important: bool,
}

#[deriving(Eq)]
pub struct QualifiedRule {
location: SourceLocation,
prelude: ~[(ComponentValue, SourceLocation)],
block: ~[(ComponentValue, SourceLocation)],
prelude: ~[ComponentValue],
block: ~[Node],
}

#[deriving(Eq)]
pub struct AtRule {
location: SourceLocation,
name: ~str,
prelude: ~[(ComponentValue, SourceLocation)],
block: Option<~[(ComponentValue, SourceLocation)]>,
prelude: ~[ComponentValue],
block: Option<~[Node]>,
}

#[deriving(Eq)]
Expand All @@ -101,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 @@ -111,6 +121,56 @@ 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)
}
}


pub trait SkipWhitespaceIterable<'self> {
pub fn skip_whitespace(self) -> SkipWhitespaceIterator<'self>;
}

impl<'self> SkipWhitespaceIterable<'self> for &'self [ComponentValue] {
pub fn skip_whitespace(self) -> SkipWhitespaceIterator<'self> {
SkipWhitespaceIterator{ iter_with_whitespace: self.iter() }
}
}

pub struct SkipWhitespaceIterator<'self> {
iter_with_whitespace: vec::VecIterator<'self, ComponentValue>,
}

impl<'self> Iterator<&'self ComponentValue> for SkipWhitespaceIterator<'self> {
fn next(&mut self) -> Option<&'self ComponentValue> {
for component_value in self.iter_with_whitespace {
if component_value != &WhiteSpace { return Some(component_value) }
}
None
}
}


pub trait MoveSkipWhitespaceIterable {
pub fn move_skip_whitespace(self) -> MoveSkipWhitespaceIterator;
}

impl MoveSkipWhitespaceIterable for ~[ComponentValue] {
pub fn move_skip_whitespace(self) -> MoveSkipWhitespaceIterator {
MoveSkipWhitespaceIterator{ iter_with_whitespace: self.move_iter() }
}
}

pub struct MoveSkipWhitespaceIterator {
iter_with_whitespace: vec::MoveIterator<ComponentValue>,
}

impl Iterator<ComponentValue> for MoveSkipWhitespaceIterator {
fn next(&mut self) -> Option<ComponentValue> {
for component_value in self.iter_with_whitespace {
if component_value != WhiteSpace { return Some(component_value) }
}
None
}
}
10 changes: 6 additions & 4 deletions color.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::libc::c_float;
use std::ascii::to_ascii_lower;

Expand Down Expand Up @@ -76,7 +80,7 @@ fn parse_color_hash(value: &str) -> Option<Color> {


#[inline]
fn parse_color_function(name: &str, arguments: &[(ComponentValue, SourceLocation)])
fn parse_color_function(name: &str, arguments: &[ComponentValue])
-> Option<Color> {
let lower_name = to_ascii_lower(name);

Expand All @@ -87,9 +91,7 @@ fn parse_color_function(name: &str, arguments: &[(ComponentValue, SourceLocation
else if "hsla" == lower_name { (false, true) }
else { return None };

let mut iter = do arguments.iter().filter_map |&(ref c, _)| {
if c != &WhiteSpace { Some(c) } else { None }
};
let mut iter = arguments.skip_whitespace();
macro_rules! expect_comma(
() => ( if iter.next() != Some(&Comma) { return None } );
)
Expand Down
151 changes: 151 additions & 0 deletions css-parsing-tests/An+B.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
[

"", null,
" \n", null,

"odd", [2, 1],
"even", [2, 0],
"ödd", null,
"éven", null,
" /**/\t OdD /**/\n", [2, 1],
" /**/\t EveN /**/\n", [2, 0],


"3", [0, 3],
"+2 ", [0, 2],
" -14 ", [0, -14],
"+ 2 ", null,
"- 14 ", null,
"3.1", null,

"3N", [3, 0],
"+2N ", [2, 0],
" -14n ", [-14, 0],
"+ 2N ", null,
"- 14N ", null,
"3.1N", null,
"3 n", null,

" N", [1, 0],
" +n", [1, 0],
" -n", [-1, 0],
"+ n", null,
"- n", null,


"3N+1", [3, 1],
"+2n+1 ", [2, 1],
" -14n+1 ", [-14, 1],
"+ 2N+1 ", null,
"- 14n+1 ", null,
"3.1n+1", null,
"3 n+1", null,

" n+1", [1, 1],
" +N+1", [1, 1],
" -n+1", [-1, 1],
"+ N+1", null,
"- N+1", null,

"3n-1", [3, -1],
"+2N-1 ", [2, -1],
" -14n-1 ", [-14, -1],
"+ 2N-1 ", null,
"- 14N-1 ", null,
"3.1n-1", null,
"3 n-1", null,

" n-1", [1, -1],
" +n-1", [1, -1],
" -n-1", [-1, -1],
"+ n-1", null,
"- n-1", null,


"3N +1", [3, 1],
"+2N +1 ", [2, 1],
" -14n +1 ", [-14, 1],
"+ 2N +1 ", null,
"- 14n +1 ", null,
"3.1N +1", null,
"3 n +1", null,

" n +1", [1, 1],
" +N +1", [1, 1],
" -n +1", [-1, 1],
"+ n +1", null,
"- N +1", null,

"3N -1", [3, -1],
"+2n -1 ", [2, -1],
" -14n -1 ", [-14, -1],
"+ 2n -1 ", null,
"- 14N -1 ", null,
"3.1N -1", null,
"3 N -1", null,

" N -1", [1, -1],
" +N -1", [1, -1],
" -n -1", [-1, -1],
"+ n -1", null,
"- n -1", null,


"3n+ 1", [3, 1],
"+2n+ 1 ", [2, 1],
" -14n+ 1 ", [-14, 1],
"+ 2n+ 1 ", null,
"- 14N+ 1 ", null,
"3.1n+ 1", null,
"3 N+ 1", null,

" N+ 1", [1, 1],
" +N+ 1", [1, 1],
" -N+ 1", [-1, 1],
"+ n+ 1", null,
"- N+ 1", null,

"3n- 1", [3, -1],
"+2N- 1 ", [2, -1],
" -14N- 1 ", [-14, -1],
"+ 2N- 1 ", null,
"- 14n- 1 ", null,
"3.1n- 1", null,
"3 n- 1", null,

" N- 1", [1, -1],
" +N- 1", [1, -1],
" -n- 1", [-1, -1],
"+ n- 1", null,
"- N- 1", null,


"3N + 1", [3, 1],
"+2N + 1 ", [2, 1],
" -14n + 1 ", [-14, 1],
"+ 2n + 1 ", null,
"- 14N + 1 ", null,
"3.1n + 1", null,
"3 N + 1", null,

" n + 1", [1, 1],
" +n + 1", [1, 1],
" -N + 1", [-1, 1],
"+ N + 1", null,
"- N + 1", null,

"3N - 1", [3, -1],
"+2n - 1 ", [2, -1],
" -14n - 1 ", [-14, -1],
"+ 2N - 1 ", null,
"- 14N - 1 ", null,
"3.1N - 1", null,
"3 n - 1", null,

" N - 1", [1, -1],
" +n - 1", [1, -1],
" -n - 1", [-1, -1],
"+ N - 1", null,
"- N - 1", null

]
11 changes: 11 additions & 0 deletions css-parsing-tests/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ associated with the expected result.
are between 0 and 255.
This file is generated the ``make_color3_keywords.py`` Python script.

``an+b.json``
Tests the `an+b <http://dev.w3.org/csswg/css-syntax/#the-anb-type>`_
syntax defined in CSS Syntax Level 3.
This `differs <http://dev.w3.org/csswg/css-syntax/#changes>`_ from the
`nth grammar rule <http://www.w3.org/TR/css3-selectors/#nth-child-pseudo>`_
in Selectors Level 3 only in that
``-`` charecters and digits can be escaped in some cases.
The Unicode input is represented by a JSON string,
the output as null for invalid syntax,
or an array of two integers ``[A, B]``.


Result representation
=====================
Expand Down
Loading