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, |
terry
2013/11/20 14:07:25
keep rest of params on same line indent +4
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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}) { | |
terry
2013/11/20 14:07:25
indent + 4
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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) { |
109 String source; | 114 String source; |
terry
2013/11/20 14:07:25
var source;
kevmoo-old
2013/11/20 19:13:11
Since 'source' is not assigned immediately, the ty
| |
110 | 115 |
111 if (input is String) { | 116 if (input is String) { |
112 source = input; | 117 source = input; |
113 } else if (input is List<int>) { | 118 } else if (input is List<int>) { |
114 // TODO(terry): The parse function needs an "encoding" argument and will | 119 // TODO(terry): The parse function needs an "encoding" argument and will |
115 // default to whatever encoding CSS defaults to. | 120 // default to whatever encoding CSS defaults to. |
116 // | 121 // |
117 // Here's some info about CSS encodings: | 122 // Here's some info about CSS encodings: |
118 // http://www.w3.org/International/questions/qa-css-charset.en.php | 123 // http://www.w3.org/International/questions/qa-css-charset.en.php |
119 // | 124 // |
(...skipping 23 matching lines...) Expand all 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 1013 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 = []; |
terry
2013/11/20 14:07:25
var simpleSequences = [];
kevmoo-old
2013/11/20 19:13:11
Done.
| |
1189 int start = _peekToken.start; | 1194 int start = _peekToken.start; |
terry
2013/11/20 14:07:25
var start - _peekToken.start;
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1272 * class | 1277 * class |
1273 * : '.' IDENT | 1278 * : '.' IDENT |
1274 */ | 1279 */ |
1275 simpleSelector() { | 1280 simpleSelector() { |
1276 // TODO(terry): Nathan makes a good point parsing of namespace and element | 1281 // TODO(terry): Nathan makes a good point parsing of namespace and element |
1277 // are essentially the same (asterisk or identifier) other | 1282 // are essentially the same (asterisk or identifier) other |
1278 // than the error message for element. Should consolidate the | 1283 // than the error message for element. Should consolidate the |
1279 // code. | 1284 // code. |
1280 // TODO(terry): Need to handle attribute namespace too. | 1285 // TODO(terry): Need to handle attribute namespace too. |
1281 var first; | 1286 var first; |
1282 int start = _peekToken.start; | 1287 int start = _peekToken.start; |
terry
2013/11/20 14:07:25
var start = ...
| |
1283 switch (_peek()) { | 1288 switch (_peek()) { |
1284 case TokenKind.ASTERISK: | 1289 case TokenKind.ASTERISK: |
1285 // Mark as universal namespace. | 1290 // Mark as universal namespace. |
1286 var tok = _next(); | 1291 var tok = _next(); |
1287 first = new Wildcard(_makeSpan(tok.start)); | 1292 first = new Wildcard(_makeSpan(tok.start)); |
1288 break; | 1293 break; |
1289 case TokenKind.IDENTIFIER: | 1294 case TokenKind.IDENTIFIER: |
1290 first = identifier(); | 1295 first = identifier(); |
1291 break; | 1296 break; |
1292 default: | 1297 default: |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 int start = _peekToken.start; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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 bool hasWhiteSpace = false; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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 Loading... | |
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 bool pseudoElement = _maybeEat(TokenKind.COLON); |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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 Loading... | |
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 int start = _peekToken.start; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
1460 | 1465 |
1461 var expression = new SelectorExpression(_makeSpan(start)); | 1466 var expression = new SelectorExpression(_makeSpan(start)); |
1462 | 1467 |
1463 Token termToken; | 1468 Token termToken; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Leaving type since it's not inferred from a first
| |
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 bool keepParsing = true; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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 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; |
terry
2013/11/20 14:07:25
var
| |
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; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Not assigned. Keeping type.
| |
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: // ^= |
1554 case TokenKind.SUFFIX_MATCH: // $= | 1559 case TokenKind.SUFFIX_MATCH: // $= |
1555 case TokenKind.SUBSTRING_MATCH: // *= | 1560 case TokenKind.SUBSTRING_MATCH: // *= |
1556 op = _peek(); | 1561 op = _peek(); |
1557 _next(); | 1562 _next(); |
1558 break; | 1563 break; |
(...skipping 27 matching lines...) Expand all 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; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Not assigned, keeping type.
| |
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 |
1607 // IDENT ':' expr '!important'? | 1612 // IDENT ':' expr '!important'? |
(...skipping 22 matching lines...) Expand all Loading... | |
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 List<SimpleSelectorSequence> simpleSequences = []; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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 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]; |
terry
2013/11/20 14:07:25
return type signature int
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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) { |
terry
2013/11/20 14:07:25
new line after exprs param and indent +4 for remai
kevmoo-old
2013/11/20 19:13:11
Done.
| |
1740 int styleType = _findStyle(property.name.toLowerCase()); | 1741 int styleType = _findStyle(property.name.toLowerCase()); |
terry
2013/11/20 14:07:25
var styleType
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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) { | |
terry
2013/11/20 14:07:25
indent only +4 for new line.
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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]) { |
terry
2013/11/20 14:07:25
returns Expressions
kevmoo-old
2013/11/20 19:13:11
Done.
| |
2004 int start = _peekToken.start; | 2007 int start = _peekToken.start; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
2005 Expressions expressions = new Expressions(_makeSpan(start)); | 2008 Expressions expressions = new Expressions(_makeSpan(start)); |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
2006 | 2009 |
2007 bool keepGoing = true; | 2010 bool keepGoing = true; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
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 |
2014 switch (_peek()) { | 2017 switch (_peek()) { |
2015 case TokenKind.SLASH: | 2018 case TokenKind.SLASH: |
2016 op = new OperatorSlash(_makeSpan(opStart)); | 2019 op = new OperatorSlash(_makeSpan(opStart)); |
2017 break; | 2020 break; |
(...skipping 36 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* | |
2075 // TIME S* | FREQ S* | function | 2078 // TIME S* | FREQ S* | function |
2076 // | 2079 // |
2077 // NUMBER: {num} | 2080 // NUMBER: {num} |
2078 // PERCENTAGE: {num}% | 2081 // PERCENTAGE: {num}% |
2079 // LENGTH: {num}['px' | 'cm' | 'mm' | 'in' | 'pt' | 'pc'] | 2082 // LENGTH: {num}['px' | 'cm' | 'mm' | 'in' | 'pt' | 'pc'] |
2080 // EMS: {num}'em' | 2083 // EMS: {num}'em' |
2081 // EXS: {num}'ex' | 2084 // EXS: {num}'ex' |
2082 // ANGLE: {num}['deg' | 'rad' | 'grad'] | 2085 // ANGLE: {num}['deg' | 'rad' | 'grad'] |
2083 // TIME: {num}['ms' | 's'] | 2086 // TIME: {num}['ms' | 's'] |
2084 // FREQ: {num}['hz' | 'khz'] | 2087 // FREQ: {num}['hz' | 'khz'] |
2085 // function: IDENT '(' expr ')' | 2088 // function: IDENT '(' expr ')' |
2086 // | 2089 // |
2087 processTerm([bool ieFilter = false]) { | 2090 processTerm([bool ieFilter = false]) { |
2088 int start = _peekToken.start; | 2091 int start = _peekToken.start; |
terry
2013/11/20 14:07:25
var
kevmoo-old
2013/11/20 19:13:11
Done.
| |
2089 Token t; // token for term's value | 2092 Token t; // token for term's value |
terry
2013/11/20 14:07:25
var
| |
2090 var value; // value of term (numeric values) | 2093 var value; // value of term (numeric values) |
2091 | 2094 |
2092 var unary = ""; | 2095 var unary = ""; |
2093 switch (_peek()) { | 2096 switch (_peek()) { |
2094 case TokenKind.HASH: | 2097 case TokenKind.HASH: |
2095 this._eat(TokenKind.HASH); | 2098 this._eat(TokenKind.HASH); |
2096 if (!_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) { | 2099 if (!_anyWhiteSpaceBeforePeekToken(TokenKind.HASH)) { |
2097 String hexText; | 2100 String hexText; |
2098 if (_peekKind(TokenKind.INTEGER)) { | 2101 if (_peekKind(TokenKind.INTEGER)) { |
2099 String hexText1 = _peekToken.text; | 2102 String hexText1 = _peekToken.text; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2186 var propName = nameValue.name; | 2189 var propName = nameValue.name; |
2187 var errMsg = TokenKind.isPredefinedName(propName) ? | 2190 var errMsg = TokenKind.isPredefinedName(propName) ? |
2188 "Improper use of property value ${propName}" : | 2191 "Improper use of property value ${propName}" : |
2189 "Unknown property value ${propName}"; | 2192 "Unknown property value ${propName}"; |
2190 _warning(errMsg, _makeSpan(start)); | 2193 _warning(errMsg, _makeSpan(start)); |
2191 } | 2194 } |
2192 return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start)); | 2195 return new LiteralTerm(nameValue, nameValue.name, _makeSpan(start)); |
2193 } | 2196 } |
2194 | 2197 |
2195 // Yes, process the color as an RGB value. | 2198 // Yes, process the color as an RGB value. |
2196 String rgbColor = TokenKind.decimalToHex( | 2199 String rgbColor = TokenKind.decimalToHex( |
terry
2013/11/20 14:07:25
var
| |
2197 TokenKind.colorValue(colorEntry), 6); | 2200 TokenKind.colorValue(colorEntry), 6); |
2198 return _parseHex(rgbColor, _makeSpan(start)); | 2201 return _parseHex(rgbColor, _makeSpan(start)); |
2199 case TokenKind.UNICODE_RANGE: | 2202 case TokenKind.UNICODE_RANGE: |
2200 var first; | 2203 var first; |
2201 var second; | 2204 var second; |
2202 var firstNumber; | 2205 var firstNumber; |
2203 var secondNumber; | 2206 var secondNumber; |
2204 _eat(TokenKind.UNICODE_RANGE, unicodeRange: true); | 2207 _eat(TokenKind.UNICODE_RANGE, unicodeRange: true); |
2205 if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) { | 2208 if (_maybeEat(TokenKind.HEX_INTEGER, unicodeRange: true)) { |
2206 first = _previousToken.text; | 2209 first = _previousToken.text; |
(...skipping 34 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; |
terry
2013/11/20 14:07:25
style is to use var.
| |
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; |
terry
2013/11/20 14:07:25
var
| |
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; |
2342 case TokenKind.DOUBLE_QUOTE: | 2345 case TokenKind.DOUBLE_QUOTE: |
(...skipping 120 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 |
2484 return new Identifier(tok.text, _makeSpan(tok.start)); | 2487 return new Identifier(tok.text, _makeSpan(tok.start)); |
2485 } | 2488 } |
2486 | 2489 |
2487 // TODO(terry): Move this to base <= 36 and into shared code. | 2490 // TODO(terry): Move this to base <= 36 and into shared code. |
2488 static int _hexDigit(int c) { | 2491 static int _hexDigit(int c) { |
2489 if(c >= 48/*0*/ && c <= 57/*9*/) { | 2492 if(c >= 48/*0*/ && c <= 57/*9*/) { |
terry
2013/11/20 14:07:25
space between if and (
kevmoo-old
2013/11/20 19:13:11
Done.
| |
2490 return c - 48; | 2493 return c - 48; |
2491 } else if (c >= 97/*a*/ && c <= 102/*f*/) { | 2494 } else if (c >= 97/*a*/ && c <= 102/*f*/) { |
2492 return c - 87; | 2495 return c - 87; |
2493 } else if (c >= 65/*A*/ && c <= 70/*F*/) { | 2496 } else if (c >= 65/*A*/ && c <= 70/*F*/) { |
2494 return c - 55; | 2497 return c - 55; |
2495 } else { | 2498 } else { |
2496 return -1; | 2499 return -1; |
2497 } | 2500 } |
2498 } | 2501 } |
2499 | 2502 |
(...skipping 28 matching lines...) Expand all 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 |
2549 * larger | 2552 * larger |
2550 * ##length in px, pt, etc. | 2553 * ##length in px, pt, etc. |
2551 * ##%, percent of parent elem's font-size | 2554 * ##%, percent of parent elem's font-size |
2552 * inherit | 2555 * inherit |
2553 */ | 2556 */ |
2554 LengthTerm size; | 2557 LengthTerm size; |
terry
2013/11/20 14:07:25
var
| |
2555 LineHeight lineHt; | 2558 LineHeight lineHt; |
terry
2013/11/20 14:07:25
var
| |
2556 bool nextIsLineHeight = false; | 2559 bool nextIsLineHeight = false; |
terry
2013/11/20 14:07:25
var
| |
2557 for (; _index < _exprs.expressions.length; _index++) { | 2560 for (; _index < _exprs.expressions.length; _index++) { |
2558 var expr = _exprs.expressions[_index]; | 2561 var expr = _exprs.expressions[_index]; |
2559 if (size == null && expr is LengthTerm) { | 2562 if (size == null && expr is LengthTerm) { |
2560 // font-size part. | 2563 // font-size part. |
2561 size = expr; | 2564 size = expr; |
2562 } else if (size != null) { | 2565 } else if (size != null) { |
2563 if (expr is OperatorSlash) { | 2566 if (expr is OperatorSlash) { |
2564 // LineHeight could follow? | 2567 // LineHeight could follow? |
2565 nextIsLineHeight = true; | 2568 nextIsLineHeight = true; |
2566 } else if (nextIsLineHeight && expr is LengthTerm) { | 2569 } else if (nextIsLineHeight && expr is LengthTerm) { |
2567 assert(expr.unit == TokenKind.UNIT_LENGTH_PX); | 2570 assert(expr.unit == TokenKind.UNIT_LENGTH_PX); |
2568 lineHt = new LineHeight(expr.value, inPixels: true); | 2571 lineHt = new LineHeight(expr.value, inPixels: true); |
2569 nextIsLineHeight = false; | 2572 nextIsLineHeight = false; |
2570 _index++; | 2573 _index++; |
2571 break; | 2574 break; |
2572 } else { | 2575 } else { |
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>[]; |
terry
2013/11/20 14:07:25
var family = [];
| |
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; |
terry
2013/11/20 14:07:25
var
| |
2617 FontExpression fontFamily; | 2620 FontExpression fontFamily; |
terry
2013/11/20 14:07:25
var
| |
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(); |
2623 } | 2626 } |
2624 if (fontFamily == null) { | 2627 if (fontFamily == null) { |
2625 fontFamily = processFontFamily(); | 2628 fontFamily = processFontFamily(); |
2626 } | 2629 } |
2627 //TODO(terry): Handle font-weight, font-style, and font-variant. See | 2630 //TODO(terry): Handle font-weight, font-style, and font-variant. See |
2628 // https://github.com/dart-lang/csslib/issues/3 | 2631 // https://github.com/dart-lang/csslib/issues/3 |
2629 // https://github.com/dart-lang/csslib/issues/4 | 2632 // https://github.com/dart-lang/csslib/issues/4 |
2630 // https://github.com/dart-lang/csslib/issues/5 | 2633 // https://github.com/dart-lang/csslib/issues/5 |
2631 } | 2634 } |
2632 | 2635 |
2633 return new FontExpression(_exprs.span, | 2636 return new FontExpression(_exprs.span, |
2634 size: fontSize.font.size, | 2637 size: fontSize.font.size, |
2635 lineHeight: fontSize.font.lineHeight, | 2638 lineHeight: fontSize.font.lineHeight, |
2636 family: fontFamily.font.family); | 2639 family: fontFamily.font.family); |
2637 } | 2640 } |
2638 } | 2641 } |
2639 | 2642 |
2640 /** | 2643 /** |
2641 * Escapes [text] for use in a CSS string. | 2644 * Escapes [text] for use in a CSS string. |
2642 * [single] specifies single quote `'` vs double quote `"`. | 2645 * [single] specifies single quote `'` vs double quote `"`. |
2643 */ | 2646 */ |
2644 String _escapeString(String text, {bool single: false}) { | 2647 String _escapeString(String text, {bool single: false}) { |
2645 StringBuffer result = null; | 2648 StringBuffer result = null; |
terry
2013/11/20 14:07:25
var
| |
2646 | 2649 |
2647 for (int i = 0; i < text.length; i++) { | 2650 for (int i = 0; i < text.length; i++) { |
2648 int code = text.codeUnitAt(i); | 2651 int code = text.codeUnitAt(i); |
terry
2013/11/20 14:07:25
var
| |
2649 var replace = null; | 2652 var replace = null; |
2650 switch (code) { | 2653 switch (code) { |
2651 case 34/*'"'*/: if (!single) replace = r'\"'; break; | 2654 case 34/*'"'*/: if (!single) replace = r'\"'; break; |
2652 case 39/*"'"*/: if (single) replace = r"\'"; break; | 2655 case 39/*"'"*/: if (single) replace = r"\'"; break; |
2653 } | 2656 } |
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 |