Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(613)

Side by Side Diff: pkg/csslib/lib/parser.dart

Issue 60983003: pkg/csslib: fixed analysis error, more cleanup (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: nits Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/csslib/lib/src/analyzer.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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 1013 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 var simpleSequences = <SimpleSelectorSequence>[];
1189 int start = _peekToken.start; 1194 var 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 }
1198 } 1203 }
1199 1204
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
1337 } 1342 }
1338 1343
1339 return false; 1344 return false;
1340 } 1345 }
1341 1346
1342 /** 1347 /**
1343 * type_selector | universal | HASH | class | attrib | pseudo 1348 * type_selector | universal | HASH | class | attrib | pseudo
1344 */ 1349 */
1345 simpleSelectorTail() { 1350 simpleSelectorTail() {
1346 // Check for HASH | class | attrib | pseudo | negation 1351 // Check for HASH | class | attrib | pseudo | negation
1347 int start = _peekToken.start; 1352 var start = _peekToken.start;
1348 switch (_peek()) { 1353 switch (_peek()) {
1349 case TokenKind.HASH: 1354 case TokenKind.HASH:
1350 _eat(TokenKind.HASH); 1355 _eat(TokenKind.HASH);
1351 1356
1352 bool hasWhiteSpace = false; 1357 var hasWhiteSpace = false;
1353 if (_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) { 1358 if (_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) {
1354 _warning("Not a valid ID selector expected #id", _makeSpan(start)); 1359 _warning("Not a valid ID selector expected #id", _makeSpan(start));
1355 hasWhiteSpace = true; 1360 hasWhiteSpace = true;
1356 } 1361 }
1357 if (_peekIdentifier()) { 1362 if (_peekIdentifier()) {
1358 var id = identifier(); 1363 var id = identifier();
1359 if (hasWhiteSpace) { 1364 if (hasWhiteSpace) {
1360 // Generate bad selector id (normalized). 1365 // Generate bad selector id (normalized).
1361 id.name = " ${id.name}"; 1366 id.name = " ${id.name}";
1362 } 1367 }
(...skipping 25 matching lines...) Expand all
1388 _peekToken.span); 1393 _peekToken.span);
1389 _next(); 1394 _next();
1390 break; 1395 break;
1391 } 1396 }
1392 } 1397 }
1393 1398
1394 processPseudoSelector(int start) { 1399 processPseudoSelector(int start) {
1395 // :pseudo-class ::pseudo-element 1400 // :pseudo-class ::pseudo-element
1396 // TODO(terry): '::' should be token. 1401 // TODO(terry): '::' should be token.
1397 _eat(TokenKind.COLON); 1402 _eat(TokenKind.COLON);
1398 bool pseudoElement = _maybeEat(TokenKind.COLON); 1403 var pseudoElement = _maybeEat(TokenKind.COLON);
1399 1404
1400 // TODO(terry): If no identifier specified consider optimizing out the 1405 // TODO(terry): If no identifier specified consider optimizing out the
1401 // : or :: and making this a normal selector. For now, 1406 // : or :: and making this a normal selector. For now,
1402 // create an empty pseudoName. 1407 // create an empty pseudoName.
1403 var pseudoName; 1408 var pseudoName;
1404 if (_peekIdentifier()) { 1409 if (_peekIdentifier()) {
1405 pseudoName = identifier(); 1410 pseudoName = identifier();
1406 } else { 1411 } else {
1407 return null; 1412 return null;
1408 } 1413 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
1449 * In CSS3, the expressions are identifiers, strings, or of the form "an+b". 1454 * In CSS3, the expressions are identifiers, strings, or of the form "an+b".
1450 * 1455 *
1451 * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ 1456 * : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+
1452 * 1457 *
1453 * num [0-9]+|[0-9]*\.[0-9]+ 1458 * num [0-9]+|[0-9]*\.[0-9]+
1454 * PLUS '+' 1459 * PLUS '+'
1455 * DIMENSION {num}{ident} 1460 * DIMENSION {num}{ident}
1456 * NUMBER {num} 1461 * NUMBER {num}
1457 */ 1462 */
1458 processSelectorExpression() { 1463 processSelectorExpression() {
1459 int start = _peekToken.start; 1464 var start = _peekToken.start;
1460 1465
1461 var expression = new SelectorExpression(_makeSpan(start)); 1466 var expression = new SelectorExpression(_makeSpan(start));
1462 1467
1463 Token termToken; 1468 Token termToken;
1464 var value; 1469 var value;
1465 1470
1466 // Special parsing for expressions in pseudo functions. Minus is used as 1471 // Special parsing for expressions in pseudo functions. Minus is used as
1467 // operator not identifier. 1472 // operator not identifier.
1468 tokenizer.selectorExpression = true; 1473 tokenizer.selectorExpression = true;
1469 1474
1470 bool keepParsing = true; 1475 var keepParsing = true;
1471 while (keepParsing) { 1476 while (keepParsing) {
1472 switch (_peek()) { 1477 switch (_peek()) {
1473 case TokenKind.PLUS: 1478 case TokenKind.PLUS:
1474 start = _peekToken.start; 1479 start = _peekToken.start;
1475 termToken = _next(); 1480 termToken = _next();
1476 expression.add(new OperatorPlus(_makeSpan(start))); 1481 expression.add(new OperatorPlus(_makeSpan(start)));
1477 break; 1482 break;
1478 case TokenKind.MINUS: 1483 case TokenKind.MINUS:
1479 start = _peekToken.start; 1484 start = _peekToken.start;
1480 termToken = _next(); 1485 termToken = _next();
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 var 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: // |=
1553 case TokenKind.PREFIX_MATCH: // ^= 1558 case TokenKind.PREFIX_MATCH: // ^=
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 23 matching lines...) Expand all
1630 1635
1631 Expressions exprs = processExpr(); 1636 Expressions exprs = processExpr();
1632 1637
1633 decl = new VarDefinition(definedName, exprs, _makeSpan(start)); 1638 decl = new VarDefinition(definedName, exprs, _makeSpan(start));
1634 } else if (_peekToken.kind == TokenKind.DIRECTIVE_INCLUDE) { 1639 } else if (_peekToken.kind == TokenKind.DIRECTIVE_INCLUDE) {
1635 // @include mixinName in the declaration area. 1640 // @include mixinName in the declaration area.
1636 var span = _makeSpan(start); 1641 var span = _makeSpan(start);
1637 var include = processInclude(span, eatSemiColon: false); 1642 var include = processInclude(span, eatSemiColon: false);
1638 decl = new IncludeMixinAtDeclaration(include, span); 1643 decl = new IncludeMixinAtDeclaration(include, span);
1639 } else if (_peekToken.kind == TokenKind.DIRECTIVE_EXTEND) { 1644 } else if (_peekToken.kind == TokenKind.DIRECTIVE_EXTEND) {
1640 List<SimpleSelectorSequence> simpleSequences = []; 1645 var simpleSequences = <TreeNode>[];
1641 1646
1642 _next(); 1647 _next();
1643 var span = _makeSpan(start); 1648 var span = _makeSpan(start);
1644 var selector = simpleSelector(); 1649 var selector = simpleSelector();
1645 if (selector == null) { 1650 if (selector == null) {
1646 _warning("@extends expecting simple selector name", span); 1651 _warning("@extends expecting simple selector name", span);
1647 } else { 1652 } else {
1648 simpleSequences.add(selector); 1653 simpleSequences.add(selector);
1649 } 1654 }
1650 if (_peekKind(TokenKind.COLON)) { 1655 if (_peekKind(TokenKind.COLON)) {
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 int _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,
1740 int styleType = _findStyle(property.name.toLowerCase()); 1741 List dartStyles) {
1742 var styleType = _findStyle(property.name.toLowerCase());
1741 if (styleType != null) { 1743 if (styleType != null) {
1742 return buildDartStyleNode(styleType, exprs, dartStyles); 1744 return buildDartStyleNode(styleType, exprs, dartStyles);
1743 } 1745 }
1744 } 1746 }
1745 1747
1746 FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) { 1748 FontExpression _mergeFontStyles(FontExpression fontExpr, List dartStyles) {
1747 // Merge all font styles for this class selector. 1749 // Merge all font styles for this class selector.
1748 for (var dartStyle in dartStyles) { 1750 for (var dartStyle in dartStyles) {
1749 if (dartStyle.isFont) { 1751 if (dartStyle.isFont) {
1750 fontExpr = new FontExpression.merge(dartStyle, fontExpr); 1752 fontExpr = new FontExpression.merge(dartStyle, fontExpr);
1751 } 1753 }
1752 } 1754 }
1753 1755
1754 return fontExpr; 1756 return fontExpr;
1755 } 1757 }
1756 1758
1757 buildDartStyleNode(int styleType, Expressions exprs, List dartStyles) { 1759 DartStyleExpression buildDartStyleNode(int styleType, Expressions exprs,
1760 List dartStyles) {
1761
1758 switch (styleType) { 1762 switch (styleType) {
1759 /* 1763 /*
1760 * Properties in order: 1764 * Properties in order:
1761 * 1765 *
1762 * font-style font-variant font-weight font-size/line-height font-family 1766 * font-style font-variant font-weight font-size/line-height font-family
1763 * 1767 *
1764 * The font-size and font-family values are required. If other values are 1768 * The font-size and font-family values are required. If other values are
1765 * missing; a default, if it exist, will be used. 1769 * missing; a default, if it exist, will be used.
1766 */ 1770 */
1767 case _fontPartFont: 1771 case _fontPartFont:
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
1890 } 1894 }
1891 break; 1895 break;
1892 default: 1896 default:
1893 // Don't handle it. 1897 // Don't handle it.
1894 return null; 1898 return null;
1895 } 1899 }
1896 } 1900 }
1897 1901
1898 // TODO(terry): Look at handling width of thin, thick, etc. any none numbers 1902 // TODO(terry): Look at handling width of thin, thick, etc. any none numbers
1899 // to convert to a number. 1903 // to convert to a number.
1900 processOneNumber(Expressions exprs, int part) { 1904 DartStyleExpression processOneNumber(Expressions exprs, int part) {
1901 var value = marginValue(exprs.expressions[0]); 1905 var value = marginValue(exprs.expressions[0]);
1902 if (value != null) { 1906 if (value != null) {
1903 switch (part) { 1907 switch (part) {
1904 case _marginPartLeft: 1908 case _marginPartLeft:
1905 return new MarginExpression(exprs.span, left: value); 1909 return new MarginExpression(exprs.span, left: value);
1906 case _marginPartTop: 1910 case _marginPartTop:
1907 return new MarginExpression(exprs.span, top: value); 1911 return new MarginExpression(exprs.span, top: value);
1908 case _marginPartRight: 1912 case _marginPartRight:
1909 return new MarginExpression(exprs.span, right: value); 1913 return new MarginExpression(exprs.span, right: value);
1910 case _marginPartBottom: 1914 case _marginPartBottom:
(...skipping 29 matching lines...) Expand all
1940 /** 1944 /**
1941 * Margins are of the format: 1945 * Margins are of the format:
1942 * 1946 *
1943 * top,right,bottom,left (4 parameters) 1947 * top,right,bottom,left (4 parameters)
1944 * top,right/left, bottom (3 parameters) 1948 * top,right/left, bottom (3 parameters)
1945 * top/bottom,right/left (2 parameters) 1949 * top/bottom,right/left (2 parameters)
1946 * top/right/bottom/left (1 parameter) 1950 * top/right/bottom/left (1 parameter)
1947 * 1951 *
1948 * The values of the margins can be a unit or unitless or auto. 1952 * The values of the margins can be a unit or unitless or auto.
1949 */ 1953 */
1950 processFourNums(Expressions exprs) { 1954 BoxEdge processFourNums(Expressions exprs) {
1951 num top; 1955 num top;
1952 num right; 1956 num right;
1953 num bottom; 1957 num bottom;
1954 num left; 1958 num left;
1955 1959
1956 int totalExprs = exprs.expressions.length; 1960 int totalExprs = exprs.expressions.length;
1957 switch (totalExprs) { 1961 switch (totalExprs) {
1958 case 1: 1962 case 1:
1959 top = marginValue(exprs.expressions[0]); 1963 top = marginValue(exprs.expressions[0]);
1960 right = top; 1964 right = top;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1993 } 1997 }
1994 } 1998 }
1995 1999
1996 // Expression grammar: 2000 // Expression grammar:
1997 // 2001 //
1998 // expression: term [ operator? term]* 2002 // expression: term [ operator? term]*
1999 // 2003 //
2000 // operator: '/' | ',' 2004 // operator: '/' | ','
2001 // term: (see processTerm) 2005 // term: (see processTerm)
2002 // 2006 //
2003 processExpr([bool ieFilter = false]) { 2007 Expressions processExpr([bool ieFilter = false]) {
2004 int start = _peekToken.start; 2008 var start = _peekToken.start;
2005 Expressions expressions = new Expressions(_makeSpan(start)); 2009 var expressions = new Expressions(_makeSpan(start));
2006 2010
2007 bool keepGoing = true; 2011 var keepGoing = true;
2008 var expr; 2012 var expr;
2009 while (keepGoing && (expr = processTerm(ieFilter)) != null) { 2013 while (keepGoing && (expr = processTerm(ieFilter)) != null) {
2010 var op; 2014 var op;
2011 2015
2012 int opStart = _peekToken.start; 2016 var opStart = _peekToken.start;
2013 2017
2014 switch (_peek()) { 2018 switch (_peek()) {
2015 case TokenKind.SLASH: 2019 case TokenKind.SLASH:
2016 op = new OperatorSlash(_makeSpan(opStart)); 2020 op = new OperatorSlash(_makeSpan(opStart));
2017 break; 2021 break;
2018 case TokenKind.COMMA: 2022 case TokenKind.COMMA:
2019 op = new OperatorComma(_makeSpan(opStart)); 2023 op = new OperatorComma(_makeSpan(opStart));
2020 break; 2024 break;
2021 case TokenKind.BACKSLASH: 2025 case TokenKind.BACKSLASH:
2022 // Backslash outside of string; detected IE8 or older signaled by \9 at 2026 // Backslash outside of string; detected IE8 or older signaled by \9 at
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2054 keepGoing = false; 2058 keepGoing = false;
2055 } else { 2059 } else {
2056 _next(); 2060 _next();
2057 } 2061 }
2058 } 2062 }
2059 } 2063 }
2060 2064
2061 return expressions; 2065 return expressions;
2062 } 2066 }
2063 2067
2064 static int MAX_UNICODE = int.parse('0x10FFFF'); 2068 static final int MAX_UNICODE = int.parse('0x10FFFF');
2065 2069
2066 // Term grammar: 2070 // Term grammar:
2067 // 2071 //
2068 // term: 2072 // term:
2069 // unary_operator? 2073 // unary_operator?
2070 // [ term_value ] 2074 // [ term_value ]
2071 // | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor 2075 // | STRING S* | IDENT S* | URI S* | UNICODERANGE S* | hexcolor
2072 // 2076 //
2073 // term_value: 2077 // term_value:
2074 // NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* | 2078 // NUMBER S* | PERCENTAGE S* | LENGTH S* | EMS S* | EXS S* | ANGLE S* |
2075 // TIME S* | FREQ S* | function 2079 // TIME S* | FREQ S* | function
2076 // 2080 //
2077 // NUMBER: {num} 2081 // NUMBER: {num}
2078 // PERCENTAGE: {num}% 2082 // PERCENTAGE: {num}%
2079 // LENGTH: {num}['px' | 'cm' | 'mm' | 'in' | 'pt' | 'pc'] 2083 // LENGTH: {num}['px' | 'cm' | 'mm' | 'in' | 'pt' | 'pc']
2080 // EMS: {num}'em' 2084 // EMS: {num}'em'
2081 // EXS: {num}'ex' 2085 // EXS: {num}'ex'
2082 // ANGLE: {num}['deg' | 'rad' | 'grad'] 2086 // ANGLE: {num}['deg' | 'rad' | 'grad']
2083 // TIME: {num}['ms' | 's'] 2087 // TIME: {num}['ms' | 's']
2084 // FREQ: {num}['hz' | 'khz'] 2088 // FREQ: {num}['hz' | 'khz']
2085 // function: IDENT '(' expr ')' 2089 // function: IDENT '(' expr ')'
2086 // 2090 //
2087 processTerm([bool ieFilter = false]) { 2091 processTerm([bool ieFilter = false]) {
2088 int start = _peekToken.start; 2092 var start = _peekToken.start;
2089 Token t; // token for term's value 2093 Token t; // token for term's value
2090 var value; // value of term (numeric values) 2094 var value; // value of term (numeric values)
2091 2095
2092 var unary = ""; 2096 var unary = "";
2093 switch (_peek()) { 2097 switch (_peek()) {
2094 case TokenKind.HASH: 2098 case TokenKind.HASH:
2095 this._eat(TokenKind.HASH); 2099 this._eat(TokenKind.HASH);
2096 if (!_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) { 2100 if (!_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) {
2097 String hexText; 2101 String hexText;
2098 if (_peekKind(TokenKind.INTEGER)) { 2102 if (_peekKind(TokenKind.INTEGER)) {
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
2186 var propName = nameValue.name; 2190 var propName = nameValue.name;
2187 var errMsg = TokenKind.isPredefinedName(propName) ? 2191 var errMsg = TokenKind.isPredefinedName(propName) ?
2188 "Improper use of property value ${propName}" : 2192 "Improper use of property value ${propName}" :
2189 "Unknown property value ${propName}"; 2193 "Unknown property value ${propName}";
2190 _warning(errMsg, _makeSpan(start)); 2194 _warning(errMsg, _makeSpan(start));
2191 } 2195 }
2192 return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start)); 2196 return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start));
2193 } 2197 }
2194 2198
2195 // Yes, process the color as an RGB value. 2199 // Yes, process the color as an RGB value.
2196 String rgbColor = TokenKind.decimalToHex( 2200 var rgbColor =
2197 TokenKind.colorValue(colorEntry), 6); 2201 TokenKind.decimalToHex(TokenKind.colorValue(colorEntry), 6);
2198 return _parseHex(rgbColor, _makeSpan(start)); 2202 return _parseHex(rgbColor, _makeSpan(start));
2199 case TokenKind.UNICODE_RANGE: 2203 case TokenKind.UNICODE_RANGE:
2200 var first; 2204 var first;
2201 var second; 2205 var second;
2202 var firstNumber; 2206 var firstNumber;
2203 var secondNumber; 2207 var secondNumber;
2204 _eat(TokenKind.UNICODE_RANGE, unicodeRange: true); 2208 _eat(TokenKind.UNICODE_RANGE, unicodeRange: true);
2205 if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) { 2209 if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) {
2206 first = _previousToken.text; 2210 first = _previousToken.text;
2207 firstNumber = int.parse('0x$first'); 2211 firstNumber = int.parse('0x$first');
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
2241 expr.expressions[0] = varUsage; 2245 expr.expressions[0] = varUsage;
2242 return expr.expressions; 2246 return expr.expressions;
2243 } 2247 }
2244 break; 2248 break;
2245 } 2249 }
2246 2250
2247 return processDimension(t, value, _makeSpan(start)); 2251 return processDimension(t, value, _makeSpan(start));
2248 } 2252 }
2249 2253
2250 /** Process all dimension units. */ 2254 /** Process all dimension units. */
2251 processDimension(Token t, var value, Span span) { 2255 LiteralTerm processDimension(Token t, var value, Span span) {
2252 var term; 2256 LiteralTerm term;
2253 var unitType = this._peek(); 2257 var unitType = this._peek();
2254 2258
2255 switch (unitType) { 2259 switch (unitType) {
2256 case TokenKind.UNIT_EM: 2260 case TokenKind.UNIT_EM:
2257 term = new EmTerm(value, t.text, span); 2261 term = new EmTerm(value, t.text, span);
2258 _next(); // Skip the unit 2262 _next(); // Skip the unit
2259 break; 2263 break;
2260 case TokenKind.UNIT_EX: 2264 case TokenKind.UNIT_EX:
2261 term = new ExTerm(value, t.text, span); 2265 term = new ExTerm(value, t.text, span);
2262 _next(); // Skip the unit 2266 _next(); // Skip the unit
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
2321 term = (value is Identifier) 2325 term = (value is Identifier)
2322 ? new LiteralTerm(value, value.name, span) 2326 ? new LiteralTerm(value, value.name, span)
2323 : new NumberTerm(value, t.text, span); 2327 : new NumberTerm(value, t.text, span);
2324 } 2328 }
2325 break; 2329 break;
2326 } 2330 }
2327 2331
2328 return term; 2332 return term;
2329 } 2333 }
2330 2334
2331 processQuotedString([bool urlString = false]) { 2335 String processQuotedString([bool urlString = false]) {
2332 int start = _peekToken.start; 2336 var start = _peekToken.start;
2333 2337
2334 // URI term sucks up everything inside of quotes(' or ") or between parens 2338 // URI term sucks up everything inside of quotes(' or ") or between parens
2335 int stopToken = urlString ? TokenKind.RPAREN : -1; 2339 var stopToken = urlString ? TokenKind.RPAREN : -1;
2336 switch (_peek()) { 2340 switch (_peek()) {
2337 case TokenKind.SINGLE_QUOTE: 2341 case TokenKind.SINGLE_QUOTE:
2338 stopToken = TokenKind.SINGLE_QUOTE; 2342 stopToken = TokenKind.SINGLE_QUOTE;
2339 start = _peekToken.start + 1; // Skip the quote might have whitespace. 2343 start = _peekToken.start + 1; // Skip the quote might have whitespace.
2340 _next(); // Skip the SINGLE_QUOTE. 2344 _next(); // Skip the SINGLE_QUOTE.
2341 break; 2345 break;
2342 case TokenKind.DOUBLE_QUOTE: 2346 case TokenKind.DOUBLE_QUOTE:
2343 stopToken = TokenKind.DOUBLE_QUOTE; 2347 stopToken = TokenKind.DOUBLE_QUOTE;
2344 start = _peekToken.start + 1; // Skip the quote might have whitespace. 2348 start = _peekToken.start + 1; // Skip the quote might have whitespace.
2345 _next(); // Skip the DOUBLE_QUOTE. 2349 _next(); // Skip the DOUBLE_QUOTE.
2346 break; 2350 break;
2347 default: 2351 default:
2348 if (urlString) { 2352 if (urlString) {
2349 if (_peek() == TokenKind.LPAREN) { 2353 if (_peek() == TokenKind.LPAREN) {
2350 _next(); // Skip the LPAREN. 2354 _next(); // Skip the LPAREN.
2351 start = _peekToken.start; 2355 start = _peekToken.start;
2352 } 2356 }
2353 stopToken = TokenKind.RPAREN; 2357 stopToken = TokenKind.RPAREN;
2354 } else { 2358 } else {
2355 _error('unexpected string', _makeSpan(start)); 2359 _error('unexpected string', _makeSpan(start));
2356 } 2360 }
2357 break; 2361 break;
2358 } 2362 }
2359 2363
2360 // Gobble up everything until we hit our stop token. 2364 // Gobble up everything until we hit our stop token.
2361 int runningStart = _peekToken.start; 2365 var runningStart = _peekToken.start;
2362 while (_peek() != stopToken && _peek() != TokenKind.END_OF_FILE) { 2366 while (_peek() != stopToken && _peek() != TokenKind.END_OF_FILE) {
2363 var tok = _next(); 2367 var tok = _next();
2364 } 2368 }
2365 2369
2366 // All characters between quotes is the string. 2370 // All characters between quotes is the string.
2367 int end = _peekToken.end; 2371 var end = _peekToken.end;
2368 var stringValue = (_peekToken.span as FileSpan).file.getText(start, 2372 var stringValue = (_peekToken.span as FileSpan).file.getText(start,
2369 end - 1); 2373 end - 1);
2370 2374
2371 if (stopToken != TokenKind.RPAREN) { 2375 if (stopToken != TokenKind.RPAREN) {
2372 _next(); // Skip the SINGLE_QUOTE or DOUBLE_QUOTE; 2376 _next(); // Skip the SINGLE_QUOTE or DOUBLE_QUOTE;
2373 } 2377 }
2374 2378
2375 return stringValue; 2379 return stringValue;
2376 } 2380 }
2377 2381
2378 // TODO(terry): Should probably understand IE's non-standard filter syntax to 2382 // TODO(terry): Should probably understand IE's non-standard filter syntax to
2379 // fully support calc, var(), etc. 2383 // fully support calc, var(), etc.
2380 /** 2384 /**
2381 * IE's filter property breaks CSS value parsing. IE's format can be: 2385 * IE's filter property breaks CSS value parsing. IE's format can be:
2382 * 2386 *
2383 * filter: progid:DXImageTransform.MS.gradient(Type=0, Color='#9d8b83'); 2387 * filter: progid:DXImageTransform.MS.gradient(Type=0, Color='#9d8b83');
2384 * 2388 *
2385 * We'll just parse everything after the 'progid:' look for the left paren 2389 * We'll just parse everything after the 'progid:' look for the left paren
2386 * then parse to the right paren ignoring everything in between. 2390 * then parse to the right paren ignoring everything in between.
2387 */ 2391 */
2388 processIEFilter(int startAfterProgidColon) { 2392 processIEFilter(int startAfterProgidColon) {
2389 int parens = 0; 2393 var parens = 0;
2390 2394
2391 while (_peek() != TokenKind.END_OF_FILE) { 2395 while (_peek() != TokenKind.END_OF_FILE) {
2392 switch (_peek()) { 2396 switch (_peek()) {
2393 case TokenKind.LPAREN: 2397 case TokenKind.LPAREN:
2394 _eat(TokenKind.LPAREN); 2398 _eat(TokenKind.LPAREN);
2395 parens++; 2399 parens++;
2396 break; 2400 break;
2397 case TokenKind.RPAREN: 2401 case TokenKind.RPAREN:
2398 _eat(TokenKind.RPAREN); 2402 _eat(TokenKind.RPAREN);
2399 if (--parens == 0) { 2403 if (--parens == 0) {
2400 var tok = tokenizer.makeIEFilter(startAfterProgidColon, 2404 var tok = tokenizer.makeIEFilter(startAfterProgidColon,
2401 _peekToken.start); 2405 _peekToken.start);
2402 return new LiteralTerm(tok.text, tok.text, tok.span); 2406 return new LiteralTerm(tok.text, tok.text, tok.span);
2403 } 2407 }
2404 break; 2408 break;
2405 default: 2409 default:
2406 _eat(_peek()); 2410 _eat(_peek());
2407 } 2411 }
2408 } 2412 }
2409 } 2413 }
2410 2414
2411 // Function grammar: 2415 // Function grammar:
2412 // 2416 //
2413 // function: IDENT '(' expr ')' 2417 // function: IDENT '(' expr ')'
2414 // 2418 //
2415 processFunction(Identifier func) { 2419 processFunction(Identifier func) {
2416 int start = _peekToken.start; 2420 var start = _peekToken.start;
2417 2421
2418 String name = func.name; 2422 var name = func.name;
2419 2423
2420 switch (name) { 2424 switch (name) {
2421 case 'url': 2425 case 'url':
2422 // URI term sucks up everything inside of quotes(' or ") or between parens 2426 // URI term sucks up everything inside of quotes(' or ") or between parens
2423 String urlParam = processQuotedString(true); 2427 var urlParam = processQuotedString(true);
2424 2428
2425 // TODO(terry): Better error messge and checking for mismatched quotes. 2429 // TODO(terry): Better error messge and checking for mismatched quotes.
2426 if (_peek() == TokenKind.END_OF_FILE) { 2430 if (_peek() == TokenKind.END_OF_FILE) {
2427 _error("problem parsing URI", _peekToken.span); 2431 _error("problem parsing URI", _peekToken.span);
2428 } 2432 }
2429 2433
2430 if (_peek() == TokenKind.RPAREN) { 2434 if (_peek() == TokenKind.RPAREN) {
2431 _next(); 2435 _next();
2432 } 2436 }
2433 2437
(...skipping 29 matching lines...) Expand all
2463 if (!_maybeEat(TokenKind.RPAREN)) { 2467 if (!_maybeEat(TokenKind.RPAREN)) {
2464 _error("problem parsing function expected ), ", _peekToken.span); 2468 _error("problem parsing function expected ), ", _peekToken.span);
2465 } 2469 }
2466 2470
2467 return new FunctionTerm(name, name, expr, _makeSpan(start)); 2471 return new FunctionTerm(name, name, expr, _makeSpan(start));
2468 } 2472 }
2469 2473
2470 return null; 2474 return null;
2471 } 2475 }
2472 2476
2473 identifier() { 2477 Identifier identifier() {
2474 var tok = _next(); 2478 var tok = _next();
2475 2479
2476 if (!TokenKind.isIdentifier(tok.kind) && 2480 if (!TokenKind.isIdentifier(tok.kind) &&
2477 !TokenKind.isKindIdentifier(tok.kind)) { 2481 !TokenKind.isKindIdentifier(tok.kind)) {
2478 if (isChecked) { 2482 if (isChecked) {
2479 _warning('expected identifier, but found $tok', tok.span); 2483 _warning('expected identifier, but found $tok', tok.span);
2480 } 2484 }
2481 return new Identifier("", _makeSpan(tok.start)); 2485 return new Identifier("", _makeSpan(tok.start));
2482 } 2486 }
2483 2487
2484 return new Identifier(tok.text, _makeSpan(tok.start)); 2488 return new Identifier(tok.text, _makeSpan(tok.start));
2485 } 2489 }
2486 2490
2487 // TODO(terry): Move this to base <= 36 and into shared code. 2491 // TODO(terry): Move this to base <= 36 and into shared code.
2488 static int _hexDigit(int c) { 2492 static int _hexDigit(int c) {
2489 if(c >= 48/*0*/ && c <= 57/*9*/) { 2493 if (c >= 48/*0*/ && c <= 57/*9*/) {
2490 return c - 48; 2494 return c - 48;
2491 } else if (c >= 97/*a*/ && c <= 102/*f*/) { 2495 } else if (c >= 97/*a*/ && c <= 102/*f*/) {
2492 return c - 87; 2496 return c - 87;
2493 } else if (c >= 65/*A*/ && c <= 70/*F*/) { 2497 } else if (c >= 65/*A*/ && c <= 70/*F*/) {
2494 return c - 55; 2498 return c - 55;
2495 } else { 2499 } else {
2496 return -1; 2500 return -1;
2497 } 2501 }
2498 } 2502 }
2499 2503
2500 HexColorTerm _parseHex(String hexText, Span span) { 2504 HexColorTerm _parseHex(String hexText, Span span) {
2501 int hexValue = 0; 2505 var hexValue = 0;
2502 2506
2503 for (int i = 0; i < hexText.length; i++) { 2507 for (var i = 0; i < hexText.length; i++) {
2504 var digit = _hexDigit(hexText.codeUnitAt(i)); 2508 var digit = _hexDigit(hexText.codeUnitAt(i));
2505 if (digit < 0) { 2509 if (digit < 0) {
2506 _warning('Bad hex number', span); 2510 _warning('Bad hex number', span);
2507 return new HexColorTerm(new BAD_HEX_VALUE(), hexText, span); 2511 return new HexColorTerm(new BAD_HEX_VALUE(), hexText, span);
2508 } 2512 }
2509 hexValue = (hexValue << 4) + digit; 2513 hexValue = (hexValue << 4) + digit;
2510 } 2514 }
2511 2515
2512 // Make 3 character hex value #RRGGBB => #RGB iff: 2516 // Make 3 character hex value #RRGGBB => #RGB iff:
2513 // high/low nibble of RR is the same, high/low nibble of GG is the same and 2517 // high/low nibble of RR is the same, high/low nibble of GG is the same and
(...skipping 14 matching lines...) Expand all
2528 } 2532 }
2529 } 2533 }
2530 2534
2531 class ExpressionsProcessor { 2535 class ExpressionsProcessor {
2532 final Expressions _exprs; 2536 final Expressions _exprs;
2533 int _index = 0; 2537 int _index = 0;
2534 2538
2535 ExpressionsProcessor(this._exprs); 2539 ExpressionsProcessor(this._exprs);
2536 2540
2537 // TODO(terry): Only handles ##px unit. 2541 // TODO(terry): Only handles ##px unit.
2538 processFontSize() { 2542 FontExpression processFontSize() {
2539 /* font-size[/line-height] 2543 /* font-size[/line-height]
2540 * 2544 *
2541 * Possible size values: 2545 * Possible size values:
2542 * xx-small 2546 * xx-small
2543 * small 2547 * small
2544 * medium [default] 2548 * medium [default]
2545 * large 2549 * large
2546 * x-large 2550 * x-large
2547 * xx-large 2551 * xx-large
2548 * smaller 2552 * smaller
2549 * larger 2553 * larger
2550 * ##length in px, pt, etc. 2554 * ##length in px, pt, etc.
2551 * ##%, percent of parent elem's font-size 2555 * ##%, percent of parent elem's font-size
2552 * inherit 2556 * inherit
2553 */ 2557 */
2554 LengthTerm size; 2558 LengthTerm size;
2555 LineHeight lineHt; 2559 LineHeight lineHt;
2556 bool nextIsLineHeight = false; 2560 var nextIsLineHeight = false;
2557 for (; _index < _exprs.expressions.length; _index++) { 2561 for (; _index < _exprs.expressions.length; _index++) {
2558 var expr = _exprs.expressions[_index]; 2562 var expr = _exprs.expressions[_index];
2559 if (size == null && expr is LengthTerm) { 2563 if (size == null && expr is LengthTerm) {
2560 // font-size part. 2564 // font-size part.
2561 size = expr; 2565 size = expr;
2562 } else if (size != null) { 2566 } else if (size != null) {
2563 if (expr is OperatorSlash) { 2567 if (expr is OperatorSlash) {
2564 // LineHeight could follow? 2568 // LineHeight could follow?
2565 nextIsLineHeight = true; 2569 nextIsLineHeight = true;
2566 } else if (nextIsLineHeight && expr is LengthTerm) { 2570 } else if (nextIsLineHeight && expr is LengthTerm) {
2567 assert(expr.unit == TokenKind.UNIT_LENGTH_PX); 2571 assert(expr.unit == TokenKind.UNIT_LENGTH_PX);
2568 lineHt = new LineHeight(expr.value, inPixels: true); 2572 lineHt = new LineHeight(expr.value, inPixels: true);
2569 nextIsLineHeight = false; 2573 nextIsLineHeight = false;
2570 _index++; 2574 _index++;
2571 break; 2575 break;
2572 } else { 2576 } else {
2573 break; 2577 break;
2574 } 2578 }
2575 } else { 2579 } else {
2576 break; 2580 break;
2577 } 2581 }
2578 } 2582 }
2579 2583
2580 return new FontExpression(_exprs.span, size: size, lineHeight: lineHt); 2584 return new FontExpression(_exprs.span, size: size, lineHeight: lineHt);
2581 } 2585 }
2582 2586
2583 processFontFamily() { 2587 FontExpression processFontFamily() {
2584 final List<String> family = <String>[]; 2588 var family = <String>[];
2585 2589
2586 /* Possible family values: 2590 /* Possible family values:
2587 * font-family: arial, Times new roman ,Lucida Sans Unicode,Courier; 2591 * font-family: arial, Times new roman ,Lucida Sans Unicode,Courier;
2588 * font-family: "Times New Roman", arial, Lucida Sans Unicode, Courier; 2592 * font-family: "Times New Roman", arial, Lucida Sans Unicode, Courier;
2589 */ 2593 */
2590 bool moreFamilies = false; 2594 var moreFamilies = false;
2591 2595
2592 for (; _index < _exprs.expressions.length; _index++) { 2596 for (; _index < _exprs.expressions.length; _index++) {
2593 Expression expr = _exprs.expressions[_index]; 2597 Expression expr = _exprs.expressions[_index];
2594 if (expr is LiteralTerm) { 2598 if (expr is LiteralTerm) {
2595 if (family.length == 0 || moreFamilies) { 2599 if (family.length == 0 || moreFamilies) {
2596 // It's font-family now. 2600 // It's font-family now.
2597 family.add(expr.toString()); 2601 family.add(expr.toString());
2598 moreFamilies = false; 2602 moreFamilies = false;
2599 } else if (isChecked) { 2603 } else if (isChecked) {
2600 messages.warning('Only font-family can be a list', _exprs.span); 2604 messages.warning('Only font-family can be a list', _exprs.span);
2601 } 2605 }
2602 } else if (expr is OperatorComma && family.length > 0) { 2606 } else if (expr is OperatorComma && family.length > 0) {
2603 moreFamilies = true; 2607 moreFamilies = true;
2604 } else { 2608 } else {
2605 break; 2609 break;
2606 } 2610 }
2607 } 2611 }
2608 2612
2609 return new FontExpression(_exprs.span, family: family); 2613 return new FontExpression(_exprs.span, family: family);
2610 } 2614 }
2611 2615
2612 processFont() { 2616 FontExpression processFont() {
2613 var family; 2617 List<String> family;
2614 2618
2615 // Process all parts of the font expression. 2619 // Process all parts of the font expression.
2616 FontExpression fontSize; 2620 FontExpression fontSize;
2617 FontExpression fontFamily; 2621 FontExpression fontFamily;
2618 for (; _index < _exprs.expressions.length; _index++) { 2622 for (; _index < _exprs.expressions.length; _index++) {
2619 var expr = _exprs.expressions[_index]; 2623 var expr = _exprs.expressions[_index];
2620 // Order is font-size font-family 2624 // Order is font-size font-family
2621 if (fontSize == null) { 2625 if (fontSize == null) {
2622 fontSize = processFontSize(); 2626 fontSize = processFontSize();
2623 } 2627 }
(...skipping 14 matching lines...) Expand all
2638 } 2642 }
2639 2643
2640 /** 2644 /**
2641 * Escapes [text] for use in a CSS string. 2645 * Escapes [text] for use in a CSS string.
2642 * [single] specifies single quote `'` vs double quote `"`. 2646 * [single] specifies single quote `'` vs double quote `"`.
2643 */ 2647 */
2644 String _escapeString(String text, {bool single: false}) { 2648 String _escapeString(String text, {bool single: false}) {
2645 StringBuffer result = null; 2649 StringBuffer result = null;
2646 2650
2647 for (int i = 0; i < text.length; i++) { 2651 for (int i = 0; i < text.length; i++) {
2648 int code = text.codeUnitAt(i); 2652 var code = text.codeUnitAt(i);
2649 var replace = null; 2653 String replace = null;
2650 switch (code) { 2654 switch (code) {
2651 case 34/*'"'*/: if (!single) replace = r'\"'; break; 2655 case 34/*'"'*/: if (!single) replace = r'\"'; break;
2652 case 39/*"'"*/: if (single) replace = r"\'"; break; 2656 case 39/*"'"*/: if (single) replace = r"\'"; break;
2653 } 2657 }
2654 2658
2655 if (replace != null && result == null) { 2659 if (replace != null && result == null) {
2656 result = new StringBuffer(text.substring(0, i)); 2660 result = new StringBuffer(text.substring(0, i));
2657 } 2661 }
2658 2662
2659 if (result != null) result.write(replace != null ? replace : text[i]); 2663 if (result != null) result.write(replace != null ? replace : text[i]);
2660 } 2664 }
2661 2665
2662 return result == null ? text : result.toString(); 2666 return result == null ? text : result.toString();
2663 } 2667 }
OLDNEW
« no previous file with comments | « no previous file | pkg/csslib/lib/src/analyzer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698