1 /* -*-java-extended-*- |
|
2 * |
|
3 * (c) COPYRIGHT MIT and INRIA, 1997. |
|
4 * Please first read the full copyright statement in file COPYRIGHT.html |
|
5 * |
|
6 * $Id: CssParser.jj,v 1.69 2009-10-11 09:19:37 ylafon Exp $ |
|
7 * |
|
8 */ |
|
9 |
|
10 options { |
|
11 IGNORE_CASE = true; |
|
12 STATIC = false; |
|
13 UNICODE_INPUT = true; |
|
14 /* |
|
15 DEBUG_TOKEN_MANAGER = true; |
|
16 DEBUG_PARSER = true; |
|
17 */ |
|
18 } |
|
19 |
|
20 PARSER_BEGIN(CssParser) |
|
21 |
|
22 package org.w3c.css.parser.analyzer; |
|
23 |
|
24 import java.io.InputStream; |
|
25 import java.io.InputStreamReader; |
|
26 import java.io.UnsupportedEncodingException; |
|
27 import java.util.Vector; |
|
28 import java.util.Enumeration; |
|
29 import java.net.URL; |
|
30 |
|
31 import org.w3c.css.values.CssValue; |
|
32 import org.w3c.css.values.CssExpression; |
|
33 import org.w3c.css.values.CssString; |
|
34 import org.w3c.css.values.CssURL; |
|
35 import org.w3c.css.values.CssLength; |
|
36 import org.w3c.css.values.CssNumber; |
|
37 import org.w3c.css.values.CssColor; |
|
38 import org.w3c.css.values.CssIdent; |
|
39 import org.w3c.css.values.CssPercentage; |
|
40 import org.w3c.css.values.CssFrequency; |
|
41 import org.w3c.css.values.CssTime; |
|
42 import org.w3c.css.values.CssDate; |
|
43 import org.w3c.css.values.CssAngle; |
|
44 import org.w3c.css.values.CssFunction; |
|
45 import org.w3c.css.values.CssUnicodeRange; |
|
46 import org.w3c.css.values.CssResolution; |
|
47 import org.w3c.css.properties.css1.CssProperty; |
|
48 import org.w3c.css.parser.Frame; |
|
49 import org.w3c.css.util.ApplContext; |
|
50 import org.w3c.css.parser.CssError; |
|
51 import org.w3c.css.parser.CssSelectors; |
|
52 import org.w3c.css.parser.CssParseException; |
|
53 import org.w3c.css.parser.AtRule; |
|
54 import org.w3c.css.parser.AtRuleMedia; |
|
55 import org.w3c.css.parser.AtRuleFontFace; |
|
56 import org.w3c.css.parser.AtRulePage; |
|
57 import org.w3c.css.parser.AtRulePreference; |
|
58 import org.w3c.css.parser.AtRulePhoneticAlphabet; |
|
59 import org.w3c.css.properties.svg.AtRuleColorProfile; |
|
60 import org.w3c.css.util.InvalidParamException; |
|
61 import org.w3c.css.util.Util; |
|
62 import org.w3c.css.util.Messages; |
|
63 import org.w3c.css.css.StyleSheetCom; |
|
64 |
|
65 import org.w3c.css.selectors.AdjacentSiblingSelector; |
|
66 import org.w3c.css.selectors.AttributeSelector; |
|
67 import org.w3c.css.selectors.ChildSelector; |
|
68 import org.w3c.css.selectors.ClassSelector; |
|
69 import org.w3c.css.selectors.DescendantSelector; |
|
70 import org.w3c.css.selectors.GeneralSiblingSelector; |
|
71 import org.w3c.css.selectors.IdSelector; |
|
72 import org.w3c.css.selectors.TypeSelector; |
|
73 import org.w3c.css.selectors.UniversalSelector; |
|
74 import org.w3c.css.selectors.attributes.AttributeAny; |
|
75 import org.w3c.css.selectors.attributes.AttributeBegin; |
|
76 import org.w3c.css.selectors.attributes.AttributeExact; |
|
77 import org.w3c.css.selectors.attributes.AttributeOneOf; |
|
78 import org.w3c.css.selectors.attributes.AttributeStart; |
|
79 import org.w3c.css.selectors.attributes.AttributeSubstr; |
|
80 import org.w3c.css.selectors.attributes.AttributeSuffix; |
|
81 |
|
82 /** |
|
83 * A CSS3 parser |
|
84 * |
|
85 * @author Philippe Le Hegaret and Sijtsche Smeman |
|
86 * @version $Revision: 1.69 $ |
|
87 */ |
|
88 public abstract class CssParser { |
|
89 |
|
90 private static char hexdigits[] = { '0', '1', '2', '3', |
|
91 '4', '5', '6', '7', |
|
92 '8', '9', 'a', 'b', |
|
93 'c', 'd', 'e', 'f' }; |
|
94 // the current atRule |
|
95 protected AtRule atRule; |
|
96 protected String mediaDeclaration = "off"; |
|
97 |
|
98 /** |
|
99 * The URL of the document |
|
100 */ |
|
101 protected URL url; |
|
102 |
|
103 protected ApplContext ac; |
|
104 |
|
105 protected boolean incompatible_error; |
|
106 |
|
107 /** |
|
108 * The current context recognized by the parser (for errors). |
|
109 */ |
|
110 protected Vector currentContext; |
|
111 |
|
112 /** |
|
113 * The current property recognized by the parser (for errors). |
|
114 */ |
|
115 protected String currentProperty; |
|
116 |
|
117 /** |
|
118 * <code>true</code> if the parser should recognized Aural properties, |
|
119 * <code>false</code> otherwise. |
|
120 */ |
|
121 protected boolean mode; |
|
122 |
|
123 /** |
|
124 * <code>true</code> if the parser had recognize a rule, |
|
125 * <code>false</code> otherwise. |
|
126 */ |
|
127 protected boolean markRule; |
|
128 |
|
129 private boolean reinited = false; |
|
130 private boolean charsetdeclared = false; |
|
131 |
|
132 static StringBuilder SPACE = new StringBuilder(" "); |
|
133 |
|
134 // to be able to remove a ruleset if the selector is not valid |
|
135 protected boolean validSelector = true; |
|
136 |
|
137 /** |
|
138 * The ac for handling errors and warnings. |
|
139 * |
|
140 * @param ac the new ac for the parser. |
|
141 */ |
|
142 public final void setApplContext(ApplContext ac) { |
|
143 this.ac = ac; |
|
144 } |
|
145 |
|
146 /** |
|
147 * Set the attribute atRule |
|
148 * |
|
149 * @param atRule the new value for the attribute |
|
150 */ |
|
151 public void setAtRule(AtRule atRule) { |
|
152 this.atRule = atRule; |
|
153 } |
|
154 |
|
155 /** |
|
156 * Set the attribute mediaDeclaration |
|
157 * |
|
158 * @param mediaDeclaration indicator if in a media expression list or not |
|
159 */ |
|
160 public void setMediaDeclaration(String mediadeclaration) { |
|
161 this.mediaDeclaration = mediadeclaration; |
|
162 } |
|
163 |
|
164 /** |
|
165 * Returns the attribute mediaDeclaration |
|
166 * |
|
167 * @return the value of the attribute |
|
168 */ |
|
169 public String getMediaDeclaration() { |
|
170 return mediaDeclaration; |
|
171 } |
|
172 |
|
173 /** |
|
174 * Returns the attribute atRule |
|
175 * |
|
176 * @return the value of the attribute |
|
177 */ |
|
178 public AtRule getAtRule() { |
|
179 return atRule; |
|
180 } |
|
181 |
|
182 /** |
|
183 * Reinitialized the parser. |
|
184 * |
|
185 * @param stream the stream data to parse. |
|
186 * @param ac the new ac to use for parsing. |
|
187 */ |
|
188 public void ReInitWithAc(InputStream stream, ApplContext ac, |
|
189 String charset) |
|
190 { |
|
191 InputStream is = /*new CommentSkipperInputStream(stream);*/stream; |
|
192 if (charset == null) { |
|
193 charset = "iso-8859-1"; |
|
194 } |
|
195 InputStreamReader isr = null; |
|
196 try { |
|
197 isr = new InputStreamReader(is, charset); |
|
198 } catch (UnsupportedEncodingException uex) { |
|
199 isr = new InputStreamReader(is); |
|
200 } |
|
201 // reinit, it can not happen... |
|
202 // ...in theory ;) |
|
203 ReInit(isr); |
|
204 markRule = false; |
|
205 reinited = true; |
|
206 setApplContext(ac); |
|
207 } |
|
208 |
|
209 /* utilities for a parser */ |
|
210 |
|
211 /** |
|
212 * Call by the import statement. |
|
213 * |
|
214 * @param url The style sheet where this import statement appears. |
|
215 * @param file the file name in the import |
|
216 */ |
|
217 public abstract void handleImport(URL url, String file, |
|
218 boolean is_url, AtRuleMedia media); |
|
219 |
|
220 /** |
|
221 * Call by the namespace declaration statement. |
|
222 * |
|
223 * @param url The style sheet where this namespace statement appears. |
|
224 * @param file the file/url name in the namespace declaration |
|
225 */ |
|
226 public abstract void handleNamespaceDeclaration(URL url, String prefix, |
|
227 String file, |
|
228 boolean is_url); |
|
229 |
|
230 /** |
|
231 * Call by the at-rule statement. |
|
232 * |
|
233 * @param ident The ident for this at-rule (for example: 'font-face') |
|
234 * @param string The string associate to this at-rule |
|
235 * @see org.w3c.css.parser.Analyzer.Couple |
|
236 */ |
|
237 public abstract void handleAtRule(String ident, String string); |
|
238 |
|
239 /* added by Sijtsche Smeman */ |
|
240 public abstract void addCharSet(String charset); |
|
241 public abstract void newAtRule(AtRule atRule); |
|
242 public abstract void endOfAtRule(); |
|
243 public abstract void setImportant(boolean important); |
|
244 public abstract void setSelectorList(Vector selectors); |
|
245 public abstract void addProperty(Vector properties); |
|
246 public abstract void endOfRule(); |
|
247 public abstract void removeThisRule(); |
|
248 public abstract void removeThisAtRule(); |
|
249 |
|
250 /** |
|
251 * Assign an expression to a property. This function create a new property |
|
252 * with <code>property</code> and assign to it the expression with the |
|
253 * importance. Don't forget to set informations too. |
|
254 * <p> |
|
255 * A subclass must provide an implementation of this method. |
|
256 * |
|
257 * @param property the name of the property |
|
258 * @param values the expression representation of values |
|
259 * @param important <code>true</code> if values are important |
|
260 * |
|
261 * @return <code>null</code>or a property |
|
262 * |
|
263 * @see org.w3c.css.css.CssProperty |
|
264 */ |
|
265 public abstract CssProperty handleDeclaration(String property, |
|
266 CssExpression values, |
|
267 boolean important) |
|
268 throws InvalidParamException; |
|
269 |
|
270 /** |
|
271 * Adds a vector of properties to a selector. |
|
272 * <p> |
|
273 * A subclass must provide an implementation of this method. |
|
274 * |
|
275 * @param selector the selector |
|
276 * @param declarations Properties to associate with contexts |
|
277 */ |
|
278 public abstract void handleRule(CssSelectors selector, |
|
279 Vector declarations); |
|
280 |
|
281 /*Added by Sijtsche Smeman */ |
|
282 |
|
283 /** |
|
284 * Returns the source file of the style sheet |
|
285 */ |
|
286 public final String getSourceFile() { |
|
287 return getURL().toString(); |
|
288 } |
|
289 |
|
290 /** |
|
291 * Returns the current line in the style sheet |
|
292 */ |
|
293 public final int getLine() { |
|
294 //return token.beginLine; |
|
295 return 0; |
|
296 } |
|
297 |
|
298 /** |
|
299 * Set the URL of the style sheet. |
|
300 * |
|
301 * @param URL The URL for the style sheet |
|
302 */ |
|
303 public final void setURL(URL url) { |
|
304 this.url = url; |
|
305 } |
|
306 |
|
307 public final URL getURL() { |
|
308 return url; |
|
309 } |
|
310 |
|
311 /** |
|
312 * Return the next selector from the inputstream |
|
313 */ |
|
314 public CssSelectors parseSelector() throws ParseException { |
|
315 return externalSelector(); |
|
316 } |
|
317 |
|
318 /* |
|
319 * Add a value to an expression |
|
320 */ |
|
321 private void setValue(CssValue v, CssExpression expr, |
|
322 char operator, Token n, int token) |
|
323 throws ParseException { |
|
324 if (n != null) { |
|
325 if (ac.getCssVersion().equals("css1") && |
|
326 (n.image).equals("inherit")) { |
|
327 incompatible_error = true; |
|
328 } |
|
329 String val = (operator == ' ') ? n.image : operator+n.image; |
|
330 |
|
331 if (n.kind == CssParserConstants.IDENT) { |
|
332 v.set(convertIdent(val), ac); |
|
333 } else if (n.kind == CssParserConstants.STRING) { |
|
334 v.set(val, ac); |
|
335 } else { |
|
336 v.set(val, ac); |
|
337 } |
|
338 } |
|
339 expr.addValue(v); |
|
340 } |
|
341 |
|
342 /* |
|
343 * Error control |
|
344 */ |
|
345 private void addError(Exception e, String skippedText) { |
|
346 if (Util.onDebug) { |
|
347 System.err.println(e.getMessage()); |
|
348 e.printStackTrace(); |
|
349 } |
|
350 CssParseException ex = new CssParseException(e); |
|
351 ex.setSkippedString(skippedText); |
|
352 ex.setProperty(currentProperty); |
|
353 ex.setContexts(currentContext); |
|
354 CssError error = new CssError(getSourceFile(), getLine(), ex); |
|
355 ac.getFrame().addError(error); |
|
356 } |
|
357 |
|
358 /* |
|
359 * Error control 2 |
|
360 */ |
|
361 private void addError(Exception e, CssExpression exp) { |
|
362 if (Util.onDebug) { |
|
363 System.err.println(e.getMessage()); |
|
364 e.printStackTrace(); |
|
365 } |
|
366 |
|
367 // if ((exp != null) && (exp.getCount() != 0)) { |
|
368 CssParseException ex = new CssParseException(e); |
|
369 ex.setExp(exp); |
|
370 ex.setProperty(currentProperty); |
|
371 ex.setContexts(currentContext); |
|
372 CssError error = new CssError(getSourceFile(), getLine(), ex); |
|
373 ac.getFrame().addError(error); |
|
374 // } |
|
375 } |
|
376 } |
|
377 |
|
378 PARSER_END(CssParser) |
|
379 |
|
380 /* |
|
381 * The tokenizer |
|
382 */ |
|
383 |
|
384 <DEFAULT> |
|
385 SPECIAL_TOKEN : |
|
386 { |
|
387 < COMMENT : "/*" ( ~["*"] )* ( "*" )+ ( ~["/", "*"] ( ~["*"] )* ( "*" )+ )* "/" > |
|
388 } |
|
389 |
|
390 <DEFAULT> |
|
391 TOKEN [IGNORE_CASE] : /* basic tokens */ |
|
392 { |
|
393 < #H : ["0"-"9", "a"-"f"] > |
|
394 | < #NONASCII : ["\200"-"\377"] > |
|
395 | < #UNICODE : "\\" <H> ( <H> )? ( <H> )? ( <H> )? ( <H> )? ( <H> )? |
|
396 ( "\r\n" | [ " ", "\t" , "\n" , "\r", "\f" ] )? > |
|
397 | < #ESCAPE : <UNICODE> | ( "\\" ~[ "\r", "\n", "\f", "0"-"9", "a"-"f" ] ) > |
|
398 | < #NMSTART : [ "a"-"z", "_" ] | <NONASCII> | <ESCAPE> > |
|
399 | < #NMCHAR : ["a"-"z", "0"-"9", "-", "_"] | <NONASCII> | <ESCAPE> > |
|
400 | < #STRING1 : "\"" ( ~[ "\n", "\r", "\f", "\\", "\"" ] | "\\" <NL> | <ESCAPE> )* "\"" > |
|
401 | < #STRING2 : "\'" ( ~[ "\n", "\r", "\f", "\\", "\'" ] | "\\" <NL> | <ESCAPE> )* "\'" > |
|
402 | < #INVALID1 : "\"" ( ~[ "\n", "\r", "\f", "\\", "\"" ] | "\\" <NL> | <ESCAPE> )* > |
|
403 | < #INVALID2 : "\'" ( ~[ "\n", "\r", "\f", "\\", "\'" ] | "\\" <NL> | <ESCAPE> )* > |
|
404 | < #_IDENT : ( <MINUS> )? <NMSTART> ( <NMCHAR> )* > |
|
405 | < #NAME : ( <NMCHAR> )+ > |
|
406 | < #NUM : ( ["0"-"9"] )+ | ( ["0"-"9"] )* "." ( ["0"-"9"] )+ > |
|
407 | < #_STRING : <STRING1> | <STRING2> > |
|
408 | < #_INVALID : <INVALID1> | <INVALID2> > |
|
409 | < #_URL : ( [ "!", "#", "$", "%", "&", "*"-"[", "]"-"~" ] | <NONASCII> | <ESCAPE> )* > |
|
410 | < #_S : ( [ " ", "\t" , "\n" , "\r", "\f" ] ) ( <COMMENT> | [ " ", "\t" , "\n" , "\r", "\f" ] )* > |
|
411 | < #_W : ( <_S> )? > |
|
412 | < #NL : ( "\n" | "\r\n" | "\r" | "\f" ) > |
|
413 } |
|
414 /* |
|
415 * The _S definition is not ( [ " ", "\t" , "\n" , "\r", "\f" ] ) + as we need to add support |
|
416 * for the unput(' ') (see http://www.w3.org/TR/CSS21/grammar.html#scanner ) |
|
417 */ |
|
418 |
|
419 <DEFAULT> |
|
420 TOKEN : |
|
421 { |
|
422 < S : ( <_S> ) > |
|
423 } |
|
424 |
|
425 <DEFAULT> |
|
426 TOKEN : |
|
427 { |
|
428 < CDO : "<!--" > |
|
429 | < CDC : "-->" > |
|
430 | < INCLUDES : <TILDE> "=" > |
|
431 | < DASHMATCH : "|=" > |
|
432 } |
|
433 |
|
434 <DEFAULT> |
|
435 TOKEN : |
|
436 { |
|
437 < LBRACE : <_W> "{" > |
|
438 | < PLUS : <_W> "+" > |
|
439 | < GREATER : <_W> ">" > |
|
440 | < COMMA : <_W> "," > |
|
441 | < TILDE : <_W> "~" > |
|
442 } |
|
443 |
|
444 <DEFAULT> |
|
445 TOKEN [IGNORE_CASE] : |
|
446 { |
|
447 < AND : "and" > |
|
448 } |
|
449 |
|
450 <DEFAULT> |
|
451 TOKEN : |
|
452 { |
|
453 <STRING : <_STRING> > |
|
454 | <INVALID : <_INVALID> > |
|
455 | <IDENT : <_IDENT> > |
|
456 | <HASHIDENT : "#" <_IDENT> > |
|
457 | <HASH : "#" <NAME> > |
|
458 } |
|
459 |
|
460 <DEFAULT> |
|
461 TOKEN : |
|
462 { |
|
463 < RBRACE : "}"> |
|
464 | < PREFIXMATCH : "^=" > |
|
465 | < SUFFIXMATCH : "$=" > |
|
466 | < SUBSTRINGMATCH : "*=" > |
|
467 | < EQ : "=" > |
|
468 | < MINUS : "-" > |
|
469 | < SEMICOLON : ";" > |
|
470 | < DIV : "/" > |
|
471 | < LBRACKET : "[" > |
|
472 | < RBRACKET : "]" > |
|
473 | < ANY : "*" > |
|
474 | < DOT : "." > |
|
475 | < LPARAN : ")" > |
|
476 | < RPARAN : "("> |
|
477 } |
|
478 |
|
479 <DEFAULT> |
|
480 TOKEN : |
|
481 { |
|
482 < COLON : ":" > |
|
483 } |
|
484 |
|
485 <DEFAULT> |
|
486 TOKEN [IGNORE_CASE] : |
|
487 { |
|
488 < MEDIARESTRICTOR : "only" | "not" > |
|
489 } |
|
490 |
|
491 <DEFAULT> |
|
492 TOKEN [IGNORE_CASE] : |
|
493 { |
|
494 < URL : "url(" ( <S> )* ( <STRING> | <_URL> ) ( <S> )* ")" > |
|
495 } |
|
496 |
|
497 <DEFAULT> |
|
498 TOKEN [IGNORE_CASE] : |
|
499 { |
|
500 < LENGTH : <NUM> "pt" |
|
501 | <NUM> "mm" |
|
502 | <NUM> "cm" |
|
503 | <NUM> "pc" |
|
504 | <NUM> "in" |
|
505 | <NUM> "gd" |
|
506 | <NUM> "px" > |
|
507 | < EMS : <NUM> "em" > |
|
508 | < EXS : <NUM> "ex" > |
|
509 | < ANGLE : <NUM> ( "deg" | "grad" | "rad" ) > |
|
510 | < TIME : <NUM> ( "ms" | "s" ) > |
|
511 | < FREQ : <NUM> "Hz" | <NUM> "kHz" > |
|
512 | < RESOLUTION : <NUM> "dpi" | <NUM> "dpcm" > |
|
513 | < DATE : <NUM> "/" <NUM> "/" <NUM> > |
|
514 | < DIMEN : <NUM> <NMSTART> ( <NMCHAR> )* > |
|
515 | < PERCENTAGE : <NUM> "%" > |
|
516 | < NUMBER : <NUM> > |
|
517 } |
|
518 |
|
519 <DEFAULT> |
|
520 TOKEN [IGNORE_CASE] : |
|
521 { |
|
522 < IMPORTANT_SYM : "!" ( <_W> )* "important" > |
|
523 } |
|
524 |
|
525 <DEFAULT> |
|
526 TOKEN : |
|
527 { |
|
528 <PSEUDOELEMENT_SYM : "::" > |
|
529 } |
|
530 |
|
531 /* RESERVED ATRULE WORDS */ |
|
532 <DEFAULT> |
|
533 TOKEN : |
|
534 { |
|
535 < CHARSET_SYM : "@charset" > |
|
536 } |
|
537 |
|
538 <DEFAULT> |
|
539 TOKEN [IGNORE_CASE] : |
|
540 { |
|
541 < IMPORT_SYM : "@import"> |
|
542 | < NAMESPACE_SYM : "@namespace"> |
|
543 | < MEDIA_SYM : "@media" > |
|
544 | < PAGE_SYM : "@page" > |
|
545 | < FONT_FACE_SYM : "@font-face" > |
|
546 | < PREF_SYM : "@preference" > |
|
547 | < COLOR_PROFILE : "@color-profile" > |
|
548 | < ATTOP : "@top" > |
|
549 | < ATRIGHT : "@right" > |
|
550 | < ATBOTTOM : "@bottom" > |
|
551 | < ATLEFT : "@left" > |
|
552 | < ATCOUNTER : "@counter" > |
|
553 | < PHONETIC_ALPHABET_SYM : "@phonetic-alphabet" > |
|
554 | < ATKEYWORD : "@" <IDENT> > |
|
555 } |
|
556 |
|
557 <DEFAULT> |
|
558 TOKEN [IGNORE_CASE] : |
|
559 { |
|
560 < #RANGE0 : <H> <H> <H> <H> <H> <H> > |
|
561 | < #RANGE1 : <H> <H> <H> <H> <H> ( "?" )? > |
|
562 | < #RANGE2 : <H> <H> <H> <H> ( "?" )? ( "?" )? > |
|
563 | < #RANGE3 : <H> <H> <H> ( "?" )? ( "?" )? ( "?" )? > |
|
564 | < #RANGE4 : <H> <H> ( "?" )? ( "?" )? ( "?" )? ( "?" )? > |
|
565 | < #RANGE5 : <H> ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? > |
|
566 | < #RANGE6 : "?" ( "?" )? ( "?" )? ( "?" )? ( "?" )? ( "?" )? > |
|
567 | < #RANGE : <RANGE0> | <RANGE1> | <RANGE2> |
|
568 | <RANGE3> | <RANGE4> | <RANGE5> | <RANGE6> > |
|
569 | < #UNI : <H> ( <H> )? ( <H> )? ( <H> )? ( <H> )? ( <H> )? > |
|
570 | < UNICODERANGE : "U+" <RANGE> | "U+" <UNI> "-" <UNI> > |
|
571 } |
|
572 |
|
573 <DEFAULT> |
|
574 TOKEN: |
|
575 { |
|
576 < CLASS : "." <IDENT> > |
|
577 } |
|
578 |
|
579 /* FIXED, added a spacial case for lang pseudoclass */ |
|
580 <DEFAULT> |
|
581 TOKEN [IGNORE_CASE] : |
|
582 { |
|
583 < FUNCTIONLANG : "lang(" > |
|
584 } |
|
585 |
|
586 <DEFAULT> |
|
587 TOKEN [IGNORE_CASE] : |
|
588 { |
|
589 < FUNCTIONNOT : ":not(" > |
|
590 } |
|
591 |
|
592 |
|
593 <DEFAULT> |
|
594 TOKEN : |
|
595 { |
|
596 < FUNCTION : <IDENT> "(" > |
|
597 } |
|
598 |
|
599 /* Quick and dirty way to catch HTML tags starting CSS documents |
|
600 (common mistake) */ |
|
601 <DEFAULT> |
|
602 TOKEN: |
|
603 { |
|
604 <HTMLSTARTTAG : "<" ( <S> )* <IDENT> ( <S> )* |
|
605 ( <IDENT> "=" ( <IDENT> | <STRING> ) ( <S> )* )* |
|
606 ">" > |
|
607 | <HTMLENDTAG : "</" ( <S> )* <IDENT> ( <S> )* ">" > |
|
608 } |
|
609 |
|
610 //<DEFAULT, IN_COMMENT> |
|
611 //TOKEN : |
|
612 //{ /* avoid token manager error */ |
|
613 // < UNKNOWN : ~[] > |
|
614 //} |
|
615 |
|
616 /* |
|
617 * The grammar of CSS2 |
|
618 */ |
|
619 |
|
620 /** |
|
621 * The main entry for the parser. |
|
622 * |
|
623 * @exception ParseException exception during the parse |
|
624 */ |
|
625 void parserUnit() : |
|
626 { |
|
627 Token n = null; |
|
628 } |
|
629 { |
|
630 try { |
|
631 // used as an error recovery for HTML tags in CSS pages |
|
632 ( ( n=<HTMLSTARTTAG> | n=<HTMLENDTAG> ) { |
|
633 addError ( |
|
634 new ParseException(ac.getMsg().getString("generator.dontmixhtml")), n.image); |
|
635 } |
|
636 )* |
|
637 ( charset() )* // * instead of ? to capture the reinit part |
|
638 ( <S> | <CDO> | <CDC> )* |
|
639 ( importDeclaration() ( ignoreStatement() ) )* |
|
640 ( namespaceDeclaration() ( ignoreStatement() ) )* |
|
641 afterImportDeclaration() |
|
642 <EOF> |
|
643 } catch (TokenMgrError err) { |
|
644 addError (new ParseException(ac.getMsg().getString("generator.unrecognize")), |
|
645 err.getMessage()); |
|
646 } |
|
647 } |
|
648 |
|
649 void charset() : |
|
650 { |
|
651 Token n = null; |
|
652 Token charsetToken = null; |
|
653 Token space1Token = null; |
|
654 Token space2Token = null; |
|
655 Token semicolonToken = null; |
|
656 int nb_S = 0; |
|
657 } |
|
658 { |
|
659 try { |
|
660 charsetToken=<CHARSET_SYM> ( space1Token=<S> { nb_S++;} )* |
|
661 n=<STRING> ( space2Token=<S> )* semicolonToken=<SEMICOLON> |
|
662 { |
|
663 if (charsetdeclared && !reinited) { |
|
664 throw new ParseException( |
|
665 ac.getMsg().getString("parser.charset")); |
|
666 } |
|
667 // the @charset must be at the beginning of the document |
|
668 if(charsetToken.beginLine != 1 || |
|
669 charsetToken.beginColumn != 1) { |
|
670 throw new ParseException( |
|
671 ac.getMsg().getString("parser.charset")); |
|
672 } |
|
673 if ("css1".equals(ac.getCssVersion())) { |
|
674 throw new ParseException(ac.getMsg().getString( |
|
675 "parser.charsetcss1")); |
|
676 } |
|
677 // stricter rule for CSS21 and soon for CSS3 |
|
678 if ("css21".equals(ac.getCssVersion())) { |
|
679 // single space before |
|
680 // case sensitive |
|
681 // no space before ; |
|
682 // no comments |
|
683 // string must start with " |
|
684 if ( (nb_S != 1) || |
|
685 (!"@charset".equals(charsetToken.image)) || |
|
686 (!" ".equals(space1Token.image)) || |
|
687 (space2Token != null && |
|
688 !"".equals(space2Token.image)) || |
|
689 (space1Token.specialToken != null) || |
|
690 (n.specialToken != null) || |
|
691 (semicolonToken.specialToken != null) || |
|
692 (n.image.charAt(0) != '\"') |
|
693 ) { |
|
694 throw new ParseException(ac.getMsg().getString( |
|
695 "parser.charsetspecial")); |
|
696 } |
|
697 } |
|
698 if (!charsetdeclared) { |
|
699 addCharSet(n.image.substring(1, n.image.length()-1)); |
|
700 charsetdeclared = true; |
|
701 } else { |
|
702 reinited = false; |
|
703 } |
|
704 } |
|
705 } catch (Exception e) { |
|
706 String skip = charsetToken + |
|
707 ((space1Token == null) ? "" : space1Token.image) + |
|
708 n + |
|
709 ((space2Token == null) ? "" : space2Token.image) + |
|
710 ";"; |
|
711 addError(e, skip); |
|
712 } |
|
713 } |
|
714 |
|
715 void afterImportDeclaration() : |
|
716 {String ret; } |
|
717 { |
|
718 ( ( ruleSet() | media() | page() | fontFace() | preference() | |
|
719 colorprofile() | phoneticAlphabet() | ret=skipStatement() |
|
720 { if ((ret == null) || (ret.length() == 0)) { |
|
721 return; |
|
722 } |
|
723 // quite ugly but necessary to avoid probably a lot of changes in the |
|
724 // grammar, still having a beautiful error message |
|
725 else if (ret.startsWith("@charset")) { |
|
726 ParseException e = |
|
727 new ParseException(ac.getMsg().getString("parser.charset")); |
|
728 addError(e, ret); |
|
729 } else if (ret.startsWith("@import")) { |
|
730 ParseException e = |
|
731 new ParseException(ac.getMsg().getString("parser.import_not_allowed")); |
|
732 addError(e, ret); |
|
733 } else { |
|
734 ParseException e = |
|
735 new ParseException(ac.getMsg().getString("generator.unrecognize")); |
|
736 addError(e, ret); |
|
737 } |
|
738 } |
|
739 ) ignoreStatement() )* |
|
740 } |
|
741 |
|
742 void ignoreStatement() : |
|
743 {} |
|
744 { |
|
745 ( ( <CDO> | <CDC> | atRuleDeclaration() ) ( <S> )* )* |
|
746 } |
|
747 |
|
748 void namespaceDeclaration() : |
|
749 { |
|
750 Token n=null; |
|
751 Token v=null; |
|
752 boolean is_url; /* for formatting */ |
|
753 String nsname; |
|
754 String prefix = null; |
|
755 CssValue val; |
|
756 } |
|
757 { |
|
758 // FIXME add namespaces in context to match when a definition happens |
|
759 ( <NAMESPACE_SYM> |
|
760 ( <S> )* |
|
761 ( n=<IDENT> { |
|
762 prefix = convertIdent(n.image); |
|
763 } |
|
764 ( <S> )* )? |
|
765 ( v=<STRING> { |
|
766 is_url = false; |
|
767 nsname = v.image.substring(1, v.image.length()-1); |
|
768 } |
|
769 | v=<URL> { |
|
770 is_url = true; |
|
771 val = new CssURL(); |
|
772 ((CssURL) val).set(v.image, ac, url); |
|
773 nsname = (String) val.get(); |
|
774 if ((nsname.charAt(0) == '"') |
|
775 || (nsname.charAt(0) == '\'')) { |
|
776 nsname = nsname.substring(1, nsname.length()-1); |
|
777 } |
|
778 } |
|
779 ) |
|
780 ( <S> )* |
|
781 <SEMICOLON> |
|
782 ( <S> )* |
|
783 ) { |
|
784 if (!ac.getCssVersion().equals("css3")) { |
|
785 addError(new InvalidParamException("at-rule", "@namespace", ac), |
|
786 (n==null)?"default":n.toString()); |
|
787 } else { |
|
788 if (v != null) { |
|
789 handleNamespaceDeclaration(getURL(), prefix, nsname, is_url); |
|
790 } |
|
791 } |
|
792 } |
|
793 } |
|
794 /** |
|
795 * The import statement |
|
796 * |
|
797 * @exception ParseException exception during the parse |
|
798 */ |
|
799 void importDeclaration() : |
|
800 {Token n; |
|
801 AtRuleMedia media = new AtRuleMedia(); |
|
802 CssValue val; |
|
803 String importFile; |
|
804 boolean is_url = false; |
|
805 } |
|
806 { |
|
807 try { |
|
808 <IMPORT_SYM> ( <S> )* |
|
809 ( n=<STRING> { |
|
810 importFile = n.image.substring(1, n.image.length() -1); |
|
811 is_url = false; |
|
812 } |
|
813 | n=<URL> { |
|
814 val = new CssURL(); |
|
815 ((CssURL) val).set(n.image, ac, url); |
|
816 importFile = (String) val.get(); |
|
817 if ((importFile.charAt(0) == '"') |
|
818 || (importFile.charAt(0) == '\'')) { |
|
819 importFile = importFile.substring(1, importFile.length()-1); |
|
820 } |
|
821 is_url = true; |
|
822 } |
|
823 ) |
|
824 ( <S> )* |
|
825 ( medium(media) |
|
826 ( <COMMA> ( <S> )* medium(media) |
|
827 )* )? <SEMICOLON> |
|
828 ( <S> )* |
|
829 { |
|
830 handleImport(getURL(), importFile, is_url, media); |
|
831 } |
|
832 } catch (ParseException e) { |
|
833 addError(e, skipStatement()); |
|
834 } |
|
835 } |
|
836 |
|
837 /** |
|
838 * @exception ParseException exception during the parse |
|
839 */ |
|
840 void media() : |
|
841 { |
|
842 AtRule old = getAtRule(); |
|
843 AtRuleMedia newRule = new AtRuleMedia(); |
|
844 setAtRule(newRule); |
|
845 Token n; |
|
846 CssProperty p = null; |
|
847 } |
|
848 { |
|
849 try { |
|
850 <MEDIA_SYM> ( <S> )* |
|
851 // <CSS3> |
|
852 (n=<MEDIARESTRICTOR> { newRule.addMediaRestrictor(convertIdent(n.image), ac); } ( <S> )+)? |
|
853 medium(newRule) |
|
854 // </CSS3> |
|
855 ( <COMMA> ( <S> )* medium(newRule) )* |
|
856 // <CSS3> |
|
857 (<AND> ( <S> )* <RPARAN> ( <S> )* p=mediadeclaration() { newRule.addMediaFeature(p); } <LPARAN> ( <S> )* )* |
|
858 // </CSS3> |
|
859 |
|
860 { |
|
861 String media = getAtRule().toString(); |
|
862 if (ac.getMedium() != null && |
|
863 !(media.equals(ac.getMedium())) && |
|
864 !(ac.getMedium().equals("all"))) { |
|
865 |
|
866 ac.getFrame().addWarning("noothermedium", |
|
867 getAtRule().toString()); |
|
868 } |
|
869 if (ac.getCssVersion().equals("css1")) { |
|
870 skipStatement(); |
|
871 addError(new InvalidParamException("noatruleyet", "", ac), |
|
872 getAtRule().toString()); |
|
873 } |
|
874 if (!ac.getCssVersion().equals("css1")) { |
|
875 newAtRule(getAtRule()); |
|
876 } |
|
877 } |
|
878 <LBRACE> ( <S> )* ( ruleSet() )* <RBRACE> ( <S> )* |
|
879 { |
|
880 if (!ac.getCssVersion().equals("css1")) { |
|
881 endOfAtRule(); |
|
882 } |
|
883 } |
|
884 } catch (ParseException e) { |
|
885 if (!ac.getCssVersion().equals("css1")) { |
|
886 addError(e, skipStatement()); |
|
887 } |
|
888 } finally { |
|
889 setAtRule(old); |
|
890 } |
|
891 } |
|
892 |
|
893 /** |
|
894 * @exception ParseException exception during the parse |
|
895 */ |
|
896 void medium(AtRuleMedia media) : /* tv, projection, screen, ... */ |
|
897 {Token n;} |
|
898 { |
|
899 n=<IDENT> ( <S> )* |
|
900 { |
|
901 try { |
|
902 media.addMedia(convertIdent(n.image), ac); |
|
903 } catch (InvalidParamException e) { |
|
904 CssError error = new CssError(getSourceFile(), getLine(), e); |
|
905 ac.getFrame().addError(error); |
|
906 } |
|
907 } |
|
908 } |
|
909 |
|
910 /** |
|
911 * @exception ParseException exception during the parse |
|
912 */ |
|
913 void page() : |
|
914 { |
|
915 Vector v ; |
|
916 Token n = null ; |
|
917 Vector collectv = new Vector() ; |
|
918 CssSelectors s = new CssSelectors(ac); |
|
919 AtRule old = getAtRule() ; |
|
920 AtRulePage newRule = new AtRulePage() ; |
|
921 setAtRule(newRule); |
|
922 s.setAtRule(getAtRule()); |
|
923 } |
|
924 { |
|
925 try { |
|
926 <PAGE_SYM> ( <S> )* |
|
927 // FIXME <CSS3> ? |
|
928 ( n=<IDENT> { newRule.setIdent(convertIdent(n.image)); } |
|
929 ( <S> )* )? |
|
930 // </CSS3> |
|
931 ( pseudo_page(newRule) )? <LBRACE> ( <S> )* ( v=pageContent() |
|
932 { |
|
933 collectv = v; |
|
934 } |
|
935 ) <RBRACE> ( <S> )* |
|
936 { |
|
937 if (!ac.getCssVersion().equals("css1")) { |
|
938 newAtRule(getAtRule()); |
|
939 } |
|
940 |
|
941 if (!ac.getCssVersion().equals("css1")) { |
|
942 addProperty(collectv); |
|
943 endOfRule(); |
|
944 endOfAtRule(); |
|
945 } |
|
946 if (v == null) { |
|
947 ac.getFrame().addWarning("no-declaration"); |
|
948 } else { |
|
949 handleRule(s, collectv); |
|
950 } |
|
951 } |
|
952 } catch (InvalidParamException ie) { |
|
953 if (!ac.getCssVersion().equals("css1")) { |
|
954 skipStatement(); |
|
955 removeThisAtRule(); |
|
956 ac.getFrame().addError(new CssError(ie)); |
|
957 } |
|
958 } catch (ParseException e) { |
|
959 if (!ac.getCssVersion().equals("css1")) { |
|
960 removeThisAtRule(); |
|
961 addError(e, skipStatement()); |
|
962 } |
|
963 } finally { |
|
964 setAtRule(old); |
|
965 } |
|
966 } |
|
967 |
|
968 Vector pageContent() : |
|
969 { CssProperty prop; |
|
970 Vector v = new Vector(); |
|
971 } |
|
972 { |
|
973 // <CSS3> ?? FIXME |
|
974 v=prefAtRule() { return v;} |
|
975 // </CSS3> |
|
976 | |
|
977 v=declarations() { return v;} /* FIXME moved here as it can match empty string */ |
|
978 } |
|
979 |
|
980 Vector prefAtRule() : |
|
981 { Token n; |
|
982 Vector v; |
|
983 } |
|
984 { |
|
985 try { |
|
986 (n=<ATTOP> | n=<ATBOTTOM> | n=<ATLEFT> | n=<ATRIGHT> ) ( <S> )* |
|
987 <LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )* |
|
988 { |
|
989 return v; |
|
990 } |
|
991 } catch (ParseException e) { |
|
992 addError(e, skipStatement()); |
|
993 } |
|
994 } |
|
995 |
|
996 void pseudo_page(AtRulePage page) : |
|
997 { Token n; } |
|
998 { |
|
999 ":" n=<IDENT> ( <S> )* |
|
1000 { |
|
1001 try { |
|
1002 page.setName(":" + convertIdent(n.image), ac); |
|
1003 } catch (InvalidParamException e) { |
|
1004 throw new InvalidParamException("pseudo", n.image, ac ); |
|
1005 /*CssError error = new CssError(getSourceFile(), getLine(), e); |
|
1006 ac.getFrame().addError(error); */ |
|
1007 } |
|
1008 } |
|
1009 } |
|
1010 |
|
1011 void fontFace() : |
|
1012 { |
|
1013 Vector v; |
|
1014 AtRule old = getAtRule(); |
|
1015 setAtRule(new AtRuleFontFace()); |
|
1016 CssSelectors s = new CssSelectors(ac); |
|
1017 s.setAtRule(getAtRule()); |
|
1018 } |
|
1019 { |
|
1020 try { |
|
1021 <FONT_FACE_SYM> ( <S> )* |
|
1022 { |
|
1023 if (ac.getCssVersion().equals("css1")) { |
|
1024 skipStatement(); |
|
1025 addError(new InvalidParamException("noatruleyet", "", ac), |
|
1026 getAtRule().toString()); |
|
1027 } |
|
1028 if (!ac.getCssVersion().equals("css1")) { |
|
1029 newAtRule(getAtRule()); |
|
1030 } |
|
1031 |
|
1032 } |
|
1033 <LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )* |
|
1034 { |
|
1035 if (!ac.getCssVersion().equals("css1")) { |
|
1036 addProperty(v); |
|
1037 endOfRule(); |
|
1038 endOfAtRule(); |
|
1039 } |
|
1040 if (v == null) { |
|
1041 ac.getFrame().addWarning("no-declaration"); |
|
1042 } else { |
|
1043 handleRule(s, v); |
|
1044 } |
|
1045 } |
|
1046 } catch (ParseException e) { |
|
1047 if (!ac.getCssVersion().equals("css1")) { |
|
1048 addError(e, skipStatement()); |
|
1049 } |
|
1050 } finally { |
|
1051 setAtRule(old); |
|
1052 } |
|
1053 } |
|
1054 |
|
1055 void colorprofile() : |
|
1056 { |
|
1057 Vector v; |
|
1058 AtRule old = getAtRule(); |
|
1059 setAtRule(new AtRuleColorProfile()); |
|
1060 CssSelectors s = new CssSelectors(ac); |
|
1061 s.setAtRule(getAtRule()); |
|
1062 } |
|
1063 { |
|
1064 try { |
|
1065 <COLOR_PROFILE> ( <S> )* |
|
1066 { |
|
1067 if (!ac.getCssVersion().equals("svg")) { |
|
1068 skipStatement(); |
|
1069 addError(new InvalidParamException("onlysvg", "", ac), |
|
1070 getAtRule().toString()); |
|
1071 } |
|
1072 if (ac.getCssVersion().equals("svg")) { |
|
1073 newAtRule(getAtRule()); |
|
1074 } |
|
1075 |
|
1076 } |
|
1077 <LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )* |
|
1078 { |
|
1079 if (ac.getCssVersion().equals("svg")) { |
|
1080 addProperty(v); |
|
1081 endOfRule(); |
|
1082 endOfAtRule(); |
|
1083 } |
|
1084 |
|
1085 if (v == null) { |
|
1086 //ac.getFrame().addWarning("medialist"); |
|
1087 } else { |
|
1088 handleRule(s, v); |
|
1089 } |
|
1090 } |
|
1091 } |
|
1092 catch (ParseException e) { |
|
1093 if (ac.getCssVersion().equals("svg")) { |
|
1094 addError(e, skipStatement()); |
|
1095 } |
|
1096 } finally { |
|
1097 setAtRule(old); |
|
1098 } |
|
1099 } |
|
1100 |
|
1101 |
|
1102 void preference() : |
|
1103 { |
|
1104 Vector v; |
|
1105 AtRule old = getAtRule(); |
|
1106 setAtRule(new AtRulePreference()); |
|
1107 CssSelectors s = new CssSelectors(ac); |
|
1108 s.setAtRule(getAtRule()); |
|
1109 } |
|
1110 { |
|
1111 try { |
|
1112 <PREF_SYM> ( <S> )* |
|
1113 { |
|
1114 if (ac.getCssVersion().equals("css1")) { |
|
1115 skipStatement(); |
|
1116 addError(new InvalidParamException("noatruleyet", "", ac), |
|
1117 getAtRule().toString()); |
|
1118 } |
|
1119 if (!ac.getCssVersion().equals("css1")) { |
|
1120 newAtRule(getAtRule()); |
|
1121 } |
|
1122 |
|
1123 } |
|
1124 <LBRACE> ( <S> )* v=declarations() <RBRACE> ( <S> )* |
|
1125 { |
|
1126 if (!ac.getCssVersion().equals("css1")) { |
|
1127 addProperty(v); |
|
1128 endOfRule(); |
|
1129 endOfAtRule(); |
|
1130 } |
|
1131 |
|
1132 if (v == null) { |
|
1133 ac.getFrame().addWarning("medialist"); |
|
1134 } else { |
|
1135 handleRule(s, v); |
|
1136 } |
|
1137 } |
|
1138 } |
|
1139 catch (ParseException e) { |
|
1140 if (!ac.getCssVersion().equals("css1")) { |
|
1141 addError(e, skipStatement()); |
|
1142 } |
|
1143 } finally { |
|
1144 setAtRule(old); |
|
1145 } |
|
1146 } |
|
1147 |
|
1148 void phoneticAlphabet() : |
|
1149 { |
|
1150 Vector v; |
|
1151 AtRule old = getAtRule(); |
|
1152 AtRulePhoneticAlphabet alphabetrule = new AtRulePhoneticAlphabet(); |
|
1153 setAtRule(alphabetrule); |
|
1154 Token n; |
|
1155 } |
|
1156 { |
|
1157 try { |
|
1158 <PHONETIC_ALPHABET_SYM> ( <S> )* n=<STRING> ( <S> )* ";" |
|
1159 { |
|
1160 if (!ac.getCssVersion().equals("css3")) { |
|
1161 skipStatement(); |
|
1162 addError(new InvalidParamException("noatruleyet", "", ac), |
|
1163 getAtRule().toString()); |
|
1164 } |
|
1165 |
|
1166 alphabetrule.addAlphabet(convertIdent(n.image), ac); |
|
1167 |
|
1168 if (!ac.getCssVersion().equals("css1") && !ac.getCssVersion().equals("css2")) { |
|
1169 newAtRule(getAtRule()); |
|
1170 } |
|
1171 |
|
1172 } |
|
1173 } catch (ParseException e) { |
|
1174 if (!ac.getCssVersion().equals("css1")) { |
|
1175 addError(e, skipStatement()); |
|
1176 } |
|
1177 } finally { |
|
1178 setAtRule(old); |
|
1179 } |
|
1180 } |
|
1181 |
|
1182 /** |
|
1183 * @exception ParseException exception during the parse |
|
1184 */ |
|
1185 void atRuleDeclaration() : |
|
1186 {Token n;} |
|
1187 { |
|
1188 n=<ATKEYWORD> |
|
1189 { |
|
1190 //ac.getFrame().addWarning("at-rule", token.toString()); |
|
1191 ac.getFrame().addError( |
|
1192 new CssError(new InvalidParamException("at-rule", |
|
1193 token, ac))); |
|
1194 skipStatement(); |
|
1195 } |
|
1196 } |
|
1197 |
|
1198 /** |
|
1199 * @exception ParseException exception during the parse |
|
1200 */ |
|
1201 void operator(CssExpression expr) : |
|
1202 {} |
|
1203 { |
|
1204 ( ( <DIV> { if (expr.getCount() > 0) expr.setOperator('/'); } |
|
1205 | <COMMA> { if (expr.getCount() > 0) expr.setOperator(','); } |
|
1206 ) ( <S> )* )? |
|
1207 } |
|
1208 |
|
1209 /** |
|
1210 * @exception ParseException exception during the parse |
|
1211 */ |
|
1212 char combinator() : |
|
1213 { |
|
1214 char connector = ' '; |
|
1215 } |
|
1216 { |
|
1217 ( ( <PLUS> { connector = '+' ; } |
|
1218 | <GREATER> { connector = '>' ; } |
|
1219 | <TILDE> { connector = '~' ; } |
|
1220 ) ( <S> )* |
|
1221 | ( <S> )+ { connector = ' ' ; } |
|
1222 ) |
|
1223 { |
|
1224 return connector; |
|
1225 } |
|
1226 } |
|
1227 |
|
1228 /** |
|
1229 * @exception ParseException exception during the parse |
|
1230 */ |
|
1231 char unaryOperator() : |
|
1232 {} |
|
1233 { |
|
1234 // FIXME <MINUS> | <PLUS> ? warning as <PLUS> is <_W>? "+" |
|
1235 "-" { return '-'; } |
|
1236 | <PLUS> { return '+'; } |
|
1237 } |
|
1238 |
|
1239 /** |
|
1240 * @exception ParseException exception during the parse |
|
1241 */ |
|
1242 String property() : |
|
1243 {Token n; } |
|
1244 { |
|
1245 n=<IDENT> ( <S> )* { currentProperty = convertIdent(n.image); |
|
1246 return currentProperty; } |
|
1247 } |
|
1248 |
|
1249 /** |
|
1250 * @exception ParseException exception during the parse |
|
1251 */ |
|
1252 void ruleSet() : |
|
1253 { CssSelectors contextual; |
|
1254 Vector<CssSelectors> context_set = new Vector<CssSelectors>(); |
|
1255 Vector<CssProperty> value_set = null; |
|
1256 currentContext = context_set; |
|
1257 } |
|
1258 { |
|
1259 try { |
|
1260 contextual=selector() |
|
1261 { |
|
1262 if (contextual != null) { |
|
1263 context_set.addElement(contextual); |
|
1264 } |
|
1265 } |
|
1266 |
|
1267 ( <COMMA> ( <S> )* |
|
1268 contextual=selector() |
|
1269 { |
|
1270 if (contextual != null) { |
|
1271 context_set.addElement(contextual); |
|
1272 } |
|
1273 } |
|
1274 )* |
|
1275 <LBRACE> { |
|
1276 validSelector = (context_set.size() > 0); |
|
1277 } |
|
1278 ( <S> )* |
|
1279 value_set=declarations() |
|
1280 <RBRACE> ( <S> )* |
|
1281 { |
|
1282 markRule = true; |
|
1283 |
|
1284 /* if (value_set == null) { |
|
1285 ac.getFrame().addWarning("no-declaration"); |
|
1286 } else {*/ |
|
1287 if (value_set != null) { |
|
1288 boolean first = true; |
|
1289 CssSelectors sel = null; |
|
1290 Enumeration<CssSelectors> e = context_set.elements(); |
|
1291 while (e.hasMoreElements()) { |
|
1292 sel = e.nextElement(); |
|
1293 if (first) { |
|
1294 handleRule(sel, value_set); |
|
1295 first = false; |
|
1296 } else { |
|
1297 // we need to duplicate properties in that case |
|
1298 // as property holds reference to the selectors and it interact |
|
1299 // badly with conflict detection |
|
1300 int vsize = value_set.size(); |
|
1301 Vector<CssProperty> v = new Vector<CssProperty>(vsize); |
|
1302 for (int i=0; i<vsize; i++) { |
|
1303 v.addElement(value_set.elementAt(i).duplicate()); |
|
1304 } |
|
1305 handleRule(sel, v); |
|
1306 } |
|
1307 } |
|
1308 setSelectorList(context_set); |
|
1309 endOfRule(); |
|
1310 } |
|
1311 currentContext = null; |
|
1312 } |
|
1313 } catch (ParseException e) { |
|
1314 if (ac.getProfile() != null) { |
|
1315 if (!ac.getProfile().equals("mobile") && !context_set.isEmpty()) { |
|
1316 addError(e, skipStatement()); |
|
1317 } |
|
1318 } |
|
1319 } catch (TokenMgrError e) { |
|
1320 addError(new ParseException(e.getMessage()), skipStatement()); |
|
1321 } |
|
1322 } |
|
1323 |
|
1324 Vector<CssProperty> declarations() : |
|
1325 { |
|
1326 if(!validSelector) { |
|
1327 validSelector = true; |
|
1328 skip_to_matching_brace(); |
|
1329 return null; |
|
1330 } |
|
1331 |
|
1332 CssProperty values; |
|
1333 Vector<CssProperty> value_set = new Vector<CssProperty>(); |
|
1334 boolean wrong_value = true; |
|
1335 } |
|
1336 { |
|
1337 ( values=declaration() |
|
1338 { if (values != null) { |
|
1339 value_set.addElement(values); |
|
1340 wrong_value = false; |
|
1341 } /* else { |
|
1342 wrong_value = true; |
|
1343 } */ |
|
1344 currentProperty = null; |
|
1345 } |
|
1346 )? |
|
1347 ( ";" ( <S> )* |
|
1348 ( values=declaration() |
|
1349 { if (values != null) { |
|
1350 value_set.addElement(values); |
|
1351 wrong_value = false; |
|
1352 }/* else { |
|
1353 wrong_value = true; |
|
1354 }*/ |
|
1355 currentProperty = null; |
|
1356 } |
|
1357 )? )* |
|
1358 { |
|
1359 if (!wrong_value) { |
|
1360 addProperty(value_set); |
|
1361 return value_set; |
|
1362 } else { |
|
1363 return null; |
|
1364 } |
|
1365 } |
|
1366 } |
|
1367 |
|
1368 /** |
|
1369 * @exception ParseException exception during the parse |
|
1370 */ |
|
1371 CssSelectors selector() : |
|
1372 { char comb; |
|
1373 CssSelectors current; } |
|
1374 { |
|
1375 try { |
|
1376 current=simple_selector(null) |
|
1377 ( |
|
1378 comb=combinator() { |
|
1379 if (ac.getProfile() != null) { |
|
1380 if (ac.getProfile().equals("mobile") || |
|
1381 getAtRule().toString().equals("@media atsc-tv") || |
|
1382 ac.getCssVersion().equals("css1")) { |
|
1383 if (comb == '+') |
|
1384 throw new InvalidParamException("nocomb", "+", ac); |
|
1385 if (comb == '>') |
|
1386 throw new InvalidParamException("nocomb", ">", ac); |
|
1387 } else if (ac.getProfile().equals("tv")) { |
|
1388 if (comb == '+') |
|
1389 throw new InvalidParamException("nocomb", "+", ac); |
|
1390 |
|
1391 } |
|
1392 } |
|
1393 if (!ac.getCssVersion().equals("css3")) { |
|
1394 if (comb == '~') { |
|
1395 throw new InvalidParamException("nocomb", "~", ac); |
|
1396 } |
|
1397 } |
|
1398 switch(comb) { |
|
1399 case '+': |
|
1400 current.addAdjacentSibling(new AdjacentSiblingSelector()); |
|
1401 break; |
|
1402 case '>': |
|
1403 current.addChild(new ChildSelector()); |
|
1404 break; |
|
1405 case '~': |
|
1406 current.addGeneralSibling(new GeneralSiblingSelector()); |
|
1407 break; |
|
1408 default: |
|
1409 current.addDescendant(new DescendantSelector()); |
|
1410 } |
|
1411 //current.setConnector(comb); |
|
1412 } |
|
1413 current=simple_selector(current) |
|
1414 )* |
|
1415 { return current; } |
|
1416 } |
|
1417 catch (InvalidParamException ie) { |
|
1418 // skipStatement(); |
|
1419 // removeThisRule(); |
|
1420 ac.getFrame().addError(new CssError(ie)); |
|
1421 Token t = getToken(1); |
|
1422 StringBuilder s = new StringBuilder(); |
|
1423 s.append(getToken(0).image); |
|
1424 // eat until , { or EOF |
|
1425 while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) { |
|
1426 s.append(t.image); |
|
1427 getNextToken(); |
|
1428 t = getToken(1); |
|
1429 } |
|
1430 return null; |
|
1431 } |
|
1432 catch (ParseException e) { |
|
1433 // validSelector = false; |
|
1434 Token t = getToken(1); |
|
1435 StringBuilder s = new StringBuilder("["); |
|
1436 s.append(getToken(0).image); |
|
1437 // eat until , { or EOF |
|
1438 while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)) { |
|
1439 s.append(t.image); |
|
1440 getNextToken(); |
|
1441 t = getToken(1); |
|
1442 } |
|
1443 s.append(']'); |
|
1444 // if (validSelector) { |
|
1445 addError(e, s.toString()); |
|
1446 // } else { |
|
1447 // addError(e,""); |
|
1448 // } |
|
1449 validSelector = true; |
|
1450 return null; |
|
1451 } |
|
1452 } |
|
1453 |
|
1454 /** |
|
1455 * I made this rule to parse a selector from a document. Combinator are avoid. |
|
1456 * @exception ParseException exception during the parse |
|
1457 */ |
|
1458 CssSelectors externalSelector() : |
|
1459 { |
|
1460 CssSelectors current; } |
|
1461 { |
|
1462 current=simple_selector(null) |
|
1463 ( ( <S> )+ |
|
1464 current=simple_selector(current) |
|
1465 )* |
|
1466 { return current; } |
|
1467 } |
|
1468 |
|
1469 /** |
|
1470 * @exception ParseException exception during the parse |
|
1471 */ |
|
1472 CssSelectors simple_selector(CssSelectors next) : |
|
1473 { CssSelectors selector = new CssSelectors(ac, next); |
|
1474 selector.setAtRule(getAtRule()); |
|
1475 //selector.setUserMedium(getUserMedium()); |
|
1476 } |
|
1477 { |
|
1478 |
|
1479 element_name(selector) ( hash(selector) | _class(selector) |
|
1480 | attrib(selector) | pseudo(selector) |
|
1481 | negation(selector) )* |
|
1482 { |
|
1483 return selector; |
|
1484 } |
|
1485 | ( hash(selector) | _class(selector) | attrib(selector) |
|
1486 | pseudo(selector) | negation(selector) )+ |
|
1487 { |
|
1488 return selector; |
|
1489 } |
|
1490 } |
|
1491 |
|
1492 /** |
|
1493 * @exception ParseException exception during the parse |
|
1494 */ |
|
1495 void _class(CssSelectors s) : |
|
1496 {Token n; } |
|
1497 { |
|
1498 /* "." n=<IDENT> { */ |
|
1499 n=<CLASS> { |
|
1500 try { |
|
1501 s.addClass(new ClassSelector(convertClassIdent(n.image.substring(1)))); |
|
1502 // s.addAttribute("class", convertIdent(n.image.substring(1)), |
|
1503 // CssSelectors.ATTRIBUTE_CLASS_SEL); |
|
1504 } catch (InvalidParamException e) { |
|
1505 // removeThisRule(); |
|
1506 ac.getFrame().addError(new CssError(e)); |
|
1507 throw new ParseException(e.getMessage()); |
|
1508 } |
|
1509 } |
|
1510 /* FIXME <DOT> n=deprecated_class() ... ?? (DONE-> to be tested) */ |
|
1511 | ( n=deprecated_class() ) { |
|
1512 if (n.image.charAt(0) == '.') { |
|
1513 n.image = n.image.substring(1); |
|
1514 |
|
1515 // the class with the first digit escaped |
|
1516 String cl = "."+hexEscapeFirst(n.image); |
|
1517 |
|
1518 String profile = ac.getProfile(); |
|
1519 if(profile == null || profile.equals("") || profile.equals("none")) { |
|
1520 profile = ac.getCssVersion(); |
|
1521 } |
|
1522 |
|
1523 if(!profile.equals("css1")) { |
|
1524 StringBuilder sb = new StringBuilder(); |
|
1525 Vector<String> param_err = new Vector<String>(2); |
|
1526 param_err.add(n.image); |
|
1527 param_err.add(cl); |
|
1528 sb.append(ac.getMsg().getString("parser.old_class", param_err)); |
|
1529 throw new ParseException(sb.toString()); |
|
1530 // s.addClass(new ClassSelector(n.image)); |
|
1531 // removeThisRule(); |
|
1532 } |
|
1533 else { |
|
1534 CssLength length = new CssLength(); |
|
1535 boolean isLength = false; |
|
1536 try { |
|
1537 length.set(n.image, ac); |
|
1538 isLength = true; |
|
1539 } |
|
1540 catch(Exception e) { |
|
1541 isLength = false; |
|
1542 } |
|
1543 if(isLength) { |
|
1544 StringBuilder sb = new StringBuilder(); |
|
1545 sb.append(ac.getMsg().getString("parser.class_dim")); |
|
1546 sb.append(n.image); |
|
1547 throw new ParseException(sb.toString()); |
|
1548 // s.addClass(new ClassSelector(n.image)); |
|
1549 // removeThisRule(); |
|
1550 } |
|
1551 else { |
|
1552 try { |
|
1553 // for css > 1, we add the rule to have a context, |
|
1554 // and we then remove it |
|
1555 s.addClass(new ClassSelector(n.image)); |
|
1556 ac.getFrame().addWarning("old_class"); |
|
1557 } catch (InvalidParamException e) { |
|
1558 throw new ParseException(e.getMessage()); |
|
1559 //ac.getFrame().addError(new CssError(e)); |
|
1560 //removeThisRule(); |
|
1561 } |
|
1562 } |
|
1563 } |
|
1564 } else { |
|
1565 throw new ParseException("Unrecognized "); |
|
1566 } |
|
1567 } |
|
1568 } |
|
1569 |
|
1570 Token deprecated_class() : |
|
1571 { |
|
1572 Token n; |
|
1573 } |
|
1574 { |
|
1575 ( n=<LENGTH> |
|
1576 | n=<EMS> |
|
1577 | n=<EXS> |
|
1578 | n=<ANGLE> |
|
1579 | n=<TIME> |
|
1580 | n=<FREQ> |
|
1581 | n=<RESOLUTION> |
|
1582 | n=<DIMEN> ) |
|
1583 { |
|
1584 return n; |
|
1585 } |
|
1586 } |
|
1587 |
|
1588 /** |
|
1589 * @exception ParseException exception during the parse |
|
1590 */ |
|
1591 void element_name(CssSelectors s) : |
|
1592 { |
|
1593 Token n=null; |
|
1594 Token p=null; |
|
1595 String prefix = null; |
|
1596 } |
|
1597 { |
|
1598 ( LOOKAHEAD(2) (n=<IDENT> | n=<ANY>)? p="|" )? { |
|
1599 // FIXME namespace, check versions of CSS in a better way. |
|
1600 if (p != null) { |
|
1601 if (!ac.getCssVersion().equals("css3")) { |
|
1602 StringBuilder sb = new StringBuilder("namespace \""); |
|
1603 if (n != null) sb.append(n.toString()); |
|
1604 sb.append("\""); |
|
1605 ac.getFrame().addError(new CssError(new |
|
1606 InvalidParamException("notversion", |
|
1607 "namespace", |
|
1608 ac.getCssVersion(), |
|
1609 ac))); |
|
1610 removeThisRule(); |
|
1611 } else if (n!=null) { |
|
1612 prefix = convertIdent(n.image); |
|
1613 if (!ac.isNamespaceDefined(getURL(), prefix)) { |
|
1614 // ns is not defined |
|
1615 addError(new ParseException("Undefined namespace"), |
|
1616 ": The namespace \""+prefix |
|
1617 +"\" is not defined. " |
|
1618 + prefix ); |
|
1619 removeThisRule(); |
|
1620 } |
|
1621 } else { |
|
1622 prefix = ""; |
|
1623 } |
|
1624 } |
|
1625 } |
|
1626 ( n=<IDENT> { // s.setElement(convertIdent(n.image), ac); |
|
1627 s.addType(new TypeSelector(prefix, convertIdent(n.image))); |
|
1628 } |
|
1629 | <ANY> { |
|
1630 if (!ac.getCssVersion().equals("css1")) { |
|
1631 // s.setElement(null); |
|
1632 s.addUniversal(new UniversalSelector(prefix)); |
|
1633 } else { |
|
1634 ac.getFrame().addError(new CssError(new InvalidParamException("notversion", |
|
1635 "*", ac.getCssVersion(), ac))); |
|
1636 } |
|
1637 } |
|
1638 ) |
|
1639 } |
|
1640 |
|
1641 /** |
|
1642 * @exception ParseException exception during the parse |
|
1643 */ |
|
1644 void attrib(CssSelectors s) : |
|
1645 { |
|
1646 Token att = null; |
|
1647 Token val = null; |
|
1648 int selectorType = CssSelectors.ATTRIBUTE_ANY; |
|
1649 } |
|
1650 { |
|
1651 <LBRACKET> ( <S> )* att=<IDENT> ( <S> )* |
|
1652 ( (<EQ> { selectorType = CssSelectors.ATTRIBUTE_EXACT; } |
|
1653 | <INCLUDES> { selectorType = CssSelectors.ATTRIBUTE_ONE_OF; } |
|
1654 | <DASHMATCH> { selectorType = CssSelectors.ATTRIBUTE_BEGIN; } |
|
1655 | <PREFIXMATCH> { selectorType = CssSelectors.ATTRIBUTE_START; } |
|
1656 | <SUFFIXMATCH> { selectorType = CssSelectors.ATTRIBUTE_SUFFIX; } |
|
1657 | <SUBSTRINGMATCH> { selectorType = CssSelectors.ATTRIBUTE_SUBSTR; } |
|
1658 ) ( <S> )* |
|
1659 ( val=<IDENT> |
|
1660 { val.image = convertIdent(val.image); } |
|
1661 | val=<STRING> |
|
1662 { val.image = convertStringIndex(val.image, 1, val.image.length() -1, false);} |
|
1663 ) |
|
1664 ( <S> )* )? |
|
1665 <RBRACKET> |
|
1666 { |
|
1667 if ("css1".equals(ac.getCssVersion())) { |
|
1668 StringBuilder reason; |
|
1669 CssParseException cp; |
|
1670 ParseException p; |
|
1671 reason = new StringBuilder(" ["); |
|
1672 if (att != null) { |
|
1673 reason.append(convertIdent(att.image)); |
|
1674 } |
|
1675 if (val != null ) { |
|
1676 reason.append('=').append(val.image); |
|
1677 } |
|
1678 reason.append(']'); |
|
1679 p = new ParseException(ac.getMsg().getString("parser.attrcss1")+ |
|
1680 reason.toString()); |
|
1681 cp = new CssParseException(p); |
|
1682 ac.getFrame().addError(new CssError(cp)); |
|
1683 removeThisRule(); |
|
1684 } |
|
1685 if (selectorType == CssSelectors.ATTRIBUTE_ANY) { |
|
1686 try { |
|
1687 s.addAttribute(new AttributeAny(att.image.toLowerCase())); |
|
1688 // s.addAttribute(att.image.toLowerCase(), null, selectorType); |
|
1689 } catch (InvalidParamException e) { |
|
1690 removeThisRule(); |
|
1691 ac.getFrame().addError(new CssError(e)); |
|
1692 } |
|
1693 } else { |
|
1694 AttributeSelector attribute; |
|
1695 switch(selectorType) { |
|
1696 case CssSelectors.ATTRIBUTE_BEGIN: |
|
1697 attribute = new AttributeBegin(att.image.toLowerCase(), |
|
1698 val.image); |
|
1699 break; |
|
1700 case CssSelectors.ATTRIBUTE_EXACT: |
|
1701 attribute = new AttributeExact(att.image.toLowerCase(), |
|
1702 val.image); |
|
1703 break; |
|
1704 case CssSelectors.ATTRIBUTE_ONE_OF: |
|
1705 attribute = new AttributeOneOf(att.image.toLowerCase(), |
|
1706 val.image); |
|
1707 break; |
|
1708 case CssSelectors.ATTRIBUTE_START: |
|
1709 attribute = new AttributeStart(att.image.toLowerCase(), |
|
1710 val.image); |
|
1711 break; |
|
1712 case CssSelectors.ATTRIBUTE_SUBSTR: |
|
1713 attribute = new AttributeSubstr(att.image.toLowerCase(), |
|
1714 val.image); |
|
1715 break; |
|
1716 case CssSelectors.ATTRIBUTE_SUFFIX: |
|
1717 attribute = new AttributeSuffix(att.image.toLowerCase(), |
|
1718 val.image); |
|
1719 break; |
|
1720 default: |
|
1721 attribute = new AttributeExact(att.image.toLowerCase(), |
|
1722 val.image); |
|
1723 break; |
|
1724 } |
|
1725 try { |
|
1726 s.addAttribute(attribute); |
|
1727 // s.addAttribute(att.image.toLowerCase(), val.image, |
|
1728 // selectorType); |
|
1729 } catch (InvalidParamException e) { |
|
1730 removeThisRule(); |
|
1731 ac.getFrame().addError(new CssError(e)); |
|
1732 } |
|
1733 } |
|
1734 } |
|
1735 } |
|
1736 |
|
1737 void negation(CssSelectors s) : |
|
1738 { |
|
1739 Token n; |
|
1740 CssSelectors ns = new CssSelectors(ac, null); |
|
1741 } |
|
1742 { // S* negation_arg S* ')' |
|
1743 // type_selector | universal | HASH | class | attrib | pseudo |
|
1744 |
|
1745 <FUNCTIONNOT> ( <S> )* |
|
1746 ( |
|
1747 element_name(ns) | |
|
1748 hash(ns) | |
|
1749 _class(ns) | |
|
1750 attrib(ns) | |
|
1751 pseudo(ns) |
|
1752 ) |
|
1753 ( <S> )* <LPARAN> |
|
1754 { |
|
1755 s.setPseudoFun("not", ns.toString()); |
|
1756 } |
|
1757 } |
|
1758 |
|
1759 /** |
|
1760 * @exception ParseException exception during the parse |
|
1761 */ |
|
1762 void pseudo(CssSelectors s) : |
|
1763 {Token n; |
|
1764 Token language = null; |
|
1765 CssExpression param = null; |
|
1766 } |
|
1767 { |
|
1768 <PSEUDOELEMENT_SYM> ( ( n=<IDENT> |
|
1769 { |
|
1770 try { |
|
1771 if (ac.getCssVersion().equals("css3")) { |
|
1772 s.addPseudoElement(convertIdent(n.image).toLowerCase()); |
|
1773 } else { |
|
1774 throw new InvalidParamException("pseudo-element", |
|
1775 "::" + convertIdent(n.image).toLowerCase() , |
|
1776 ac.getCssVersion() ,ac); |
|
1777 } |
|
1778 } catch(InvalidParamException e) { |
|
1779 // removeThisRule(); |
|
1780 // ac.getFrame().addError(new CssError(e)); |
|
1781 validSelector = false; |
|
1782 throw new ParseException(e.getMessage()); |
|
1783 } |
|
1784 } ) ) |
|
1785 | |
|
1786 <COLON> ( ( n=<IDENT> |
|
1787 { |
|
1788 try { |
|
1789 s.addPseudoClass(convertIdent(n.image).toLowerCase()); |
|
1790 } catch(InvalidParamException e) { |
|
1791 removeThisRule(); |
|
1792 ac.getFrame().addError(new CssError(e)); |
|
1793 } |
|
1794 } ) |
|
1795 // FXIXME rewrite to make :lang( use a special case |
|
1796 | ( ( n=<FUNCTIONLANG> ( <S> )* (language=<NUMBER> | language=<IDENT> | language=<STRING> ) ( <S> )* ) { |
|
1797 try { |
|
1798 s.setPseudoFun(convertStringIndex(n.image, 0, |
|
1799 n.image.length() -1, false).toLowerCase(), |
|
1800 convertIdent(language.image)); |
|
1801 } catch(InvalidParamException e) { |
|
1802 removeThisRule(); |
|
1803 ac.getFrame().addError(new CssError(e)); |
|
1804 } |
|
1805 } |
|
1806 | ( n=<FUNCTION> ( <S> )* param=expression() ) { |
|
1807 try { |
|
1808 s.setPseudoFun(convertStringIndex(n.image, 0, |
|
1809 n.image.length() -1, |
|
1810 false).toLowerCase(), |
|
1811 param.toString()); |
|
1812 } catch(InvalidParamException e) { |
|
1813 removeThisRule(); |
|
1814 ac.getFrame().addError(new CssError(e)); |
|
1815 } |
|
1816 } |
|
1817 ) <LPARAN> |
|
1818 ) |
|
1819 } |
|
1820 |
|
1821 /** |
|
1822 * @exception ParseException exception during the parse |
|
1823 */ |
|
1824 void hash(CssSelectors s) : |
|
1825 {Token n; } |
|
1826 { |
|
1827 n=<HASHIDENT> { |
|
1828 n.image = n.image.substring(1); |
|
1829 if(Character.isDigit(n.image.charAt(0))) { |
|
1830 String profile = ac.getProfile(); |
|
1831 if(profile == null || profile.equals("") || profile.equals("none")) { |
|
1832 profile = ac.getCssVersion(); |
|
1833 } |
|
1834 |
|
1835 if(!profile.equals("css1")) { |
|
1836 // the id with the first digit escaped |
|
1837 String cl = "\\" + Integer.toString(n.image.charAt(0), 16); |
|
1838 cl += n.image.substring(1); |
|
1839 |
|
1840 addError(new ParseException(ac.getMsg().getString( |
|
1841 "parser.old_id")), |
|
1842 "To make \"." + n.image + "\" a valid id, CSS2" + |
|
1843 " requires the first digit to be escaped " + |
|
1844 "(\"#" + cl + "\")"); |
|
1845 // for css > 1, we add the rule to have a context, |
|
1846 // and we then remove it |
|
1847 s.addId(new IdSelector(n.image)); |
|
1848 removeThisRule(); |
|
1849 } |
|
1850 else { |
|
1851 CssLength length = new CssLength(); |
|
1852 boolean isLength = false; |
|
1853 try { |
|
1854 length.set(n.image, ac); |
|
1855 isLength = true; |
|
1856 } |
|
1857 catch(Exception e) { |
|
1858 isLength = false; |
|
1859 } |
|
1860 if(isLength) { |
|
1861 addError(new ParseException(ac.getMsg().getString( |
|
1862 "parser.id_dim")), n.image); |
|
1863 // we add the rule to have a context, and then we remove it |
|
1864 s.addId(new IdSelector(n.image)); |
|
1865 removeThisRule(); |
|
1866 } |
|
1867 else { |
|
1868 try { |
|
1869 s.addId(new IdSelector(n.image)); |
|
1870 ac.getFrame().addWarning("old_id"); |
|
1871 } catch (InvalidParamException e) { |
|
1872 ac.getFrame().addError(new CssError(e)); |
|
1873 removeThisRule(); |
|
1874 } |
|
1875 } |
|
1876 } |
|
1877 } |
|
1878 else { |
|
1879 try { |
|
1880 s.addId(new IdSelector(n.image)); |
|
1881 } catch (InvalidParamException e) { |
|
1882 ac.getFrame().addError(new CssError(e)); |
|
1883 removeThisRule(); |
|
1884 } |
|
1885 } |
|
1886 } |
|
1887 | n=<HASH> { |
|
1888 throw new ParseException(ac.getMsg().getString("parser.invalid_id_selector")); |
|
1889 } |
|
1890 } |
|
1891 |
|
1892 /** |
|
1893 * @exception ParseException exception during the parse |
|
1894 */ |
|
1895 CssProperty mediadeclaration() : |
|
1896 { String string_property; |
|
1897 CssExpression values = null; |
|
1898 boolean important = false; |
|
1899 setMediaDeclaration("on"); |
|
1900 } |
|
1901 { |
|
1902 try { |
|
1903 string_property=property() (":" ( <S> )* |
|
1904 values=expr() ( important=prio() )? )? |
|
1905 { |
|
1906 |
|
1907 try { |
|
1908 |
|
1909 setImportant(important); |
|
1910 |
|
1911 if (incompatible_error) { |
|
1912 throw new InvalidParamException("notforcss1", "inherit", ac); |
|
1913 } |
|
1914 |
|
1915 CssProperty p = handleDeclaration(string_property.toLowerCase(), |
|
1916 values, important); |
|
1917 return p; |
|
1918 |
|
1919 } catch (InvalidParamException e) { |
|
1920 incompatible_error = false; |
|
1921 if (null != values) { |
|
1922 values.starts(); |
|
1923 } |
|
1924 addError(e, (CssExpression) values); |
|
1925 } |
|
1926 return null; |
|
1927 } |
|
1928 } catch (NumberFormatException e) { |
|
1929 skipAfterExpression(e); |
|
1930 return null; |
|
1931 } catch (ParseException e) { |
|
1932 skipAfterExpression(e); |
|
1933 return null; |
|
1934 } finally { |
|
1935 setMediaDeclaration("off"); |
|
1936 } |
|
1937 } |
|
1938 |
|
1939 |
|
1940 /** |
|
1941 * @exception ParseException exception during the parse |
|
1942 */ |
|
1943 CssProperty declaration() : |
|
1944 { String string_property; |
|
1945 CssExpression values; |
|
1946 boolean important = false; |
|
1947 } |
|
1948 { |
|
1949 try { |
|
1950 string_property=property() ":" ( <S> )* |
|
1951 values=expr() ( important=prio() )? |
|
1952 { |
|
1953 try { |
|
1954 |
|
1955 setImportant(important); |
|
1956 |
|
1957 if (incompatible_error) { |
|
1958 throw new InvalidParamException("notforcss1", "inherit", ac); |
|
1959 } |
|
1960 |
|
1961 if (values.getCount() != 0) { |
|
1962 CssProperty p = handleDeclaration(string_property.toLowerCase(), |
|
1963 values, important); |
|
1964 // Did the property recognize all values in the expression ? |
|
1965 |
|
1966 if (!values.end() && ac.getMedium() == null) { |
|
1967 addError(new InvalidParamException("unrecognize", "", ac), |
|
1968 values); |
|
1969 } else { |
|
1970 // ok, return the new property |
|
1971 return p; |
|
1972 } |
|
1973 } |
|
1974 } catch (InvalidParamException e) { |
|
1975 incompatible_error = false; |
|
1976 values.starts(); |
|
1977 addError(e, (CssExpression) values); |
|
1978 } |
|
1979 return null; |
|
1980 } |
|
1981 } catch (NumberFormatException e) { |
|
1982 skipAfterExpression(e); |
|
1983 return null; |
|
1984 } catch (ParseException e) { |
|
1985 skipAfterExpression(e); |
|
1986 return null; |
|
1987 } catch (NullPointerException e) { |
|
1988 // NullPointerException happen if in handling a property |
|
1989 // something bad happen (like setting values on sub properties |
|
1990 // that had not been initialized (for an unknown reason yet). |
|
1991 skipAfterExpression(e); |
|
1992 return null; |
|
1993 } |
|
1994 } |
|
1995 |
|
1996 /** |
|
1997 * @exception ParseException exception during the parse |
|
1998 */ |
|
1999 boolean prio() : |
|
2000 {} |
|
2001 { |
|
2002 <IMPORTANT_SYM> ( <S> )* { return true; } |
|
2003 } |
|
2004 |
|
2005 CssExpression expression() : |
|
2006 { |
|
2007 CssExpression exp = new CssExpression(); |
|
2008 char operator = ' '; |
|
2009 Token n = null; |
|
2010 } |
|
2011 { |
|
2012 ( ( <PLUS> { operator = '+' ; } |
|
2013 | <MINUS> { operator = '-'; } |
|
2014 | n=<NUMBER> { setValue(new CssNumber(), exp, operator, n, NUMBER); } |
|
2015 // FIXME dimen should be a CssDimension() |
|
2016 | n=<DIMEN> { setValue(new CssIdent(), exp, operator, n, IDENT); } |
|
2017 | n=<STRING> { setValue(new CssString(), exp, operator, n, STRING); } |
|
2018 | n=<IDENT> { setValue(new CssIdent(), exp, operator, n, IDENT); } |
|
2019 ) ( <S> )* )+ |
|
2020 { return exp; } |
|
2021 } |
|
2022 /** |
|
2023 * @exception ParseException exception during the parse |
|
2024 */ |
|
2025 CssExpression expr() : |
|
2026 { |
|
2027 CssExpression values = new CssExpression(); |
|
2028 } |
|
2029 { |
|
2030 term(values) ( operator(values) term(values) )* |
|
2031 { return values; } |
|
2032 } |
|
2033 |
|
2034 /** |
|
2035 * @exception ParseException exception during the parse |
|
2036 */ |
|
2037 void term(CssExpression exp) : |
|
2038 { Token n; |
|
2039 char operator = ' '; |
|
2040 CssValue func; |
|
2041 } |
|
2042 { |
|
2043 ( ( operator=unaryOperator() )? |
|
2044 ( n=<NUMBER> { setValue(new CssNumber(), exp, operator, n, NUMBER); } |
|
2045 | n=<PERCENTAGE> { setValue(new CssPercentage(), exp, operator, n, |
|
2046 PERCENTAGE); } |
|
2047 | n=<LENGTH> { setValue(new CssLength(), exp, operator, n, LENGTH); } |
|
2048 | n=<EMS> { setValue(new CssLength(), exp, operator, n, EMS); } |
|
2049 | n=<EXS> { setValue(new CssLength(), exp, operator, n, EXS); } |
|
2050 | n=<ANGLE> { setValue(new CssAngle(), exp, operator, n, ANGLE);} |
|
2051 | n=<TIME> { setValue(new CssTime(), exp, operator, n, TIME); } |
|
2052 | n=<FREQ> { setValue(new CssFrequency(), exp, operator, n, FREQ); } |
|
2053 | n=<RESOLUTION> { setValue(new CssResolution(), exp, operator, n, RESOLUTION); } |
|
2054 | n=<DATE> { setValue(new CssDate(), exp, operator, n, DATE); } |
|
2055 | n=<DIMEN> { |
|
2056 addError(new ParseException(ac.getMsg().getString("parser.unknown-dimension")), n.image); } |
|
2057 | func=function() { setValue(func, exp, operator, null, FUNCTION); } |
|
2058 ) ( <S> )* ) |
|
2059 | (( n=<STRING> { setValue(new CssString(), exp, operator, n, STRING); } |
|
2060 | n=<IDENT> |
|
2061 { |
|
2062 /* |
|
2063 * Common error : |
|
2064 * H1 { |
|
2065 * color : black |
|
2066 * background : white |
|
2067 * } |
|
2068 */ |
|
2069 Token t = getToken(1); |
|
2070 Token semicolon = new Token(); |
|
2071 semicolon.kind = SEMICOLON; |
|
2072 semicolon.image = ";"; |
|
2073 if (t.kind == COLON) { |
|
2074 /* @@SEEME. (generate a warning?) */ |
|
2075 /* @@SEEME if expression is a single ident, |
|
2076 generate an error ? */ |
|
2077 addError(new ParseException(ac.getMsg().getString("parser.semi-colon")), |
|
2078 (CssExpression) null); |
|
2079 rejectToken(semicolon); |
|
2080 } else { |
|
2081 setValue(new CssIdent(), exp, operator, n, IDENT); |
|
2082 } |
|
2083 } |
|
2084 | hexcolor(exp) |
|
2085 | n=<URL> { |
|
2086 CssURL _u = new CssURL(); |
|
2087 _u.set(n.image, ac, url); |
|
2088 exp.addValue(_u); |
|
2089 } |
|
2090 | n=<UNICODERANGE> { setValue(new CssUnicodeRange(), exp, operator, n, |
|
2091 UNICODERANGE); } |
|
2092 ) ( <S> )* ) |
|
2093 } |
|
2094 |
|
2095 /** |
|
2096 * @exception ParseException exception during the parse |
|
2097 */ |
|
2098 CssValue function() : |
|
2099 {Token n; |
|
2100 CssExpression exp; |
|
2101 org.w3c.css.values.CssColor color = new org.w3c.css.values.CssColor(); |
|
2102 org.w3c.css.values.ATSCColor colorATSC = new org.w3c.css.values.ATSCColor(); |
|
2103 } |
|
2104 { |
|
2105 n=<FUNCTION> ( <S> )* exp=expr() |
|
2106 ")" { |
|
2107 String funcname = n.image.toLowerCase(); |
|
2108 if (funcname.equals("rgb(")) { |
|
2109 if (!getAtRule().toString().equals("@media atsc-tv")) { |
|
2110 color.setRGBColor(exp, ac); |
|
2111 return color; |
|
2112 } else { |
|
2113 colorATSC.setRGBColor(exp, ac); |
|
2114 return colorATSC; |
|
2115 } |
|
2116 } else if (n.image.toLowerCase().equals("atsc-rgba(")) { |
|
2117 if (getAtRule().toString().equals("@media atsc-tv")) { |
|
2118 colorATSC.setATSCrgba(exp, ac); |
|
2119 return colorATSC; |
|
2120 } else { |
|
2121 addError(new InvalidParamException("onlyATSC", "", ac), |
|
2122 getAtRule().toString()); |
|
2123 return null; |
|
2124 } |
|
2125 } else { |
|
2126 CssFunction f = new CssFunction(); |
|
2127 f.set(n.image.substring(0, n.image.length() - 1), |
|
2128 exp); |
|
2129 return f; |
|
2130 } |
|
2131 } |
|
2132 } |
|
2133 |
|
2134 /** |
|
2135 * @exception ParseException exception during the parse |
|
2136 */ |
|
2137 void hexcolor(CssExpression exp) : |
|
2138 {Token n; |
|
2139 } |
|
2140 { |
|
2141 ( n=<HASHIDENT> | n=<HASH> ) { |
|
2142 n.image = Util.strip(n.image); |
|
2143 setValue(new org.w3c.css.values.CssColor(), exp, ' ', n, HASH); |
|
2144 } |
|
2145 } |
|
2146 |
|
2147 /* |
|
2148 * @@SEEME EOF |
|
2149 */ |
|
2150 |
|
2151 JAVACODE |
|
2152 String skipStatement() { |
|
2153 StringBuilder s = new StringBuilder(); |
|
2154 Token tok = getToken(0); |
|
2155 boolean first = true; |
|
2156 |
|
2157 if (tok.image != null) { |
|
2158 s.append(tok.image); |
|
2159 } |
|
2160 /* FIXME here, two option, we skip during an error, or outside |
|
2161 an error, currently both can fail with a TokenMgrError, should |
|
2162 we catch all, or only when filling message for errors? |
|
2163 |
|
2164 -> taking the "always skip" approach. |
|
2165 */ |
|
2166 while (true) { |
|
2167 try { |
|
2168 tok = getToken(1); |
|
2169 if (tok.kind == EOF) { |
|
2170 if (first) { |
|
2171 return null; |
|
2172 } else { |
|
2173 break; |
|
2174 } |
|
2175 } |
|
2176 s.append(tok.image); |
|
2177 if (tok.kind == LBRACE) { |
|
2178 getNextToken(); |
|
2179 s.append(skip_to_matching_brace()); |
|
2180 getNextToken(); |
|
2181 tok = getToken(1); |
|
2182 break; |
|
2183 } else if ((tok.kind == RBRACE) || (tok.kind == SEMICOLON)) { |
|
2184 getNextToken(); |
|
2185 tok = getToken(1); |
|
2186 break; |
|
2187 } |
|
2188 getNextToken(); |
|
2189 } catch (TokenMgrError tokenerror) { |
|
2190 // read one char at a time, and loop |
|
2191 try { |
|
2192 s.append(jj_input_stream.readChar()); |
|
2193 continue; |
|
2194 } catch (java.io.IOException ioex) { |
|
2195 return s.toString().trim(); |
|
2196 } |
|
2197 } |
|
2198 first = false; |
|
2199 } |
|
2200 |
|
2201 // skip white space |
|
2202 while (tok.kind == S) { |
|
2203 getNextToken(); |
|
2204 tok = getToken(1); |
|
2205 } |
|
2206 String statement = s.toString().trim(); |
|
2207 return statement; |
|
2208 } |
|
2209 |
|
2210 JAVACODE |
|
2211 String skip_to_matching_brace() { |
|
2212 StringBuilder s = new StringBuilder(); |
|
2213 Token tok; |
|
2214 int nesting = 1; |
|
2215 /* FIXME |
|
2216 same as above */ |
|
2217 while (true) { |
|
2218 tok = getToken(1); |
|
2219 if (tok.kind == EOF) { |
|
2220 break; |
|
2221 } |
|
2222 s.append(tok.image); |
|
2223 if (tok.kind == LBRACE) { |
|
2224 nesting++; |
|
2225 } else if (tok.kind == RBRACE) { |
|
2226 nesting--; |
|
2227 if (nesting == 0) { |
|
2228 break; |
|
2229 } |
|
2230 } |
|
2231 getNextToken(); |
|
2232 } |
|
2233 return s.toString(); |
|
2234 } |
|
2235 |
|
2236 /* |
|
2237 * @@HACK |
|
2238 * I can't insert a token into the tokens flow. |
|
2239 * It's jj_consume_token implementation dependant! :-( |
|
2240 */ |
|
2241 JAVACODE |
|
2242 void rejectToken(Token t) { |
|
2243 Token fakeToken = new Token(); |
|
2244 t.next = token; |
|
2245 fakeToken.next = t; |
|
2246 token = fakeToken; |
|
2247 } |
|
2248 |
|
2249 /** skip after an expression |
|
2250 */ |
|
2251 JAVACODE |
|
2252 void skipAfterExpression(Exception e) { |
|
2253 StringBuilder s = new StringBuilder(); |
|
2254 s.append(getToken(0).image); |
|
2255 while (true) { |
|
2256 try { |
|
2257 Token t = getToken(1); |
|
2258 if (t.kind == LBRACE) { |
|
2259 s.append(t.image); |
|
2260 getNextToken(); |
|
2261 s.append(skip_to_matching_brace()); |
|
2262 getNextToken(); |
|
2263 t = getToken(1); |
|
2264 continue; |
|
2265 } |
|
2266 if ((t.kind == SEMICOLON) || (t.kind == RBRACE) |
|
2267 || (t.kind == EOF)) { |
|
2268 break; |
|
2269 } |
|
2270 s.append(t.image); |
|
2271 getNextToken(); |
|
2272 t = getToken(1); |
|
2273 } catch (TokenMgrError tmerr) { |
|
2274 try { |
|
2275 s.append(jj_input_stream.readChar()); |
|
2276 continue; |
|
2277 } catch (java.io.IOException ioex) { |
|
2278 ioex.printStackTrace(); |
|
2279 break; |
|
2280 } |
|
2281 } |
|
2282 } |
|
2283 String statement = s.toString().trim(); |
|
2284 addError(e, s.toString()); |
|
2285 } |
|
2286 |
|
2287 JAVACODE |
|
2288 String convertStringIndex(String s, int start, int len, boolean escapeFirst) { |
|
2289 int index = start; |
|
2290 int t; |
|
2291 int maxCount = 0; |
|
2292 if ((start == 0) && (len == s.length()) && (s.indexOf('\\') == -1)) { |
|
2293 return s; |
|
2294 } |
|
2295 StringBuilder buf = new StringBuilder(len); |
|
2296 |
|
2297 while (index < len) { |
|
2298 char c = s.charAt(index); |
|
2299 if (c == '\\') { |
|
2300 if (++index < len) { |
|
2301 c = s.charAt(index); |
|
2302 switch (c) { |
|
2303 case '0': case '1': case '2': case '3': case '4': |
|
2304 case '5': case '6': case '7': case '8': case '9': |
|
2305 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
|
2306 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
|
2307 int numValue = Character.digit(c, 16); |
|
2308 int count = 1; |
|
2309 if (maxCount == 0) { |
|
2310 maxCount = (ac.getCssVersion().equals("css1") ? |
|
2311 4 : 6); |
|
2312 } |
|
2313 while (index + 1 < len) { |
|
2314 c = s.charAt(index+1); |
|
2315 t = Character.digit(c, 16); |
|
2316 if (t != -1 && count++ < maxCount) { |
|
2317 numValue = (numValue<<4) | t; |
|
2318 index++; |
|
2319 } else { |
|
2320 if (c == ' ' || c == '\t' || |
|
2321 c == '\n' || c == '\f' ) { |
|
2322 // skip the latest white space |
|
2323 index++; |
|
2324 } else if ( c == '\r' ) { |
|
2325 index++; |
|
2326 // special case for \r\n |
|
2327 if (index+1 < len) { |
|
2328 if (s.charAt(index + 1) == '\n') { |
|
2329 index++; |
|
2330 } |
|
2331 } |
|
2332 } |
|
2333 break; |
|
2334 } |
|
2335 } |
|
2336 if (!escapeFirst && numValue < 255 && numValue>31) { |
|
2337 if (! ( (numValue>96 && numValue<123) // [a-z] |
|
2338 || (numValue>64 && numValue<91) // [A-Z] |
|
2339 || (numValue>47 && numValue<58) // [0-9] |
|
2340 || (numValue == 95) // _ |
|
2341 || (numValue == 45) // - |
|
2342 ) |
|
2343 ) { |
|
2344 buf.append('\\'); |
|
2345 } |
|
2346 buf.append((char) numValue); |
|
2347 break; |
|
2348 } |
|
2349 char b[] = new char[maxCount]; |
|
2350 t = maxCount; |
|
2351 while (t > 0) { |
|
2352 b[--t] = hexdigits[numValue & 0xF]; |
|
2353 numValue >>>= 4; |
|
2354 } |
|
2355 buf.append('\\').append(b); |
|
2356 break; |
|
2357 case '\n': |
|
2358 case '\f': |
|
2359 break; |
|
2360 case '\r': |
|
2361 if (index + 1 < len) { |
|
2362 if (s.charAt(index + 1) == '\n') { |
|
2363 index ++; |
|
2364 } |
|
2365 } |
|
2366 break; |
|
2367 case '-' : case '_' : case 'g' : case 'G' : |
|
2368 case 'h' : case 'H' : case 'i' : case 'I' : |
|
2369 case 'j' : case 'J' : case 'k' : case 'K' : |
|
2370 case 'l' : case 'L' : case 'm' : case 'M' : |
|
2371 case 'n' : case 'N' : case 'o' : case 'O' : |
|
2372 case 'p' : case 'P' : case 'q' : case 'Q' : |
|
2373 case 'r' : case 'R' : case 's' : case 'S' : |
|
2374 case 't' : case 'T' : case 'u' : case 'U' : |
|
2375 case 'v' : case 'V' : case 'w' : case 'W' : |
|
2376 case 'x' : case 'X' : case 'y' : case 'Y' : |
|
2377 case 'z' : case 'Z' : |
|
2378 buf.append(c); |
|
2379 break; |
|
2380 default: |
|
2381 buf.append('\\').append(c); |
|
2382 } |
|
2383 } else { |
|
2384 throw new ParseException("invalid string"); |
|
2385 } |
|
2386 } else { |
|
2387 buf.append(c); |
|
2388 } |
|
2389 escapeFirst = false; |
|
2390 index++; |
|
2391 } |
|
2392 return buf.toString(); |
|
2393 } |
|
2394 |
|
2395 JAVACODE |
|
2396 String convertIdent(String s) { |
|
2397 return convertStringIndex(s, 0, s.length(), false); |
|
2398 } |
|
2399 |
|
2400 JAVACODE |
|
2401 String convertClassIdent(String s) { |
|
2402 return convertStringIndex(s, 0, s.length(), true); |
|
2403 } |
|
2404 |
|
2405 JAVACODE |
|
2406 String convertString(String s) { |
|
2407 return convertStringIndex(s, 0, s.length(), false); |
|
2408 } |
|
2409 |
|
2410 JAVACODE |
|
2411 String hexEscapeFirst(String s) { |
|
2412 StringBuilder sb = new StringBuilder(); |
|
2413 sb.append('\\').append(Integer.toString(s.charAt(0), 16)); |
|
2414 char c = s.charAt(1); |
|
2415 if (((c >= '0') && (c <= '9')) || |
|
2416 ((c >= 'A') && (c <= 'F')) || |
|
2417 ((c >= 'a') && (c <= 'f'))) { |
|
2418 sb.append(' '); |
|
2419 } |
|
2420 sb.append(s.substring(1)); |
|
2421 return sb.toString(); |
|
2422 } |
|
2423 /* |
|
2424 * compile-command: javacc CssParser.jj & jc CssParser.java |
|
2425 */ |
|