w3c.css.parser.analyzer.CssParser.jj Maven / Gradle / Ivy
/* -*-java-extended-*-
*
* (c) COPYRIGHT MIT and INRIA, 1997.
* Please first read the full copyright statement in file COPYRIGHT.html
*
* $Id$
*
*/
options {
IGNORE_CASE = true;
STATIC = false;
UNICODE_INPUT = true;
/*
DEBUG_TOKEN_MANAGER = true;
DEBUG_PARSER = true;
*/
}
PARSER_BEGIN(CssParser)
package org.w3c.css.parser.analyzer;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.net.URL;
import org.w3c.css.values.CssValue;
import org.w3c.css.values.CssOperator;
import org.w3c.css.values.CssAngle;
import org.w3c.css.values.CssCheckableValue;
import org.w3c.css.values.CssExpression;
import org.w3c.css.values.CssString;
import org.w3c.css.values.CssURL;
import org.w3c.css.values.CssLength;
import org.w3c.css.values.CssNumber;
import org.w3c.css.values.CssAttr;
import org.w3c.css.values.CssBracket;
import org.w3c.css.values.CssCalc;
import org.w3c.css.values.CssClamp;
import org.w3c.css.values.CssColor;
import org.w3c.css.values.CssComparator;
import org.w3c.css.values.CssFlexibleLength;
import org.w3c.css.values.CssFunction;
import org.w3c.css.values.CssFrequency;
import org.w3c.css.values.CssHashIdent;
import org.w3c.css.values.CssIdent;
import org.w3c.css.values.CssImage;
import org.w3c.css.values.CssMax;
import org.w3c.css.values.CssMin;
import org.w3c.css.values.CssPercentage;
import org.w3c.css.values.CssSwitch;
import org.w3c.css.values.CssTime;
import org.w3c.css.values.CssUnicodeRange;
import org.w3c.css.values.CssResolution;
import org.w3c.css.values.CssRatio;
import org.w3c.css.values.CssSemitone;
import org.w3c.css.values.CssTypes;
import org.w3c.css.values.CssVolume;
import org.w3c.css.properties.css.CssProperty;
import org.w3c.css.parser.CssError;
import org.w3c.css.parser.CssErrorToken;
import org.w3c.css.parser.CssSelectors;
import org.w3c.css.parser.CssParseException;
import org.w3c.css.parser.AtRule;
import org.w3c.css.atrules.svg.AtRuleColorProfile;
import org.w3c.css.atrules.css.AtRuleCounterStyle;
import org.w3c.css.atrules.css.AtRuleFontFace;
import org.w3c.css.atrules.css.AtRuleKeyframes;
import org.w3c.css.atrules.css.AtRuleMedia;
import org.w3c.css.atrules.css.media.MediaFeature;
import org.w3c.css.atrules.css.media.MediaRangeFeature;
import org.w3c.css.atrules.css.AtRulePage;
import org.w3c.css.atrules.css.AtRulePhoneticAlphabet;
import org.w3c.css.atrules.css.AtRulePreference;
import org.w3c.css.atrules.css.AtRuleSupports;
import org.w3c.css.atrules.css.supports.SupportsFeature;
import org.w3c.css.atrules.css.AtRuleViewport;
import org.w3c.css.util.ApplContext;
import org.w3c.css.util.CssProfile;
import org.w3c.css.util.CssVersion;
import org.w3c.css.util.InvalidParamException;
import org.w3c.css.util.WarningParamException;
import org.w3c.css.util.Util;
import org.w3c.css.selectors.AdjacentSiblingSelector;
import org.w3c.css.selectors.AttributeSelector;
import org.w3c.css.selectors.ChildSelector;
import org.w3c.css.selectors.ClassSelector;
import org.w3c.css.selectors.DescendantSelector;
import org.w3c.css.selectors.GeneralSiblingSelector;
import org.w3c.css.selectors.IdSelector;
import org.w3c.css.selectors.TypeSelector;
import org.w3c.css.selectors.UniversalSelector;
import org.w3c.css.selectors.attributes.AttributeAny;
import org.w3c.css.selectors.attributes.AttributeBegin;
import org.w3c.css.selectors.attributes.AttributeExact;
import org.w3c.css.selectors.attributes.AttributeOneOf;
import org.w3c.css.selectors.attributes.AttributeStart;
import org.w3c.css.selectors.attributes.AttributeSubstr;
import org.w3c.css.selectors.attributes.AttributeSuffix;
/**
* A CSS parser
*
* @author Philippe Le Hegaret, Sijtsche Smeman, Yves Lafon
*/
public abstract class CssParser {
private static char hexdigits[] = { '0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f' };
// the current atRule
protected AtRule atRule;
protected boolean mediaDeclaration = false;
/**
* The URL of the document
*/
protected URL url;
protected ApplContext ac;
protected boolean incompatible_error;
/**
* The current context recognized by the parser (for errors).
*/
protected ArrayList currentContext;
/**
* The current property recognized by the parser (for errors).
*/
protected String currentProperty;
/**
* true
if the parser should recognized Aural properties,
* false
otherwise.
*/
protected boolean mode;
/**
* true
if the parser had recognize a rule,
* false
otherwise.
*/
protected boolean markRule;
private boolean reinited = false;
private boolean charsetdeclared = false;
// to be able to remove a ruleset if the selector is not valid
protected boolean validSelector = true;
/**
* The ac for handling errors and warnings.
*
* @param ac the new ac for the parser.
*/
public final void setApplContext(ApplContext ac) {
this.ac = ac;
}
/**
* Set the attribute atRule
*
* @param atRule the new value for the attribute
*/
public void setAtRule(AtRule atRule) {
this.atRule = atRule;
}
/**
* Set the attribute mediaDeclaration
*
* @param mediadeclaration indicator if in a media expression list or not
*/
public void setMediaDeclaration(boolean mediadeclaration) {
this.mediaDeclaration = mediadeclaration;
}
/**
* Returns the attribute mediaDeclaration
*
* @return the value of the attribute
*/
public boolean hasMediaDeclaration() {
return mediaDeclaration;
}
/**
* Returns the attribute atRule
*
* @return the value of the attribute
*/
public AtRule getAtRule() {
return atRule;
}
/**
* Reinitialized the parser.
*
* @param stream the stream data to parse.
* @param ac the new ac to use for parsing.
*/
public void ReInitWithAc(InputStream stream, ApplContext ac,
String charset)
{
InputStream is = /*new CommentSkipperInputStream(stream);*/stream;
if (charset == null) {
charset = "iso-8859-1";
}
InputStreamReader isr = null;
try {
isr = new InputStreamReader(is, charset);
} catch (UnsupportedEncodingException uex) {
isr = new InputStreamReader(is);
}
// reinit, it can not happen...
// ...in theory ;)
ReInit(isr);
markRule = false;
reinited = true;
setApplContext(ac);
}
/* utilities for a parser */
/**
* Call by the import statement.
*
* @param url The style sheet where this import statement appears.
* @param file the file name in the import
*/
public abstract void handleImport(URL url, String file,
boolean is_url, AtRuleMedia media);
/**
* Call by the namespace declaration statement.
*
* @param url The style sheet where this namespace statement appears.
* @param file the file/url name in the namespace declaration
*/
public abstract void handleNamespaceDeclaration(URL url, String prefix,
String file,
boolean is_url);
/**
* Call by the at-rule statement.
*
* @param ident The ident for this at-rule (for example: 'font-face')
* @param string The string associate to this at-rule
* @see org.w3c.css.parser.analyzer.Couple
*/
public abstract void handleAtRule(String ident, String string);
/* added by Sijtsche Smeman */
public abstract void addCharSet(String charset) throws ParseException;
public abstract void newAtRule(AtRule atRule);
public abstract void endOfAtRule();
public abstract void setImportant(boolean important);
public abstract void setSelectorList(ArrayList selectors);
public abstract void addProperty(ArrayList properties);
public abstract void endOfRule();
public abstract void removeThisRule();
public abstract void removeThisAtRule();
/**
* Assign an expression to a property. This function create a new property
* with property
and assign to it the expression with the
* importance. Don't forget to set informations too.
*
* A subclass must provide an implementation of this method.
*
* @param property the name of the property
* @param values the expression representation of values
* @param important true
if values are important
*
* @return null
or a property
*
* @see org.w3c.css.properties.css.CssProperty
*/
public abstract CssProperty handleDeclaration(String property,
CssExpression values,
boolean important)
throws InvalidParamException;
/**
* Assign an expression to a mediafeature.
* This function create a new mediafeature
* with mediaFeature
and assign to it the expression.
*
* A subclass must provide an implementation of this method.
*
* @param mediaFeature the name of the media feature
* @param expr the expression representation of values
*
* @return null
or a property
*
* @see org.w3c.css.properties.css.CssProperty
*/
public abstract MediaFeature handleMediaFeature(AtRuleMedia rule,
String mediaFeature,
CssExpression expr)
throws InvalidParamException;
/**
* Adds a ArrayList of properties to a selector.
*
* A subclass must provide an implementation of this method.
*
* @param selector the selector
* @param declarations Properties to associate with contexts
*/
public abstract void handleRule(CssSelectors selector,
ArrayList declarations);
/*Added by Sijtsche Smeman */
/**
* Returns the source file of the style sheet
*/
public final String getSourceFile() {
return getURL().toString();
}
/**
* Returns the current line in the style sheet
*/
public final int getLine() {
//return token.beginLine;
return 0;
}
/**
* Returns the beginLine in the style sheet
*/
public final int getBeginLine() {
return token.beginLine;
}
/**
* Returns the beginColumn in the style sheet
*/
public final int getBeginColumn() {
return token.beginColumn;
}
/**
* Returns the endLine in the style sheet
*/
public final int getEndLine() {
return token.endLine;
}
/**
* Returns the endColumn in the style sheet
*/
public final int getEndColumn() {
return token.endColumn;
}
/**
* Set the URL of the style sheet.
*
* @param url The URL for the style sheet
*/
public final void setURL(URL url) {
this.url = url;
}
public final URL getURL() {
return url;
}
/**
* Return the next selector from the inputstream
*/
public CssSelectors parseSelector() throws ParseException {
return externalSelector();
}
/**
* Return the next @media rule from the inputstream
*/
public AtRuleMedia parseMediaDeclaration() throws ParseException {
AtRuleMedia newRule = AtRuleMedia.getInstance(ac.getCssVersion());
mediaquerylist(newRule);
return newRule;
}
/*
* Add a value to an expression
*/
private void setValue(CssValue v, CssExpression expr,
char operator, Token n, int token)
throws ParseException {
if ( token == FUNCTION ) {
if ( v.getType() == CssTypes.CSS_FUNCTION ) {
CssFunction f = (CssFunction) v;
if (f.getParameters().hasVendorExtensions()) {
expr.markVendorExtension();
}
if (f.getParameters().hasCssHack()) {
expr.markCssHack();
}
}
}
if (n != null) {
if (ac.getCssVersion() == CssVersion.CSS1 &&
(n.image).equals("inherit")) {
incompatible_error = true;
}
String val = addOperator(operator, n.image);
if (n.kind == CssParserConstants.IDENT) {
String s = convertIdent(val);
if ('-' == s.charAt(0)) {
expr.markVendorExtension();
}
v.set(convertIdent(val), ac);
} else if (n.kind == CssParserConstants.STRING) {
v.set(val, ac);
} else {
v.set(val, ac);
}
}
expr.addValue(v);
}
/*
* Error control
*/
private void addError(Exception e, String skippedText) {
if (Util.onDebug) {
System.err.println(e.getMessage());
e.printStackTrace();
}
CssParseException ex = new CssParseException(e);
ex.setSkippedString(skippedText);
ex.setProperty(currentProperty);
ex.setContexts(currentContext);
CssError error = new CssError(getSourceFile(), getBeginLine(),
getBeginColumn(), getEndLine(), getEndColumn(), ex);
ac.getFrame().addError(error);
}
/*
* Error control 2
*/
private void addError(Exception e, CssExpression exp) {
if (Util.onDebug) {
System.err.println(e.getMessage());
e.printStackTrace();
}
// if ((exp != null) && (exp.getCount() != 0)) {
CssParseException ex = new CssParseException(e);
ex.setExp(exp);
ex.setProperty(currentProperty);
ex.setContexts(currentContext);
CssError error = new CssError(getSourceFile(), getBeginLine(),
getBeginColumn(), getEndLine(), getEndColumn(), ex);
ac.getFrame().addError(error);
// }
}
private void addParseError(ParseException e, String skipped) {
if (Util.onDebug) {
System.err.println(e.getMessage());
e.printStackTrace();
}
CssErrorToken err = new CssErrorToken(e, skipped);
ac.getFrame().addError(err);
}
private static String addOperator(char operator, String value) {
return (' ' == operator) ? value : operator+value;
}
}
PARSER_END(CssParser)
/*
* The tokenizer
*/
SPECIAL_TOKEN :
{
< COMMENT : "/*" ( ~["*"] )* ( "*" )+ ( ~["/", "*"] ( ~["*"] )* ( "*" )+ )* "/" >
}
TOKEN [IGNORE_CASE] : /* basic tokens */
{
< #H : ["0"-"9", "a"-"f"] >
| < #NONASCII : ["\u0080"-"\uFFFF"] >
| < #UNICODE : "\\" ( )? ( )? ( )? ( )? ( )?
( "\r\n" | [ " ", "\t" , "\n" , "\r", "\f" ] )? >
| < #ESCAPE : | ( "\\" ~[ "\r", "\n", "\f", "0"-"9", "a"-"f" ] ) >
| < #NMSTART : [ "a"-"z", "_" ] | | >
| < #NMCHAR : ["a"-"z", "0"-"9", "-", "_"] | | >
| < #STRING1 : "\"" ( ~[ "\n", "\r", "\f", "\\", "\"" ] | "\\" | )* "\"" >
| < #STRING2 : "\'" ( ~[ "\n", "\r", "\f", "\\", "\'" ] | "\\" | )* "\'" >
| < #INVALID1 : "\"" ( ~[ "\n", "\r", "\f", "\\", "\"" ] | "\\" | )* >
| < #INVALID2 : "\'" ( ~[ "\n", "\r", "\f", "\\", "\'" ] | "\\" | )* >
| < #_IDENT : ( )? ( )* >
| < #NAME : ( )+ >
| < #NUM : ( ["0"-"9"] )+ | ( ["0"-"9"] )* "." ( ["0"-"9"] )+ >
| < #_STRING : | >
| < #_INVALID : | >
| < #_URL : ( [ "!", "#", "$", "%", "&", "*"-"[", "]"-"~" ] | | )* >
| < #_S : ( [ " ", "\t" , "\n" , "\r", "\f" ] ) ( | [ " ", "\t" , "\n" , "\r", "\f" ] )* >
| < #_W : ( <_S> )? >
| < #NL : ( "\n" | "\r\n" | "\r" | "\f" ) >
}
/*
* The _S definition is not ( [ " ", "\t" , "\n" , "\r", "\f" ] ) + as we need to add support
* for the unput(' ') (see http://www.w3.org/TR/CSS21/grammar.html#scanner )
*/
TOKEN :
{
< S : ( <_S> ) >
}
TOKEN :
{
< CDO : "" >
| < INCLUDES : "=" >
| < DASHMATCH : "|=" >
}
TOKEN :
{
< LBRACE : <_W> "{" >
| < PLUS : <_W> "+" >
| < MINUS : "-" >
| < GREATER : <_W> ">" >
| < GREATEREQ : <_W> ">=" >
| < COMMA : <_W> "," >
| < TILDE : <_W> "~" >
}
TOKEN [IGNORE_CASE] :
{
< AND : "and" >
| < OR : "or" >
}
TOKEN [IGNORE_CASE] :
{
< ONLY : "only" >
| < NOT : "not" >
}
TOKEN :
{
>
| >
| >
| >
| >
|
}
TOKEN :
{
( )* >
}
TOKEN :
{
< RBRACE : "}">
| < PREFIXMATCH : "^=" >
| < SUFFIXMATCH : "$=" >
| < SUBSTRINGMATCH : "*=" >
| < EQ : "=" >
| < SEMICOLON : ";" >
| < DIV : "/" >
| < LBRACKET : "[" >
| < RBRACKET : "]" >
| < ANY : "*" >
| < DOT : "." >
| < LPARAN : ")" >
| < RPARAN : "(">
}
TOKEN :
{
< COLON : ":" >
}
TOKEN [IGNORE_CASE] :
{
< URL : "url(" ( )* ( | <_URL> ) ( )* >
}
TOKEN [IGNORE_CASE] :
{
< RELFONTLENGTH : "em"
| "ex"
| "cap"
| "ch"
| "ic"
| "lh"
| "rlh"
| "rem" >
| "vw"
| "vh"
| "vi"
| "vb"
| "vmin"
| "vmax" >
| "cm"
| "mm"
| "q"
| "in"
| "pt"
| "pc"
| "px" >
| < FLEX : "fr" >
| < ANGLE : ( "deg" | "grad" | "rad" | "turn" ) >
| < SPL : "db" >
| < ST : "st" >
| < TIME : ( "ms" | "s" ) >
| < FREQ : ( "Hz" | "kHz" ) >
| < RESOLUTION : ( "dpi" | "dpcm" | "dppx" | "x") >
| < DIMEN_9 : ( )* "\\9" >
| < DIMEN : ( )* >
| < PERCENTAGE : "%" >
| < NUMBER : >
}
TOKEN [IGNORE_CASE] :
{
< IMPORTANT_SYM : "!" ( <_W> )* "important" >
| < IMPORTANT_NOT : "!" ( <_W> )* "ie" ( [ "7", "9" ] )? >
}
TOKEN :
{
}
/* RESERVED ATRULE WORDS */
TOKEN :
{
< CHARSET_SYM : "@charset" >
}
TOKEN [IGNORE_CASE] :
{
< PAGE_SYM : "@page" >
| < PAGE_TOP_LEFT_CORNER : "@top-left-corner" >
| < PAGE_TOP_LEFT : "@top-left" >
| < PAGE_TOP_CENTER : "@top-center" >
| < PAGE_TOP_RIGHT : "@top-right" >
| < PAGE_TOP_RIGHT_CORNER : "@top-right-corner" >
| < PAGE_BOTTOM_LEFT_CORNER : "@bottom-left-corner" >
| < PAGE_BOTTOM_LEFT : "@bottom-left" >
| < PAGE_BOTTOM_CENTER : "@bottom-center" >
| < PAGE_BOTTOM_RIGHT : "@bottom-right" >
| < PAGE_BOTTOM_RIGHT_CORNER : "@bottom-right-corner" >
| < PAGE_LEFT_TOP : "@left-top" >
| < PAGE_LEFT_MIDDLE : "@left-middle" >
| < PAGE_LEFT_BOTTOM : "@left-bottom" >
| < PAGE_RIGHT_TOP : "@right-top" >
| < PAGE_RIGHT_MIDDLE : "@right-middle" >
| < PAGE_RIGHT_BOTTOM : "@right-bottom" >
}
TOKEN [IGNORE_CASE] :
{
< IMPORT_SYM : "@import">
| < NAMESPACE_SYM : "@namespace">
| < MEDIA_SYM : "@media" >
| < FONT_FACE_SYM : "@font-face" >
| < KEYFRAMES_SYM : "@keyframes" >
| < PREF_SYM : "@preference" >
| < COLOR_PROFILE : "@color-profile" >
| < A_COUNTER : "@counter" >
| < COUNTER_STYLE_SYM : "@counter-style" >
| < PHONETIC_ALPHABET_SYM : "@phonetic-alphabet" >
| < SUPPORTS_SYM : "@supports" >
| < VIEWPORT_SYM : "@viewport" >
| < ATKEYWORD : "@" >
}
TOKEN [IGNORE_CASE] :
{
< #RANGE0 : >
| < #RANGE1 : ( "?" )? >
| < #RANGE2 : ( "?" )? ( "?" )? >
| < #RANGE3 : ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE4 : ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE5 : ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE6 : "?" ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? >
| < #RANGE : | |
| | | | >
| < #UNI : ( )? ( )? ( )? ( )? ( )? >
| < UNICODERANGE : "U+" | "U+" "-" >
}
TOKEN:
{
< CLASS : "." >
}
/* FIXED, added a spacial case for lang pseudoclass */
TOKEN [IGNORE_CASE] :
{
< FUNCTIONLANG : "lang(" >
|
|
|
|
|
|
|
}
TOKEN :
{
< FUNCTION : >
}
/* Quick and dirty way to catch HTML tags starting CSS documents
(common mistake) */
TOKEN:
{
)* ( )*
( "=" ( | ) ( )* )*
">" >
| )* ( )* ">" >
}
//
//TOKEN :
//{ /* avoid token manager error */
// < UNKNOWN : ~[] >
//}
/*
* The grammar of CSS2
*/
/**
* The main entry for the parser.
*
* @exception ParseException exception during the parse
*/
void parserUnit() :
{
Token n = null;
}
{
try {
// used as an error recovery for HTML tags in CSS pages
( ( n= | n= ) {
addError (new ParseException(ac.getMsg().getString("generator.dontmixhtml")), n.image);
}
)*
( charset() )* // * instead of ? to capture the reinit part
( | | )*
( importDeclaration() ( ignoreStatement() ) )*
( namespaceDeclaration() ( ignoreStatement() ) )*
afterImportDeclaration()
} catch (TokenMgrError err) {
addError (new ParseException(ac.getMsg().getString("generator.unrecognize")),
err.getMessage());
}
}
Token ident() : {
Token n = null;
}
{
( n= | n= | n= | n= | n= ) {
return n;
}
}
void charset() :
{
Token n = null;
Token charsetToken = null;
Token space1Token = null;
Token space2Token = null;
Token semicolonToken = null;
int nb_S = 0;
CssVersion version = ac.getCssVersion();
}
{
try {
charsetToken= ( space1Token= { nb_S++;} )*
n= ( space2Token= )* semicolonToken=
{
if (charsetdeclared && !reinited) {
throw new ParseException(
ac.getMsg().getString("parser.charset"));
}
// the @charset must be at the beginning of the document
if(charsetToken.beginLine != 1 ||
charsetToken.beginColumn != 1) {
throw new ParseException(
ac.getMsg().getString("parser.charset"));
}
if (version == CssVersion.CSS1) {
throw new ParseException(ac.getMsg().getString(
"parser.charsetcss1"));
}
// stricter rule for CSS21 and soon for CSS3
// if equal of above CSS21
if (version.compareTo(CssVersion.CSS21) >= 0) {
// single space before
// case sensitive
// no space before ;
// no comments
// string must start with "
if ( (nb_S != 1) ||
(!"@charset".equals(charsetToken.image)) ||
(!" ".equals(space1Token.image)) ||
(space2Token != null &&
!"".equals(space2Token.image)) ||
(space1Token.specialToken != null) ||
(n.specialToken != null) ||
(semicolonToken.specialToken != null) ||
(n.image.charAt(0) != '\"')
) {
throw new ParseException(ac.getMsg().getString(
"parser.charsetspecial"));
}
}
if (!charsetdeclared) {
addCharSet(n.image.substring(1, n.image.length()-1));
charsetdeclared = true;
} else {
reinited = false;
}
}
} catch (Exception e) {
String skip = charsetToken +
((space1Token == null) ? "" : space1Token.image) +
n +
((space2Token == null) ? "" : space2Token.image) +
";";
addError(e, skip);
}
}
void nested_at_rules() : {
}
{
( media() | page() | fontFace() | keyframes() | preference() | viewport()
| colorprofile() | counterstyle() | phoneticAlphabet() | supports() | atRuleDeclaration() )
}
void afterImportDeclaration() :
{String ret; }
{
( ( ruleSet() | nested_at_rules() | ret=skipStatement()
{ if ((ret == null) || (ret.length() == 0)) {
return;
}
// quite ugly but necessary to avoid probably a lot of changes in the
// grammar, still having a beautiful error message
else if (ret.startsWith("@charset")) {
ParseException e =
new ParseException(ac.getMsg().getString("parser.charset"));
addError(e, ret);
} else if (ret.startsWith("@import")) {
ParseException e =
new ParseException(ac.getMsg().getString("parser.import_not_allowed"));
addError(e, ret);
} else {
ParseException e =
new ParseException(ac.getMsg().getString("generator.unrecognize"));
addError(e, ret);
}
}
) ignoreStatement() )*
}
void ignoreStatement() :
{}
{
( ( | ) ( )* )*
}
void namespaceDeclaration() :
{
Token n=null;
Token v=null;
boolean is_url; /* for formatting */
String nsname;
String prefix = null;
CssValue val;
}
{
// FIXME add namespaces in context to match when a definition happens
(
( )*
( n=ident() {
prefix = convertIdent(n.image);
}
( )* )?
( v= {
is_url = false;
nsname = v.image.substring(1, v.image.length()-1);
}
| v= {
is_url = true;
val = new CssURL();
((CssURL) val).set(v.image, ac, url);
nsname = (String) val.get();
if ((nsname.charAt(0) == '"')
|| (nsname.charAt(0) == '\'')) {
nsname = nsname.substring(1, nsname.length()-1);
}
}
)
( )*
( )*
) {
// If less than CSS 3
if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) {
addError(new InvalidParamException("at-rule", "@namespace", ac),
(n==null)?"default":n.toString());
} else {
if (v != null) {
handleNamespaceDeclaration(getURL(), prefix, nsname, is_url);
}
}
}
}
/**
* The import statement
*
* @exception ParseException exception during the parse
*/
void importDeclaration() :
{Token n;
AtRuleMedia media = AtRuleMedia.getInstance(ac.getCssVersion());
CssValue val;
String importFile;
boolean is_url = false;
}
{
try {
( )*
( n= {
importFile = n.image.substring(1, n.image.length() -1);
is_url = false;
}
| n= {
val = new CssURL();
((CssURL) val).set(n.image, ac, url);
importFile = (String) val.get();
if ((importFile.charAt(0) == '"')
|| (importFile.charAt(0) == '\'')) {
importFile = importFile.substring(1, importFile.length()-1);
}
is_url = true;
}
)
( )*
( mediaquerylist(media) )?
( )*
{
handleImport(getURL(), importFile, is_url, media);
}
} catch (ParseException e) {
addError(e, skipStatement());
}
}
/**
* @exception ParseException exception during the parse
*/
AtRuleMedia media() :
{
AtRule old = getAtRule();
AtRuleMedia newRule = AtRuleMedia.getInstance(ac.getCssVersion());
setAtRule(newRule);
Token n;
CssProperty p = null;
boolean isCss1 = (ac.getCssVersion() == CssVersion.CSS1);
boolean emptyList = true;
int begl = 0, begc = 0, endl = 0, endc = 0;
}
{
try {
n= {
begl = getBeginLine();
begc = getBeginColumn();
} ( )*
( mediaquerylist(newRule)
{
String media = getAtRule().toString();
emptyList = false;
if (ac.getMedium() != null &&
!(media.equals(ac.getMedium())) &&
!(ac.getMedium().equals("all"))) {
ac.getFrame().addWarning("noothermedium", getAtRule().toString());
}
if (isCss1) {
skipStatement();
addError(new InvalidParamException("noatruleyet", "", ac),
getAtRule().toString());
} else {
newAtRule(getAtRule());
}
}
)?
{ endl = getEndLine() ; endc = getEndColumn() ; } ( )* ( ruleSet() | nested_at_rules() )* ( )*
{
if (!isCss1) {
endOfAtRule();
}
}
} catch (ParseException e) {
if (!isCss1) {
addError(e, skipStatement());
}
newRule = null;
} finally {
if (emptyList && ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) {
ac.getFrame().addError(new CssError(getSourceFile(), begl, begc, endl, endc,
new InvalidParamException("emptymedia", ac)));
}
setAtRule(old);
return newRule;
}
}
void ratio(CssExpression exp, char operator) :
{
Token w,h,n;
}
{
( w= ( )* ( )* h= ) {
StringBuilder sb = new StringBuilder();
sb.append(w.image).append('/').append(h.image);
n = Token.newToken(w.kind, sb.toString());
setValue(new CssRatio(), exp, operator, n, NUMBER);
}
}
void mediaquerylist(AtRuleMedia mediaRule) :
{
}
{
mediaquery(mediaRule)
( ( )* mediaquery(mediaRule) )*
}
void mediaquery(AtRuleMedia mediaRule) :
{
Token n;
String mediarestrictor = null;
}
{
( LOOKAHEAD(3) mediacondition(mediaRule, true, null) |
( ( ( n= | n= ) { mediarestrictor = convertIdent(n.image); } ( )* )? n= { mediaRule.addMedia(mediarestrictor, convertIdent(n.image), ac); } ( )* ( n= { mediarestrictor = convertIdent(n.image); } ( )* mediaconditionwithoutor(mediaRule, false, mediarestrictor) )? ) )
}
void mediacondition(AtRuleMedia mediaRule, boolean defaultMedia, String comb) :
{
Token n;
String combinator = null;
}
{
( n= { combinator = convertIdent(n.image); } ( )* mediainparens(mediaRule, defaultMedia, combinator) ) |
( mediainparens(mediaRule, defaultMedia, null) ( ( n= { combinator = convertIdent(n.image); } ( )* mediainparens(mediaRule, false, combinator) )+ | ( n= { combinator = convertIdent(n.image); } ( )* mediainparens(mediaRule, false, combinator) )+ )? )
}
void mediaconditionwithoutor(AtRuleMedia mediaRule, boolean defaultMedia, String comb) :
{
Token n;
String mediarestrictor = null;
}
{
( n= { mediarestrictor = convertIdent(n.image); } ( )* mediainparens(mediaRule, defaultMedia, mediarestrictor) ) |
( mediainparens(mediaRule, defaultMedia, comb) ( n= { mediarestrictor = convertIdent(n.image); } ( )* mediainparens(mediaRule, defaultMedia, mediarestrictor) )* )
}
void mediainparens(AtRuleMedia mediaRule, boolean defaultMedia, String comb) :
{
CssExpression val = null;
String mediaFeatureName = null;
Token n;
}
{
( LOOKAHEAD(4) ( ( )* mediacondition(mediaRule, defaultMedia, comb) ( )* ) | LOOKAHEAD(5) mediarange(mediaRule, defaultMedia, comb) | mediaexpression(mediaRule, defaultMedia, comb) )
}
void mediaexpression(AtRuleMedia mediaRule, boolean defaultMedia, String comb) :
{
CssExpression val = null;
String mediaFeatureName = null;
Token n;
}
{
( )* n= {
// here we add the default media if not present
if (defaultMedia) {
mediaRule.addMedia(null, null, ac);
}
mediaFeatureName = convertIdent(n.image); }
( )*
( ( )* val=mediaexpr() )? ( )* {
MediaFeature mf = handleMediaFeature(mediaRule, mediaFeatureName, val);
if (mf != null) {
mediaRule.addMediaFeature(mf, ac);
mf.setCombinator(comb);
// mf.setParens();
}
}
}
/**
* @exception ParseException exception during the parse
*/
void supports() :
{
AtRule old = getAtRule();
AtRuleSupports newRule = new AtRuleSupports();
setAtRule(newRule);
Token n;
CssProperty p = null;
CssVersion version = ac.getCssVersion();
boolean isCss1 = (version == CssVersion.CSS1);
SupportsFeature sf;
}
{
try {
n = ( )* {
if (version.compareTo(CssVersion.CSS3) < 0) {
skipStatement();
addError(new InvalidParamException("noatruleyet", "", ac),
getAtRule().toString());
}
}
//
// handle supports rules
//
sf=supports_condition(newRule) { newRule.addFeature(sf, ac); newAtRule(getAtRule()); }
( )* ( ruleSet() | nested_at_rules() )* ( )*
{
if (!isCss1) {
endOfAtRule();
}
}
} catch (ParseException e) {
if (!isCss1) {
addError(e, skipStatement());
}
newRule = null;
} finally {
setAtRule(old);
}
}
SupportsFeature supports_condition(AtRuleSupports supportsRule):
{
Token t;
SupportsFeature f = null;
SupportsFeature nf, mf;
boolean got_multi = false;
}
{
(