| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| part of csslib.visitor; |
| |
| ///////////////////////////////////////////////////////////////////////// |
| // CSS specific types: |
| ///////////////////////////////////////////////////////////////////////// |
| |
| class Identifier extends TreeNode { |
| String name; |
| |
| Identifier(this.name, Span span): super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitIdentifier(this); |
| |
| String toString() => name; |
| } |
| |
| class Wildcard extends TreeNode { |
| Wildcard(Span span): super(span); |
| visit(VisitorBase visitor) => visitor.visitWildcard(this); |
| } |
| |
| class ThisOperator extends TreeNode { |
| ThisOperator(Span span): super(span); |
| visit(VisitorBase visitor) => visitor.visitThisOperator(this); |
| } |
| |
| class Negation extends TreeNode { |
| Negation(Span span): super(span); |
| visit(VisitorBase visitor) => visitor.visitNegation(this); |
| } |
| |
| // /* .... */ |
| class CssComment extends TreeNode { |
| final String comment; |
| |
| CssComment(this.comment, Span span): super(span); |
| visit(VisitorBase visitor) => visitor.visitCssComment(this); |
| } |
| |
| // CDO/CDC (Comment Definition Open <!-- and Comment Definition Close -->). |
| class CommentDefinition extends CssComment { |
| CommentDefinition(String comment, Span span): super(comment, span); |
| visit(VisitorBase visitor) => visitor.visitCommentDefinition(this); |
| } |
| |
| class SelectorGroup extends TreeNode { |
| List<Selector> _selectors; |
| |
| SelectorGroup(this._selectors, Span span): super(span); |
| |
| List<Selector> get selectors => _selectors; |
| |
| visit(VisitorBase visitor) => visitor.visitSelectorGroup(this); |
| } |
| |
| class Selector extends TreeNode { |
| final List<SimpleSelectorSequence> _simpleSelectorSequences; |
| |
| Selector(this._simpleSelectorSequences, Span span) : super(span); |
| |
| List<SimpleSelectorSequence> get simpleSelectorSequences => |
| _simpleSelectorSequences; |
| |
| add(SimpleSelectorSequence seq) => _simpleSelectorSequences.add(seq); |
| |
| int get length => _simpleSelectorSequences.length; |
| |
| visit(VisitorBase visitor) => visitor.visitSelector(this); |
| } |
| |
| class SimpleSelectorSequence extends TreeNode { |
| /** +, >, ~, NONE */ |
| final int _combinator; |
| final SimpleSelector _selector; |
| |
| SimpleSelectorSequence(this._selector, Span span, |
| [int combinator = TokenKind.COMBINATOR_NONE]) |
| : _combinator = combinator, super(span); |
| |
| get simpleSelector => _selector; |
| |
| bool get isCombinatorNone => _combinator == TokenKind.COMBINATOR_NONE; |
| bool get isCombinatorPlus => _combinator == TokenKind.COMBINATOR_PLUS; |
| bool get isCombinatorGreater => _combinator == TokenKind.COMBINATOR_GREATER; |
| bool get isCombinatorTilde => _combinator == TokenKind.COMBINATOR_TILDE; |
| bool get isCombinatorDescendant => |
| _combinator == TokenKind.COMBINATOR_DESCENDANT; |
| |
| String get _combinatorToString => |
| isCombinatorDescendant ? ' ' : |
| isCombinatorPlus ? ' + ' : |
| isCombinatorGreater ? ' > ' : |
| isCombinatorTilde ? ' ~ ' : ''; |
| |
| visit(VisitorBase visitor) => visitor.visitSimpleSelectorSequence(this); |
| } |
| |
| /* All other selectors (element, #id, .class, attribute, pseudo, negation, |
| * namespace, *) are derived from this selector. |
| */ |
| class SimpleSelector extends TreeNode { |
| final _name; |
| |
| SimpleSelector(this._name, Span span) : super(span); |
| |
| // Name can be an Identifier or WildCard we'll return either the name or '*'. |
| String get name => isWildcard ? '*' : isThis ? '&' : _name.name; |
| |
| bool get isWildcard => _name is Wildcard; |
| |
| bool get isThis => _name is ThisOperator; |
| |
| visit(VisitorBase visitor) => visitor.visitSimpleSelector(this); |
| } |
| |
| // element name |
| class ElementSelector extends SimpleSelector { |
| ElementSelector(name, Span span) : super(name, span); |
| visit(VisitorBase visitor) => visitor.visitElementSelector(this); |
| } |
| |
| // namespace|element |
| class NamespaceSelector extends SimpleSelector { |
| final _namespace; // null, Wildcard or Identifier |
| |
| NamespaceSelector(this._namespace, var name, Span span) : super(name, span); |
| |
| String get namespace => |
| _namespace is Wildcard ? '*' : _namespace == null ? '' : _namespace.name; |
| |
| bool get isNamespaceWildcard => _namespace is Wildcard; |
| |
| SimpleSelector get nameAsSimpleSelector => _name; |
| |
| visit(VisitorBase visitor) => visitor.visitNamespaceSelector(this); |
| } |
| |
| // [attr op value] |
| class AttributeSelector extends SimpleSelector { |
| final int _op; |
| final _value; |
| |
| AttributeSelector(Identifier name, this._op, this._value, |
| Span 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 '*='; |
| case TokenKind.NO_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 != null) { |
| if (_value is Identifier) { |
| return _value.name; |
| } else { |
| return '"${_value}"'; |
| } |
| } else { |
| return ''; |
| } |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitAttributeSelector(this); |
| } |
| |
| // #id |
| class IdSelector extends SimpleSelector { |
| IdSelector(Identifier name, Span span) : super(name, span); |
| visit(VisitorBase visitor) => visitor.visitIdSelector(this); |
| } |
| |
| // .class |
| class ClassSelector extends SimpleSelector { |
| ClassSelector(Identifier name, Span span) : super(name, span); |
| visit(VisitorBase visitor) => visitor.visitClassSelector(this); |
| } |
| |
| // :pseudoClass |
| class PseudoClassSelector extends SimpleSelector { |
| PseudoClassSelector(Identifier name, Span span) : super(name, span); |
| visit(VisitorBase visitor) => visitor.visitPseudoClassSelector(this); |
| } |
| |
| // ::pseudoElement |
| class PseudoElementSelector extends SimpleSelector { |
| PseudoElementSelector(Identifier name, Span span) : super(name, span); |
| visit(VisitorBase visitor) => visitor.visitPseudoElementSelector(this); |
| } |
| |
| // :pseudoClassFunction(expression) |
| class PseudoClassFunctionSelector extends PseudoClassSelector { |
| SelectorExpression expression; |
| |
| PseudoClassFunctionSelector(Identifier name, this.expression, Span span) |
| : super(name, span); |
| visit(VisitorBase visitor) => visitor.visitPseudoClassFunctionSelector(this); |
| } |
| |
| // ::pseudoElementFunction(expression) |
| class PseudoElementFunctionSelector extends PseudoElementSelector { |
| SelectorExpression expression; |
| |
| PseudoElementFunctionSelector(Identifier name, this.expression, Span span) |
| : super(name, span); |
| visit(VisitorBase visitor) => |
| visitor.visitPseudoElementFunctionSelector(this); |
| } |
| |
| class SelectorExpression extends TreeNode { |
| final List<Expression> _expressions = []; |
| |
| SelectorExpression(Span span): super(span); |
| |
| add(Expression expression) { |
| _expressions.add(expression); |
| } |
| |
| List<Expression> get expressions => _expressions; |
| |
| visit(VisitorBase visitor) => visitor.visitSelectorExpression(this); |
| } |
| |
| // :NOT(negation_arg) |
| class NegationSelector extends SimpleSelector { |
| SimpleSelector negationArg; |
| |
| NegationSelector(this.negationArg, Span span) |
| : super(new Negation(span), span); |
| |
| visit(VisitorBase visitor) => visitor.visitNegationSelector(this); |
| } |
| |
| class StyleSheet extends TreeNode { |
| /** |
| * Contains charset, ruleset, directives (media, page, etc.), and selectors. |
| */ |
| final topLevels; |
| |
| StyleSheet(this.topLevels, Span span) : super(span) { |
| for (final node in topLevels) { |
| assert(node is TopLevelProduction || node is Directive); |
| } |
| } |
| |
| /** Selectors only in this tree. */ |
| StyleSheet.selector(this.topLevels, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitStyleSheet(this); |
| } |
| |
| class TopLevelProduction extends TreeNode { |
| TopLevelProduction(Span span) : super(span); |
| visit(VisitorBase visitor) => visitor.visitTopLevelProduction(this); |
| } |
| |
| class RuleSet extends TopLevelProduction { |
| final SelectorGroup _selectorGroup; |
| final DeclarationGroup _declarationGroup; |
| |
| RuleSet(this._selectorGroup, this._declarationGroup, Span span) : super(span); |
| |
| SelectorGroup get selectorGroup => _selectorGroup; |
| DeclarationGroup get declarationGroup => _declarationGroup; |
| |
| visit(VisitorBase visitor) => visitor.visitRuleSet(this); |
| } |
| |
| class Directive extends TreeNode { |
| Directive(Span span) : super(span); |
| |
| bool get isBuiltIn => true; // Known CSS directive? |
| bool get isExtension => false; // SCSS extension? |
| |
| visit(VisitorBase visitor) => visitor.visitDirective(this); |
| } |
| |
| class ImportDirective extends Directive { |
| /** import name specified. */ |
| final String import; |
| |
| /** Any media queries for this import. */ |
| final List<MediaQuery> mediaQueries; |
| |
| ImportDirective(this.import, this.mediaQueries, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitImportDirective(this); |
| } |
| |
| /** |
| * MediaExpression grammar: |
| * '(' S* media_feature S* [ ':' S* expr ]? ')' S* |
| */ |
| class MediaExpression extends TreeNode { |
| final bool andOperator; |
| final Identifier _mediaFeature; |
| final Expressions exprs; |
| |
| MediaExpression(this.andOperator, this._mediaFeature, this.exprs, Span span) |
| : super(span); |
| |
| String get mediaFeature => _mediaFeature.name; |
| |
| visit(VisitorBase visitor) => visitor.visitMediaExpression(this); |
| } |
| |
| /** |
| * MediaQuery grammar: |
| * : [ONLY | NOT]? S* media_type S* [ AND S* media_expression ]* |
| * | media_expression [ AND S* media_expression ]* |
| * media_type |
| * : IDENT |
| * media_expression |
| * : '(' S* media_feature S* [ ':' S* expr ]? ')' S* |
| * media_feature |
| * : IDENT |
| */ |
| class MediaQuery extends TreeNode { |
| /** not, only or no operator. */ |
| final int _mediaUnary; |
| final Identifier _mediaType; |
| final List<MediaExpression> expressions; |
| |
| MediaQuery(this._mediaUnary, this._mediaType, this.expressions, Span span) |
| : super(span); |
| |
| bool get hasMediaType => _mediaType != null; |
| String get mediaType => _mediaType.name; |
| |
| bool get hasUnary => _mediaUnary != -1; |
| String get unary => |
| TokenKind.idToValue(TokenKind.MEDIA_OPERATORS, _mediaUnary).toUpperCase(); |
| |
| visit(VisitorBase visitor) => visitor.visitMediaQuery(this); |
| } |
| |
| class MediaDirective extends Directive { |
| List<MediaQuery> mediaQueries; |
| List<RuleSet> rulesets; |
| |
| MediaDirective(this.mediaQueries, this.rulesets, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitMediaDirective(this); |
| } |
| |
| class HostDirective extends Directive { |
| List<RuleSet> rulesets; |
| |
| HostDirective(this.rulesets, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitHostDirective(this); |
| } |
| |
| class PageDirective extends Directive { |
| final String _ident; |
| final String _pseudoPage; |
| List<DeclarationGroup> _declsMargin; |
| |
| PageDirective(this._ident, this._pseudoPage, this._declsMargin, |
| Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitPageDirective(this); |
| |
| bool get hasIdent => _ident != null && _ident.length > 0; |
| bool get hasPseudoPage => _pseudoPage != null && _pseudoPage.length > 0; |
| } |
| |
| class CharsetDirective extends Directive { |
| final String charEncoding; |
| |
| CharsetDirective(this.charEncoding, Span span) : super(span); |
| visit(VisitorBase visitor) => visitor.visitCharsetDirective(this); |
| } |
| |
| class KeyFrameDirective extends Directive { |
| /* |
| * Either @keyframe or keyframe prefixed with @-webkit-, @-moz-, @-ms-, @-o-. |
| */ |
| final int _keyframeName; |
| final _name; |
| final List<KeyFrameBlock> _blocks; |
| |
| KeyFrameDirective(this._keyframeName, this._name, Span span) |
| : _blocks = [], super(span); |
| |
| add(KeyFrameBlock block) { |
| _blocks.add(block); |
| } |
| |
| String get keyFrameName { |
| switch (_keyframeName) { |
| case TokenKind.DIRECTIVE_KEYFRAMES: |
| case TokenKind.DIRECTIVE_MS_KEYFRAMES: |
| return '@keyframes'; |
| case TokenKind.DIRECTIVE_WEB_KIT_KEYFRAMES: return '@-webkit-keyframes'; |
| case TokenKind.DIRECTIVE_MOZ_KEYFRAMES: return '@-moz-keyframes'; |
| case TokenKind.DIRECTIVE_O_KEYFRAMES: return '@-o-keyframes'; |
| } |
| } |
| |
| String get name => _name; |
| |
| visit(VisitorBase visitor) => visitor.visitKeyFrameDirective(this); |
| } |
| |
| class KeyFrameBlock extends Expression { |
| final Expressions _blockSelectors; |
| final DeclarationGroup _declarations; |
| |
| KeyFrameBlock(this._blockSelectors, this._declarations, Span span) |
| : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitKeyFrameBlock(this); |
| } |
| |
| class FontFaceDirective extends Directive { |
| final DeclarationGroup _declarations; |
| |
| FontFaceDirective(this._declarations, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitFontFaceDirective(this); |
| } |
| |
| class StyletDirective extends Directive { |
| final String _dartClassName; |
| final List<RuleSet> _rulesets; |
| |
| StyletDirective(this._dartClassName, this._rulesets, Span span) : super(span); |
| |
| bool get isBuiltIn => false; |
| bool get isExtension => true; |
| |
| String get dartClassName => _dartClassName; |
| List<RuleSet> get rulesets => _rulesets; |
| |
| visit(VisitorBase visitor) => visitor.visitStyletDirective(this); |
| } |
| |
| class NamespaceDirective extends Directive { |
| /** Namespace prefix. */ |
| final String _prefix; |
| |
| /** URI associated with this namespace. */ |
| final String _uri; |
| |
| NamespaceDirective(this._prefix, this._uri, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitNamespaceDirective(this); |
| |
| String get prefix => _prefix.length > 0 ? '$_prefix ' : ''; |
| } |
| |
| /** To support Less syntax @name: expression */ |
| class VarDefinitionDirective extends Directive { |
| final VarDefinition def; |
| |
| VarDefinitionDirective(this.def, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitVarDefinitionDirective(this); |
| } |
| |
| class Declaration extends TreeNode { |
| final Identifier _property; |
| final Expression _expression; |
| /** Style exposed to Dart. */ |
| var _dart; |
| final bool important; |
| |
| /** |
| * IE CSS hacks that can only be read by a particular IE version. |
| * 7 implies IE 7 or older property (e.g., *background: blue;) |
| * Note: IE 8 or older property (e.g., background: green\9;) is handled |
| * by IE8Term in declaration expression handling. |
| * Note: IE 6 only property with a leading underscore is a valid IDENT |
| * since an ident can start with underscore (e.g., _background: red;) |
| */ |
| final bool isIE7; |
| |
| Declaration(this._property, this._expression, this._dart, Span span, |
| {important: false, ie7: false}) |
| : this.important = important, this.isIE7 = ie7, super(span); |
| |
| String get property => isIE7 ? '*${_property.name}' : _property.name; |
| Expression get expression => _expression; |
| |
| bool get hasDartStyle => _dart != null; |
| get dartStyle => _dart; |
| set dartStyle(dStyle) { |
| _dart = dStyle; |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitDeclaration(this); |
| } |
| |
| // TODO(terry): Consider 2 kinds of VarDefinitions static at top-level and |
| // dynamic when in a declaration. Currently, Less syntax |
| // '@foo: expression' and 'var-foo: expression' in a declaration |
| // are statically resolved. Better solution, if @foo or var-foo |
| // are top-level are then statically resolved and var-foo in a |
| // declaration group (surrounded by a selector) would be dynamic. |
| class VarDefinition extends Declaration { |
| VarDefinition(Identifier definedName, Expression expr, Span span) |
| : super(definedName, expr, null, span); |
| |
| String get definedName => _property.name; |
| |
| set dartStyle(dStyle) { } |
| |
| visit(VisitorBase visitor) => visitor.visitVarDefinition(this); |
| } |
| |
| class DeclarationGroup extends TreeNode { |
| /** Can be either Declaration or RuleSet (if nested selector). */ |
| final List _declarations; |
| |
| DeclarationGroup(this._declarations, Span span) : super(span); |
| |
| List get declarations => _declarations; |
| |
| visit(VisitorBase visitor) => visitor.visitDeclarationGroup(this); |
| } |
| |
| class MarginGroup extends DeclarationGroup { |
| final int margin_sym; // TokenType for for @margin sym. |
| |
| MarginGroup(this.margin_sym, List<Declaration> decls, Span span) |
| : super(decls, span); |
| visit(VisitorBase visitor) => visitor.visitMarginGroup(this); |
| } |
| |
| class VarUsage extends Expression { |
| final String name; |
| final List<Expression> defaultValues; |
| |
| VarUsage(this.name, this.defaultValues, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitVarUsage(this); |
| } |
| |
| class OperatorSlash extends Expression { |
| OperatorSlash(Span span) : super(span); |
| visit(VisitorBase visitor) => visitor.visitOperatorSlash(this); |
| } |
| |
| class OperatorComma extends Expression { |
| OperatorComma(Span span) : super(span); |
| visit(VisitorBase visitor) => visitor.visitOperatorComma(this); |
| } |
| |
| class OperatorPlus extends Expression { |
| OperatorPlus(Span span) : super(span); |
| visit(VisitorBase visitor) => visitor.visitOperatorPlus(this); |
| } |
| |
| class OperatorMinus extends Expression { |
| OperatorMinus(Span span) : super(span); |
| visit(VisitorBase visitor) => visitor.visitOperatorMinus(this); |
| } |
| |
| class UnicodeRangeTerm extends Expression { |
| final String first; |
| final String second; |
| |
| UnicodeRangeTerm(this.first, this.second, Span span) : super(span); |
| |
| bool get hasSecond => second != null; |
| |
| visit(VisitorBase visitor) => visitor.visitUnicodeRangeTerm(this); |
| } |
| |
| class LiteralTerm extends Expression { |
| // TODO(terry): value and text fields can be made final once all CSS resources |
| // are copied/symlink'd in the build tool and UriVisitor in |
| // web_ui is removed. |
| var value; |
| String text; |
| |
| LiteralTerm(this.value, this.text, Span span) : super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitLiteralTerm(this); |
| } |
| |
| class NumberTerm extends LiteralTerm { |
| NumberTerm(value, String t, Span span) : super(value, t, span); |
| visit(VisitorBase visitor) => visitor.visitNumberTerm(this); |
| } |
| |
| class UnitTerm extends LiteralTerm { |
| final int _unit; |
| |
| UnitTerm(value, String t, Span span, this._unit) : super(value, t, span); |
| |
| int get unit => _unit; |
| |
| visit(VisitorBase visitor) => visitor.visitUnitTerm(this); |
| |
| String unitToString() => TokenKind.unitToString(_unit); |
| |
| String toString() => '$text${unitToString()}'; |
| } |
| |
| class LengthTerm extends UnitTerm { |
| LengthTerm(value, String t, Span 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(VisitorBase visitor) => visitor.visitLengthTerm(this); |
| } |
| |
| class PercentageTerm extends LiteralTerm { |
| PercentageTerm(value, String t, Span span) : super(value, t, span); |
| visit(VisitorBase visitor) => visitor.visitPercentageTerm(this); |
| } |
| |
| class EmTerm extends LiteralTerm { |
| EmTerm(value, String t, Span span) : super(value, t, span); |
| visit(VisitorBase visitor) => visitor.visitEmTerm(this); |
| } |
| |
| class ExTerm extends LiteralTerm { |
| ExTerm(value, String t, Span span) : super(value, t, span); |
| visit(VisitorBase visitor) => visitor.visitExTerm(this); |
| } |
| |
| class AngleTerm extends UnitTerm { |
| AngleTerm(var value, String t, Span 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 || |
| this._unit == TokenKind.UNIT_ANGLE_TURN); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitAngleTerm(this); |
| } |
| |
| class TimeTerm extends UnitTerm { |
| TimeTerm(var value, String t, Span 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(VisitorBase visitor) => visitor.visitTimeTerm(this); |
| } |
| |
| class FreqTerm extends UnitTerm { |
| FreqTerm(var value, String t, Span span, |
| [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
| assert(_unit == TokenKind.UNIT_FREQ_HZ || _unit == TokenKind.UNIT_FREQ_KHZ); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitFreqTerm(this); |
| } |
| |
| class FractionTerm extends LiteralTerm { |
| FractionTerm(var value, String t, Span span) : super(value, t, span); |
| |
| visit(VisitorBase visitor) => visitor.visitFractionTerm(this); |
| } |
| |
| class UriTerm extends LiteralTerm { |
| UriTerm(String value, Span span) : super(value, value, span); |
| |
| visit(VisitorBase visitor) => visitor.visitUriTerm(this); |
| } |
| |
| class ResolutionTerm extends UnitTerm { |
| ResolutionTerm(var value, String t, Span span, |
| [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
| assert(_unit == TokenKind.UNIT_RESOLUTION_DPI || |
| _unit == TokenKind.UNIT_RESOLUTION_DPCM || |
| _unit == TokenKind.UNIT_RESOLUTION_DPPX); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitResolutionTerm(this); |
| } |
| |
| class ChTerm extends UnitTerm { |
| ChTerm(var value, String t, Span span, |
| [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
| assert(_unit == TokenKind.UNIT_CH); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitChTerm(this); |
| } |
| |
| class RemTerm extends UnitTerm { |
| RemTerm(var value, String t, Span span, |
| [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
| assert(_unit == TokenKind.UNIT_REM); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitRemTerm(this); |
| } |
| |
| class ViewportTerm extends UnitTerm { |
| ViewportTerm(var value, String t, Span span, |
| [int unit = TokenKind.UNIT_LENGTH_PX]) : super(value, t, span, unit) { |
| assert(_unit == TokenKind.UNIT_VIEWPORT_VW || |
| _unit == TokenKind.UNIT_VIEWPORT_VH || |
| _unit == TokenKind.UNIT_VIEWPORT_VMIN || |
| _unit == TokenKind.UNIT_VIEWPORT_VMAX); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitViewportTerm(this); |
| } |
| |
| /** Type to signal a bad hex value for HexColorTerm.value. */ |
| class BAD_HEX_VALUE { } |
| |
| class HexColorTerm extends LiteralTerm { |
| HexColorTerm(var value, String t, Span span) : super(value, t, span); |
| |
| visit(VisitorBase visitor) => visitor.visitHexColorTerm(this); |
| } |
| |
| class FunctionTerm extends LiteralTerm { |
| final Expressions _params; |
| |
| FunctionTerm(var value, String t, this._params, Span span) |
| : super(value, t, span); |
| |
| visit(VisitorBase visitor) => visitor.visitFunctionTerm(this); |
| } |
| |
| /** |
| * A "\9" was encountered at the end of the expression and before a semi-colon. |
| * This is an IE trick to ignore a property or value except by IE 8 and older |
| * browsers. |
| */ |
| class IE8Term extends LiteralTerm { |
| IE8Term(Span span) : super('\\9', '\\9', span); |
| visit(VisitorBase visitor) => visitor.visitIE8Term(this); |
| } |
| |
| class GroupTerm extends Expression { |
| final List<LiteralTerm> _terms; |
| |
| GroupTerm(Span span) : _terms = [], super(span); |
| |
| add(LiteralTerm term) { |
| _terms.add(term); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitGroupTerm(this); |
| } |
| |
| class ItemTerm extends NumberTerm { |
| ItemTerm(var value, String t, Span span) : super(value, t, span); |
| |
| visit(VisitorBase visitor) => visitor.visitItemTerm(this); |
| } |
| |
| class Expressions extends Expression { |
| final List<Expression> expressions = []; |
| |
| Expressions(Span span): super(span); |
| |
| add(Expression expression) { |
| expressions.add(expression); |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitExpressions(this); |
| } |
| |
| class BinaryExpression extends Expression { |
| final Token op; |
| final Expression x; |
| final Expression y; |
| |
| BinaryExpression(this.op, this.x, this.y, Span span): super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitBinaryExpression(this); |
| } |
| |
| class UnaryExpression extends Expression { |
| final Token op; |
| final Expression self; |
| |
| UnaryExpression(this.op, this.self, Span span): super(span); |
| |
| visit(VisitorBase visitor) => visitor.visitUnaryExpression(this); |
| } |
| |
| abstract class DartStyleExpression extends TreeNode { |
| static final int unknownType = 0; |
| static final int fontStyle = 1; |
| static final int marginStyle = 2; |
| static final int borderStyle = 3; |
| static final int paddingStyle = 4; |
| static final int heightStyle = 5; |
| static final int widthStyle = 6; |
| |
| final int _styleType; |
| int priority; |
| |
| DartStyleExpression(this._styleType, Span span) : super(span); |
| |
| /* |
| * Merges give 2 DartStyleExpression (or derived from DartStyleExpression, |
| * e.g., FontExpression, etc.) will merge if the two expressions are of the |
| * same property name (implies same exact type e.g, FontExpression). |
| */ |
| merged(DartStyleExpression newDartExpr); |
| |
| bool get isUnknown => _styleType == 0 || _styleType == null; |
| bool get isFont => _styleType == fontStyle; |
| bool get isMargin => _styleType == marginStyle; |
| bool get isBorder => _styleType == borderStyle; |
| bool get isPadding => _styleType == paddingStyle; |
| bool get isHeight => _styleType == heightStyle; |
| bool get isWidth => _styleType == widthStyle; |
| bool get isBoxExpression => isMargin || isBorder || isPadding; |
| |
| bool isSame(DartStyleExpression other) => this._styleType == other._styleType; |
| |
| visit(VisitorBase visitor) => visitor.visitDartStyleExpression(this); |
| } |
| |
| class FontExpression extends DartStyleExpression { |
| Font font; |
| |
| // font-style font-variant font-weight font-size/line-height font-family |
| FontExpression(Span span, {var size, List<String>family, |
| int weight, String style, String variant, LineHeight lineHeight}) |
| : super(DartStyleExpression.fontStyle, span) { |
| // TODO(terry): Only px/pt for now need to handle all possible units to |
| // support calc expressions on units. |
| font = new Font(size : size is LengthTerm ? size.value : size, |
| family: family, weight: weight, style: style, variant: variant, |
| lineHeight: lineHeight); |
| } |
| |
| merged(FontExpression newFontExpr) { |
| if (this.isFont && newFontExpr.isFont) { |
| return new FontExpression.merge(this, newFontExpr); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Merge the two FontExpression and return the result. |
| */ |
| factory FontExpression.merge(FontExpression x, FontExpression y) { |
| return new FontExpression._merge(x, y, y.span); |
| } |
| |
| FontExpression._merge(FontExpression x, FontExpression y, Span span) |
| : super(DartStyleExpression.fontStyle, span), |
| font = new Font.merge(x.font, y.font); |
| |
| visit(VisitorBase visitor) => visitor.visitFontExpression(this); |
| } |
| |
| abstract class BoxExpression extends DartStyleExpression { |
| final BoxEdge box; |
| |
| BoxExpression(int styleType, Span span, this.box) |
| : super(styleType, span); |
| |
| /* |
| * Merges give 2 DartStyleExpression (or derived from DartStyleExpression, |
| * e.g., FontExpression, etc.) will merge if the two expressions are of the |
| * same property name (implies same exact type e.g, FontExpression). |
| */ |
| merged(BoxExpression newDartExpr); |
| |
| visit(VisitorBase visitor) => visitor.visitBoxExpression(this); |
| |
| String get formattedBoxEdge { |
| if (box.top == box.left && box.top == box.bottom && |
| box.top== box.right) { |
| return '.uniform(${box.top})'; |
| } else { |
| var left = box.left == null ? 0 : box.left; |
| var top = box.top == null ? 0 : box.top; |
| var right = box.right == null ? 0 : box.right; |
| var bottom = box.bottom == null ? 0 : box.bottom; |
| return '.clockwiseFromTop($top,$right,$bottom,$left)'; |
| } |
| } |
| } |
| |
| class MarginExpression extends BoxExpression { |
| // TODO(terry): Does auto for margin need to be exposed to Dart UI framework? |
| /** Margin expression ripped apart. */ |
| MarginExpression(Span span, {num top, num right, num bottom, num left}) |
| : super(DartStyleExpression.marginStyle, span, |
| new BoxEdge(left, top, right, bottom)); |
| |
| MarginExpression.boxEdge(Span span, BoxEdge box) |
| : super(DartStyleExpression.marginStyle, span, box); |
| |
| merged(MarginExpression newMarginExpr) { |
| if (this.isMargin && newMarginExpr.isMargin) { |
| return new MarginExpression.merge(this, newMarginExpr); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Merge the two MarginExpressions and return the result. |
| */ |
| factory MarginExpression.merge(MarginExpression x, MarginExpression y) { |
| return new MarginExpression._merge(x, y, y.span); |
| } |
| |
| MarginExpression._merge(MarginExpression x, MarginExpression y, Span span) |
| : super(x._styleType, span, new BoxEdge.merge(x.box, y.box)); |
| |
| visit(VisitorBase visitor) => visitor.visitMarginExpression(this); |
| } |
| |
| class BorderExpression extends BoxExpression { |
| /** Border expression ripped apart. */ |
| BorderExpression(Span span, {num top, num right, num bottom, num left}) |
| : super(DartStyleExpression.borderStyle, span, |
| new BoxEdge(left, top, right, bottom)); |
| |
| BorderExpression.boxEdge(Span span, BoxEdge box) |
| : super(DartStyleExpression.borderStyle, span, box); |
| |
| merged(BorderExpression newBorderExpr) { |
| if (this.isBorder && newBorderExpr.isBorder) { |
| return new BorderExpression.merge(this, newBorderExpr); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Merge the two BorderExpression and return the result. |
| */ |
| factory BorderExpression.merge(BorderExpression x, BorderExpression y) { |
| return new BorderExpression._merge(x, y, y.span); |
| } |
| |
| BorderExpression._merge(BorderExpression x, BorderExpression y, |
| Span span) |
| : super(DartStyleExpression.borderStyle, span, |
| new BoxEdge.merge(x.box, y.box)); |
| |
| visit(VisitorBase visitor) => visitor.visitBorderExpression(this); |
| } |
| |
| class HeightExpression extends DartStyleExpression { |
| final height; |
| |
| HeightExpression(Span span, this.height) |
| : super(DartStyleExpression.heightStyle, span); |
| |
| merged(HeightExpression newHeightExpr) { |
| if (this.isHeight && newHeightExpr.isHeight) { |
| return newHeightExpr; |
| } |
| |
| return null; |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitHeightExpression(this); |
| } |
| |
| class WidthExpression extends DartStyleExpression { |
| final width; |
| |
| WidthExpression(Span span, this.width) |
| : super(DartStyleExpression.widthStyle, span); |
| |
| merged(WidthExpression newWidthExpr) { |
| if (this.isWidth && newWidthExpr.isWidth) { |
| return newWidthExpr; |
| } |
| |
| return null; |
| } |
| |
| visit(VisitorBase visitor) => visitor.visitWidthExpression(this); |
| } |
| |
| class PaddingExpression extends BoxExpression { |
| /** Padding expression ripped apart. */ |
| PaddingExpression(Span span, {num top, num right, num bottom, num left}) |
| : super(DartStyleExpression.paddingStyle, span, |
| new BoxEdge(left, top, right, bottom)); |
| |
| PaddingExpression.boxEdge(Span span, BoxEdge box) |
| : super(DartStyleExpression.paddingStyle, span, box); |
| |
| merged(PaddingExpression newPaddingExpr) { |
| if (this.isPadding && newPaddingExpr.isPadding) { |
| return new PaddingExpression.merge(this, newPaddingExpr); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Merge the two PaddingExpression and return the result. |
| */ |
| factory PaddingExpression.merge(PaddingExpression x, PaddingExpression y) { |
| return new PaddingExpression._merge(x, y, y.span); |
| } |
| |
| PaddingExpression._merge(PaddingExpression x, PaddingExpression y, Span span) |
| : super(DartStyleExpression.paddingStyle, span, |
| new BoxEdge.merge(x.box, y.box)); |
| |
| visit(VisitorBase visitor) => visitor.visitPaddingExpression(this); |
| } |