Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library csslib.parser; | 5 library csslib.parser; |
| 6 | 6 |
| 7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
| 8 | 8 |
| 9 import 'package:source_maps/span.dart' show SourceFile, Span, FileSpan; | 9 import 'package:source_maps/span.dart' show SourceFile, Span, FileSpan; |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 | 23 |
| 24 /** Used for parser lookup ahead (used for nested selectors Less support). */ | 24 /** Used for parser lookup ahead (used for nested selectors Less support). */ |
| 25 class ParserState extends TokenizerState { | 25 class ParserState extends TokenizerState { |
| 26 final Token peekToken; | 26 final Token peekToken; |
| 27 final Token previousToken; | 27 final Token previousToken; |
| 28 | 28 |
| 29 ParserState(this.peekToken, this.previousToken, Tokenizer tokenizer) | 29 ParserState(this.peekToken, this.previousToken, Tokenizer tokenizer) |
| 30 : super(tokenizer); | 30 : super(tokenizer); |
| 31 } | 31 } |
| 32 | 32 |
| 33 void _createMessages({List errors, List options}) { | 33 void _createMessages({List<Message> errors, List<String> options}) { |
| 34 if (errors == null) errors = []; | 34 if (errors == null) errors = []; |
| 35 | 35 |
| 36 if (options == null) { | 36 if (options == null) { |
| 37 options = ['--no-colors', 'memory']; | 37 options = ['--no-colors', 'memory']; |
| 38 } | 38 } |
| 39 var opt = PreprocessorOptions.parse(options); | 39 var opt = PreprocessorOptions.parse(options); |
| 40 messages = new Messages(options: opt, printHandler: errors.add); | 40 messages = new Messages(options: opt, printHandler: errors.add); |
| 41 } | 41 } |
| 42 | 42 |
| 43 /** CSS checked mode enabled. */ | 43 /** CSS checked mode enabled. */ |
| 44 bool get isChecked => messages.options.checked; | 44 bool get isChecked => messages.options.checked; |
| 45 | 45 |
| 46 // TODO(terry): Remove nested name parameter. | 46 // TODO(terry): Remove nested name parameter. |
| 47 /** Parse and analyze the CSS file. */ | 47 /** Parse and analyze the CSS file. */ |
| 48 StyleSheet compile(var input, {List errors, List options, bool nested: true, | 48 StyleSheet compile(var input, {List<Message> errors, List<String> options, |
| 49 bool polyfill: false, List<StyleSheet> includes: null}) { | 49 bool nested: true, |
| 50 bool polyfill: false, | |
| 51 List<StyleSheet> includes: null}) { | |
| 52 | |
| 50 if (includes == null) { | 53 if (includes == null) { |
| 51 includes = []; | 54 includes = []; |
| 52 } | 55 } |
| 53 | 56 |
| 54 var source = _inputAsString(input); | 57 var source = _inputAsString(input); |
| 55 | 58 |
| 56 _createMessages(errors: errors, options: options); | 59 _createMessages(errors: errors, options: options); |
| 57 | 60 |
| 58 var file = new SourceFile.text(null, source); | 61 var file = new SourceFile.text(null, source); |
| 59 | 62 |
| 60 var tree = new _Parser(file, source).parse(); | 63 var tree = new _Parser(file, source).parse(); |
| 61 | 64 |
| 62 analyze([tree], errors: errors, options: options); | 65 analyze([tree], errors: errors, options: options); |
| 63 | 66 |
| 64 if (polyfill) { | 67 if (polyfill) { |
| 65 var processCss = new PolyFill(messages, true); | 68 var processCss = new PolyFill(messages, true); |
| 66 processCss.process(tree, includes: includes); | 69 processCss.process(tree, includes: includes); |
| 67 } | 70 } |
| 68 | 71 |
| 69 return tree; | 72 return tree; |
| 70 } | 73 } |
| 71 | 74 |
| 72 /** Analyze the CSS file. */ | 75 /** Analyze the CSS file. */ |
| 73 void analyze(List<StyleSheet> styleSheets, {List errors, List options}) { | 76 void analyze(List<StyleSheet> styleSheets, |
| 77 {List<Message> errors, List<String> options}) { | |
| 78 | |
| 74 _createMessages(errors: errors, options: options); | 79 _createMessages(errors: errors, options: options); |
| 75 new Analyzer(styleSheets, messages).run(); | 80 new Analyzer(styleSheets, messages).run(); |
| 76 } | 81 } |
| 77 | 82 |
| 78 /** | 83 /** |
| 79 * Parse the [input] CSS stylesheet into a tree. The [input] can be a [String], | 84 * Parse the [input] CSS stylesheet into a tree. The [input] can be a [String], |
| 80 * or [List<int>] of bytes and returns a [StyleSheet] AST. The optional | 85 * or [List<int>] of bytes and returns a [StyleSheet] AST. The optional |
| 81 * [errors] list will contain each error/warning as a [Message]. | 86 * [errors] list will contain each error/warning as a [Message]. |
| 82 */ | 87 */ |
| 83 StyleSheet parse(var input, {List errors, List options}) { | 88 StyleSheet parse(var input, {List<Message> errors, List<String> options}) { |
| 84 var source = _inputAsString(input); | 89 var source = _inputAsString(input); |
| 85 | 90 |
| 86 _createMessages(errors: errors, options: options); | 91 _createMessages(errors: errors, options: options); |
| 87 | 92 |
| 88 var file = new SourceFile.text(null, source); | 93 var file = new SourceFile.text(null, source); |
| 89 | 94 |
| 90 return new _Parser(file, source).parse(); | 95 return new _Parser(file, source).parse(); |
| 91 } | 96 } |
| 92 | 97 |
| 93 /** | 98 /** |
| 94 * Parse the [input] CSS selector into a tree. The [input] can be a [String], | 99 * Parse the [input] CSS selector into a tree. The [input] can be a [String], |
| 95 * or [List<int>] of bytes and returns a [StyleSheet] AST. The optional | 100 * or [List<int>] of bytes and returns a [StyleSheet] AST. The optional |
| 96 * [errors] list will contain each error/warning as a [Message]. | 101 * [errors] list will contain each error/warning as a [Message]. |
| 97 */ | 102 */ |
| 98 StyleSheet selector(var input, {List errors}) { | 103 StyleSheet selector(var input, {List<Message> errors}) { |
| 99 var source = _inputAsString(input); | 104 var source = _inputAsString(input); |
| 100 | 105 |
| 101 _createMessages(errors: errors); | 106 _createMessages(errors: errors); |
| 102 | 107 |
| 103 var file = new SourceFile.text(null, source); | 108 var file = new SourceFile.text(null, source); |
| 104 | 109 |
| 105 return new _Parser(file, source).parseSelector(); | 110 return new _Parser(file, source).parseSelector(); |
| 106 } | 111 } |
| 107 | 112 |
| 108 String _inputAsString(var input) { | 113 String _inputAsString(var input) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 143 final _Parser _parser; | 148 final _Parser _parser; |
| 144 | 149 |
| 145 Parser(SourceFile file, String text, {int start: 0, String baseUrl}) : | 150 Parser(SourceFile file, String text, {int start: 0, String baseUrl}) : |
| 146 _parser = new _Parser(file, text, start: start, baseUrl: baseUrl); | 151 _parser = new _Parser(file, text, start: start, baseUrl: baseUrl); |
| 147 | 152 |
| 148 StyleSheet parse() => _parser.parse(); | 153 StyleSheet parse() => _parser.parse(); |
| 149 } | 154 } |
| 150 | 155 |
| 151 /** A simple recursive descent parser for CSS. */ | 156 /** A simple recursive descent parser for CSS. */ |
| 152 class _Parser { | 157 class _Parser { |
| 153 Tokenizer tokenizer; | 158 final Tokenizer tokenizer; |
| 154 | 159 |
| 155 /** Base url of CSS file. */ | 160 /** Base url of CSS file. */ |
| 156 final String _baseUrl; | 161 final String _baseUrl; |
| 157 | 162 |
| 158 /** | 163 /** |
| 159 * File containing the source being parsed, used to report errors with | 164 * File containing the source being parsed, used to report errors with |
| 160 * source-span locations. | 165 * source-span locations. |
| 161 */ | 166 */ |
| 162 final SourceFile file; | 167 final SourceFile file; |
| 163 | 168 |
| (...skipping 779 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 943 if (_maybeEat(TokenKind.LPAREN)) { | 948 if (_maybeEat(TokenKind.LPAREN)) { |
| 944 var terms = []; | 949 var terms = []; |
| 945 var expr; | 950 var expr; |
| 946 var keepGoing = true; | 951 var keepGoing = true; |
| 947 while (keepGoing && (expr = processTerm()) != null) { | 952 while (keepGoing && (expr = processTerm()) != null) { |
| 948 // VarUsage is returns as a list | 953 // VarUsage is returns as a list |
| 949 terms.add(expr is List ? expr[0] : expr); | 954 terms.add(expr is List ? expr[0] : expr); |
| 950 keepGoing = !_peekKind(TokenKind.RPAREN); | 955 keepGoing = !_peekKind(TokenKind.RPAREN); |
| 951 if (keepGoing) { | 956 if (keepGoing) { |
| 952 if (_maybeEat(TokenKind.COMMA)) { | 957 if (_maybeEat(TokenKind.COMMA)) { |
| 953 params.add(terms); | 958 params.add(terms); |
|
terry
2013/11/07 18:17:05
Good I thought it should stay as add.
| |
| 954 terms = []; | 959 terms = []; |
| 955 } | 960 } |
| 956 } | 961 } |
| 957 } | 962 } |
| 958 params.add(terms); | 963 params.add(terms); |
| 959 _maybeEat(TokenKind.RPAREN); | 964 _maybeEat(TokenKind.RPAREN); |
| 960 } | 965 } |
| 961 | 966 |
| 962 if (eatSemiColon) { | 967 if (eatSemiColon) { |
| 963 _eat(TokenKind.SEMICOLON); | 968 _eat(TokenKind.SEMICOLON); |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1177 } while (_maybeEat(TokenKind.COMMA)); | 1182 } while (_maybeEat(TokenKind.COMMA)); |
| 1178 | 1183 |
| 1179 if (selectors.length > 0) { | 1184 if (selectors.length > 0) { |
| 1180 return new SelectorGroup(selectors, _makeSpan(start)); | 1185 return new SelectorGroup(selectors, _makeSpan(start)); |
| 1181 } | 1186 } |
| 1182 } | 1187 } |
| 1183 | 1188 |
| 1184 /** | 1189 /** |
| 1185 * Return list of selectors | 1190 * Return list of selectors |
| 1186 */ | 1191 */ |
| 1187 processSelector() { | 1192 Selector processSelector() { |
| 1188 List<SimpleSelectorSequence> simpleSequences = []; | 1193 List<SimpleSelectorSequence> simpleSequences = []; |
| 1189 int start = _peekToken.start; | 1194 int start = _peekToken.start; |
| 1190 while (true) { | 1195 while (true) { |
| 1191 // First item is never descendant make sure it's COMBINATOR_NONE. | 1196 // First item is never descendant make sure it's COMBINATOR_NONE. |
| 1192 var selectorItem = simpleSelectorSequence(simpleSequences.length == 0); | 1197 var selectorItem = simpleSelectorSequence(simpleSequences.length == 0); |
| 1193 if (selectorItem != null) { | 1198 if (selectorItem != null) { |
| 1194 simpleSequences.add(selectorItem); | 1199 simpleSequences.add(selectorItem); |
| 1195 } else { | 1200 } else { |
| 1196 break; | 1201 break; |
| 1197 } | 1202 } |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1532 // | 1537 // |
| 1533 // DASHMATCH: '|=' | 1538 // DASHMATCH: '|=' |
| 1534 // | 1539 // |
| 1535 // PREFIXMATCH: '^=' | 1540 // PREFIXMATCH: '^=' |
| 1536 // | 1541 // |
| 1537 // SUFFIXMATCH: '$=' | 1542 // SUFFIXMATCH: '$=' |
| 1538 // | 1543 // |
| 1539 // SUBSTRMATCH: '*=' | 1544 // SUBSTRMATCH: '*=' |
| 1540 // | 1545 // |
| 1541 // | 1546 // |
| 1542 processAttribute() { | 1547 AttributeSelector processAttribute() { |
| 1543 int start = _peekToken.start; | 1548 int start = _peekToken.start; |
| 1544 | 1549 |
| 1545 if (_maybeEat(TokenKind.LBRACK)) { | 1550 if (_maybeEat(TokenKind.LBRACK)) { |
| 1546 var attrName = identifier(); | 1551 var attrName = identifier(); |
| 1547 | 1552 |
| 1548 int op; | 1553 int op; |
| 1549 switch (_peek()) { | 1554 switch (_peek()) { |
| 1550 case TokenKind.EQUALS: | 1555 case TokenKind.EQUALS: |
| 1551 case TokenKind.INCLUDES: // ~= | 1556 case TokenKind.INCLUDES: // ~= |
| 1552 case TokenKind.DASH_MATCH: // |= | 1557 case TokenKind.DASH_MATCH: // |= |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1586 // | 1591 // |
| 1587 // property: IDENT [or IE hacks] | 1592 // property: IDENT [or IE hacks] |
| 1588 // prio: !important | 1593 // prio: !important |
| 1589 // expr: (see processExpr) | 1594 // expr: (see processExpr) |
| 1590 // | 1595 // |
| 1591 // Here are the ugly IE hacks we need to support: | 1596 // Here are the ugly IE hacks we need to support: |
| 1592 // property: expr prio? \9; - IE8 and below property, /9 before semi-colon | 1597 // property: expr prio? \9; - IE8 and below property, /9 before semi-colon |
| 1593 // *IDENT - IE7 or below | 1598 // *IDENT - IE7 or below |
| 1594 // _IDENT - IE6 property (automatically a valid ident) | 1599 // _IDENT - IE6 property (automatically a valid ident) |
| 1595 // | 1600 // |
| 1596 processDeclaration(List dartStyles) { | 1601 Declaration processDeclaration(List dartStyles) { |
| 1597 Declaration decl; | 1602 Declaration decl; |
| 1598 | 1603 |
| 1599 int start = _peekToken.start; | 1604 int start = _peekToken.start; |
| 1600 | 1605 |
| 1601 // IE7 hack of * before property name if so the property is IE7 or below. | 1606 // IE7 hack of * before property name if so the property is IE7 or below. |
| 1602 var ie7 = _peekKind(TokenKind.ASTERISK); | 1607 var ie7 = _peekKind(TokenKind.ASTERISK); |
| 1603 if (ie7) { | 1608 if (ie7) { |
| 1604 _next(); | 1609 _next(); |
| 1605 } | 1610 } |
| 1606 | 1611 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1723 'padding-top': _paddingPartTop, | 1728 'padding-top': _paddingPartTop, |
| 1724 'padding-right': _paddingPartRight, | 1729 'padding-right': _paddingPartRight, |
| 1725 'padding-bottom': _paddingPartBottom | 1730 'padding-bottom': _paddingPartBottom |
| 1726 }; | 1731 }; |
| 1727 | 1732 |
| 1728 static const Map<String, int> _nameToFontWeight = const { | 1733 static const Map<String, int> _nameToFontWeight = const { |
| 1729 'bold' : FontWeight.bold, | 1734 'bold' : FontWeight.bold, |
| 1730 'normal' : FontWeight.normal | 1735 'normal' : FontWeight.normal |
| 1731 }; | 1736 }; |
| 1732 | 1737 |
| 1733 static _findStyle(String styleName) { | 1738 static _findStyle(String styleName) => _stylesToDart[styleName]; |
| 1734 if (_stylesToDart.containsKey(styleName)) { | |
| 1735 return _stylesToDart[styleName]; | |
| 1736 } | |
| 1737 } | |
| 1738 | 1739 |
| 1739 _styleForDart(Identifier property, Expressions exprs, List dartStyles) { | 1740 DartStyleExpression _styleForDart(Identifier property, Expressions exprs, List dartStyles) { |
| 1740 int styleType = _findStyle(property.name.toLowerCase()); | 1741 int styleType = _findStyle(property.name.toLowerCase()); |
| 1741 if (styleType != null) { | 1742 if (styleType != null) { |
| 1742 return buildDartStyleNode(styleType, exprs, dartStyles); | 1743 return buildDartStyleNode(styleType, exprs, dartStyles); |
| 1743 } | 1744 } |
| 1744 } | 1745 } |
| 1745 | 1746 |
| 1746 FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) { | 1747 FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) { |
| 1747 // Merge all font styles for this class selector. | 1748 // Merge all font styles for this class selector. |
| 1748 for (var dartStyle in dartStyles) { | 1749 for (var dartStyle in dartStyles) { |
| 1749 if (dartStyle.isFont) { | 1750 if (dartStyle.isFont) { |
| 1750 fontExpr = new FontExpression.merge(dartStyle, fontExpr); | 1751 fontExpr = new FontExpression.merge(dartStyle, fontExpr); |
| 1751 } | 1752 } |
| 1752 } | 1753 } |
| 1753 | 1754 |
| 1754 return fontExpr; | 1755 return fontExpr; |
| 1755 } | 1756 } |
| 1756 | 1757 |
| 1757 buildDartStyleNode(int styleType, Expressions exprs, List dartStyles) { | 1758 DartStyleExpression buildDartStyleNode(int styleType, Expressions exprs, |
| 1759 List dartStyles) { | |
| 1760 | |
| 1758 switch (styleType) { | 1761 switch (styleType) { |
| 1759 /* | 1762 /* |
| 1760 * Properties in order: | 1763 * Properties in order: |
| 1761 * | 1764 * |
| 1762 * font-style font-variant font-weight font-size/line-height font-family | 1765 * font-style font-variant font-weight font-size/line-height font-family |
| 1763 * | 1766 * |
| 1764 * The font-size and font-family values are required. If other values are | 1767 * The font-size and font-family values are required. If other values are |
| 1765 * missing; a default, if it exist, will be used. | 1768 * missing; a default, if it exist, will be used. |
| 1766 */ | 1769 */ |
| 1767 case _fontPartFont: | 1770 case _fontPartFont: |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1890 } | 1893 } |
| 1891 break; | 1894 break; |
| 1892 default: | 1895 default: |
| 1893 // Don't handle it. | 1896 // Don't handle it. |
| 1894 return null; | 1897 return null; |
| 1895 } | 1898 } |
| 1896 } | 1899 } |
| 1897 | 1900 |
| 1898 // TODO(terry): Look at handling width of thin, thick, etc. any none numbers | 1901 // TODO(terry): Look at handling width of thin, thick, etc. any none numbers |
| 1899 // to convert to a number. | 1902 // to convert to a number. |
| 1900 processOneNumber(Expressions exprs, int part) { | 1903 DartStyleExpression processOneNumber(Expressions exprs, int part) { |
| 1901 var value = marginValue(exprs.expressions[0]); | 1904 var value = marginValue(exprs.expressions[0]); |
| 1902 if (value != null) { | 1905 if (value != null) { |
| 1903 switch (part) { | 1906 switch (part) { |
| 1904 case _marginPartLeft: | 1907 case _marginPartLeft: |
| 1905 return new MarginExpression(exprs.span, left: value); | 1908 return new MarginExpression(exprs.span, left: value); |
| 1906 case _marginPartTop: | 1909 case _marginPartTop: |
| 1907 return new MarginExpression(exprs.span, top: value); | 1910 return new MarginExpression(exprs.span, top: value); |
| 1908 case _marginPartRight: | 1911 case _marginPartRight: |
| 1909 return new MarginExpression(exprs.span, right: value); | 1912 return new MarginExpression(exprs.span, right: value); |
| 1910 case _marginPartBottom: | 1913 case _marginPartBottom: |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 1940 /** | 1943 /** |
| 1941 * Margins are of the format: | 1944 * Margins are of the format: |
| 1942 * | 1945 * |
| 1943 * top,right,bottom,left (4 parameters) | 1946 * top,right,bottom,left (4 parameters) |
| 1944 * top,right/left, bottom (3 parameters) | 1947 * top,right/left, bottom (3 parameters) |
| 1945 * top/bottom,right/left (2 parameters) | 1948 * top/bottom,right/left (2 parameters) |
| 1946 * top/right/bottom/left (1 parameter) | 1949 * top/right/bottom/left (1 parameter) |
| 1947 * | 1950 * |
| 1948 * The values of the margins can be a unit or unitless or auto. | 1951 * The values of the margins can be a unit or unitless or auto. |
| 1949 */ | 1952 */ |
| 1950 processFourNums(Expressions exprs) { | 1953 BoxEdge processFourNums(Expressions exprs) { |
| 1951 num top; | 1954 num top; |
| 1952 num right; | 1955 num right; |
| 1953 num bottom; | 1956 num bottom; |
| 1954 num left; | 1957 num left; |
| 1955 | 1958 |
| 1956 int totalExprs = exprs.expressions.length; | 1959 int totalExprs = exprs.expressions.length; |
| 1957 switch (totalExprs) { | 1960 switch (totalExprs) { |
| 1958 case 1: | 1961 case 1: |
| 1959 top = marginValue(exprs.expressions[0]); | 1962 top = marginValue(exprs.expressions[0]); |
| 1960 right = top; | 1963 right = top; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1993 } | 1996 } |
| 1994 } | 1997 } |
| 1995 | 1998 |
| 1996 // Expression grammar: | 1999 // Expression grammar: |
| 1997 // | 2000 // |
| 1998 // expression: term [ operator? term]* | 2001 // expression: term [ operator? term]* |
| 1999 // | 2002 // |
| 2000 // operator: '/' | ',' | 2003 // operator: '/' | ',' |
| 2001 // term: (see processTerm) | 2004 // term: (see processTerm) |
| 2002 // | 2005 // |
| 2003 processExpr([bool ieFilter = false]) { | 2006 Expression processExpr([bool ieFilter = false]) { |
| 2004 int start = _peekToken.start; | 2007 int start = _peekToken.start; |
| 2005 Expressions expressions = new Expressions(_makeSpan(start)); | 2008 Expressions expressions = new Expressions(_makeSpan(start)); |
| 2006 | 2009 |
| 2007 bool keepGoing = true; | 2010 bool keepGoing = true; |
| 2008 var expr; | 2011 var expr; |
| 2009 while (keepGoing && (expr = processTerm(ieFilter)) != null) { | 2012 while (keepGoing && (expr = processTerm(ieFilter)) != null) { |
| 2010 var op; | 2013 var op; |
| 2011 | 2014 |
| 2012 int opStart = _peekToken.start; | 2015 int opStart = _peekToken.start; |
| 2013 | 2016 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2054 keepGoing = false; | 2057 keepGoing = false; |
| 2055 } else { | 2058 } else { |
| 2056 _next(); | 2059 _next(); |
| 2057 } | 2060 } |
| 2058 } | 2061 } |
| 2059 } | 2062 } |
| 2060 | 2063 |
| 2061 return expressions; | 2064 return expressions; |
| 2062 } | 2065 } |
| 2063 | 2066 |
| 2064 static int MAX_UNICODE = int.parse('0x10FFFF'); | 2067 static final int MAX_UNICODE = int.parse('0x10FFFF'); |
| 2065 | 2068 |
| 2066 // Term grammar: | 2069 // Term grammar: |
| 2067 // | 2070 // |
| 2068 // term: | 2071 // term: |
| 2069 // unary_operator? | 2072 // unary_operator? |
| 2070 // [ term_value ] | 2073 // [ term_value ] |
| 2071 // | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor | 2074 // | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor |
| 2072 // | 2075 // |
| 2073 // term_value: | 2076 // term_value: |
| 2074 // NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* | | 2077 // NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* | |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2241 expr.expressions[0] = varUsage; | 2244 expr.expressions[0] = varUsage; |
| 2242 return expr.expressions; | 2245 return expr.expressions; |
| 2243 } | 2246 } |
| 2244 break; | 2247 break; |
| 2245 } | 2248 } |
| 2246 | 2249 |
| 2247 return processDimension(t, value, _makeSpan(start)); | 2250 return processDimension(t, value, _makeSpan(start)); |
| 2248 } | 2251 } |
| 2249 | 2252 |
| 2250 /** Process all dimension units. */ | 2253 /** Process all dimension units. */ |
| 2251 processDimension(Token t, var value, Span span) { | 2254 LiteralTerm processDimension(Token t, var value, Span span) { |
| 2252 var term; | 2255 LiteralTerm term; |
| 2253 var unitType = this._peek(); | 2256 var unitType = this._peek(); |
| 2254 | 2257 |
| 2255 switch (unitType) { | 2258 switch (unitType) { |
| 2256 case TokenKind.UNIT_EM: | 2259 case TokenKind.UNIT_EM: |
| 2257 term = new EmTerm(value, t.text, span); | 2260 term = new EmTerm(value, t.text, span); |
| 2258 _next(); // Skip the unit | 2261 _next(); // Skip the unit |
| 2259 break; | 2262 break; |
| 2260 case TokenKind.UNIT_EX: | 2263 case TokenKind.UNIT_EX: |
| 2261 term = new ExTerm(value, t.text, span); | 2264 term = new ExTerm(value, t.text, span); |
| 2262 _next(); // Skip the unit | 2265 _next(); // Skip the unit |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2321 term = (value is Identifier) | 2324 term = (value is Identifier) |
| 2322 ? new LiteralTerm(value, value.name, span) | 2325 ? new LiteralTerm(value, value.name, span) |
| 2323 : new NumberTerm(value, t.text, span); | 2326 : new NumberTerm(value, t.text, span); |
| 2324 } | 2327 } |
| 2325 break; | 2328 break; |
| 2326 } | 2329 } |
| 2327 | 2330 |
| 2328 return term; | 2331 return term; |
| 2329 } | 2332 } |
| 2330 | 2333 |
| 2331 processQuotedString([bool urlString = false]) { | 2334 String processQuotedString([bool urlString = false]) { |
| 2332 int start = _peekToken.start; | 2335 int start = _peekToken.start; |
| 2333 | 2336 |
| 2334 // URI term sucks up everything inside of quotes(' or ") or between parens | 2337 // URI term sucks up everything inside of quotes(' or ") or between parens |
| 2335 int stopToken = urlString ? TokenKind.RPAREN : -1; | 2338 int stopToken = urlString ? TokenKind.RPAREN : -1; |
| 2336 switch (_peek()) { | 2339 switch (_peek()) { |
| 2337 case TokenKind.SINGLE_QUOTE: | 2340 case TokenKind.SINGLE_QUOTE: |
| 2338 stopToken = TokenKind.SINGLE_QUOTE; | 2341 stopToken = TokenKind.SINGLE_QUOTE; |
| 2339 start = _peekToken.start + 1; // Skip the quote might have whitespace. | 2342 start = _peekToken.start + 1; // Skip the quote might have whitespace. |
| 2340 _next(); // Skip the SINGLE_QUOTE. | 2343 _next(); // Skip the SINGLE_QUOTE. |
| 2341 break; | 2344 break; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2463 if (!_maybeEat(TokenKind.RPAREN)) { | 2466 if (!_maybeEat(TokenKind.RPAREN)) { |
| 2464 _error("problem parsing function expected ), ", _peekToken.span); | 2467 _error("problem parsing function expected ), ", _peekToken.span); |
| 2465 } | 2468 } |
| 2466 | 2469 |
| 2467 return new FunctionTerm(name, name, expr, _makeSpan(start)); | 2470 return new FunctionTerm(name, name, expr, _makeSpan(start)); |
| 2468 } | 2471 } |
| 2469 | 2472 |
| 2470 return null; | 2473 return null; |
| 2471 } | 2474 } |
| 2472 | 2475 |
| 2473 identifier() { | 2476 Identifier identifier() { |
| 2474 var tok = _next(); | 2477 var tok = _next(); |
| 2475 | 2478 |
| 2476 if (!TokenKind.isIdentifier(tok.kind) && | 2479 if (!TokenKind.isIdentifier(tok.kind) && |
| 2477 !TokenKind.isKindIdentifier(tok.kind)) { | 2480 !TokenKind.isKindIdentifier(tok.kind)) { |
| 2478 if (isChecked) { | 2481 if (isChecked) { |
| 2479 _warning('expected identifier, but found $tok', tok.span); | 2482 _warning('expected identifier, but found $tok', tok.span); |
| 2480 } | 2483 } |
| 2481 return new Identifier("", _makeSpan(tok.start)); | 2484 return new Identifier("", _makeSpan(tok.start)); |
| 2482 } | 2485 } |
| 2483 | 2486 |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2528 } | 2531 } |
| 2529 } | 2532 } |
| 2530 | 2533 |
| 2531 class ExpressionsProcessor { | 2534 class ExpressionsProcessor { |
| 2532 final Expressions _exprs; | 2535 final Expressions _exprs; |
| 2533 int _index = 0; | 2536 int _index = 0; |
| 2534 | 2537 |
| 2535 ExpressionsProcessor(this._exprs); | 2538 ExpressionsProcessor(this._exprs); |
| 2536 | 2539 |
| 2537 // TODO(terry): Only handles ##px unit. | 2540 // TODO(terry): Only handles ##px unit. |
| 2538 processFontSize() { | 2541 FontExpression processFontSize() { |
| 2539 /* font-size[/line-height] | 2542 /* font-size[/line-height] |
| 2540 * | 2543 * |
| 2541 * Possible size values: | 2544 * Possible size values: |
| 2542 * xx-small | 2545 * xx-small |
| 2543 * small | 2546 * small |
| 2544 * medium [default] | 2547 * medium [default] |
| 2545 * large | 2548 * large |
| 2546 * x-large | 2549 * x-large |
| 2547 * xx-large | 2550 * xx-large |
| 2548 * smaller | 2551 * smaller |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 2573 break; | 2576 break; |
| 2574 } | 2577 } |
| 2575 } else { | 2578 } else { |
| 2576 break; | 2579 break; |
| 2577 } | 2580 } |
| 2578 } | 2581 } |
| 2579 | 2582 |
| 2580 return new FontExpression(_exprs.span, size: size, lineHeight: lineHt); | 2583 return new FontExpression(_exprs.span, size: size, lineHeight: lineHt); |
| 2581 } | 2584 } |
| 2582 | 2585 |
| 2583 processFontFamily() { | 2586 FontExpression processFontFamily() { |
| 2584 final List<String> family = <String>[]; | 2587 final List<String> family = <String>[]; |
| 2585 | 2588 |
| 2586 /* Possible family values: | 2589 /* Possible family values: |
| 2587 * font-family: arial, Times new roman ,Lucida Sans Unicode,Courier; | 2590 * font-family: arial, Times new roman ,Lucida Sans Unicode,Courier; |
| 2588 * font-family: "Times New Roman", arial, Lucida Sans Unicode, Courier; | 2591 * font-family: "Times New Roman", arial, Lucida Sans Unicode, Courier; |
| 2589 */ | 2592 */ |
| 2590 bool moreFamilies = false; | 2593 bool moreFamilies = false; |
| 2591 | 2594 |
| 2592 for (; _index < _exprs.expressions.length; _index++) { | 2595 for (; _index < _exprs.expressions.length; _index++) { |
| 2593 Expression expr = _exprs.expressions[_index]; | 2596 Expression expr = _exprs.expressions[_index]; |
| 2594 if (expr is LiteralTerm) { | 2597 if (expr is LiteralTerm) { |
| 2595 if (family.length == 0 || moreFamilies) { | 2598 if (family.length == 0 || moreFamilies) { |
| 2596 // It's font-family now. | 2599 // It's font-family now. |
| 2597 family.add(expr.toString()); | 2600 family.add(expr.toString()); |
| 2598 moreFamilies = false; | 2601 moreFamilies = false; |
| 2599 } else if (isChecked) { | 2602 } else if (isChecked) { |
| 2600 messages.warning('Only font-family can be a list', _exprs.span); | 2603 messages.warning('Only font-family can be a list', _exprs.span); |
| 2601 } | 2604 } |
| 2602 } else if (expr is OperatorComma && family.length > 0) { | 2605 } else if (expr is OperatorComma && family.length > 0) { |
| 2603 moreFamilies = true; | 2606 moreFamilies = true; |
| 2604 } else { | 2607 } else { |
| 2605 break; | 2608 break; |
| 2606 } | 2609 } |
| 2607 } | 2610 } |
| 2608 | 2611 |
| 2609 return new FontExpression(_exprs.span, family: family); | 2612 return new FontExpression(_exprs.span, family: family); |
| 2610 } | 2613 } |
| 2611 | 2614 |
| 2612 processFont() { | 2615 FontExpression processFont() { |
| 2613 var family; | 2616 var family; |
| 2614 | 2617 |
| 2615 // Process all parts of the font expression. | 2618 // Process all parts of the font expression. |
| 2616 FontExpression fontSize; | 2619 FontExpression fontSize; |
| 2617 FontExpression fontFamily; | 2620 FontExpression fontFamily; |
| 2618 for (; _index < _exprs.expressions.length; _index++) { | 2621 for (; _index < _exprs.expressions.length; _index++) { |
| 2619 var expr = _exprs.expressions[_index]; | 2622 var expr = _exprs.expressions[_index]; |
| 2620 // Order is font-size font-family | 2623 // Order is font-size font-family |
| 2621 if (fontSize == null) { | 2624 if (fontSize == null) { |
| 2622 fontSize = processFontSize(); | 2625 fontSize = processFontSize(); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2654 | 2657 |
| 2655 if (replace != null && result == null) { | 2658 if (replace != null && result == null) { |
| 2656 result = new StringBuffer(text.substring(0, i)); | 2659 result = new StringBuffer(text.substring(0, i)); |
| 2657 } | 2660 } |
| 2658 | 2661 |
| 2659 if (result != null) result.write(replace != null ? replace : text[i]); | 2662 if (result != null) result.write(replace != null ? replace : text[i]); |
| 2660 } | 2663 } |
| 2661 | 2664 |
| 2662 return result == null ? text : result.toString(); | 2665 return result == null ? text : result.toString(); |
| 2663 } | 2666 } |
| OLD | NEW |