Chromium Code Reviews| 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) { |