marginSym = this._margin_sym();
line = tokenStream.token().startLine;
col = tokenStream.token().startCol;
this._readDeclarations(true);
_margin_sym: function() {
* BOTTOMRIGHTCORNER_SYM |
var tokenStream = this._tokenStream;
if (tokenStream.match([Tokens.TOPLEFTCORNER_SYM, Tokens.TOPLEFT_SYM,
Tokens.TOPCENTER_SYM, Tokens.TOPRIGHT_SYM, Tokens.TOPRIGHTCORNER_SYM,
Tokens.BOTTOMLEFTCORNER_SYM, Tokens.BOTTOMLEFT_SYM,
Tokens.BOTTOMCENTER_SYM, Tokens.BOTTOMRIGHT_SYM,
Tokens.BOTTOMRIGHTCORNER_SYM, Tokens.LEFTTOP_SYM,
Tokens.LEFTMIDDLE_SYM, Tokens.LEFTBOTTOM_SYM, Tokens.RIGHTTOP_SYM,
Tokens.RIGHTMIDDLE_SYM, Tokens.RIGHTBOTTOM_SYM])) {
return SyntaxUnit.fromToken(tokenStream.token());
_pseudo_page: function() {
var tokenStream = this._tokenStream;
tokenStream.mustMatch(Tokens.COLON);
tokenStream.mustMatch(Tokens.IDENT);
//TODO: CSS3 Paged Media says only "left", "center", and "right" are allowed
return tokenStream.token().value;
* '{' S* declaration [ ';' S* declaration ]* '}' S*
var tokenStream = this._tokenStream,
tokenStream.mustMatch(Tokens.FONT_FACE_SYM);
line = tokenStream.token().startLine;
col = tokenStream.token().startCol;
this._readDeclarations(true);
* '{' S* declaration? [ ';' S* declaration? ]* '}' S*
var tokenStream = this._tokenStream,
tokenStream.mustMatch(Tokens.VIEWPORT_SYM);
line = tokenStream.token().startLine;
col = tokenStream.token().startCol;
this._readDeclarations(true);
* _document_function [ ',' S* _document_function ]* S*
var tokenStream = this._tokenStream,
tokenStream.mustMatch(Tokens.DOCUMENT_SYM);
token = tokenStream.token();
if (/^@\-([^\-]+)\-/.test(token.value)) {
functions.push(this._document_function());
while (tokenStream.match(Tokens.COMMA)) {
functions.push(this._document_function());
tokenStream.mustMatch(Tokens.LBRACE);
switch (tokenStream.peek()) {
case Tokens.FONT_FACE_SYM:
case Tokens.VIEWPORT_SYM:
case Tokens.KEYFRAMES_SYM:
case Tokens.DOCUMENT_SYM:
ok = Boolean(this._ruleset());
tokenStream.mustMatch(Tokens.RBRACE);
token = tokenStream.token();
_document_function: function() {
var tokenStream = this._tokenStream,
if (tokenStream.match(Tokens.URI)) {
value = tokenStream.token().value;
value = this._function();
_operator: function(inFunction) {
* operator (outside function)
* : '/' S* | ',' S* | /( empty )/
* operator (inside function)
* : '/' S* | '+' S* | '*' S* | '-' S* /( empty )/
var tokenStream = this._tokenStream,
if (tokenStream.match([Tokens.SLASH, Tokens.COMMA]) ||
(inFunction && tokenStream.match([Tokens.PLUS, Tokens.STAR, Tokens.MINUS]))) {
token = tokenStream.token();
return token ? PropertyValuePart.fromToken(token) : null;
_combinator: function() {
* : PLUS S* | GREATER S* | TILDE S* | S+
var tokenStream = this._tokenStream,
if (tokenStream.match([Tokens.PLUS, Tokens.GREATER, Tokens.TILDE])) {
token = tokenStream.token();
value = new Combinator(token.value, token.startLine, token.startCol);
_unary_operator: function() {
var tokenStream = this._tokenStream;
if (tokenStream.match([Tokens.MINUS, Tokens.PLUS])) {
return tokenStream.token().value;
var tokenStream = this._tokenStream,
//check for star hack - throws error if not allowed
if (tokenStream.peek() === Tokens.STAR && this.options.starHack) {
token = tokenStream.token();
if (tokenStream.match(Tokens.IDENT)) {
token = tokenStream.token();
tokenValue = token.value;
//check for underscore hack - no error if not allowed because it's valid CSS syntax
if (tokenValue.charAt(0) === "_" && this.options.underscoreHack) {
tokenValue = tokenValue.substring(1);
value = new PropertyName(tokenValue, hack, (line||token.startLine), (col||token.startCol));
//Augmented with CSS3 Selectors
* '{' S* declaration? [ ';' S* declaration? ]* '}' S*
var tokenStream = this._tokenStream,
* Error Recovery: If even a single selector fails to parse,
* then the entire ruleset should be thrown away.
selectors = this._selectors_group();
if (ex instanceof SyntaxError && !this.options.strict) {
//skip over everything until closing brace
tt = tokenStream.advance([Tokens.RBRACE]);
if (tt === Tokens.RBRACE) {
//if there's a right brace, the rule is finished so don't do anything
//otherwise, rethrow the error because it wasn't handled properly
//not a syntax error, rethrow it
//trigger parser to continue
//if it got here, all selectors parsed
this._readDeclarations(true);
_selectors_group: function() {
* : selector [ COMMA S* selector ]*
var tokenStream = this._tokenStream,
selector = this._selector();
selectors.push(selector);
while (tokenStream.match(Tokens.COMMA)) {
selector = this._selector();
selectors.push(selector);
this._unexpectedToken(tokenStream.LT(1));
return selectors.length ? selectors : null;
* : simple_selector_sequence [ combinator simple_selector_sequence ]*
var tokenStream = this._tokenStream,
//if there's no simple selector, then there's no selector
nextSelector = this._simple_selector_sequence();
if (nextSelector === null) {
selector.push(nextSelector);
combinator = this._combinator();
if (combinator !== null) {
selector.push(combinator);
nextSelector = this._simple_selector_sequence();
//there must be a next selector
if (nextSelector === null) {
this._unexpectedToken(tokenStream.LT(1));
//nextSelector is an instance of SelectorPart
selector.push(nextSelector);
//if there's not whitespace, we're done
if (this._readWhitespace()) {