root/css4swing/CSS.g

Revision 1779, 18.4 kB (checked in by eitan, 3 years ago)

fixed issue with css grammar parsing selector composed of element + cssclass; used to have an issue with whitespace relator implying descendance

Line 
1 grammar CSS;
2
3 tokens
4 {
5   CHILD='>';
6   SIBLING='+';
7 }
8
9 @header
10 {
11   package com.u2d.cssparser;
12
13   import com.u2d.css4swing.*;
14   import com.u2d.css4swing.selector.*;
15   import com.u2d.css4swing.property.*;
16 }
17 @lexer::header { package com.u2d.cssparser; }
18
19 @members
20 {
21   Stylesheet sheet = new Stylesheet();
22 }
23
24 stylesheet returns [Stylesheet value]
25     : (nsdecl)* (rule)*
26     {
27       $value = sheet;
28     }
29     ;
30
31 nsdecl
32   : '@namespace' ID PkgName
33   {
34     sheet.addNamespace($ID.text, $PkgName.text);
35   }
36   ;
37
38 rule
39   @init { Rule rule; }
40   : s=selector { rule = sheet.addRule($s.value); }
41         (',' additionalselector=selector {rule.addSelector($additionalselector.value); } )*
42     '{'
43       (declaration[rule])*
44     '}'
45   ;
46
47
48 // ------ selector subgrammar ------
49
50 selector returns [Selector value]
51  :
52  first=selectorterm
53  {
54    value = $first.value ;
55  }
56  (
57    ( relator next=selectorterm )
58    {
59      value = new CompositeSelector(value, $relator.value, $next.value);
60    }
61    |
62    ( next=selectorterm )
63    {
64      value = new CompositeSelector(value, new Descendant(), $next.value);
65    }
66  )*
67  ;
68  
69 relator returns [Relator value]
70  : CHILD { $value = new Child(); }
71  | SIBLING { $value = new Sibling(); }
72  ;
73
74 selectorterm returns [SimpleSelector value]
75  @init
76  {
77    $value = new SimpleSelector();
78  }
79  : csselementname[$value]
80  | cssclass[$value]
81  | cssident=Cssident
82      {
83        $value.setIdent($cssident.text.substring(1));
84      }
85  | (nsRef[$value])? both=ElementAndClass
86    {
87      String[] parts = $both.text.split("\\.");
88      $value.setElementName(parts[0]);
89      $value.setCssClassName(parts[1]);
90    }
91  ;
92
93 nsRef[SimpleSelector s]: ID '|' { $s.setNamespace($ID.text); } ;
94 csselementname[SimpleSelector s] : (nsRef[$s])? ID  { $s.setElementName($ID.text); } ;
95 cssclass[SimpleSelector s] : '.' ID { $s.setCssClassName($ID.text); } ;
96
97
98 // ----- declarations ------
99
100 declaration[Rule rule]
101     : sizingdecl[rule] | colordecl[rule] | imagedecl[rule]
102     | cursordecl[rule] | linestyledecl[rule]
103     | fontsizedecl[rule] | fontweightdecl[rule]
104     | fontstyledecl[rule] | fontfamilydecl[rule]
105     | textaligndecl[rule]
106     | shorthandpropertydecl[rule]
107     | borderradiusdecl[rule]
108     | opacitydecl[rule]
109     | ignoredecl[rule]
110     ;
111
112 boxdims[Rule rule]
113  @init
114  {
115    SizingDeclaration leftdecl, rightdecl, topdecl, bottomdecl;
116    leftdecl = rightdecl = topdecl = bottomdecl = new MarginLeft(); // to make compiler happy..
117  }
118  : ('margin' {
119                     leftdecl = new MarginLeft();
120                     rightdecl = new MarginRight();
121                     topdecl = new MarginTop();
122                     bottomdecl = new MarginBottom();
123                    }
124     | 'padding' {
125                     leftdecl = new PaddingLeft();
126                     rightdecl = new PaddingRight();
127                     topdecl = new PaddingTop();
128                     bottomdecl = new PaddingBottom();
129                    }
130     | 'border-width' {
131                     leftdecl = new BorderLeftWidth();
132                     rightdecl = new BorderRightWidth();
133                     topdecl = new BorderTopWidth();
134                     bottomdecl = new BorderBottomWidth();
135                    }
136      ) ':' (
137         first=measure second=measure third=measure fourth=measure
138         {
139           topdecl.setValue($first.value);
140           rightdecl.setValue($second.value);
141           bottomdecl.setValue($third.value);
142           leftdecl.setValue($fourth.value);
143         }
144         | first=measure second=measure third=measure
145         {
146           topdecl.setValue($first.value);
147           leftdecl.setValue($second.value);
148           rightdecl.setValue($second.value);
149           bottomdecl.setValue($third.value);
150         }
151         | first=measure second=measure
152         {
153           topdecl.setValue($first.value);
154           bottomdecl.setValue($first.value);
155           leftdecl.setValue($second.value);
156           rightdecl.setValue($second.value);
157         }
158         | first=measure
159         {
160           topdecl.setValue($first.value);
161           bottomdecl.setValue($first.value);
162           leftdecl.setValue($first.value);
163           rightdecl.setValue($first.value);
164         }
165      )
166
167     {
168       $rule.addDeclaration(leftdecl);
169       $rule.addDeclaration(rightdecl);
170       $rule.addDeclaration(topdecl);
171       $rule.addDeclaration(bottomdecl);
172     }
173    ';'
174  ;
175
176 shorthandpropertydecl[Rule rule]
177   : boxdims[rule]
178   | fontdecl[rule]
179   | 'border' ':' borderWidth=measure linestyle borderColor=color ';'
180    {
181      $rule.addDeclaration(new BorderLeftWidth($borderWidth.value));
182      $rule.addDeclaration(new BorderLeftStyle($linestyle.value));
183      $rule.addDeclaration(new BorderLeftColor($borderColor.value));
184      $rule.addDeclaration(new BorderRightWidth($borderWidth.value));
185      $rule.addDeclaration(new BorderRightStyle($linestyle.value));
186      $rule.addDeclaration(new BorderRightColor($borderColor.value));
187      $rule.addDeclaration(new BorderTopWidth($borderWidth.value));
188      $rule.addDeclaration(new BorderTopStyle($linestyle.value));
189      $rule.addDeclaration(new BorderTopColor($borderColor.value));
190      $rule.addDeclaration(new BorderBottomWidth($borderWidth.value));
191      $rule.addDeclaration(new BorderBottomStyle($linestyle.value));
192      $rule.addDeclaration(new BorderBottomColor($borderColor.value));
193    }
194   | 'border-left' ':' borderWidth=measure linestyle borderColor=color ';'
195    {
196      $rule.addDeclaration(new BorderLeftWidth($borderWidth.value));
197      $rule.addDeclaration(new BorderLeftStyle($linestyle.value));
198      $rule.addDeclaration(new BorderLeftColor($borderColor.value));
199    }
200   | 'border-right' ':' borderWidth=measure linestyle borderColor=color ';'
201    {
202      $rule.addDeclaration(new BorderRightWidth($borderWidth.value));
203      $rule.addDeclaration(new BorderRightStyle($linestyle.value));
204      $rule.addDeclaration(new BorderRightColor($borderColor.value));
205    }
206   | 'border-top' ':' borderWidth=measure linestyle borderColor=color ';'
207    {
208      $rule.addDeclaration(new BorderTopWidth($borderWidth.value));
209      $rule.addDeclaration(new BorderTopStyle($linestyle.value));
210      $rule.addDeclaration(new BorderTopColor($borderColor.value));
211    }
212   | 'border-bottom' ':' borderWidth=measure linestyle borderColor=color ';'
213    {
214      $rule.addDeclaration(new BorderBottomWidth($borderWidth.value));
215      $rule.addDeclaration(new BorderBottomStyle($linestyle.value));
216      $rule.addDeclaration(new BorderBottomColor($borderColor.value));
217    }
218   | 'border-style' ':' linestyle ';'
219    {
220      $rule.addDeclaration(new BorderLeftStyle($linestyle.value));
221      $rule.addDeclaration(new BorderRightStyle($linestyle.value));
222      $rule.addDeclaration(new BorderTopStyle($linestyle.value));
223      $rule.addDeclaration(new BorderBottomStyle($linestyle.value));
224    }
225   | 'border-color' ':' color ';'
226   {
227     $rule.addDeclaration(new BorderLeftColor($color.value));
228     $rule.addDeclaration(new BorderRightColor($color.value));
229     $rule.addDeclaration(new BorderTopColor($color.value));
230     $rule.addDeclaration(new BorderBottomColor($color.value));
231   }
232   ;
233
234 fontdecl[Rule rule]
235  : 'font' ':' ( bold='bold'
236       {
237         $rule.addDeclaration( new FontWeight(java.awt.Font.BOLD) );
238       } )?
239       ( italic='italic'
240       {
241         $rule.addDeclaration( new FontStyle(java.awt.Font.ITALIC) );
242       })?
243       fontsize=measure family=fontFamilyValues
244       {
245         $rule.addDeclaration(new FontSize($fontsize.value));
246         $rule.addDeclaration(new FontFamily($family.value));
247       } ';'
248  ;
249
250 opacitydecl[Rule rule]
251  : 'opacity' ':' FLOAT ';'
252  {
253    float value = Float.parseFloat($FLOAT.text);
254    Declaration opacity = new Opacity(value);
255    $rule.addDeclaration(opacity);
256  }
257  ;
258
259 ignoredecl[Rule rule]
260  : '-c4s-ignore' ':' BOOL ';'
261  {
262    boolean value = Boolean.parseBoolean($BOOL.text);
263    Declaration ignore = new Ignore(value);
264    $rule.addDeclaration(ignore);
265  }
266  ;
267
268 borderradiusdecl[Rule rule]
269   : borderRadiusProp ':' borderRadius ';'
270   {
271     BorderRadius declaration = $borderRadiusProp.value;
272     declaration.setValue($borderRadius.value);
273     $rule.addDeclaration(declaration);
274   }
275   ;
276  
277 borderRadiusProp returns [BorderRadius value]
278   : 'border-top-right-radius' { $value = new BorderRadiusTopRight(); }
279   | 'border-bottom-right-radius' { $value = new BorderRadiusBottomRight(); }
280   | 'border-bottom-left-radius' { $value = new BorderRadiusBottomLeft(); }
281   | 'border-top-left-radius' { $value = new BorderRadiusTopLeft(); }
282   | 'border-radius' { $value = new BorderRadius(); }
283   ;
284  
285 borderRadius returns [BorderRadius value]
286   : horiz=measure
287   {
288     $value = new BorderRadius($horiz.value);
289   }
290   (vert=measure
291     {
292       $value = new BorderRadius($horiz.value, $vert.value);
293     }
294   )?
295   ;
296
297
298 // -------------------- sizing declarations .. --
299
300 sizingdecl[Rule rule]
301     :   sizingProp ':' measure ';'
302     {
303       SizingDeclaration d = $sizingProp.value;
304       d.setValue($measure.value);
305       $rule.addDeclaration(d);
306     }
307     ;
308
309 sizingProp returns [SizingDeclaration value]
310   : 'margin-left' { $value = new MarginLeft(); }
311   | 'margin-right' { $value = new MarginRight(); }
312   | 'margin-top' { $value = new MarginTop(); }
313   | 'margin-bottom' { $value = new MarginBottom(); }
314   | 'border-left-width' { $value = new BorderLeftWidth(); }
315   | 'border-right-width' { $value = new BorderRightWidth(); }
316   | 'border-top-width' { $value = new BorderTopWidth(); }
317   | 'border-bottom-width' { $value = new BorderBottomWidth(); }
318   | 'padding-left' { $value = new PaddingLeft(); }
319   | 'padding-right' { $value = new PaddingRight(); }
320   | 'padding-top' { $value = new PaddingTop(); }
321   | 'padding-bottom' { $value = new PaddingBottom(); }
322   ;
323
324 measure returns [Measure value]
325  : j_int unit
326  {
327    $value = new Measure($j_int.value, $unit.text);
328  }
329  ;
330
331 unit : 'pt' | 'px' | 'em' | 'ex' ;
332
333 // -------------------- image declaration .. ---
334 imagedecl[Rule rule]
335   @init
336   {
337     BackgroundImage d = new BackgroundImage();
338   }
339   : 'background-image' ':'
340     ( imageResourceRef { d.setValue($imageResourceRef.value); }
341       | 'none' { d.setValue(null); } )
342     (placementMethod { d.setPlacementMethod($placementMethod.text); } )? ';'
343   {
344     $rule.addDeclaration(d);
345   }
346   ;
347
348 placementMethod : 'centered' | 'tiled' | 'stretched' ;
349
350 imageResourceRef returns [java.awt.Image value]
351   : resourceRef
352   {
353     $value = new javax.swing.ImageIcon($resourceRef.value).getImage();
354   }
355   ;
356
357 resourceRef returns [java.net.URL value]
358   :  'resource(' path=StringLiteral ')'
359   {
360     String text = Utils.unquote($path.text);
361     $value = getClass().getClassLoader().getResource(text);
362   }
363   ;
364
365 // -------------------- color declarations .. ---
366
367
368 colordecl[Rule rule]
369    :  colorProp ':' paint ';'
370    {
371      ColorDeclaration d = $colorProp.value;
372      d.setValue($paint.value);
373      $rule.addDeclaration(d);
374    }
375    ;
376
377 colorProp returns [ColorDeclaration value]
378   : 'background-color' { $value = new BackgroundColor(); }
379   | 'color' { $value = new ForegroundColor(); }
380   | 'border-left-color' { $value = new BorderLeftColor(); }
381   | 'border-right-color' { $value = new BorderRightColor(); }
382   | 'border-top-color' { $value = new BorderTopColor(); }
383   | 'border-bottom-color' { $value = new BorderBottomColor(); }
384   ;
385
386 paint returns [java.awt.Paint value]
387   : color { $value = $color.value; }
388   | gradient { $value = $gradient.value; }
389   ;
390    
391 color returns [java.awt.Color value]
392   : colorName { $value = new java.awt.Color($colorName.value); }
393   | hexColor { $value = new java.awt.Color($hexColor.value); }
394   | 'transparent' { $value = new java.awt.Color(0, 0, 0, 0); }
395   | rgbSpec { $value = $rgbSpec.value; }
396   | rgbaSpec { $value = $rgbaSpec.value; }
397   ;
398
399 rgbSpec returns [java.awt.Color value]
400   : 'rgb(' red=j_int ',' green=j_int ',' blue=j_int ')'
401   {
402     $value = new java.awt.Color($red.value, $green.value, $blue.value);
403   }
404   ;
405  
406 rgbaSpec returns [java.awt.Color value]
407   : 'rgba(' red=j_int ',' green=j_int ',' blue=j_int ',' alpha=FLOAT ')'
408   {
409     int alphaInt = (int) (Float.parseFloat($alpha.text) * 255);
410     $value = new java.awt.Color($red.value, $green.value, $blue.value, alphaInt);
411   }
412   ;
413
414 gradient returns [java.awt.GradientPaint value]
415   : 'gradient(' x1=j_int ',' y1=j_int ',' color1=color ',' x2=j_int ',' y2=j_int ',' color2=color ')'
416   {
417     $value = new java.awt.GradientPaint($x1.value, $y1.value, $color1.value,
418                                         $x2.value, $y2.value, $color2.value);
419   }
420   ;
421
422 j_int returns [int value]
423   : i=INT
424   {
425     $value = Integer.parseInt($i.text);
426   }
427   ;
428
429 colorName returns [int value]
430   : 'maroon' { $value = 0x800000; }
431   | 'red'  { $value = 0xff0000; }
432   | 'orange'  { $value = 0xffA500; }
433   | 'yellow'  { $value = 0xffff00; }
434   | 'olive'  { $value = 0x808000; }
435   | 'purple'  { $value = 0x800080; }
436   | 'fuchsia'  { $value = 0xff00ff; }
437   | 'white'  { $value = 0xffffff; }
438   | 'lime'  { $value = 0x00ff00; }
439   | 'green'  { $value = 0x008000; }
440   | 'navy'  { $value = 0x000080; }
441   | 'blue'   { $value = 0x0000ff; }
442   | 'aqua'  { $value = 0x00ffff; }
443   | 'teal'  { $value = 0x008080; }
444   | 'black'  { $value = 0x000000; }
445   | 'silver'  { $value = 0xc0c0c0; }
446   | 'gray' { $value = 0x808080; }
447      ;
448
449 hexColor returns [int value]
450    : HexNum
451      {
452        String num =  $HexNum.text.substring(1);
453        if (num.length() >= 6)
454        {
455            $value = (int) Long.parseLong(num, 16);
456        }
457        else if (num.length() >= 3)
458        {
459            StringBuffer buf = new StringBuffer();
460            buf.append(num.charAt(0))
461               .append(num.charAt(0))
462               .append(num.charAt(1))
463               .append(num.charAt(1))
464               .append(num.charAt(2))
465               .append(num.charAt(2));
466            if (num.length() > 3)
467            {
468              buf.append(num.charAt(3))
469                 .append(num.charAt(3));
470            }
471            $value = (int) Long.parseLong(buf.toString(), 16);
472        }
473      }
474    ;
475
476 // --------------------
477
478 fontsizedecl[Rule rule]
479     :   'font-size' ':' value=measure ';'
480     {
481       Declaration d = new FontSize($value.value);
482       $rule.addDeclaration(d);
483     }
484     ;
485 fontweightdecl[Rule rule]
486    :  'font-weight' ':' fontWeightValue ';'
487    {
488      Declaration d = new FontWeight($fontWeightValue.value);
489      $rule.addDeclaration(d);
490    }
491    ;
492 fontWeightValue returns [int value]
493   : 'bold' { $value = java.awt.Font.BOLD; }
494   | 'normal' { $value = java.awt.Font.PLAIN; }
495   ;
496
497 fontstyledecl[Rule rule]
498    :  'font-style' ':' fontStyleValue ';'
499    {
500      $rule.addDeclaration( new FontStyle($fontStyleValue.value) );
501    }
502    ;
503 fontStyleValue returns [int value]
504   : 'italic' { $value = java.awt.Font.ITALIC; }
505   | 'normal' { $value = java.awt.Font.PLAIN; }
506   ;
507
508 fontfamilydecl[Rule rule]
509    :  'font-family' ':' fontFamilyValues ';'
510    {
511      Declaration d = new FontFamily($fontFamilyValues.value);
512      $rule.addDeclaration(d);
513    }
514    ;
515
516 fontFamilyValues returns [List value]
517   @init
518   {
519     $value = new ArrayList();
520   }
521   : ( item=fontFamilyValue ',' { $value.add($item.value); } )* last=fontFamilyValue
522       {
523         $value.add($last.value);
524       }
525   ;
526
527 fontFamilyValue returns [String value]
528   :  ID { $value = $ID.text; }
529   | StringLiteral { $value = Utils.unquote($StringLiteral.text); }
530   | genericFamilyName { $value = $genericFamilyName.value; }
531   ;
532
533 genericFamilyName returns [String value]
534   : 'serif' { $value = FontFamily.SERIF; }
535   | 'sans-serif' { $value = FontFamily.SANS_SERIF; }
536   | 'monospace' { $value = FontFamily.MONOSPACE; }
537   /*
538   | 'cursive' { $value = "?"; }
539   | 'fantasy' { $value = "?"; }
540   */
541   ;
542
543 // ----------------------------------
544
545 textaligndecl[Rule rule]
546   @init
547   {
548     TextAlign decl = new TextAlign();
549   }
550   : 'text-align' ':'
551      ('left' { decl.setValue(TextAlign.Alignment.LEFT); }
552      | 'right' { decl.setValue(TextAlign.Alignment.RIGHT); }
553      | 'center' { decl.setValue(TextAlign.Alignment.CENTER); }
554      ) ';'
555   {
556     $rule.addDeclaration(decl);
557   }
558   ;
559
560 // ----------------------------------
561
562 cursordecl[Rule rule]
563    : 'cursor' ':' cursor ';'
564    {
565      $rule.addDeclaration(new Cursor($cursor.value));
566    }
567    ;
568
569 cursor returns [int value]
570   : 'crosshair' { $value = java.awt.Cursor.CROSSHAIR_CURSOR; }
571   | 'default' { $value = java.awt.Cursor.DEFAULT_CURSOR; }
572   | 'pointer' { $value = java.awt.Cursor.HAND_CURSOR; }
573   | 'move'  { $value = java.awt.Cursor.MOVE_CURSOR; }
574   | 'e-resize'  { $value = java.awt.Cursor.E_RESIZE_CURSOR; }
575   | 'ne-resize'  { $value = java.awt.Cursor.NE_RESIZE_CURSOR; }
576   | 'nw-resize'  { $value = java.awt.Cursor.NW_RESIZE_CURSOR; }
577   | 'n-resize'  { $value = java.awt.Cursor.N_RESIZE_CURSOR; }
578   | 'se-resize'  { $value = java.awt.Cursor.SE_RESIZE_CURSOR; }
579   | 'sw-resize'  { $value = java.awt.Cursor.SW_RESIZE_CURSOR; }
580   | 's-resize'  { $value = java.awt.Cursor.S_RESIZE_CURSOR; }
581   | 'w-resize'  { $value = java.awt.Cursor.W_RESIZE_CURSOR; }
582   | 'text'  { $value = java.awt.Cursor.TEXT_CURSOR; }
583   | 'wait'  { $value = java.awt.Cursor.WAIT_CURSOR; }
584   /*
585   | 'help'  { $value = java.awt.Cursor.? ; }
586   | 'progress' { $value = java.awt.Cursor.? ; }
587   */
588   ;
589
590 // ----------------------------------
591
592 linestyledecl[Rule rule]
593    : prop=borderStyleProp ':' linestyle ';'
594    {
595      LineStyleDeclaration d = $prop.value;
596      d.setValue($linestyle.value);
597      $rule.addDeclaration(d);
598    }
599    ;
600
601 borderStyleProp returns [LineStyleDeclaration value]
602   : 'border-left-style' { $value = new BorderLeftStyle(); }
603   | 'border-right-style' { $value = new BorderRightStyle(); }
604   | 'border-top-style'  { $value = new BorderTopStyle(); }
605   | 'border-bottom-style' { $value = new BorderBottomStyle(); }
606   ;
607
608 /* TODO: finish this: */
609
610 linestyle returns [LineStyle value]
611   : 'dotted' { $value = LineStyle.DOTTED; }
612   | 'dashed' { $value = LineStyle.DASHED; }
613   | 'solid' { $value = LineStyle.SOLID; }
614   /*
615   | 'none'
616   | 'hidden'
617   | 'double'
618   | 'groove'
619   | 'ridge'
620   | 'inset'
621   | 'outset'
622   */
623   ;
624
625 // Lexer Rules ..
626
627 BOOL : 'true' | 'false' ;
628
629 Percentage : FLOAT '%' ;
630 INT :   (Digit)+ ;
631 HexNum : '#' (HexDigit)+ ;
632 Cssident : '#' ID ;
633 ElementAndClass : ID '.' ID;
634 FLOAT   :   (Digit)+ ('.' Digit*)? ;
635 ID  : Nmstart ( Nmchar )* ;
636 PkgName : (ID ( '.' ID)* ) ;
637
638 StringLiteral :  '"' ( EscapeSequence | ~('\\'|'"') )* '"' ;
639
640 fragment
641 Nmchar : Nmstart|Digit|'-' ;
642
643 fragment
644 Nmstart : 'a'..'z'|'A'..'Z'|'_' ;
645
646 fragment
647 EscapeSequence
648     :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
649     |   UnicodeEscape
650     |   OctalEscape
651     ;
652
653 fragment
654 OctalEscape
655     :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
656     |   '\\' ('0'..'7') ('0'..'7')
657     |   '\\' ('0'..'7')
658     ;
659
660 fragment
661 UnicodeEscape
662     :   '\\' 'u' HexDigit HexDigit HexDigit HexDigit
663     ;
664
665 fragment
666 HexDigit : (Digit|'a'..'f'|'A'..'F') ;
667
668 fragment
669 Digit : ('0'..'9') ;
670
671 WS : (' '|'\t'|'\n'|'\r'|'\f')+ { $channel=HIDDEN; } ;
672 ML_COMMENT : '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;} ;
673
Note: See TracBrowser for help on using the browser.