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 |