Index: mojo/public/dart/third_party/csslib/lib/src/tree.dart |
diff --git a/mojo/public/dart/third_party/csslib/lib/src/tree.dart b/mojo/public/dart/third_party/csslib/lib/src/tree.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5dad435b48467053e18de2c236227ace717117fb |
--- /dev/null |
+++ b/mojo/public/dart/third_party/csslib/lib/src/tree.dart |
@@ -0,0 +1,1425 @@ |
+// 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, SourceSpan span) : super(span); |
+ |
+ Identifier clone() => new Identifier(name, span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitIdentifier(this); |
+ |
+ String toString() => name; |
+} |
+ |
+class Wildcard extends TreeNode { |
+ Wildcard(SourceSpan span) : super(span); |
+ Wildcard clone() => new Wildcard(span); |
+ visit(VisitorBase visitor) => visitor.visitWildcard(this); |
+ |
+ String get name => '*'; |
+} |
+ |
+class ThisOperator extends TreeNode { |
+ ThisOperator(SourceSpan span) : super(span); |
+ ThisOperator clone() => new ThisOperator(span); |
+ visit(VisitorBase visitor) => visitor.visitThisOperator(this); |
+ |
+ String get name => '&'; |
+} |
+ |
+class Negation extends TreeNode { |
+ Negation(SourceSpan span) : super(span); |
+ Negation clone() => new Negation(span); |
+ visit(VisitorBase visitor) => visitor.visitNegation(this); |
+ |
+ String get name => 'not'; |
+} |
+ |
+// /* .... */ |
+class CssComment extends TreeNode { |
+ final String comment; |
+ |
+ CssComment(this.comment, SourceSpan span) : super(span); |
+ CssComment clone() => new CssComment(comment, span); |
+ visit(VisitorBase visitor) => visitor.visitCssComment(this); |
+} |
+ |
+// CDO/CDC (Comment Definition Open <!-- and Comment Definition Close -->). |
+class CommentDefinition extends CssComment { |
+ CommentDefinition(String comment, SourceSpan span) : super(comment, span); |
+ CommentDefinition clone() => new CommentDefinition(comment, span); |
+ visit(VisitorBase visitor) => visitor.visitCommentDefinition(this); |
+} |
+ |
+class SelectorGroup extends TreeNode { |
+ final List<Selector> selectors; |
+ |
+ SelectorGroup(this.selectors, SourceSpan span) : super(span); |
+ |
+ SelectorGroup clone() => new SelectorGroup(selectors, span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitSelectorGroup(this); |
+} |
+ |
+class Selector extends TreeNode { |
+ final List<SimpleSelectorSequence> simpleSelectorSequences; |
+ |
+ Selector(this.simpleSelectorSequences, SourceSpan span) : super(span); |
+ |
+ void add(SimpleSelectorSequence seq) => simpleSelectorSequences.add(seq); |
+ |
+ int get length => simpleSelectorSequences.length; |
+ |
+ Selector clone() { |
+ var simpleSequences = |
+ simpleSelectorSequences.map((ss) => ss.clone()).toList(); |
+ |
+ return new Selector(simpleSequences, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitSelector(this); |
+} |
+ |
+class SimpleSelectorSequence extends TreeNode { |
+ /** +, >, ~, NONE */ |
+ int combinator; |
+ final SimpleSelector simpleSelector; |
+ |
+ SimpleSelectorSequence(this.simpleSelector, SourceSpan span, |
+ [int combinator = TokenKind.COMBINATOR_NONE]) |
+ : combinator = combinator, |
+ super(span); |
+ |
+ 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 ? ' ~ ' : ''; |
+ |
+ SimpleSelectorSequence clone() => |
+ new SimpleSelectorSequence(simpleSelector, span, combinator); |
+ |
+ visit(VisitorBase visitor) => visitor.visitSimpleSelectorSequence(this); |
+ |
+ String toString() => simpleSelector.name; |
+} |
+ |
+/* All other selectors (element, #id, .class, attribute, pseudo, negation, |
+ * namespace, *) are derived from this selector. |
+ */ |
+abstract class SimpleSelector extends TreeNode { |
+ final _name; // Wildcard, ThisOperator, Identifier, Negation, others? |
+ |
+ SimpleSelector(this._name, SourceSpan span) : super(span); |
+ |
+ String get name => _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, SourceSpan span) : super(name, span); |
+ visit(VisitorBase visitor) => visitor.visitElementSelector(this); |
+ |
+ ElementSelector clone() => new ElementSelector(_name, span); |
+ |
+ String toString() => name; |
+} |
+ |
+// namespace|element |
+class NamespaceSelector extends SimpleSelector { |
+ final _namespace; // null, Wildcard or Identifier |
+ |
+ NamespaceSelector(this._namespace, var name, SourceSpan span) |
+ : super(name, span); |
+ |
+ String get namespace => |
+ _namespace is Wildcard ? '*' : _namespace == null ? '' : _namespace.name; |
+ |
+ bool get isNamespaceWildcard => _namespace is Wildcard; |
+ |
+ SimpleSelector get nameAsSimpleSelector => _name; |
+ |
+ NamespaceSelector clone() => new NamespaceSelector(_namespace, "", span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitNamespaceSelector(this); |
+ |
+ String toString() => "$namespace|${nameAsSimpleSelector.name}"; |
+} |
+ |
+// [attr op value] |
+class AttributeSelector extends SimpleSelector { |
+ final int _op; |
+ final _value; |
+ |
+ AttributeSelector(Identifier name, this._op, this._value, SourceSpan span) |
+ : super(name, span); |
+ |
+ int get operatorKind => _op; |
+ |
+ get value => _value; |
+ |
+ 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 ''; |
+ } |
+ } |
+ |
+ AttributeSelector clone() => new AttributeSelector(_name, _op, _value, span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitAttributeSelector(this); |
+ |
+ String toString() => "[$name${matchOperator()}${valueToString()}]"; |
+} |
+ |
+// #id |
+class IdSelector extends SimpleSelector { |
+ IdSelector(Identifier name, SourceSpan span) : super(name, span); |
+ IdSelector clone() => new IdSelector(_name, span); |
+ visit(VisitorBase visitor) => visitor.visitIdSelector(this); |
+ |
+ String toString() => "#$_name"; |
+} |
+ |
+// .class |
+class ClassSelector extends SimpleSelector { |
+ ClassSelector(Identifier name, SourceSpan span) : super(name, span); |
+ ClassSelector clone() => new ClassSelector(_name, span); |
+ visit(VisitorBase visitor) => visitor.visitClassSelector(this); |
+ |
+ String toString() => ".$_name"; |
+} |
+ |
+// :pseudoClass |
+class PseudoClassSelector extends SimpleSelector { |
+ PseudoClassSelector(Identifier name, SourceSpan span) : super(name, span); |
+ visit(VisitorBase visitor) => visitor.visitPseudoClassSelector(this); |
+ |
+ PseudoClassSelector clone() => new PseudoClassSelector(_name, span); |
+ |
+ String toString() => ":$name"; |
+} |
+ |
+// ::pseudoElement |
+class PseudoElementSelector extends SimpleSelector { |
+ PseudoElementSelector(Identifier name, SourceSpan span) : super(name, span); |
+ visit(VisitorBase visitor) => visitor.visitPseudoElementSelector(this); |
+ |
+ PseudoElementSelector clone() => new PseudoElementSelector(_name, span); |
+ |
+ String toString() => "::$name"; |
+} |
+ |
+// :pseudoClassFunction(expression) |
+class PseudoClassFunctionSelector extends PseudoClassSelector { |
+ final SelectorExpression expression; |
+ |
+ PseudoClassFunctionSelector(Identifier name, this.expression, SourceSpan span) |
+ : super(name, span); |
+ |
+ PseudoClassFunctionSelector clone() => |
+ new PseudoClassFunctionSelector(_name, expression, span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitPseudoClassFunctionSelector(this); |
+} |
+ |
+// ::pseudoElementFunction(expression) |
+class PseudoElementFunctionSelector extends PseudoElementSelector { |
+ final SelectorExpression expression; |
+ |
+ PseudoElementFunctionSelector( |
+ Identifier name, this.expression, SourceSpan span) |
+ : super(name, span); |
+ |
+ PseudoElementFunctionSelector clone() => |
+ new PseudoElementFunctionSelector(_name, expression, span); |
+ |
+ visit(VisitorBase visitor) => |
+ visitor.visitPseudoElementFunctionSelector(this); |
+} |
+ |
+class SelectorExpression extends TreeNode { |
+ final List<Expression> expressions; |
+ |
+ SelectorExpression(this.expressions, SourceSpan span) : super(span); |
+ |
+ SelectorExpression clone() { |
+ return new SelectorExpression( |
+ expressions.map((e) => e.clone()).toList(), span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitSelectorExpression(this); |
+} |
+ |
+// :NOT(negation_arg) |
+class NegationSelector extends SimpleSelector { |
+ final SimpleSelector negationArg; |
+ |
+ NegationSelector(this.negationArg, SourceSpan span) |
+ : super(new Negation(span), span); |
+ |
+ NegationSelector clone() => new NegationSelector(negationArg, span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitNegationSelector(this); |
+} |
+ |
+class NoOp extends TreeNode { |
+ NoOp() : super(null); |
+ |
+ NoOp clone() => new NoOp(); |
+ |
+ visit(VisitorBase visitor) => visitor.visitNoOp(this); |
+} |
+ |
+class StyleSheet extends TreeNode { |
+ /** |
+ * Contains charset, ruleset, directives (media, page, etc.), and selectors. |
+ */ |
+ final List<TreeNode> topLevels; |
+ |
+ StyleSheet(this.topLevels, SourceSpan span) : super(span) { |
+ for (final node in topLevels) { |
+ assert(node is TopLevelProduction || node is Directive); |
+ } |
+ } |
+ |
+ /** Selectors only in this tree. */ |
+ StyleSheet.selector(this.topLevels, SourceSpan span) : super(span); |
+ |
+ StyleSheet clone() { |
+ var clonedTopLevels = topLevels.map((e) => e.clone()).toList(); |
+ return new StyleSheet(clonedTopLevels, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitStyleSheet(this); |
+} |
+ |
+class TopLevelProduction extends TreeNode { |
+ TopLevelProduction(SourceSpan span) : super(span); |
+ TopLevelProduction clone() => new TopLevelProduction(span); |
+ visit(VisitorBase visitor) => visitor.visitTopLevelProduction(this); |
+} |
+ |
+class RuleSet extends TopLevelProduction { |
+ final SelectorGroup _selectorGroup; |
+ final DeclarationGroup _declarationGroup; |
+ |
+ RuleSet(this._selectorGroup, this._declarationGroup, SourceSpan span) |
+ : super(span); |
+ |
+ SelectorGroup get selectorGroup => _selectorGroup; |
+ DeclarationGroup get declarationGroup => _declarationGroup; |
+ |
+ RuleSet clone() { |
+ var cloneSelectorGroup = _selectorGroup.clone(); |
+ var cloneDeclarationGroup = _declarationGroup.clone(); |
+ return new RuleSet(cloneSelectorGroup, cloneDeclarationGroup, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitRuleSet(this); |
+} |
+ |
+class Directive extends TreeNode { |
+ Directive(SourceSpan span) : super(span); |
+ |
+ bool get isBuiltIn => true; // Known CSS directive? |
+ bool get isExtension => false; // SCSS extension? |
+ |
+ Directive clone() => new Directive(span); |
+ 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, SourceSpan span) |
+ : super(span); |
+ |
+ ImportDirective clone() { |
+ var cloneMediaQueries = []; |
+ for (var mediaQuery in mediaQueries) { |
+ cloneMediaQueries.add(mediaQuery.clone()); |
+ } |
+ return new ImportDirective(import, cloneMediaQueries, 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, SourceSpan span) |
+ : super(span); |
+ |
+ String get mediaFeature => _mediaFeature.name; |
+ |
+ MediaExpression clone() { |
+ var clonedExprs = exprs.clone(); |
+ return new MediaExpression(andOperator, _mediaFeature, clonedExprs, span); |
+ } |
+ |
+ 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, SourceSpan 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(); |
+ |
+ MediaQuery clone() { |
+ var cloneExpressions = []; |
+ for (var expr in expressions) { |
+ cloneExpressions.add(expr.clone()); |
+ } |
+ return new MediaQuery(_mediaUnary, _mediaType, cloneExpressions, span); |
+ } |
+ visit(VisitorBase visitor) => visitor.visitMediaQuery(this); |
+} |
+ |
+class MediaDirective extends Directive { |
+ final List<MediaQuery> mediaQueries; |
+ final List<RuleSet> rulesets; |
+ |
+ MediaDirective(this.mediaQueries, this.rulesets, SourceSpan span) |
+ : super(span); |
+ |
+ MediaDirective clone() { |
+ var cloneQueries = []; |
+ for (var mediaQuery in mediaQueries) { |
+ cloneQueries.add(mediaQuery.clone()); |
+ } |
+ var cloneRulesets = []; |
+ for (var ruleset in rulesets) { |
+ cloneRulesets.add(ruleset.clone()); |
+ } |
+ return new MediaDirective(cloneQueries, cloneRulesets, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitMediaDirective(this); |
+} |
+ |
+class HostDirective extends Directive { |
+ final List<RuleSet> rulesets; |
+ |
+ HostDirective(this.rulesets, SourceSpan span) : super(span); |
+ |
+ HostDirective clone() { |
+ var cloneRulesets = []; |
+ for (var ruleset in rulesets) { |
+ cloneRulesets.add(ruleset.clone()); |
+ } |
+ return new HostDirective(cloneRulesets, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitHostDirective(this); |
+} |
+ |
+class PageDirective extends Directive { |
+ final String _ident; |
+ final String _pseudoPage; |
+ final List<DeclarationGroup> _declsMargin; |
+ |
+ PageDirective( |
+ this._ident, this._pseudoPage, this._declsMargin, SourceSpan span) |
+ : super(span); |
+ |
+ PageDirective clone() { |
+ var cloneDeclsMargin = []; |
+ for (var declMargin in _declsMargin) { |
+ cloneDeclsMargin.add(declMargin.clone()); |
+ } |
+ return new PageDirective(_ident, _pseudoPage, cloneDeclsMargin, 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, SourceSpan span) : super(span); |
+ CharsetDirective clone() => new CharsetDirective(charEncoding, 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, SourceSpan 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'; |
+ } |
+ } |
+ |
+ KeyFrameDirective clone() { |
+ var cloneBlocks = []; |
+ for (var block in _blocks) { |
+ cloneBlocks.add(block.clone()); |
+ } |
+ return new KeyFrameDirective(_keyframeName, cloneBlocks, span); |
+ } |
+ visit(VisitorBase visitor) => visitor.visitKeyFrameDirective(this); |
+} |
+ |
+class KeyFrameBlock extends Expression { |
+ final Expressions _blockSelectors; |
+ final DeclarationGroup _declarations; |
+ |
+ KeyFrameBlock(this._blockSelectors, this._declarations, SourceSpan span) |
+ : super(span); |
+ |
+ KeyFrameBlock clone() => |
+ new KeyFrameBlock(_blockSelectors.clone(), _declarations.clone(), span); |
+ visit(VisitorBase visitor) => visitor.visitKeyFrameBlock(this); |
+} |
+ |
+class FontFaceDirective extends Directive { |
+ final DeclarationGroup _declarations; |
+ |
+ FontFaceDirective(this._declarations, SourceSpan span) : super(span); |
+ |
+ FontFaceDirective clone() => |
+ new FontFaceDirective(_declarations.clone(), span); |
+ visit(VisitorBase visitor) => visitor.visitFontFaceDirective(this); |
+} |
+ |
+class StyletDirective extends Directive { |
+ final String dartClassName; |
+ final List<RuleSet> rulesets; |
+ |
+ StyletDirective(this.dartClassName, this.rulesets, SourceSpan span) |
+ : super(span); |
+ |
+ bool get isBuiltIn => false; |
+ bool get isExtension => true; |
+ |
+ StyletDirective clone() { |
+ var cloneRulesets = []; |
+ for (var ruleset in rulesets) { |
+ cloneRulesets.add(ruleset.clone()); |
+ } |
+ return new StyletDirective(dartClassName, cloneRulesets, span); |
+ } |
+ |
+ 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, SourceSpan span) : super(span); |
+ |
+ NamespaceDirective clone() => new NamespaceDirective(_prefix, _uri, 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, SourceSpan span) : super(span); |
+ |
+ VarDefinitionDirective clone() => |
+ new VarDefinitionDirective(def.clone(), span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitVarDefinitionDirective(this); |
+} |
+ |
+class MixinDefinition extends Directive { |
+ final String name; |
+ final List definedArgs; |
+ final bool varArgs; |
+ |
+ MixinDefinition(this.name, this.definedArgs, this.varArgs, SourceSpan span) |
+ : super(span); |
+ |
+ MixinDefinition clone() { |
+ var cloneDefinedArgs = []; |
+ for (var definedArg in definedArgs) { |
+ cloneDefinedArgs.add(definedArg.clone()); |
+ } |
+ return new MixinDefinition(name, cloneDefinedArgs, varArgs, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitMixinDefinition(this); |
+} |
+ |
+/** Support a Sass @mixin. See http://sass-lang.com for description. */ |
+class MixinRulesetDirective extends MixinDefinition { |
+ final List<RuleSet> rulesets; |
+ |
+ MixinRulesetDirective(String name, List<VarDefinitionDirective> args, |
+ bool varArgs, this.rulesets, SourceSpan span) |
+ : super(name, args, varArgs, span); |
+ |
+ MixinRulesetDirective clone() { |
+ var clonedArgs = []; |
+ for (var arg in definedArgs) { |
+ clonedArgs.add(arg.clone()); |
+ } |
+ var clonedRulesets = []; |
+ for (var ruleset in rulesets) { |
+ clonedRulesets.add(ruleset.clone()); |
+ } |
+ return new MixinRulesetDirective( |
+ name, clonedArgs, varArgs, clonedRulesets, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitMixinRulesetDirective(this); |
+} |
+ |
+class MixinDeclarationDirective extends MixinDefinition { |
+ final DeclarationGroup declarations; |
+ |
+ MixinDeclarationDirective(String name, List<VarDefinitionDirective> args, |
+ bool varArgs, this.declarations, SourceSpan span) |
+ : super(name, args, varArgs, span); |
+ |
+ MixinDeclarationDirective clone() { |
+ var clonedArgs = []; |
+ for (var arg in definedArgs) { |
+ clonedArgs.add(arg.clone()); |
+ } |
+ return new MixinDeclarationDirective( |
+ name, clonedArgs, varArgs, declarations.clone(), span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitMixinDeclarationDirective(this); |
+} |
+ |
+/** To support consuming a SASS mixin @include. */ |
+class IncludeDirective extends Directive { |
+ final String name; |
+ final List<List<TreeNode>> args; |
+ |
+ IncludeDirective(this.name, this.args, SourceSpan span) : super(span); |
+ |
+ IncludeDirective clone() { |
+ var cloneArgs = []; |
+ for (var arg in args) { |
+ for (var term in arg) { |
+ cloneArgs.add(term.clone()); |
+ } |
+ } |
+ return new IncludeDirective(name, cloneArgs, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitIncludeDirective(this); |
+} |
+ |
+/** To support SASS @content. */ |
+class ContentDirective extends Directive { |
+ ContentDirective(SourceSpan span) : super(span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitContentDirective(this); |
+} |
+ |
+class Declaration extends TreeNode { |
+ final Identifier _property; |
+ final Expression _expression; |
+ /** Style exposed to Dart. */ |
+ dynamic dartStyle; |
+ 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.dartStyle, SourceSpan 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 => dartStyle != null; |
+ |
+ Declaration clone() => new Declaration( |
+ _property.clone(), _expression.clone(), dartStyle, span, |
+ important: important); |
+ |
+ 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 { |
+ bool badUsage = false; |
+ |
+ VarDefinition(Identifier definedName, Expression expr, SourceSpan span) |
+ : super(definedName, expr, null, span); |
+ |
+ String get definedName => _property.name; |
+ |
+ VarDefinition clone() => new VarDefinition( |
+ _property.clone(), expression != null ? expression.clone() : null, span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitVarDefinition(this); |
+} |
+ |
+/** |
+ * Node for usage of @include mixin[(args,...)] found in a declaration group |
+ * instead of at a ruleset (toplevel) e.g., |
+ * div { |
+ * @include mixin1; |
+ * } |
+ */ |
+class IncludeMixinAtDeclaration extends Declaration { |
+ final IncludeDirective include; |
+ |
+ IncludeMixinAtDeclaration(this.include, SourceSpan span) |
+ : super(null, null, null, span); |
+ |
+ IncludeMixinAtDeclaration clone() => |
+ new IncludeMixinAtDeclaration(include.clone(), span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitIncludeMixinAtDeclaration(this); |
+} |
+ |
+class ExtendDeclaration extends Declaration { |
+ final List<TreeNode> selectors; |
+ |
+ ExtendDeclaration(this.selectors, SourceSpan span) |
+ : super(null, null, null, span); |
+ |
+ ExtendDeclaration clone() { |
+ var newSelector = selectors.map((s) => s.clone()).toList(); |
+ return new ExtendDeclaration(newSelector, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitExtendDeclaration(this); |
+} |
+ |
+class DeclarationGroup extends TreeNode { |
+ /** Can be either Declaration or RuleSet (if nested selector). */ |
+ final List declarations; |
+ |
+ DeclarationGroup(this.declarations, SourceSpan span) : super(span); |
+ |
+ DeclarationGroup clone() { |
+ var clonedDecls = declarations.map((d) => d.clone()).toList(); |
+ return new DeclarationGroup(clonedDecls, span); |
+ } |
+ |
+ 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, SourceSpan span) |
+ : super(decls, span); |
+ MarginGroup clone() => |
+ new MarginGroup(margin_sym, super.clone() as dynamic, span); |
+ visit(VisitorBase visitor) => visitor.visitMarginGroup(this); |
+} |
+ |
+class VarUsage extends Expression { |
+ final String name; |
+ final List<Expression> defaultValues; |
+ |
+ VarUsage(this.name, this.defaultValues, SourceSpan span) : super(span); |
+ |
+ VarUsage clone() { |
+ var clonedValues = []; |
+ for (var expr in defaultValues) { |
+ clonedValues.add(expr.clone()); |
+ } |
+ return new VarUsage(name, clonedValues, span); |
+ } |
+ |
+ visit(VisitorBase visitor) => visitor.visitVarUsage(this); |
+} |
+ |
+class OperatorSlash extends Expression { |
+ OperatorSlash(SourceSpan span) : super(span); |
+ OperatorSlash clone() => new OperatorSlash(span); |
+ visit(VisitorBase visitor) => visitor.visitOperatorSlash(this); |
+} |
+ |
+class OperatorComma extends Expression { |
+ OperatorComma(SourceSpan span) : super(span); |
+ OperatorComma clone() => new OperatorComma(span); |
+ visit(VisitorBase visitor) => visitor.visitOperatorComma(this); |
+} |
+ |
+class OperatorPlus extends Expression { |
+ OperatorPlus(SourceSpan span) : super(span); |
+ OperatorPlus clone() => new OperatorPlus(span); |
+ visit(VisitorBase visitor) => visitor.visitOperatorPlus(this); |
+} |
+ |
+class OperatorMinus extends Expression { |
+ OperatorMinus(SourceSpan span) : super(span); |
+ OperatorMinus clone() => new OperatorMinus(span); |
+ visit(VisitorBase visitor) => visitor.visitOperatorMinus(this); |
+} |
+ |
+class UnicodeRangeTerm extends Expression { |
+ final String first; |
+ final String second; |
+ |
+ UnicodeRangeTerm(this.first, this.second, SourceSpan span) : super(span); |
+ |
+ bool get hasSecond => second != null; |
+ |
+ UnicodeRangeTerm clone() => new UnicodeRangeTerm(first, second, span); |
+ |
+ 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. |
+ dynamic value; |
+ String text; |
+ |
+ LiteralTerm(this.value, this.text, SourceSpan span) : super(span); |
+ |
+ LiteralTerm clone() => new LiteralTerm(value, text, span); |
+ |
+ visit(VisitorBase visitor) => visitor.visitLiteralTerm(this); |
+} |
+ |
+class NumberTerm extends LiteralTerm { |
+ NumberTerm(value, String t, SourceSpan span) : super(value, t, span); |
+ NumberTerm clone() => new NumberTerm(value, text, span); |
+ visit(VisitorBase visitor) => visitor.visitNumberTerm(this); |
+} |
+ |
+class UnitTerm extends LiteralTerm { |
+ final int unit; |
+ |
+ UnitTerm(value, String t, SourceSpan span, this.unit) : super(value, t, span); |
+ |
+ UnitTerm clone() => new UnitTerm(value, text, span, unit); |
+ |
+ visit(VisitorBase visitor) => visitor.visitUnitTerm(this); |
+ |
+ String unitToString() => TokenKind.unitToString(unit); |
+ |
+ String toString() => '$text${unitToString()}'; |
+} |
+ |
+class LengthTerm extends UnitTerm { |
+ LengthTerm(value, String t, 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); |
+ } |
+ LengthTerm clone() => new LengthTerm(value, text, span, unit); |
+ visit(VisitorBase visitor) => visitor.visitLengthTerm(this); |
+} |
+ |
+class PercentageTerm extends LiteralTerm { |
+ PercentageTerm(value, String t, SourceSpan span) : super(value, t, span); |
+ PercentageTerm clone() => new PercentageTerm(value, text, span); |
+ visit(VisitorBase visitor) => visitor.visitPercentageTerm(this); |
+} |
+ |
+class EmTerm extends LiteralTerm { |
+ EmTerm(value, String t, SourceSpan span) : super(value, t, span); |
+ EmTerm clone() => new EmTerm(value, text, span); |
+ visit(VisitorBase visitor) => visitor.visitEmTerm(this); |
+} |
+ |
+class ExTerm extends LiteralTerm { |
+ ExTerm(value, String t, SourceSpan span) : super(value, t, span); |
+ ExTerm clone() => new ExTerm(value, text, span); |
+ visit(VisitorBase visitor) => visitor.visitExTerm(this); |
+} |
+ |
+class AngleTerm extends UnitTerm { |
+ AngleTerm(var value, String t, 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 || |
+ this.unit == TokenKind.UNIT_ANGLE_TURN); |
+ } |
+ |
+ AngleTerm clone() => new AngleTerm(value, text, span, unit); |
+ visit(VisitorBase visitor) => visitor.visitAngleTerm(this); |
+} |
+ |
+class TimeTerm extends UnitTerm { |
+ TimeTerm(var value, String t, 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); |
+ } |
+ |
+ TimeTerm clone() => new TimeTerm(value, text, span, unit); |
+ visit(VisitorBase visitor) => visitor.visitTimeTerm(this); |
+} |
+ |
+class FreqTerm extends UnitTerm { |
+ FreqTerm(var value, String t, SourceSpan span, |
+ [int unit = TokenKind.UNIT_LENGTH_PX]) |
+ : super(value, t, span, unit) { |
+ assert(unit == TokenKind.UNIT_FREQ_HZ || unit == TokenKind.UNIT_FREQ_KHZ); |
+ } |
+ |
+ FreqTerm clone() => new FreqTerm(value, text, span, unit); |
+ visit(VisitorBase visitor) => visitor.visitFreqTerm(this); |
+} |
+ |
+class FractionTerm extends LiteralTerm { |
+ FractionTerm(var value, String t, SourceSpan span) : super(value, t, span); |
+ |
+ FractionTerm clone() => new FractionTerm(value, text, span); |
+ visit(VisitorBase visitor) => visitor.visitFractionTerm(this); |
+} |
+ |
+class UriTerm extends LiteralTerm { |
+ UriTerm(String value, SourceSpan span) : super(value, value, span); |
+ |
+ UriTerm clone() => new UriTerm(value, span); |
+ visit(VisitorBase visitor) => visitor.visitUriTerm(this); |
+} |
+ |
+class ResolutionTerm extends UnitTerm { |
+ ResolutionTerm(var value, String t, SourceSpan 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); |
+ } |
+ |
+ ResolutionTerm clone() => new ResolutionTerm(value, text, span, unit); |
+ visit(VisitorBase visitor) => visitor.visitResolutionTerm(this); |
+} |
+ |
+class ChTerm extends UnitTerm { |
+ ChTerm(var value, String t, SourceSpan span, |
+ [int unit = TokenKind.UNIT_LENGTH_PX]) |
+ : super(value, t, span, unit) { |
+ assert(unit == TokenKind.UNIT_CH); |
+ } |
+ |
+ ChTerm clone() => new ChTerm(value, text, span, unit); |
+ visit(VisitorBase visitor) => visitor.visitChTerm(this); |
+} |
+ |
+class RemTerm extends UnitTerm { |
+ RemTerm(var value, String t, SourceSpan span, |
+ [int unit = TokenKind.UNIT_LENGTH_PX]) |
+ : super(value, t, span, unit) { |
+ assert(unit == TokenKind.UNIT_REM); |
+ } |
+ |
+ RemTerm clone() => new RemTerm(value, text, span, unit); |
+ visit(VisitorBase visitor) => visitor.visitRemTerm(this); |
+} |
+ |
+class ViewportTerm extends UnitTerm { |
+ ViewportTerm(var value, String t, SourceSpan 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); |
+ } |
+ |
+ ViewportTerm clone() => new ViewportTerm(value, text, span, unit); |
+ 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, SourceSpan span) : super(value, t, span); |
+ |
+ HexColorTerm clone() => new HexColorTerm(value, text, span); |
+ visit(VisitorBase visitor) => visitor.visitHexColorTerm(this); |
+} |
+ |
+class FunctionTerm extends LiteralTerm { |
+ final Expressions _params; |
+ |
+ FunctionTerm(var value, String t, this._params, SourceSpan span) |
+ : super(value, t, span); |
+ |
+ FunctionTerm clone() => new FunctionTerm(value, text, _params.clone(), 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(SourceSpan span) : super('\\9', '\\9', span); |
+ IE8Term clone() => new IE8Term(span); |
+ visit(VisitorBase visitor) => visitor.visitIE8Term(this); |
+} |
+ |
+class GroupTerm extends Expression { |
+ final List<LiteralTerm> _terms; |
+ |
+ GroupTerm(SourceSpan span) |
+ : _terms = [], |
+ super(span); |
+ |
+ void add(LiteralTerm term) { |
+ _terms.add(term); |
+ } |
+ |
+ GroupTerm clone() => new GroupTerm(span); |
+ visit(VisitorBase visitor) => visitor.visitGroupTerm(this); |
+} |
+ |
+class ItemTerm extends NumberTerm { |
+ ItemTerm(var value, String t, SourceSpan span) : super(value, t, span); |
+ |
+ ItemTerm clone() => new ItemTerm(value, text, span); |
+ visit(VisitorBase visitor) => visitor.visitItemTerm(this); |
+} |
+ |
+class Expressions extends Expression { |
+ final List<Expression> expressions = []; |
+ |
+ Expressions(SourceSpan span) : super(span); |
+ |
+ void add(Expression expression) { |
+ expressions.add(expression); |
+ } |
+ |
+ Expressions clone() { |
+ var clonedExprs = new Expressions(span); |
+ for (var expr in expressions) { |
+ clonedExprs.add(expr.clone()); |
+ } |
+ return clonedExprs; |
+ } |
+ 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, SourceSpan span) : super(span); |
+ |
+ BinaryExpression clone() => |
+ new BinaryExpression(op, x.clone(), y.clone(), span); |
+ visit(VisitorBase visitor) => visitor.visitBinaryExpression(this); |
+} |
+ |
+class UnaryExpression extends Expression { |
+ final Token op; |
+ final Expression self; |
+ |
+ UnaryExpression(this.op, this.self, SourceSpan span) : super(span); |
+ |
+ UnaryExpression clone() => new UnaryExpression(op, self.clone(), span); |
+ visit(VisitorBase visitor) => visitor.visitUnaryExpression(this); |
+} |
+ |
+abstract class DartStyleExpression extends TreeNode { |
+ static const int unknownType = 0; |
+ static const int fontStyle = 1; |
+ static const int marginStyle = 2; |
+ static const int borderStyle = 3; |
+ static const int paddingStyle = 4; |
+ static const int heightStyle = 5; |
+ static const int widthStyle = 6; |
+ |
+ final int _styleType; |
+ int priority; |
+ |
+ DartStyleExpression(this._styleType, SourceSpan 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 { |
+ final Font font; |
+ |
+ // font-style font-variant font-weight font-size/line-height font-family |
+ // TODO(terry): Only px/pt for now need to handle all possible units to |
+ // support calc expressions on units. |
+ FontExpression(SourceSpan span, {dynamic size, List<String> family, |
+ int weight, String style, String variant, LineHeight lineHeight}) |
+ : font = new Font( |
+ size: size is LengthTerm ? size.value : size, |
+ family: family, |
+ weight: weight, |
+ style: style, |
+ variant: variant, |
+ lineHeight: lineHeight), |
+ super(DartStyleExpression.fontStyle, span); |
+ |
+ FontExpression merged(DartStyleExpression newFontExpr) { |
+ if (newFontExpr is FontExpression && 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, SourceSpan span) |
+ : font = new Font.merge(x.font, y.font), |
+ super(DartStyleExpression.fontStyle, span); |
+ |
+ FontExpression clone() => new FontExpression(span, |
+ size: font.size, |
+ family: font.family, |
+ weight: font.weight, |
+ style: font.style, |
+ variant: font.variant, |
+ lineHeight: font.lineHeight); |
+ |
+ visit(VisitorBase visitor) => visitor.visitFontExpression(this); |
+} |
+ |
+abstract class BoxExpression extends DartStyleExpression { |
+ final BoxEdge box; |
+ |
+ BoxExpression(int styleType, SourceSpan span, this.box) |
+ : super(styleType, span); |
+ |
+ 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(SourceSpan span, {num top, num right, num bottom, num left}) |
+ : super(DartStyleExpression.marginStyle, span, |
+ new BoxEdge(left, top, right, bottom)); |
+ |
+ MarginExpression.boxEdge(SourceSpan span, BoxEdge box) |
+ : super(DartStyleExpression.marginStyle, span, box); |
+ |
+ merged(DartStyleExpression newMarginExpr) { |
+ if (newMarginExpr is MarginExpression && |
+ 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, SourceSpan span) |
+ : super(x._styleType, span, new BoxEdge.merge(x.box, y.box)); |
+ |
+ MarginExpression clone() => new MarginExpression(span, |
+ top: box.top, right: box.right, bottom: box.bottom, left: box.left); |
+ |
+ visit(VisitorBase visitor) => visitor.visitMarginExpression(this); |
+} |
+ |
+class BorderExpression extends BoxExpression { |
+ /** Border expression ripped apart. */ |
+ BorderExpression(SourceSpan span, {num top, num right, num bottom, num left}) |
+ : super(DartStyleExpression.borderStyle, span, |
+ new BoxEdge(left, top, right, bottom)); |
+ |
+ BorderExpression.boxEdge(SourceSpan span, BoxEdge box) |
+ : super(DartStyleExpression.borderStyle, span, box); |
+ |
+ merged(DartStyleExpression newBorderExpr) { |
+ if (newBorderExpr is BorderExpression && |
+ 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, SourceSpan span) |
+ : super(DartStyleExpression.borderStyle, span, |
+ new BoxEdge.merge(x.box, y.box)); |
+ |
+ BorderExpression clone() => new BorderExpression(span, |
+ top: box.top, right: box.right, bottom: box.bottom, left: box.left); |
+ |
+ visit(VisitorBase visitor) => visitor.visitBorderExpression(this); |
+} |
+ |
+class HeightExpression extends DartStyleExpression { |
+ final height; |
+ |
+ HeightExpression(SourceSpan span, this.height) |
+ : super(DartStyleExpression.heightStyle, span); |
+ |
+ merged(DartStyleExpression newHeightExpr) { |
+ if (newHeightExpr is DartStyleExpression && |
+ this.isHeight && |
+ newHeightExpr.isHeight) { |
+ return newHeightExpr; |
+ } |
+ |
+ return null; |
+ } |
+ |
+ HeightExpression clone() => new HeightExpression(span, height); |
+ visit(VisitorBase visitor) => visitor.visitHeightExpression(this); |
+} |
+ |
+class WidthExpression extends DartStyleExpression { |
+ final width; |
+ |
+ WidthExpression(SourceSpan span, this.width) |
+ : super(DartStyleExpression.widthStyle, span); |
+ |
+ merged(DartStyleExpression newWidthExpr) { |
+ if (newWidthExpr is WidthExpression && |
+ this.isWidth && |
+ newWidthExpr.isWidth) { |
+ return newWidthExpr; |
+ } |
+ |
+ return null; |
+ } |
+ |
+ WidthExpression clone() => new WidthExpression(span, width); |
+ visit(VisitorBase visitor) => visitor.visitWidthExpression(this); |
+} |
+ |
+class PaddingExpression extends BoxExpression { |
+ /** Padding expression ripped apart. */ |
+ PaddingExpression(SourceSpan span, {num top, num right, num bottom, num left}) |
+ : super(DartStyleExpression.paddingStyle, span, |
+ new BoxEdge(left, top, right, bottom)); |
+ |
+ PaddingExpression.boxEdge(SourceSpan span, BoxEdge box) |
+ : super(DartStyleExpression.paddingStyle, span, box); |
+ |
+ merged(DartStyleExpression newPaddingExpr) { |
+ if (newPaddingExpr is PaddingExpression && |
+ 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, SourceSpan span) |
+ : super(DartStyleExpression.paddingStyle, span, |
+ new BoxEdge.merge(x.box, y.box)); |
+ |
+ PaddingExpression clone() => new PaddingExpression(span, |
+ top: box.top, right: box.right, bottom: box.bottom, left: box.left); |
+ visit(VisitorBase visitor) => visitor.visitPaddingExpression(this); |
+} |