Index: utils/css/tree.dart |
diff --git a/utils/css/tree.dart b/utils/css/tree.dart |
index 8a279c3b4546fecafc4681a422eee9aca27dd5c9..cca0ed7f74b16e0d71f74ede03dcc752860044a7 100644 |
--- a/utils/css/tree.dart |
+++ b/utils/css/tree.dart |
@@ -11,7 +11,7 @@ |
class Identifier extends lang.Node { |
String name; |
- Identifier(this.name, lang.SourceSpan span): super(span) {} |
+ Identifier(this.name, lang.SourceSpan span): super(span); |
visit(TreeVisitor visitor) => visitor.visitIdentifier(this); |
@@ -26,28 +26,41 @@ class Wildcard extends lang.Node { |
String toString() => '*'; |
} |
+// /* .... */ |
+class Comment extends lang.Node { |
+ String comment; |
+ |
+ Comment(this.comment, lang.SourceSpan span): super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitComment(this); |
+ |
+ String toString() => '/* ${comment} */'; |
+} |
+ |
+// CDO/CDC (Comment Definition Open <!-- and Comment Definition Close -->). |
+class CommentDefinition extends Comment { |
+ CommentDefinition(String comment, lang.SourceSpan span): super(comment, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitCommentDefinition(this); |
+ |
+ String toString() => '<!-- ${comment} -->'; |
+} |
+ |
class SelectorGroup extends lang.Node { |
- // List of SimpleSelector(s) list contain any mix SimpleSelector or |
- // SimpleSlectorName (or class derived from SimpleSelectorName e.g., |
- // IdSelector, ClassSelector, ElementSelector, PseudoClassSelector, |
- // PseudoElementSelector, NotSelector, or Attribute |
- List<SimpleSelector> selectors; |
+ List<Selector> _selectors; |
+ |
+ SelectorGroup(this._selectors, lang.SourceSpan span): super(span); |
- SelectorGroup(this.selectors, lang.SourceSpan span): super(span); |
+ List<Selector> get selectors() => _selectors; |
visit(TreeVisitor visitor) => visitor.visitSelectorGroup(this); |
String toString() { |
StringBuffer buff = new StringBuffer(); |
- for (selector in selectors) { |
- if (selector.isCombinatorDescendant()) { |
- buff.add(' '); |
- } else if (selector.isCombinatorPlus()) { |
- buff.add(' + '); |
- } else if (selector.isCombinatorGreater()) { |
- buff.add(' > '); |
- } else if (selector.isCombinatorTilde()) { |
- buff.add(' ~ '); |
+ int idx = 0; |
+ for (var selector in _selectors) { |
+ if (idx++ > 0) { |
+ buff.add(', '); |
} |
buff.add(selector.toString()); |
} |
@@ -63,34 +76,72 @@ class SelectorGroup extends lang.Node { |
} |
} |
+class Selector extends lang.Node { |
+ List<SimpleSelectorSequence> _simpleSelectorSequences; |
+ |
+ Selector(this._simpleSelectorSequences, lang.SourceSpan span) : super(span); |
+ |
+ List<SimpleSelectorSequence> get simpleSelectorSequences() => |
+ _simpleSelectorSequences; |
+ |
+ add(SimpleSelectorSequence seq) => _simpleSelectorSequences.add(seq); |
+ |
+ List<SimpleSelectorSequence> get simpleSelectorSquences() => |
+ _simpleSelectorSequences; |
+ |
+ int get length() => _simpleSelectorSequences.length; |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ for (_simpleSelectorSequence in _simpleSelectorSequences) { |
+ buff.add(_simpleSelectorSequence.toString()); |
+ } |
+ return buff.toString(); |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitSelector(this); |
+} |
+ |
+class SimpleSelectorSequence extends lang.Node { |
+ int _combinator; // +, >, ~, NONE |
+ SimpleSelector _selector; |
+ |
+ SimpleSelectorSequence(this._selector, lang.SourceSpan span, |
+ [this._combinator = TokenKind.COMBINATOR_NONE]) : super(span); |
+ |
+ get simpleSelector() => _selector; |
+ |
+ bool isCombinatorNone() => _combinator == TokenKind.COMBINATOR_NONE; |
+ bool isCombinatorPlus() => _combinator == TokenKind.COMBINATOR_PLUS; |
+ bool isCombinatorGreater() => _combinator == TokenKind.COMBINATOR_GREATER; |
+ bool isCombinatorTilde() => _combinator == TokenKind.COMBINATOR_TILDE; |
+ bool isCombinatorDescendant() => |
+ _combinator == TokenKind.COMBINATOR_DESCENDANT; |
+ |
+ String _combinatorToString() => |
+ isCombinatorDescendant() ? ' ' : |
+ isCombinatorPlus() ? '+' : |
+ isCombinatorGreater() ? '>' : |
+ isCombinatorTilde() ? '~' : ''; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitSimpleSelectorSequence(this); |
+ |
+ String toString() => _combinatorToString() + _selector.toString(); |
+} |
+ |
/* All other selectors (element, #id, .class, attribute, pseudo, negation, |
* namespace, *) are derived from this selector. |
*/ |
class SimpleSelector extends lang.Node { |
- int _combinator; // +, >, ~ or descendant (space), and NONE |
var _name; |
- SimpleSelector(this._name, lang.SourceSpan span, |
- [this._combinator = TokenKind.COMBINATOR_NONE]) : super(span); |
+ SimpleSelector(this._name, lang.SourceSpan span) : super(span); |
// Name can be an Identifier or WildCard we'll return either the name or '*'. |
String get name() => isWildcard() ? '*' : _name.name; |
bool isWildcard() => _name is Wildcard; |
- // TODO(terry): Kind of hacky to reset combinator to NONE |
- void resetCombinatorNone() { |
- assert(isCombinatorDescendant()); |
- _combinator = TokenKind.COMBINATOR_NONE; |
- } |
- |
- bool isCombinatorNone() => _combinator == TokenKind.COMBINATOR_NONE; |
- bool isCombinatorDescendant() => |
- _combinator == TokenKind.COMBINATOR_DESCENDANT; |
- bool isCombinatorPlus() => _combinator == TokenKind.COMBINATOR_PLUS; |
- bool isCombinatorGreater() => _combinator == TokenKind.COMBINATOR_GREATER; |
- bool isCombinatorTilde() => _combinator == TokenKind.COMBINATOR_TILDE; |
- |
visit(TreeVisitor visitor) => visitor.visitSimpleSelector(this); |
String toString() => name; |
@@ -98,9 +149,7 @@ class SimpleSelector extends lang.Node { |
// element name |
class ElementSelector extends SimpleSelector { |
- ElementSelector(var name, lang.SourceSpan span, |
- [int combinator = TokenKind.COMBINATOR_NONE]) : |
- super(name, span, combinator); |
+ ElementSelector(var name, lang.SourceSpan span) : super(name, span); |
visit(TreeVisitor visitor) => visitor.visitElementSelector(this); |
@@ -119,9 +168,8 @@ class ElementSelector extends SimpleSelector { |
class NamespaceSelector extends SimpleSelector { |
var _namespace; // null, Wildcard or Identifier |
- NamespaceSelector(this._namespace, var name, lang.SourceSpan span, |
- [int combinator = TokenKind.COMBINATOR_NONE]) : |
- super(name, span, combinator); |
+ NamespaceSelector(this._namespace, var name, lang.SourceSpan span) : |
+ super(name, span); |
String get namespace() => _namespace is Wildcard ? '*' : _namespace.name; |
@@ -134,11 +182,65 @@ class NamespaceSelector extends SimpleSelector { |
String toString() => "$namespace|$nameAsSimpleSelector"; |
} |
+// [attr op value] |
+class AttributeSelector extends SimpleSelector { |
+ int _op; |
+ var _value; |
+ |
+ AttributeSelector(Identifier name, this._op, this._value, |
+ lang.SourceSpan span) : super(name, span); |
+ |
+ String matchOperator() { |
+ switch (_op) { |
+ case TokenKind.EQUALS: |
+ return '='; |
+ case TokenKind.INCLUDES: |
+ return '~='; |
+ case TokenKind.DASH_MATCH: |
+ return '|='; |
+ case TokenKind.PREFIX_MATCH: |
+ return '^='; |
+ case TokenKind.SUFFIX_MATCH: |
+ return '\$='; |
+ case TokenKind.SUBSTRING_MATCH: |
+ return '*='; |
+ } |
+ } |
+ |
+ // Return the TokenKind for operator used by visitAttributeSelector. |
+ String matchOperatorAsTokenString() { |
+ switch (_op) { |
+ case TokenKind.EQUALS: |
+ return 'EQUALS'; |
+ case TokenKind.INCLUDES: |
+ return 'INCLUDES'; |
+ case TokenKind.DASH_MATCH: |
+ return 'DASH_MATCH'; |
+ case TokenKind.PREFIX_MATCH: |
+ return 'PREFIX_MATCH'; |
+ case TokenKind.SUFFIX_MATCH: |
+ return 'SUFFIX_MATCH'; |
+ case TokenKind.SUBSTRING_MATCH: |
+ return 'SUBSTRING_MATCH'; |
+ } |
+ } |
+ |
+ String valueToString() { |
+ if (_value is Identifier) { |
+ return _value.name; |
+ } else { |
+ return '"${_value}"'; |
+ } |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitAttributeSelector(this); |
+ |
+ String toString() => "[${name} ${matchOperator()} ${valueToString()}]"; |
+} |
+ |
// #id |
class IdSelector extends SimpleSelector { |
- IdSelector(Identifier name, lang.SourceSpan span, |
- [int combinator = TokenKind.COMBINATOR_NONE]) : |
- super(name, span, combinator); |
+ IdSelector(Identifier name, lang.SourceSpan span) : super(name, span); |
visit(TreeVisitor visitor) => visitor.visitIdSelector(this); |
@@ -147,9 +249,7 @@ class IdSelector extends SimpleSelector { |
// .class |
class ClassSelector extends SimpleSelector { |
- ClassSelector(Identifier name, lang.SourceSpan span, |
- [int combinator = TokenKind.COMBINATOR_NONE]) : |
- super(name, span, combinator); |
+ ClassSelector(Identifier name, lang.SourceSpan span) : super(name, span); |
visit(TreeVisitor visitor) => visitor.visitClassSelector(this); |
@@ -158,9 +258,8 @@ class ClassSelector extends SimpleSelector { |
// :pseudoClass |
class PseudoClassSelector extends SimpleSelector { |
- PseudoClassSelector(Identifier name, lang.SourceSpan span, |
- [int combinator = TokenKind.COMBINATOR_NONE]) : |
- super(name, span, combinator); |
+ PseudoClassSelector(Identifier name, lang.SourceSpan span) : |
+ super(name, span); |
visit(TreeVisitor visitor) => visitor.visitPseudoClassSelector(this); |
@@ -169,9 +268,8 @@ class PseudoClassSelector extends SimpleSelector { |
// ::pseudoElement |
class PseudoElementSelector extends SimpleSelector { |
- PseudoElementSelector(Identifier name, lang.SourceSpan span, |
- [int combinator = TokenKind.COMBINATOR_NONE]) : |
- super(name, span, combinator); |
+ PseudoElementSelector(Identifier name, lang.SourceSpan span) : |
+ super(name, span); |
visit(TreeVisitor visitor) => visitor.visitPseudoElementSelector(this); |
@@ -181,32 +279,597 @@ class PseudoElementSelector extends SimpleSelector { |
// TODO(terry): Implement |
// NOT |
class NotSelector extends SimpleSelector { |
- NotSelector(String name, lang.SourceSpan span, |
- [lang.Token combinator = TokenKind.COMBINATOR_NONE]) : |
- super(name, span, combinator); |
+ NotSelector(String name, lang.SourceSpan span) : super(name, span); |
visit(TreeVisitor visitor) => visitor.visitNotSelector(this); |
} |
-// TODO(terry): Implement |
-// [attribute] |
-class Attribute extends lang.Node { |
- var name; // NamespaceSelector or SimpleSelector |
- int matchType; // ~=, |=, ^=, $=, *=, = |
- String value; |
+class Stylesheet extends lang.Node { |
+ // Contains charset, ruleset, directives (media, page, etc.) |
+ List<lang.Node> _topLevels; |
+ |
+ Stylesheet(this._topLevels, lang.SourceSpan span) : super(span) { |
+ for (var node in _topLevels) { |
+ assert(node is TopLevelProduction || node is Directive); |
+ } |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitStylesheet(this); |
+ |
+ List<lang.Node> get topLevels() => _topLevels; |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ for (var topLevel in _topLevels) { |
+ buff.add(topLevel.toString()); |
+ } |
+ return buff.toString(); |
+ } |
+ |
+ /** A multiline string showing the node and its children. */ |
+ String toDebugString() { |
+ var to = new lang.TreeOutput(); |
+ var tp = new TreePrinter(to); |
+ this.visit(tp); |
+ return to.buf.toString(); |
+ } |
+} |
+ |
+class TopLevelProduction extends lang.Node { |
+ TopLevelProduction(lang.SourceSpan span) : super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitTopLevelProduction(this); |
+ |
+ String toString() => "TopLevelProduction"; |
+} |
+ |
+class RuleSet extends TopLevelProduction { |
+ SelectorGroup _selectorGroup; |
+ DeclarationGroup _declarationGroup; |
+ |
+ RuleSet(this._selectorGroup, this._declarationGroup, lang.SourceSpan span) : |
+ super(span); |
+ |
+ SelectorGroup get selectorGroup() => _selectorGroup; |
+ DeclarationGroup get declarationGroup() => _declarationGroup; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitRuleSet(this); |
+ |
+ String toString() => |
+ "\n${_selectorGroup.toString()} {\n" + |
+ "${_declarationGroup.toString()}}\n"; |
+} |
+ |
+class Directive extends lang.Node { |
+ Directive(lang.SourceSpan span) : super(span); |
+ |
+ String toString() => "Directive"; |
+ |
+ bool get isBuiltIn() => true; // Known CSS directive? |
+ bool get isExtension() => false; // SCSS extension? |
+ |
+ visit(TreeVisitor visitor) => visitor.visitDirective(this); |
+} |
+ |
+class ImportDirective extends Directive { |
+ String _import; |
+ List<String> _media; |
+ |
+ ImportDirective(this._import, this._media, lang.SourceSpan span) : |
+ super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitImportDirective(this); |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ |
+ buff.add('@import url(${_import})'); |
+ |
+ int idx = 0; |
+ for (var medium in _media) { |
+ buff.add(idx++ == 0 ? ' $medium' : ',$medium'); |
+ } |
+ buff.add('\n'); |
+ |
+ return buff.toString(); |
+ } |
+} |
+ |
+class MediaDirective extends Directive { |
+ List<String> _media; |
+ RuleSet _ruleset; |
nweiz
2012/01/04 19:05:41
Shouldn't this be a list of RuleSets?
|
+ |
+ MediaDirective(this._media, this._ruleset, lang.SourceSpan span) : |
+ super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitMediaDirective(this); |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ |
+ buff.add('@media'); |
+ int idx = 0; |
+ for (var medium in _media) { |
+ buff.add(idx++ == 0 ? ' $medium' : ',$medium'); |
+ } |
+ buff.add(' {\n'); |
+ buff.add(_ruleset.toString()); |
+ buff.add('\n\}\n'); |
+ |
+ return buff.toString(); |
+ } |
+} |
+ |
+class PageDirective extends Directive { |
+ String _pseudoPage; |
+ DeclarationGroup _decls; |
+ |
+ PageDirective(this._pseudoPage, this._decls, lang.SourceSpan span) : |
+ super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitPageDirective(this); |
+ |
+ // @page : pseudoPage { |
+ // decls |
+ // } |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ |
+ buff.add('@page '); |
+ if (_pseudoPage != null) { |
+ buff.add(': ${_pseudoPage} '); |
+ } |
+ buff.add('{\n${_decls.toString()}\n}\n'); |
+ |
+ return buff.toString(); |
+ } |
+} |
+ |
+class KeyFrameDirective extends Directive { |
+ var _name; |
+ List<KeyFrameBlock> _blocks; |
+ |
+ KeyFrameDirective(this._name, lang.SourceSpan span) : |
+ _blocks = [], super(span); |
+ |
+ add(KeyFrameBlock block) { |
+ _blocks.add(block); |
+ } |
+ |
+ String get name() => _name; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitKeyFrameDirective(this); |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ buff.add('@-webkit-keyframes ${_name} {\n'); |
+ for (var block in _blocks) { |
+ buff.add(block.toString()); |
+ } |
+ buff.add('}\n'); |
+ return buff.toString(); |
+ } |
+} |
+ |
+class KeyFrameBlock extends lang.Expression { |
+ Expressions _blockSelectors; |
+ DeclarationGroup _declarations; |
+ |
+ KeyFrameBlock(this._blockSelectors, this._declarations, lang.SourceSpan span): |
+ super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitKeyFrameBlock(this); |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ buff.add(' ${_blockSelectors.toString()} {\n'); |
+ buff.add(_declarations.toString()); |
+ buff.add(' }\n'); |
+ return buff.toString(); |
+ } |
+} |
+ |
+// TODO(terry): TBD |
+class FontFaceDirective extends Directive { |
+ List<Declaration> _declarations; |
nweiz
2012/01/04 19:05:41
Shouldn't this be a DeclarationGroup?
|
+ |
+ FontFaceDirective(this._declarations, lang.SourceSpan span) : super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitFontFaceDirective(this); |
+ |
+ String toString() { |
+ return "TO BE DONE"; |
+ } |
+} |
+ |
+class IncludeDirective extends Directive { |
+ String _include; |
+ Stylesheet _stylesheet; |
+ |
+ IncludeDirective(this._include, this._stylesheet, lang.SourceSpan span) : |
+ super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitIncludeDirective(this); |
+ |
+ bool get isBuiltIn() => false; |
+ bool get isExtension() => true; |
+ |
+ Stylesheet get styleSheet() => _stylesheet; |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ buff.add('/****** @include ${_include} ******/\n'); |
+ buff.add(_stylesheet != null ? _stylesheet.toString() : '// <EMPTY>'); |
+ buff.add('/****** End of ${_include} ******/\n\n'); |
+ return buff.toString(); |
+ } |
+} |
+ |
+class StyletDirective extends Directive { |
+ String _dartClassName; |
+ List<RuleSet> _rulesets; |
+ |
+ StyletDirective(this._dartClassName, this._rulesets, lang.SourceSpan span) : |
+ super(span); |
+ |
+ bool get isBuiltIn() => false; |
+ bool get isExtension() => true; |
+ |
+ String get dartClassName() => _dartClassName; |
+ List<RuleSet> get rulesets() => _rulesets; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitStyletDirective(this); |
+ |
+ // TODO(terry): Output Dart class |
+ String toString() => '/* @stylet export as ${_dartClassName} */\n'; |
+} |
+ |
+class Declaration extends lang.Node { |
+ Identifier _property; |
+ lang.Expression _expression; |
+ bool _important; |
+ |
+ Declaration(this._property, this._expression, lang.SourceSpan span) : |
+ _important = false, super(span); |
+ |
+ String get property() => _property.name; |
+ lang.Expression get expression() => _expression; |
+ |
+ bool get important() => _important; |
+ set important(bool value) => _important = value; |
+ String importantAsString() => _important ? ' !important' : ''; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitDeclaration(this); |
+ |
+ String toString() => |
+ "${_property.name}: ${_expression.toString()}${importantAsString()}"; |
+} |
+ |
+class DeclarationGroup extends lang.Node { |
+ List<Declaration> _declarations; |
+ |
+ DeclarationGroup(this._declarations, lang.SourceSpan span) : super(span); |
+ |
+ List<Declaration> get declarations() => _declarations; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitDeclarationGroup(this); |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ int idx = 0; |
+ for (var declaration in _declarations) { |
+ buff.add(" ${declaration.toString()};\n"); |
+ } |
+ return buff.toString(); |
+ } |
+} |
+ |
+class OperatorSlash extends lang.Expression { |
+ OperatorSlash(lang.SourceSpan span) : super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitOperatorSlash(this); |
+ |
+ String toString() => ' /'; |
+} |
+ |
+class OperatorComma extends lang.Expression { |
+ OperatorComma(lang.SourceSpan span) : super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitOperatorComma(this); |
+ |
+ String toString() => ','; |
+} |
+ |
+class LiteralTerm extends lang.Expression { |
+ var _value; |
+ String _text; |
+ |
+ LiteralTerm(this._value, this._text, lang.SourceSpan span) : super(span); |
+ |
+ get value() => _value; |
+ String get text() => _text; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitLiteralTerm(this); |
+ |
+ String toString() => _text; |
+} |
+ |
+class NumberTerm extends LiteralTerm { |
+ NumberTerm(var value, String t, lang.SourceSpan span) : super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitNumberTerm(this); |
+} |
+ |
+class UnitTerm extends LiteralTerm { |
+ int _unit; |
+ |
+ UnitTerm(var value, String t, lang.SourceSpan span, this._unit) : |
+ super(value, t, span); |
+ |
+ int get unit() => _unit; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitUnitTerm(this); |
+ |
+ String toString() => '${text}${unitToString()}'; |
+ String unitToString() => TokenKind.unitToString(_unit); |
+} |
+ |
+class LengthTerm extends UnitTerm { |
+ LengthTerm(var value, String t, lang.SourceSpan span, |
+ [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
+ assert(this._unit == TokenKind.UNIT_LENGTH_PX || |
+ this._unit == TokenKind.UNIT_LENGTH_CM || |
+ this._unit == TokenKind.UNIT_LENGTH_MM || |
+ this._unit == TokenKind.UNIT_LENGTH_IN || |
+ this._unit == TokenKind.UNIT_LENGTH_PT || |
+ this._unit == TokenKind.UNIT_LENGTH_PC); |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitLengthTerm(this); |
+} |
+ |
+class PercentageTerm extends LiteralTerm { |
+ PercentageTerm(var value, String t, lang.SourceSpan span) : |
+ super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitPercentageTerm(this); |
+ |
+ String toString() => '${text}%'; |
+ |
+} |
+ |
+class EmTerm extends LiteralTerm { |
+ EmTerm(var value, String t, lang.SourceSpan span) : |
+ super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitEmTerm(this); |
+ |
+ String toString() => '${text}em'; |
+} |
+ |
+class ExTerm extends LiteralTerm { |
+ ExTerm(var value, String t, lang.SourceSpan span) : |
+ super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitExTerm(this); |
+ |
+ String toString() => '${text}ex'; |
+} |
+ |
+class AngleTerm extends UnitTerm { |
+ AngleTerm(var value, String t, lang.SourceSpan span, |
+ [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
+ assert(this._unit == TokenKind.UNIT_ANGLE_DEG || |
+ this._unit == TokenKind.UNIT_ANGLE_RAD || |
+ this._unit == TokenKind.UNIT_ANGLE_GRAD); |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitAngleTerm(this); |
+} |
+ |
+class TimeTerm extends UnitTerm { |
+ TimeTerm(var value, String t, lang.SourceSpan span, |
+ [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
+ assert(this._unit == TokenKind.UNIT_ANGLE_DEG || |
+ this._unit == TokenKind.UNIT_TIME_MS || |
+ this._unit == TokenKind.UNIT_TIME_S); |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitTimeTerm(this); |
+} |
+ |
+class FreqTerm extends UnitTerm { |
+ FreqTerm(var value, String t, lang.SourceSpan span, |
+ [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
+ assert(_unit == TokenKind.UNIT_FREQ_HZ || _unit == TokenKind.UNIT_FREQ_KHZ); |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitFreqTerm(this); |
+} |
+ |
+class FractionTerm extends LiteralTerm { |
+ FractionTerm(var value, String t, lang.SourceSpan span) : |
+ super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitFractionTerm(this); |
+ |
+ String toString() => '${text}fr'; |
+} |
+ |
+class UriTerm extends LiteralTerm { |
+ UriTerm(String value, lang.SourceSpan span) : super(value, value, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitUriTerm(this); |
+ |
+ String toString() => 'url(${text})'; |
+} |
+ |
+class HexColorTerm extends LiteralTerm { |
+ HexColorTerm(var value, String t, lang.SourceSpan span) : |
+ super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitHexColorTerm(this); |
+ |
+ String toString() => '#${text}'; |
+} |
+ |
+class FunctionTerm extends LiteralTerm { |
+ Expressions _params; |
+ |
+ FunctionTerm(var value, String t, this._params, lang.SourceSpan span) |
+ : super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitFunctionTerm(this); |
+ |
+ String toString() { |
+ // TODO(terry): Optimize rgb to a hexcolor. |
+ StringBuffer buff = new StringBuffer(); |
+ |
+ buff.add('${text}('); |
+ buff.add(_params.toString()); |
+ buff.add(')'); |
+ |
+ return buff.toString(); |
+ } |
+} |
+ |
+class GroupTerm extends lang.Expression { |
+ List<LiteralTerm> _terms; |
+ |
+ GroupTerm(lang.SourceSpan span) : _terms = [], super(span); |
+ |
+ add(LiteralTerm term) { |
+ _terms.add(term); |
+ } |
+ |
+ visit(TreeVisitor visitor) => visitor.visitGroupTerm(this); |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ buff.add('('); |
+ int idx = 0; |
+ for (var term in _terms) { |
+ if (idx++ > 0) { |
+ buff.add(' '); |
+ } |
+ buff.add(term.toString()); |
+ } |
+ buff.add(')'); |
+ return buff.toString(); |
+ } |
+} |
+ |
+class ItemTerm extends NumberTerm { |
+ ItemTerm(var value, String t, lang.SourceSpan span) : super(value, t, span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitItemTerm(this); |
+ |
+ String toString() => '[${text}]'; |
+} |
+ |
+class Expressions extends lang.Expression { |
+ List<lang.Expression> _expressions; |
+ |
+ Expressions(lang.SourceSpan span): super(span), _expressions = []; |
+ |
+ add(lang.Expression expression) { |
+ _expressions.add(expression); |
+ } |
+ |
+ List<lang.Expression> get expressions() => _expressions; |
+ |
+ visit(TreeVisitor visitor) => visitor.visitExpressions(this); |
+ |
+ String toString() { |
+ StringBuffer buff = new StringBuffer(); |
+ int idx = 0; |
+ for (var expression in _expressions) { |
+ // Add space seperator between terms without an operator. |
+ // TODO(terry): Should have a BinaryExpression to solve this problem. |
+ if (idx > 0 && |
+ !(expression is OperatorComma || expression is OperatorSlash)) { |
+ buff.add(' '); |
+ } |
+ buff.add(expression.toString()); |
+ idx++; |
+ } |
+ return buff.toString(); |
+ } |
+} |
+ |
+class BinaryExpression extends lang.Expression { |
+ lang.Token op; |
+ lang.Expression x; |
+ lang.Expression y; |
+ |
+ BinaryExpression(this.op, this.x, this.y, lang.SourceSpan span): super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitBinaryExpression(this); |
+} |
+ |
+class UnaryExpression extends lang.Expression { |
+ lang.Token op; |
+ lang.Expression self; |
+ |
+ UnaryExpression(this.op, this.self, lang.SourceSpan span): super(span); |
+ |
+ visit(TreeVisitor visitor) => visitor.visitUnaryExpression(this); |
} |
interface TreeVisitor { |
+ void visitComment(Comment node); |
+ void visitCommentDefinition(CommentDefinition node); |
+ void visitStylesheet(Stylesheet node); |
+ void visitTopLevelProduction(TopLevelProduction node); |
+ void visitDirective(Directive node); |
+ void visitMediaDirective(MediaDirective node); |
+ void visitPageDirective(PageDirective node); |
+ void visitImportDirective(ImportDirective node); |
+ void visitKeyFrameDirective(KeyFrameDirective node); |
+ void visitKeyFrameBlock(KeyFrameBlock node); |
+ void visitFontFaceDirective(FontFaceDirective node); |
+ void visitIncludeDirective(IncludeDirective node); |
+ void visitStyletDirective(StyletDirective node); |
+ |
+ void visitRuleSet(RuleSet node); |
+ void visitDeclarationGroup(DeclarationGroup node); |
+ void visitDeclaration(Declaration node); |
void visitSelectorGroup(SelectorGroup node); |
+ void visitSelector(Selector node); |
+ void visitSimpleSelectorSequence(SimpleSelectorSequence node); |
void visitSimpleSelector(SimpleSelector node); |
void visitElementSelector(ElementSelector node); |
void visitNamespaceSelector(NamespaceSelector node); |
+ void visitAttributeSelector(AttributeSelector node); |
void visitIdSelector(IdSelector node); |
void visitClassSelector(ClassSelector node); |
void visitPseudoClassSelector(PseudoClassSelector node); |
void visitPseudoElementSelector(PseudoElementSelector node); |
void visitNotSelector(NotSelector node); |
+ void visitLiteralTerm(LiteralTerm node); |
+ void visitHexColorTerm(HexColorTerm node); |
+ void visitNumberTerm(NumberTerm node); |
+ void visitUnitTerm(UnitTerm node); |
+ void visitLengthTerm(LengthTerm node); |
+ void visitPercentageTerm(PercentageTerm node); |
+ void visitEmTerm(EmTerm node); |
+ void visitExTerm(ExTerm node); |
+ void visitAngleTerm(AngleTerm node); |
+ void visitTimeTerm(TimeTerm node); |
+ void visitFreqTerm(FreqTerm node); |
+ void visitFractionTerm(FractionTerm node); |
+ void visitUriTerm(UriTerm node); |
+ void visitFunctionTerm(FunctionTerm node); |
+ void visitGroupTerm(GroupTerm node); |
+ void visitItemTerm(ItemTerm node); |
+ void visitOperatorSlash(OperatorSlash node); |
+ void visitOperatorComma(OperatorComma node); |
+ |
+ void visitExpressions(Expressions node); |
+ void visitBinaryExpression(BinaryExpression node); |
+ void visitUnaryExpression(UnaryExpression node); |
+ |
void visitIdentifier(Identifier node); |
void visitWildcard(Wildcard node); |
@@ -218,13 +881,144 @@ class TreePrinter implements TreeVisitor { |
var output; |
TreePrinter(this.output) { output.printer = this; } |
+ void visitStylesheet(Stylesheet node) { |
+ output.heading('Stylesheet', node.span); |
+ output.depth++; |
+ output.writeNodeList('productions', node._topLevels); |
+ output.depth--; |
+ } |
+ |
+ void visitTopLevelProduction(TopLevelProduction node) { |
+ output.heading('TopLevelProduction', node.span); |
+ } |
+ |
+ void visitDirective(Directive node) { |
+ output.heading('Directive', node.span); |
+ } |
+ |
+ void visitComment(Comment node) { |
+ output.heading('Comment', node.span); |
+ output.depth++; |
+ output.writeValue('comment value', node.comment); |
+ output.depth--; |
+ } |
+ |
+ void visitCommentDefinition(CommentDefinition node) { |
+ output.heading('CommentDefinition (CDO/CDC)', node.span); |
+ output.depth++; |
+ output.writeValue('comment value', node.comment); |
+ output.depth--; |
+ } |
+ |
+ void visitMediaDirective(MediaDirective node) { |
+ output.heading('MediaDirective', node.span); |
+ output.depth++; |
+ output.writeNodeList('media', node._media); |
+ visitRuleSet(node._ruleset); |
+ output.depth--; |
+ } |
+ |
+ void visitPageDirective(PageDirective node) { |
+ output.heading('PageDirective', node.span); |
+ output.depth++; |
+ output.writeValue('pseudo page', node._pseudoPage); |
+ visitDeclarationGroup(node._decls); |
+ output.depth; |
+} |
+ |
+ void visitImportDirective(ImportDirective node) { |
+ output.heading('ImportDirective', node.span); |
+ output.depth++; |
+ output.writeValue('import', node._import); |
+ output.writeNodeList('media', node._media); |
+ output.depth--; |
+ } |
+ |
+ void visitKeyFrameDirective(KeyFrameDirective node) { |
+ output.heading('KeyFrameDirective', node.span); |
+ output.depth++; |
+ output.writeValue('name', node._name); |
+ output.writeNodeList('blocks', node._blocks); |
+ output.depth--; |
+ } |
+ |
+ void visitKeyFrameBlock(KeyFrameBlock node) { |
+ output.heading('KeyFrameBlock', node.span); |
+ output.depth++; |
+ visitExpressions(node._blockSelectors); |
+ visitDeclarationGroup(node._declarations); |
+ output.depth--; |
+ } |
+ |
+ void visitFontFaceDirective(FontFaceDirective node) { |
+ // TODO(terry): To Be Implemented |
+ } |
+ |
+ void visitIncludeDirective(IncludeDirective node) { |
+ output.heading('IncludeDirective', node.span); |
+ output.writeValue('include', node._include); |
+ output.depth++; |
+ if (node._stylesheet != null) { |
+ visitStylesheet(node._stylesheet); |
+ } else { |
+ output.writeValue('StyleSheet', '<EMPTY>'); |
+ } |
+ output.depth--; |
+ } |
+ |
+ void visitStyletDirective(StyletDirective node) { |
+ output.heading('StyletDirective', node.span); |
+ output.writeValue('dartClassName', node._dartClassName); |
+ output.depth++; |
+ output.writeNodeList('rulesets', node._rulesets); |
+ output.depth--; |
+} |
+ |
+ void visitRuleSet(RuleSet node) { |
+ output.heading('Ruleset', node.span); |
+ output.depth++; |
+ visitSelectorGroup(node._selectorGroup); |
+ visitDeclarationGroup(node._declarationGroup); |
+ output.depth--; |
+ } |
+ |
+ void visitDeclarationGroup(DeclarationGroup node) { |
+ output.heading('DeclarationGroup', node.span); |
+ output.depth++; |
+ output.writeNodeList('declarations', node._declarations); |
+ output.depth--; |
+ } |
+ |
+ void visitDeclaration(Declaration node) { |
+ output.heading('Declaration', node.span); |
+ output.depth++; |
+ output.write('property'); |
+ visitIdentifier(node._property); |
+ output.writeNode('expression', node._expression); |
+ if (node.important) { |
+ output.writeValue('!important', 'true'); |
+ } |
+ output.depth--; |
+ } |
+ |
void visitSelectorGroup(SelectorGroup node) { |
output.heading('Selector Group', node.span); |
+ output.depth++; |
output.writeNodeList('selectors', node.selectors); |
- output.writeln(''); |
+ output.depth--; |
} |
- void visitSimpleSelector(SimpleSelector node) { |
+ void visitSelector(Selector node) { |
+ output.heading('Selector', node.span); |
+ output.depth++; |
+ output.writeNodeList('simpleSelectorsSequences', |
+ node._simpleSelectorSequences); |
+ output.depth--; |
+ } |
+ |
+ void visitSimpleSelectorSequence(SimpleSelectorSequence node) { |
+ output.heading('SimpleSelectorSequence', node.span); |
+ output.depth++; |
if (node.isCombinatorNone()) { |
output.writeValue('combinator', "NONE"); |
} else if (node.isCombinatorDescendant()) { |
@@ -238,48 +1032,236 @@ class TreePrinter implements TreeVisitor { |
} else { |
output.writeValue('combinator', "ERROR UNKNOWN"); |
} |
+ |
+ var selector = node._selector; |
+ if (selector is NamespaceSelector) { |
+ visitNamespaceSelector(selector); |
+ } else if (selector is ElementSelector) { |
+ visitElementSelector(selector); |
+ } else if (selector is IdSelector) { |
+ visitIdSelector(selector); |
+ } else if (selector is ClassSelector) { |
+ visitClassSelector(selector); |
+ } else if (selector is PseudoClassSelector) { |
+ visitPseudoClassSelector(selector); |
+ } else if (selector is PseudoElementSelector) { |
+ visitPseudoElementSelector(selector); |
+ } else if (selector is NotSelector) { |
+ visitNotSelector(selector); |
+ } else if (selector is AttributeSelector) { |
+ visitAttributeSelector(selector); |
+ } else { |
+ output.heading('SimpleSelector', selector.span); |
+ output.depth++; |
+ visitSimpleSelector(selector); |
+ output.depth--; |
+ } |
+ |
+ output.depth--; |
+ } |
+ |
+ void visitSimpleSelector(SimpleSelector node) { |
+ visitIdentifier(node._name); |
} |
void visitNamespaceSelector(NamespaceSelector node) { |
output.heading('Namespace Selector', node.span); |
+ output.depth++; |
+ |
+ var namespace = node._namespace; |
+ if (namespace is Identifier) { |
+ visitIdentifier(namespace); |
+ } else if (namespace is Wildcard) { |
+ visitWildcard(namespace); |
+ } else { |
+ output.writeln("NULL"); |
+ } |
+ |
visitSimpleSelector(node); |
- output.writeNode('namespace', node._namespace); |
- output.writeNode('name', node._name); |
+ output.depth--; |
} |
void visitElementSelector(ElementSelector node) { |
output.heading('Element Selector', node.span); |
+ output.depth++; |
visitSimpleSelector(node); |
- output.writeNode('name', node._name); |
+ output.depth--; |
+ } |
+ |
+ void visitAttributeSelector(AttributeSelector node) { |
+ output.heading('AttributeSelector', node.span); |
+ output.depth++; |
+ visitSimpleSelector(node); |
+ String tokenStr = node.matchOperatorAsTokenString(); |
+ output.writeValue('operator', '${node.matchOperator()} (${tokenStr})'); |
+ output.writeValue('value', node.valueToString()); |
+ output.depth--; |
} |
void visitIdSelector(IdSelector node) { |
output.heading('Id Selector', node.span); |
+ output.depth++; |
visitSimpleSelector(node); |
- output.writeNode('name', node._name); |
+ output.depth--; |
} |
void visitClassSelector(ClassSelector node) { |
output.heading('Class Selector', node.span); |
+ output.depth++; |
visitSimpleSelector(node); |
- output.writeNode('name', node._name); |
+ output.depth--; |
} |
void visitPseudoClassSelector(PseudoClassSelector node) { |
output.heading('Pseudo Class Selector', node.span); |
+ output.depth++; |
visitSimpleSelector(node); |
- output.writeNode('name', node._name); |
+ output.depth--; |
} |
void visitPseudoElementSelector(PseudoElementSelector node) { |
output.heading('Pseudo Element Selector', node.span); |
+ output.depth++; |
visitSimpleSelector(node); |
- output.writeNode('name', node._name); |
+ output.depth--; |
} |
void visitNotSelector(NotSelector node) { |
visitSimpleSelector(node); |
+ output.depth++; |
output.heading('Not Selector', node.span); |
+ output.depth--; |
+ } |
+ |
+ void visitLiteralTerm(LiteralTerm node) { |
+ output.heading('LiteralTerm', node.span); |
+ output.depth++; |
+ output.writeValue('value', node.text); |
+ output.depth--; |
+ } |
+ |
+ void visitHexColorTerm(HexColorTerm node) { |
+ output.heading('HexColorTerm', node.span); |
+ output.depth++; |
+ output.writeValue('hex value', node.text); |
+ output.writeValue('decimal value', node.value); |
+ output.depth--; |
+ } |
+ |
+ void visitNumberTerm(NumberTerm node) { |
+ output.heading('NumberTerm', node.span); |
+ output.depth++; |
+ output.writeValue('value', node.text); |
+ output.depth--; |
+ } |
+ |
+ void visitUnitTerm(UnitTerm node) { |
+ String unitValue; |
+ |
+ output.depth++; |
+ output.writeValue('value', node.text); |
+ output.writeValue('unit', node.unitToString()); |
+ output.depth--; |
+ } |
+ |
+ void visitLengthTerm(LengthTerm node) { |
+ output.heading('LengthTerm', node.span); |
+ visitUnitTerm(node); |
+ } |
+ |
+ void visitPercentageTerm(PercentageTerm node) { |
+ output.heading('PercentageTerm', node.span); |
+ output.depth++; |
+ visitLiteralTerm(node); |
+ output.depth--; |
+ } |
+ |
+ void visitEmTerm(EmTerm node) { |
+ output.heading('EmTerm', node.span); |
+ output.depth++; |
+ visitLiteralTerm(node); |
+ output.depth--; |
+ } |
+ |
+ void visitExTerm(ExTerm node) { |
+ output.heading('ExTerm', node.span); |
+ output.depth++; |
+ visitLiteralTerm(node); |
+ output.depth--; |
+ } |
+ |
+ void visitAngleTerm(AngleTerm node) { |
+ output.heading('AngleTerm', node.span); |
+ visitUnitTerm(node); |
+ } |
+ |
+ void visitTimeTerm(TimeTerm node) { |
+ output.heading('TimeTerm', node.span); |
+ visitUnitTerm(node); |
+ } |
+ |
+ void visitFreqTerm(FreqTerm node) { |
+ output.heading('FreqTerm', node.span); |
+ visitUnitTerm(node); |
+ } |
+ |
+ void visitFractionTerm(FractionTerm node) { |
+ output.heading('FractionTerm', node.span); |
+ output.depth++; |
+ visitLiteralTerm(node); |
+ output.depth--; |
+ } |
+ |
+ void visitUriTerm(UriTerm node) { |
+ output.heading('UriTerm', node.span); |
+ output.depth++; |
+ visitLiteralTerm(node); |
+ output.depth--; |
+ } |
+ |
+ void visitFunctionTerm(FunctionTerm node) { |
+ output.heading('FunctionTerm', node.span); |
+ output.depth++; |
+ visitLiteralTerm(node); |
+ visitExpressions(node._params); |
+ output.depth--; |
+ } |
+ |
+ void visitGroupTerm(GroupTerm node) { |
+ output.heading('GroupTerm', node.span); |
+ output.depth++; |
+ output.writeNodeList('grouped terms', node._terms); |
+ output.depth--; |
+ } |
+ |
+ void visitItemTerm(ItemTerm node) { |
+ output.heading('ItemTerm', node.span); |
+ visitNumberTerm(node); |
+ } |
+ |
+ void visitOperatorSlash(OperatorSlash node) { |
+ output.heading('OperatorSlash', node.span); |
+ } |
+ |
+ void visitOperatorComma(OperatorComma node) { |
+ output.heading('OperatorComma', node.span); |
+ } |
+ |
+ void visitExpressions(Expressions node) { |
+ output.heading('Expressions', node.span); |
+ output.depth++; |
+ output.writeNodeList('expressions', node._expressions); |
+ output.depth--; |
+ } |
+ |
+ void visitBinaryExpression(BinaryExpression node) { |
+ output.heading('BinaryExpression', node.span); |
+ // TODO(terry): TBD |
+ } |
+ |
+ void visitUnaryExpression(UnaryExpression node) { |
+ output.heading('UnaryExpression', node.span); |
+ // TODO(terry): TBD |
} |
void visitIdentifier(Identifier node) { |