All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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 nullor 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 nullor 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; } { ( ( )+ nf=supports_condition_in_parens(supportsRule) { nf.setNot(true); return nf; } ) | ( nf=supports_condition_in_parens(supportsRule) ( ( ( )+ mf=supports_condition_in_parens(supportsRule) { if (f == null) { f = new SupportsFeature(); f.addFeature(nf); } mf.setAnd(true); f.addFeature(mf); } )+ | ( ( )+ mf=supports_condition_in_parens(supportsRule) { if (f == null) { f = new SupportsFeature(); f.addFeature(nf); } mf.setOr(true); f.addFeature(mf); } )+ )? ) { if (f == null) { return nf; } return f; } } SupportsFeature supports_condition_in_parens(AtRuleSupports supportsRule): { CssProperty p; SupportsFeature f = new SupportsFeature(); SupportsFeature nf; } { ( ( )* ( LOOKAHEAD(3) nf=supports_condition(supportsRule) { f.addFeature(nf); } | p=declaration() { f.setProperty(p); } ) ( )* ) { return f; } // | general_enclosed(supportsRule) } void general_enclosed(AtRuleSupports supportsRule): { } { ( | ) ( )* ( ident() )* ( )* } void unused_production_generic_syntax() : { CssExpression values = new CssExpression(); } { ( )* term(values) { } } void unused_production_definition() : { CssExpression values = new CssExpression(); } { ( )* term(values) { } } /** * @exception ParseException exception during the parse */ void page() : { Token n = null ; ArrayList collectv = new ArrayList(); CssSelectors s = new CssSelectors(ac); AtRule old = getAtRule() ; AtRulePage newRule = AtRulePage.getInstance(ac.getCssVersion()); setAtRule(newRule); s.setAtRule(getAtRule()); boolean isCss1 = (ac.getCssVersion() == CssVersion.CSS1); boolean gotContent = false; } { try { { if (!isCss1) newAtRule(newRule); } ( )* ( page_selector_list(newRule) )? ( )* ( gotContent = pageContent() ) ( )* { if (!isCss1) { if (gotContent) { endOfRule(); } endOfAtRule(); } } } catch (InvalidParamException ie) { if (!isCss1) { skipStatement(); removeThisAtRule(); ac.getFrame() .addError(new CssError(getSourceFile(), getBeginLine(), getBeginColumn(), getEndLine(), getEndColumn(), ie)); } } catch (ParseException e) { if (!isCss1) { removeThisAtRule(); addError(e, skipStatement()); } } finally { setAtRule(old); } } boolean pageContent() : { CssProperty prop; ArrayList v = null; ArrayList allv = new ArrayList(); CssSelectors s = new CssSelectors(ac); boolean gotContent = false; } { v=declarations() { if ( v != null ) { gotContent = true; allv.addAll(v); } } ( prefAtRule() { gotContent = true; } v=declarations() { if ( v != null ) { allv.addAll(v); } } )* { if ( allv.isEmpty() ) { if (!gotContent) ac.getFrame().addWarning("no-declaration"); } else { addProperty(allv); handleRule(s, allv); } return gotContent; } } ArrayList prefAtRule() : { Token n; ArrayList v; AtRulePage newRule = AtRulePage.getInstance(ac.getCssVersion()); AtRule old = getAtRule(); CssSelectors s = new CssSelectors(ac); } { // This only happen in CSS3 and beyond. try { ( n= | n= | n= | n= | n= | n= | n= | n= | n= | n= | n= | n= | n= | n= | n= | n= ) { ((org.w3c.css.atrules.css3.AtRulePage) newRule).setKeyword(convertIdent(n.image).substring(1)); setAtRule(newRule); s.setAtRule(getAtRule()); newAtRule(getAtRule()); } ( )* ( )* v=declarations() { if ( v == null ) { ac.getFrame().addWarning("no-declaration"); } else { addProperty(v); handleRule(s, v); } endOfRule(); endOfAtRule(); } ( )* { // FIXME return v; } } catch (ParseException e) { addError(e, skipStatement()); } finally { setAtRule(old); } } void page_selector_list(AtRulePage pageRule) : { Token n = null; Token p = null; Token o = null; boolean gotFirst = false; String ns = null; ArrayList ps = null; } { ( ( ( n=ident() { ns = convertIdent(n.image); } ) ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )* ) { pageRule.addSelector(ns, ps, ac); ns = null; ps = null; } | ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )+ { pageRule.addSelector(null, ps, ac); ps = null; } ) ( ) * ( ( )* ( ( ( n=ident() { ns = convertIdent(n.image); } ) ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )* ) { pageRule.addSelector(ns, ps, ac); ns = null; ps = null; } | ( ":" p=ident() { if (ps == null) { ps = new ArrayList(); } ps.add(":"+convertIdent(p.image)); } )+ { pageRule.addSelector(null, ps, ac); ps = null; } ) ( )* )* } /** * @exception ParseException exception during the parse */ CssSelectors keyframe_selector(CssSelectors next) : { CssSelectors selector = new CssSelectors(ac, next); selector.setAtRule(getAtRule()); Token n; Token op = null; } { try { ( n=ident() { CssIdent ident = new CssIdent(); ident.set(convertIdent(n.image), ac); AtRuleKeyframes.checkSelectorValue(ident, ac); selector.addType(new TypeSelector(ident.toString())); } | ( op= | op= )? n= { CssPercentage p = new CssPercentage(); if (op == null) { p.set(n.image, ac); } else { p.set(op.image+n.image, ac); } AtRuleKeyframes.checkSelectorValue(p, ac); selector.addType(new TypeSelector(n.image)); } ) ( )* { return selector; } } catch (InvalidParamException ie) { ac.getFrame() .addError(new CssError(getSourceFile(), getBeginLine(), getBeginColumn(), getEndLine(), getEndColumn(), ie)); Token t = getToken(1); StringBuilder s = new StringBuilder(); s.append(getToken(0).image); // eat until , { or EOF while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) { s.append(t.image); getNextToken(); t = getToken(1); } return null; } catch (ParseException e) { // TODO fix the error Token t = getToken(1); int _line = t.beginLine; int _col = t.beginColumn; StringBuilder s = new StringBuilder(); s.append(" ["); s.append(getToken(0).image); // eat until , { or EOF while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) { s.append(t.image); getNextToken(); t = getToken(1); } s.append(']'); addParseError(e, s.toString()); validSelector = true; return null; } } void keyframes() : { Token n; ArrayList v; AtRule old = getAtRule(); AtRuleKeyframes krule = new AtRuleKeyframes("-internal-"); setAtRule(krule); CssSelectors s; ArrayList sl; CssVersion version = ac.getCssVersion(); } { try { ( )+ n=ident() ( )* { krule.setName(convertIdent(n.image)); if (version.compareTo(CssVersion.CSS3) < 0) { skipStatement(); addError(new InvalidParamException("noatruleyet", "", ac), getAtRule().toString()); } else { newAtRule(getAtRule()); } } ( )* ( s=keyframe_selector(null) { sl = new ArrayList(); if (s != null) { s.setAtRule(getAtRule()); sl.add(s); } } ( ( )* s=keyframe_selector(null) { if (s != null) { s.setAtRule(getAtRule()); sl.add(s); } } )* ( )* v=declarations() ( )* { validSelector = (sl.size() != 0); if (validSelector) { if (v == null) { ac.getFrame().addWarning("no-declaration"); } else { boolean first = true; for (CssSelectors _s : sl) { if (first) { handleRule(_s, v); first = false; } else { ArrayList vcopy = new ArrayList(v.size()); for (CssProperty p : v) { vcopy.add(p.duplicate()); } handleRule(_s, vcopy); } } } setSelectorList(sl); endOfRule(); } } )* ( )* { endOfAtRule(); } } catch (ParseException e) { addError(e, skipStatement()); } finally { setAtRule(old); } } void fontFace() : { ArrayList v; AtRule old = getAtRule(); setAtRule(new AtRuleFontFace()); CssSelectors s = new CssSelectors(ac); s.setAtRule(getAtRule()); boolean isCss1 = (ac.getCssVersion() == CssVersion.CSS1); } { try { ( )* { if (isCss1) { skipStatement(); addError(new InvalidParamException("noatruleyet", "", ac), getAtRule().toString()); } else { newAtRule(getAtRule()); } } ( )* v=declarations() ( )* { if (!isCss1) { addProperty(v); endOfRule(); endOfAtRule(); } if (v == null) { ac.getFrame().addWarning("no-declaration"); } else { handleRule(s, v); } } } catch (ParseException e) { if (!isCss1) { addError(e, skipStatement()); } } finally { setAtRule(old); } } void colorprofile() : { ArrayList v; AtRule old = getAtRule(); setAtRule(new AtRuleColorProfile()); CssSelectors s = new CssSelectors(ac); s.setAtRule(getAtRule()); CssProfile profile = ac.getCssProfile(); boolean isSVG = ((profile == CssProfile.SVG) || (profile == CssProfile.SVGBASIC) || (profile == CssProfile.SVGTINY)); } { try { ( )* { if (!isSVG) { skipStatement(); addError(new InvalidParamException("onlysvg", "", ac), getAtRule().toString()); } else { newAtRule(getAtRule()); } } ( )* v=declarations() ( )* { if (isSVG) { addProperty(v); endOfRule(); endOfAtRule(); } if (v == null) { //ac.getFrame().addWarning("medialist"); } else { handleRule(s, v); } } } catch (ParseException e) { if (isSVG) { addError(e, skipStatement()); } } finally { setAtRule(old); } } void viewport() : { ArrayList v; AtRule old = getAtRule(); setAtRule(new AtRuleViewport()); CssSelectors s = new CssSelectors(ac); s.setAtRule(getAtRule()); CssVersion version = ac.getCssVersion(); } { try { ( )* { if (version.compareTo(CssVersion.CSS3) < 0) { skipStatement(); addError(new InvalidParamException("noatruleyet", "", ac), getAtRule().toString()); } else { newAtRule(getAtRule()); } } ( )* v=declarations() ( )* { if (version.compareTo(CssVersion.CSS3) >= 0) { addProperty(v); endOfRule(); endOfAtRule(); } if (v == null) { ac.getFrame().addWarning("no-declaration"); } else { handleRule(s, v); } } } catch (ParseException e) { if (version.compareTo(CssVersion.CSS3) < 0) { addError(e, skipStatement()); } } finally { setAtRule(old); } } void counterstyle() : { Token n; ArrayList v; AtRule old = getAtRule(); AtRuleCounterStyle csrule = new AtRuleCounterStyle(); setAtRule(csrule); CssSelectors s = new CssSelectors(ac);; CssVersion version = ac.getCssVersion(); } { try { ( )+ n=ident() ( )* { csrule.setName(convertIdent(n.image)); if (version.compareTo(CssVersion.CSS3) < 0) { skipStatement(); addError(new InvalidParamException("noatruleyet", "", ac), getAtRule().toString()); } else { newAtRule(getAtRule()); } } ( )* v=declarations() ( )* { if (version.compareTo(CssVersion.CSS3) >= 0) { addProperty(v); endOfRule(); endOfAtRule(); } if (v == null) { ac.getFrame().addWarning("no-declaration"); } else { handleRule(s, v); } } } catch (ParseException e) { addError(e, skipStatement()); } finally { setAtRule(old); } } void preference() : { ArrayList v; AtRule old = getAtRule(); setAtRule(new AtRulePreference()); CssSelectors s = new CssSelectors(ac); s.setAtRule(getAtRule()); boolean isCSS1 = (ac.getCssVersion() == CssVersion.CSS1); } { try { ( )* { if (isCSS1) { skipStatement(); addError(new InvalidParamException("noatruleyet", "", ac), getAtRule().toString()); } else { newAtRule(getAtRule()); } } ( )* v=declarations() ( )* { if (!isCSS1) { addProperty(v); endOfRule(); endOfAtRule(); } if (v == null) { ac.getFrame().addWarning("medialist"); } else { handleRule(s, v); } } } catch (ParseException e) { if (!isCSS1) { addError(e, skipStatement()); } } finally { setAtRule(old); } } void phoneticAlphabet() : { AtRule old = getAtRule(); AtRulePhoneticAlphabet alphabetrule = new AtRulePhoneticAlphabet(); setAtRule(alphabetrule); Token n; CssVersion version = ac.getCssVersion(); } { try { ( )* n= ( )* ";" { // FIXME comparison > CSS3 if (version.compareTo(CssVersion.CSS3) < 0) { skipStatement(); addError(new InvalidParamException("noatruleyet", "", ac), getAtRule().toString()); } alphabetrule.addAlphabet(convertIdent(n.image), ac); if ((version != CssVersion.CSS1) && (version != CssVersion.CSS2)) { newAtRule(getAtRule()); } } } catch (ParseException e) { if (version != CssVersion.CSS1) { addError(e, skipStatement()); } } finally { setAtRule(old); } } /** * @exception ParseException exception during the parse */ void atRuleDeclaration() : {Token n;} { n= { if (n.toString().charAt(1) == '-') { if (ac.getTreatVendorExtensionsAsWarnings()) { ac.getFrame() // .addWarning("at-rule", // n.toString()); } else { addAtRuleError(); } } else { addAtRuleError(); } skipStatement(); } } JAVACODE void addAtRuleError() { // ac.getFrame() .addError(new CssError(getSourceFile(), getBeginLine(), getBeginColumn(), getEndLine(), getEndColumn(), new InvalidParamException("at-rule", token, ac))); } /** * @exception ParseException exception during the parse */ void operator(CssExpression expr) : {} { ( ( { if (expr.getCount() > 0) expr.setOperator(','); } ) ( )* )? } /** * @exception ParseException exception during the parse */ char combinator() : { char connector = ' '; } { ( ( { connector = '+' ; } | { connector = '>' ; } | { connector = '~' ; } ) ( )* | ( )+ { connector = ' ' ; } ) { return connector; } } /** * @exception ParseException exception during the parse */ char unaryOperator() : {} { // FIXME | ? warning as is <_W>? "+" { return '-'; } | { return '+'; } } /** * @exception ParseException exception during the parse */ String property() : {Token n; Token hack= null; } { // ( hack? ident | hackedIdent ) ( )* ( (hack="!" | hack="$" | hack="%" | hack="&" | hack="`" | hack="?" | hack="<" | hack="|" | hack= | hack= | hack= | hack= | hack= | hack= | hack= | hack= | hack= | hack= | hack= | hack=
)? n=ident() | n=) ( )* { currentProperty = convertIdent(n.image); if (hack != null && !"".equals(hack)) { String hackp = hack.image+currentProperty; if (ac.getTreatCssHacksAsWarnings()) { ac.getFrame().addWarning("css-hack", hackp); return null; } else { throw new ParseException(String.format(ac.getMsg().getString("warning.css-hack"), hackp)); } } return currentProperty; } | ( n= | n= | n= ) { if (ac.getTreatCssHacksAsWarnings()) { ac.getFrame().addWarning("css-hack", n.image); // should we continue and validate the content, or skip ? currentProperty = convertIdent(n.image).substring(1); return null; } throw new ParseException(String.format(ac.getMsg().getString("warning.css-hack"), n.image)); } ( )* } /** * @exception ParseException exception during the parse */ void ruleSet() : { CssSelectors contextual; ArrayList context_set = new ArrayList(); ArrayList value_set = null; currentContext = context_set; } { try { contextual=selector() { if (contextual != null) { context_set.add(contextual); } } ( ( )* contextual=selector() { if (contextual != null) { context_set.add(contextual); } } )* { validSelector = (context_set.size() > 0); } ( )* value_set=declarations() ( )* { markRule = true; /* if (value_set == null) { ac.getFrame().addWarning("no-declaration"); } else {*/ if (value_set != null) { boolean first = true; for (CssSelectors sel : context_set) { if (first) { handleRule(sel, value_set); first = false; } else { // we need to duplicate properties in that case // as property holds reference to the selectors and it interact // badly with conflict detection int vsize = value_set.size(); ArrayList v = new ArrayList(vsize); for (CssProperty p : value_set) { v.add(p.duplicate()); } handleRule(sel, v); } } setSelectorList(context_set); endOfRule(); } currentContext = null; } } catch (ParseException e) { if ((ac.getCssProfile() != CssProfile.MOBILE) && !context_set.isEmpty()) { addError(e, skipStatement()); } } catch (TokenMgrError e) { addError(new ParseException(e.getMessage()), skipStatement()); } } ArrayList declarations() : { if(!validSelector) { validSelector = true; skip_to_matching_brace(); return null; } CssProperty values; ArrayList value_set = new ArrayList(); boolean wrong_value = true; } { ( values=declaration() { if (values != null) { value_set.add(values); wrong_value = false; } /* else { wrong_value = true; } */ currentProperty = null; } )? ( ";" ( )* ( values=declaration() { if (values != null) { value_set.add(values); wrong_value = false; }/* else { wrong_value = true; }*/ currentProperty = null; } )? )* { if (!wrong_value) { addProperty(value_set); return value_set; } else { return null; } } } /** * Used only when HTML is parsed, as otherwise parsing * is missed */ ArrayList attributeDeclarations() : { ArrayList p = null; } { try { ( )* p=declarations() { return p; } } catch (TokenMgrError tokenerror) { throw new ParseException(ac.getMsg().getString("generator.unrecognize")); } } /** * @exception ParseException exception during the parse */ CssSelectors selector() : { char comb; CssSelectors current; } { try { current=simple_selector(null) ( comb=combinator() { if ((ac.getCssProfile() == CssProfile.MOBILE) || getAtRule().toString().equals("@media atsc-tv") || (ac.getCssVersion() == CssVersion.CSS1)) { if (comb == '+') { throw new InvalidParamException("nocomb", "+", ac); } if (comb == '>') { throw new InvalidParamException("nocomb", ">", ac); } } else if (ac.getCssProfile() == CssProfile.TV) { if (comb == '+') { throw new InvalidParamException("nocomb", "+", ac); } } // if version < CSS3, ~ is undefined if (ac.getCssVersion().compareTo(CssVersion.CSS3) < 0) { if (comb == '~') { throw new InvalidParamException("nocomb", "~", ac); } } switch(comb) { case '+': current.addAdjacentSibling(new AdjacentSiblingSelector()); break; case '>': current.addChild(new ChildSelector()); break; case '~': current.addGeneralSibling(new GeneralSiblingSelector()); break; default: current.addDescendant(new DescendantSelector()); } //current.setConnector(comb); } current=simple_selector(current) )* { return current; } } catch (InvalidParamException ie) { // skipStatement(); // removeThisRule(); ac.getFrame() .addError(new CssError(getSourceFile(), getBeginLine(), getBeginColumn(), getEndLine(), getEndColumn(), ie)); Token t = getToken(1); StringBuilder s = new StringBuilder(); s.append(getToken(0).image); // eat until , { or EOF while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) { s.append(t.image); getNextToken(); t = getToken(1); } return null; } catch (ParseException e) { // validSelector = false; Token t = getToken(1); StringBuilder s = new StringBuilder("["); s.append(getToken(0).image); // eat until , { or EOF while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) { s.append(t.image); getNextToken(); t = getToken(1); } s.append(']'); // if (validSelector) { addError(e, s.toString()); // } else { // addError(e,""); // } validSelector = true; return null; } } /** * I made this rule to parse a selector from a document. Combinator are avoid. * @exception ParseException exception during the parse */ CssSelectors externalSelector() : { CssSelectors current; } { current=simple_selector(null) ( ( )+ current=simple_selector(current) )* { return current; } } /** * @exception ParseException exception during the parse */ CssSelectors simple_selector(CssSelectors next) : { CssSelectors selector = new CssSelectors(ac, next); selector.setAtRule(getAtRule()); //selector.setUserMedium(getUserMedium()); } { element_name(selector) ( hash(selector) | _class(selector) | attrib(selector) | pseudo(selector) | negation(selector) )* { return selector; } | ( hash(selector) | _class(selector) | attrib(selector) | pseudo(selector) | negation(selector) )+ { return selector; } } /** * @exception ParseException exception during the parse */ void _class(CssSelectors s) : {Token n; } { /* "." n= { */ n= { try { s.addClass(new ClassSelector(convertClassIdent(n.image.substring(1)))); // s.addAttribute("class", convertIdent(n.image.substring(1)), // CssSelectors.ATTRIBUTE_CLASS_SEL); } catch (InvalidParamException e) { // removeThisRule(); ac.getFrame() .addError(new CssError(getSourceFile(), getBeginLine(), getBeginColumn(), getEndLine(), getEndColumn(), e)); throw new ParseException(e.getMessage()); } } /* FIXME n=deprecated_class() ... ?? (DONE-> to be tested) */ | ( n=deprecated_class() ) { if (n.image.charAt(0) == '.') { n.image = n.image.substring(1); // the class with the first digit escaped String cl = "."+hexEscapeFirst(n.image); CssVersion version = ac.getCssVersion(); // String profile = ac.getProfile(); // if(profile == null || profile.equals("") || profile.equals("none")) { // profile = ac.getCssVersionString(); // } if(version != CssVersion.CSS1) { StringBuilder sb = new StringBuilder(); ArrayList param_err = new ArrayList(2); param_err.add(n.image); param_err.add(cl); sb.append(ac.getMsg().getString("parser.old_class", param_err)); throw new ParseException(sb.toString()); // s.addClass(new ClassSelector(n.image)); // removeThisRule(); } else { CssLength length = new CssLength(); boolean isLength = false; try { length.set(n.image, ac); isLength = true; } catch(Exception e) { isLength = false; } if(isLength) { StringBuilder sb = new StringBuilder(); sb.append(ac.getMsg().getString("parser.class_dim")); sb.append(n.image); throw new ParseException(sb.toString()); // s.addClass(new ClassSelector(n.image)); // removeThisRule(); } else { try { // for css > 1, we add the rule to have a context, // and we then remove it s.addClass(new ClassSelector(n.image)); ac.getFrame().addWarning("old_class"); } catch (InvalidParamException e) { throw new ParseException(e.getMessage()); //ac.getFrame().addError(new CssError(e)); //removeThisRule(); } } } } else { throw new ParseException("Unrecognized "); } } } Token deprecated_class() : { Token n; } { ( n= | n= | n= | n= | n=
{ setValue(new CssSwitch(), exp, operator, n, DIV); } | ( n= | n= ) { setValue(new CssBracket(), exp, operator, n, RBRACKET); } | n=ident() { /* * Common error : * H1 { * color : black * background : white * } */ Token t = getToken(1); Token semicolon = new Token(); semicolon.kind = SEMICOLON; semicolon.image = ";"; if (t.kind == COLON) { /* @@SEEME. (generate a warning?) */ /* @@SEEME if expression is a single ident, generate an error ? */ addError(new ParseException(String.format(ac.getMsg().getString("parser.semi-colon"), n)), (CssExpression) null); rejectToken(semicolon); } else { setValue(new CssIdent(), exp, operator, n, IDENT); } } | hashident(exp) | n= { CssURL _u = new CssURL(); _u.set(n.image, ac, url); exp.addValue(_u); } | n= { setValue(new CssUnicodeRange(), exp, operator, n, UNICODERANGE); } ) ) ( LOOKAHEAD(2) )* } /** * @exception ParseException exception during the parse */ void mediaterm(CssExpression exp) : { Token n; char operator = ' '; CssValue func; } { ( ( operator=unaryOperator() )? ( ( LOOKAHEAD( ( )* "/" ) ratio(exp, operator) | n= { setValue(new CssNumber(), exp, operator, n, NUMBER); } ) | n= { setValue(new CssPercentage(), exp, operator, n, PERCENTAGE); } | n= { setValue(new CssLength(), exp, operator, n, RELFONTLENGTH); } | n= { setValue(new CssLength(), exp, operator, n, RELVIEWLENGTH); } | n= { setValue(new CssLength(), exp, operator, n, ABSOLUTLENGTH); } | n= { setValue(new CssFlexibleLength(), exp, operator, n, FLEX); } | n= { setValue(new CssAngle(), exp, operator, n, ANGLE);} | n=
( )* ( operator=unaryOperator() )? ( n= { v2 = new CssNumber(); v2.set(addOperator(operator, n.image), ac); } | n= ( )* ( ( )* expr() )* ( )* ) ) ) { if (concat) { nc = new CssCalc(ac, c); nc.addRightSide(o.image, v2); c = nc; } else { c.addRightSide(o.image, v2); concat = true; } } )* ) { return c; } } CssCheckableValue mathunit() : { Token n; CssCheckableValue v = null; char operator = ' '; } { ( ( operator=unaryOperator() )? ( n= { v = new CssNumber(); v.set(addOperator(operator, n.image), ac); } | n= { v = new CssPercentage(); v.set(addOperator(operator, n.image), ac); } | n= { v = new CssLength(); v.set(addOperator(operator, n.image), ac); } | n= { v = new CssLength(); v.set(addOperator(operator, n.image), ac); } | n= { v = new CssLength(); v.set(addOperator(operator, n.image), ac); } | n= { v = new CssFlexibleLength(); v.set(addOperator(operator, n.image), ac); } | n= { v = new CssAngle(); v.set(addOperator(operator, n.image), ac); } | n=