| Index: pkg/csslib/lib/src/polyfill.dart
|
| diff --git a/pkg/csslib/lib/src/polyfill.dart b/pkg/csslib/lib/src/polyfill.dart
|
| index ab56771e6861535fd9c176c9f600835063ea76ca..ef3c7b97d455457048a8b974a9a421a8c07d4dd7 100644
|
| --- a/pkg/csslib/lib/src/polyfill.dart
|
| +++ b/pkg/csslib/lib/src/polyfill.dart
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| +// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| @@ -11,6 +11,8 @@ part of csslib.parser;
|
| class PolyFill {
|
| final Messages _messages;
|
| final bool _warningsAsErrors;
|
| + Map<String, VarDefinition> _allVarDefinitions =
|
| + new Map<String, VarDefinition>();
|
|
|
| Set<StyleSheet> allStyleSheets = new Set<StyleSheet>();
|
|
|
| @@ -25,55 +27,45 @@ class PolyFill {
|
| * Run the analyzer on every file that is a style sheet or any component that
|
| * has a style tag.
|
| */
|
| - void process(StyleSheet stylesheet) {
|
| - // TODO(terry): Process all imported stylesheets.
|
| -
|
| - var styleSheets = processVars([stylesheet]);
|
| - allStyleSheets.addAll(styleSheets);
|
| + void process(StyleSheet styleSheet, {List<StyleSheet> includes: null}) {
|
| + if (includes != null) {
|
| + processVarDefinitions(includes);
|
| + }
|
| + processVars(styleSheet);
|
|
|
| - normalize();
|
| + // Remove all var definitions for this style sheet.
|
| + new _RemoveVarDefinitions().visitTree(styleSheet);
|
| }
|
|
|
| - void normalize() {
|
| - // Remove all var definitions for all style sheets analyzed.
|
| - for (var tree in allStyleSheets)
|
| - new _RemoveVarDefinitions().visitTree(tree);
|
| + /** Process all includes looking for var definitions. */
|
| + void processVarDefinitions(List<StyleSheet> includes) {
|
| + for (var include in includes) {
|
| + _allVarDefinitions = (new _VarDefinitionsIncludes(_allVarDefinitions)
|
| + ..visitTree(include)).varDefs;
|
| + }
|
| }
|
|
|
| - List<StyleSheet> processVars(List<StyleSheet> styleSheets) {
|
| - // TODO(terry): Process all dependencies.
|
| + void processVars(StyleSheet styleSheet) {
|
| // Build list of all var definitions.
|
| - Map varDefs = new Map();
|
| - for (var tree in styleSheets) {
|
| - var allDefs = (new _VarDefinitions()..visitTree(tree)).found;
|
| - allDefs.forEach((key, value) {
|
| - varDefs[key] = value;
|
| - });
|
| - }
|
| + var mainStyleSheetVarDefs =
|
| + (new _VarDefAndUsage(this._messages, _allVarDefinitions)
|
| + ..visitTree(styleSheet)).varDefs;
|
|
|
| // Resolve all definitions to a non-VarUsage (terminal expression).
|
| - varDefs.forEach((key, value) {
|
| - for (var expr in (value.expression as Expressions).expressions) {
|
| - var def = _findTerminalVarDefinition(varDefs, value);
|
| - varDefs[key] = def;
|
| + mainStyleSheetVarDefs.forEach((key, value) {
|
| + for (Expression expr in (value.expression as Expressions).expressions) {
|
| + mainStyleSheetVarDefs[key] =
|
| + _findTerminalVarDefinition(_allVarDefinitions, value);
|
| }
|
| });
|
| -
|
| - // Resolve all var usages.
|
| - for (var tree in styleSheets) {
|
| - new _ResolveVarUsages(varDefs).visitTree(tree);
|
| - }
|
| -
|
| - return styleSheets;
|
| }
|
| }
|
|
|
| -/**
|
| - * Find var- definitions in a style sheet.
|
| - * [found] list of known definitions.
|
| - */
|
| -class _VarDefinitions extends Visitor {
|
| - final Map<String, VarDefinition> found = new Map();
|
| +/** Build list of all var definitions in all includes. */
|
| +class _VarDefinitionsIncludes extends Visitor {
|
| + final Map<String, VarDefinition> varDefs;
|
| +
|
| + _VarDefinitionsIncludes(this.varDefs);
|
|
|
| void visitTree(StyleSheet tree) {
|
| visitStyleSheet(tree);
|
| @@ -81,9 +73,9 @@ class _VarDefinitions extends Visitor {
|
|
|
| visitVarDefinition(VarDefinition node) {
|
| // Replace with latest variable definition.
|
| - found[node.definedName] = node;
|
| + varDefs[node.definedName] = node;
|
| super.visitVarDefinition(node);
|
| - }
|
| + }
|
|
|
| void visitVarDefinitionDirective(VarDefinitionDirective node) {
|
| visitVarDefinition(node.def);
|
| @@ -91,78 +83,98 @@ class _VarDefinitions extends Visitor {
|
| }
|
|
|
| /**
|
| - * Resolve any CSS expression which contains a var() usage to the ultimate real
|
| - * CSS expression value e.g.,
|
| - *
|
| - * var-one: var(two);
|
| - * var-two: #ff00ff;
|
| - *
|
| - * .test {
|
| - * color: var(one);
|
| - * }
|
| - *
|
| - * then .test's color would be #ff00ff
|
| + * Find var- definitions in a style sheet.
|
| + * [found] list of known definitions.
|
| */
|
| -class _ResolveVarUsages extends Visitor {
|
| - final Map<String, VarDefinition> varDefs;
|
| - bool inVarDefinition = false;
|
| - bool inUsage = false;
|
| - Expressions currentExpressions;
|
| +class _VarDefAndUsage extends Visitor {
|
| + final Messages _messages;
|
| + final Map<String, VarDefinition> _knownVarDefs;
|
| + final Map<String, VarDefinition> varDefs = new Map<String, VarDefinition>();
|
|
|
| - _ResolveVarUsages(this.varDefs);
|
| + VarDefinition currVarDefinition;
|
| + List<Expression> currentExpressions;
|
| +
|
| + _VarDefAndUsage(this._messages, this._knownVarDefs);
|
|
|
| void visitTree(StyleSheet tree) {
|
| visitStyleSheet(tree);
|
| }
|
|
|
| - void visitVarDefinition(VarDefinition varDef) {
|
| - inVarDefinition = true;
|
| - super.visitVarDefinition(varDef);
|
| - inVarDefinition = false;
|
| + visitVarDefinition(VarDefinition node) {
|
| + // Replace with latest variable definition.
|
| + currVarDefinition = node;
|
| +
|
| + _knownVarDefs[node.definedName] = node;
|
| + varDefs[node.definedName] = node;
|
| +
|
| + super.visitVarDefinition(node);
|
| +
|
| + currVarDefinition = null;
|
| + }
|
| +
|
| + void visitVarDefinitionDirective(VarDefinitionDirective node) {
|
| + visitVarDefinition(node.def);
|
| }
|
|
|
| void visitExpressions(Expressions node) {
|
| - currentExpressions = node;
|
| + currentExpressions = node.expressions;
|
| super.visitExpressions(node);
|
| currentExpressions = null;
|
| }
|
|
|
| void visitVarUsage(VarUsage node) {
|
| + if (currVarDefinition != null && currVarDefinition.badUsage) return;
|
| +
|
| // Don't process other var() inside of a varUsage. That implies that the
|
| // default is a var() too. Also, don't process any var() inside of a
|
| // varDefinition (they're just place holders until we've resolved all real
|
| // usages.
|
| - if (!inUsage && !inVarDefinition && currentExpressions != null) {
|
| - var expressions = currentExpressions.expressions;
|
| - var index = expressions.indexOf(node);
|
| - assert(index >= 0);
|
| - var def = varDefs[node.name];
|
| - if (def != null) {
|
| - // Found a VarDefinition use it.
|
| - _resolveVarUsage(currentExpressions.expressions, index, def);
|
| - } else if (node.defaultValues.any((e) => e is VarUsage)) {
|
| - // Don't have a VarDefinition need to use default values resolve all
|
| - // default values.
|
| - var terminalDefaults = [];
|
| - for (var defaultValue in node.defaultValues) {
|
| - terminalDefaults.addAll(resolveUsageTerminal(defaultValue));
|
| + var expressions = currentExpressions;
|
| + var index = expressions.indexOf(node);
|
| + assert(index >= 0);
|
| + var def = _knownVarDefs[node.name];
|
| + if (def != null) {
|
| + if (def.badUsage) {
|
| + // Remove any expressions pointing to a bad var definition.
|
| + expressions.removeAt(index);
|
| + return;
|
| + }
|
| + _resolveVarUsage(currentExpressions, index,
|
| + _findTerminalVarDefinition(_knownVarDefs, def));
|
| + } else if (node.defaultValues.any((e) => e is VarUsage)) {
|
| + // Don't have a VarDefinition need to use default values resolve all
|
| + // default values.
|
| + var terminalDefaults = [];
|
| + for (var defaultValue in node.defaultValues) {
|
| + terminalDefaults.addAll(resolveUsageTerminal(defaultValue));
|
| + }
|
| + expressions.replaceRange(index, index + 1, terminalDefaults);
|
| + } else if (node.defaultValues.isNotEmpty){
|
| + // No VarDefinition but default value is a terminal expression; use it.
|
| + expressions.replaceRange(index, index + 1, node.defaultValues);
|
| + } else {
|
| + if (currVarDefinition != null) {
|
| + currVarDefinition.badUsage = true;
|
| + var mainStyleSheetDef = varDefs[node.name];
|
| + if (mainStyleSheetDef != null) {
|
| + varDefs.remove(currVarDefinition.property);
|
| }
|
| - expressions.replaceRange(index, index + 1, terminalDefaults);
|
| - } else {
|
| - // No VarDefinition but default value is a terminal expression; use it.
|
| - expressions.replaceRange(index, index + 1, node.defaultValues);
|
| }
|
| + // Remove var usage that points at an undefined definition.
|
| + expressions.removeAt(index);
|
| + _messages.warning("Variable is not defined.", node.span);
|
| }
|
|
|
| - inUsage = true;
|
| + var oldExpressions = currentExpressions;
|
| + currentExpressions = node.defaultValues;
|
| super.visitVarUsage(node);
|
| - inUsage = false;
|
| + currentExpressions = oldExpressions;
|
| }
|
|
|
| List<Expression> resolveUsageTerminal(VarUsage usage) {
|
| var result = [];
|
|
|
| - var varDef = varDefs[usage.name];
|
| + var varDef = _knownVarDefs[usage.name];
|
| var expressions;
|
| if (varDef == null) {
|
| // VarDefinition not found try the defaultValues.
|
|
|