OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 | 3 |
4 /** | 4 /** |
5 * A simple recursive descent parser for CSS. | 5 * A simple recursive descent parser for CSS. |
6 */ | 6 */ |
7 class Parser { | 7 class Parser { |
8 Tokenizer tokenizer; | 8 Tokenizer tokenizer; |
9 | 9 |
10 var _fs; // If non-null filesystem to read files. | 10 var _fs; // If non-null filesystem to read files. |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 | 97 |
98 void _eatSemicolon() { | 98 void _eatSemicolon() { |
99 _eat(TokenKind.SEMICOLON); | 99 _eat(TokenKind.SEMICOLON); |
100 } | 100 } |
101 | 101 |
102 void _errorExpected(String expected) { | 102 void _errorExpected(String expected) { |
103 var tok = _next(); | 103 var tok = _next(); |
104 var message; | 104 var message; |
105 try { | 105 try { |
106 message = 'expected $expected, but found $tok'; | 106 message = 'expected $expected, but found $tok'; |
107 } catch (var e) { | 107 } catch (final e) { |
108 message = 'parsing error expected $expected'; | 108 message = 'parsing error expected $expected'; |
109 } | 109 } |
110 _error(message, tok.span); | 110 _error(message, tok.span); |
111 } | 111 } |
112 | 112 |
113 void _error(String message, [lang.SourceSpan location=null]) { | 113 void _error(String message, [lang.SourceSpan location=null]) { |
114 if (location === null) { | 114 if (location === null) { |
115 location = _peekToken.span; | 115 location = _peekToken.span; |
116 } | 116 } |
117 | 117 |
118 lang.world.fatal(message, location); // syntax errors are fatal for now | 118 lang.world.fatal(message, location); // syntax errors are fatal for now |
119 } | 119 } |
120 | 120 |
| 121 void _warning(String message, [lang.SourceSpan location=null]) { |
| 122 if (location === null) { |
| 123 location = _peekToken.span; |
| 124 } |
| 125 |
| 126 lang.world.warning(message, location); |
| 127 } |
| 128 |
121 lang.SourceSpan _makeSpan(int start) { | 129 lang.SourceSpan _makeSpan(int start) { |
122 return new lang.SourceSpan(source, start, _previousToken.end); | 130 return new lang.SourceSpan(source, start, _previousToken.end); |
123 } | 131 } |
124 | 132 |
125 /////////////////////////////////////////////////////////////////// | 133 /////////////////////////////////////////////////////////////////// |
126 // Top level productions | 134 // Top level productions |
127 /////////////////////////////////////////////////////////////////// | 135 /////////////////////////////////////////////////////////////////// |
128 | 136 |
129 // Templates are @{selectors} single line nothing else. | 137 // Templates are @{selectors} single line nothing else. |
130 SelectorGroup parseTemplate() { | 138 SelectorGroup parseTemplate() { |
(...skipping 625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
756 _eat(TokenKind.RBRACK); | 764 _eat(TokenKind.RBRACK); |
757 | 765 |
758 return new ItemTerm(term.value, term.text, _makeSpan(start)); | 766 return new ItemTerm(term.value, term.text, _makeSpan(start)); |
759 case TokenKind.IDENTIFIER: | 767 case TokenKind.IDENTIFIER: |
760 var nameValue = identifier(); // Snarf up the ident we'll remap, maybe. | 768 var nameValue = identifier(); // Snarf up the ident we'll remap, maybe. |
761 | 769 |
762 if (_maybeEat(TokenKind.LPAREN)) { | 770 if (_maybeEat(TokenKind.LPAREN)) { |
763 // FUNCTION | 771 // FUNCTION |
764 return processFunction(nameValue); | 772 return processFunction(nameValue); |
765 } else { | 773 } else { |
| 774 // TODO(terry): Need to have a list of known identifiers today only |
| 775 // 'from' is special. |
| 776 if (nameValue.name == 'from') { |
| 777 return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start)); |
| 778 } |
| 779 |
766 // What kind of identifier is it? | 780 // What kind of identifier is it? |
767 int value; | 781 int value; |
768 try { | 782 try { |
769 // Named color? | 783 // Named color? |
770 value = TokenKind.matchColorName(nameValue.name); | 784 value = TokenKind.matchColorName(nameValue.name); |
771 | 785 |
772 // Yes, process the color as an RGB value. | 786 // Yes, process the color as an RGB value. |
773 String rgbColor = TokenKind.decimalToHex(value); | 787 String rgbColor = TokenKind.decimalToHex(value); |
774 int value; | 788 int value; |
775 try { | 789 try { |
776 value = parseHex(rgbColor); | 790 value = parseHex(rgbColor); |
777 } catch (HexNumberException hne) { | 791 } catch (HexNumberException hne) { |
778 _error('Bad hex number', _makeSpan(start)); | 792 _error('Bad hex number', _makeSpan(start)); |
779 } | 793 } |
780 return new HexColorTerm(value, rgbColor, _makeSpan(start)); | 794 return new HexColorTerm(value, rgbColor, _makeSpan(start)); |
781 } catch (var error) { | 795 } catch (final error) { |
782 if (error is NoColorMatchException) { | 796 if (error is NoColorMatchException) { |
783 // Other named things to match with validator? | 797 // TODO(terry): Other named things to match with validator? |
784 // TODO(terry): TBD | 798 _warning('Unknown property value ${error.name}', _makeSpan(start)); |
785 // _error('Unknown property value ${error.name}', _makeSpan(start)); | |
786 | |
787 value = nameValue.name; | |
788 print('Warning: unknown property value ${error.name}'); | |
789 return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start)); | 799 return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start)); |
790 | |
791 } | 800 } |
792 } | 801 } |
793 } | 802 } |
794 } | 803 } |
795 | 804 |
796 var term; | 805 var term; |
797 var unitType = this._peek(); | 806 var unitType = this._peek(); |
798 | 807 |
799 switch (unitType) { | 808 switch (unitType) { |
800 case TokenKind.UNIT_EM: | 809 case TokenKind.UNIT_EM: |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
856 case TokenKind.SINGLE_QUOTE: | 865 case TokenKind.SINGLE_QUOTE: |
857 stopToken = TokenKind.SINGLE_QUOTE; | 866 stopToken = TokenKind.SINGLE_QUOTE; |
858 _next(); // Skip the SINGLE_QUOTE. | 867 _next(); // Skip the SINGLE_QUOTE. |
859 break; | 868 break; |
860 case TokenKind.DOUBLE_QUOTE: | 869 case TokenKind.DOUBLE_QUOTE: |
861 stopToken = TokenKind.DOUBLE_QUOTE; | 870 stopToken = TokenKind.DOUBLE_QUOTE; |
862 _next(); // Skip the DOUBLE_QUOTE. | 871 _next(); // Skip the DOUBLE_QUOTE. |
863 break; | 872 break; |
864 default: | 873 default: |
865 if (urlString) { | 874 if (urlString) { |
| 875 if (_peek() == TokenKind.LPAREN) { |
| 876 _next(); // Skip the LPAREN. |
| 877 } |
866 stopToken = TokenKind.RPAREN; | 878 stopToken = TokenKind.RPAREN; |
867 } else { | 879 } else { |
868 _error('unexpected string', _makeSpan(start)); | 880 _error('unexpected string', _makeSpan(start)); |
869 } | 881 } |
870 } | 882 } |
871 | 883 |
872 StringBuffer stringValue = new StringBuffer(); | 884 StringBuffer stringValue = new StringBuffer(); |
873 | 885 |
874 // Gobble up everything until we hit our stop token. | 886 // Gobble up everything until we hit our stop token. |
875 int runningStart = _peekToken.start; | 887 int runningStart = _peekToken.start; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
959 | 971 |
960 return result; | 972 return result; |
961 } | 973 } |
962 } | 974 } |
963 | 975 |
964 /** Not a hex number. */ | 976 /** Not a hex number. */ |
965 class HexNumberException implements Exception { | 977 class HexNumberException implements Exception { |
966 HexNumberException(); | 978 HexNumberException(); |
967 } | 979 } |
968 | 980 |
OLD | NEW |