| 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;
|
| +
|
| + 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;
|
| +
|
| + 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) {
|
|
|