Make visitor interfaces wholly abstract.

This commit is contained in:
Natalie Weizenbaum 2016-08-29 11:09:45 -07:00 committed by Natalie Weizenbaum
parent ffb85921cb
commit cdc3065dfb
8 changed files with 102 additions and 233 deletions

View File

@ -22,6 +22,4 @@ class PlaceholderSelector extends SimpleSelector {
bool operator ==(other) => other is PlaceholderSelector && other.name == name;
int get hashCode => name.hashCode;
String toString() => "%$name";
}

View File

@ -3,41 +3,13 @@
// https://opensource.org/licenses/MIT.
import '../../ast/css.dart';
import 'selector.dart';
import 'value.dart';
abstract class CssVisitor<T> extends SelectorVisitor<T>
implements ValueVisitor<T> {
T visitComment(CssComment node) => null;
T visitDeclaration(CssDeclaration node) => null;
T visitImport(CssImport node) => null;
T visitAtRule(CssAtRule node) {
if (node.children == null) return null;
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitMediaRule(CssMediaRule node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitStyleRule(CssStyleRule node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitStylesheet(CssStylesheet node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
abstract class CssVisitor<T> {
T visitAtRule(CssAtRule node);
T visitComment(CssComment node);
T visitDeclaration(CssDeclaration node);
T visitImport(CssImport node);
T visitMediaRule(CssMediaRule node);
T visitStyleRule(CssStyleRule node);
T visitStylesheet(CssStylesheet node);
}

View File

@ -5,56 +5,14 @@
import '../../ast/sass.dart';
abstract class ExpressionVisitor<T> {
T visitVariableExpression(VariableExpression node) => null;
T visitBooleanExpression(BooleanExpression node) => null;
T visitNumberExpression(NumberExpression node) => null;
T visitColorExpression(ColorExpression node) => null;
T visitUnaryOperatorExpression(UnaryOperatorExpression node) {
node.operand.accept(this);
return null;
}
T visitIdentifierExpression(IdentifierExpression node) {
_visitInterpolation(node.text);
return null;
}
T visitListExpression(ListExpression node) {
for (var expression in node.contents) {
expression.accept(this);
}
return null;
}
T visitMapExpression(MapExpression node) {
for (var pair in node.pairs) {
pair.first.accept(this);
pair.last.accept(this);
}
return null;
}
T visitFunctionExpression(FunctionExpression node) {
for (var expression in node.arguments.positional) {
expression.accept(this);
}
for (var expression in node.arguments.named.values) {
expression.accept(this);
}
node.arguments.rest?.accept(this);
node.arguments.keywordRest?.accept(this);
return null;
}
T visitStringExpression(StringExpression node) {
_visitInterpolation(node.text);
return null;
}
void _visitInterpolation(Interpolation node) {
for (var value in node.contents) {
if (value is Expression) value.accept(this);
}
}
T visitBooleanExpression(BooleanExpression node);
T visitColorExpression(ColorExpression node);
T visitFunctionExpression(FunctionExpression node);
T visitIdentifierExpression(IdentifierExpression node);
T visitListExpression(ListExpression node);
T visitMapExpression(MapExpression node);
T visitNumberExpression(NumberExpression node);
T visitStringExpression(StringExpression node);
T visitUnaryOperatorExpression(UnaryOperatorExpression node);
T visitVariableExpression(VariableExpression node);
}

View File

@ -5,37 +5,15 @@
import '../../ast/selector.dart';
abstract class SelectorVisitor<T> {
T visitAttributeSelector(AttributeSelector attribute) => null;
T visitClassSelector(ClassSelector klass) => null;
T visitIDSelector(IDSelector id) => null;
T visitParentSelector(ParentSelector placeholder) => null;
T visitPlaceholderSelector(PlaceholderSelector placeholder) => null;
T visitTypeSelector(TypeSelector type) => null;
T visitUniversalSelector(UniversalSelector universal) => null;
T visitComplexSelector(ComplexSelector complex) {
for (var component in complex.components) {
if (component is CompoundSelector) component.accept(this);
}
return null;
}
T visitCompoundSelector(CompoundSelector compound) {
for (var simple in compound.components) {
simple.accept(this);
}
return null;
}
T visitSelectorList(SelectorList list) {
for (var complex in list.components) {
complex.accept(this);
}
return null;
}
T visitPseudoSelector(PseudoSelector pseudo) {
if (pseudo.selector != null) visitSelectorList(pseudo.selector);
return null;
}
T visitAttributeSelector(AttributeSelector attribute);
T visitClassSelector(ClassSelector klass);
T visitComplexSelector(ComplexSelector complex);
T visitCompoundSelector(CompoundSelector compound);
T visitIDSelector(IDSelector id);
T visitParentSelector(ParentSelector placeholder);
T visitPlaceholderSelector(PlaceholderSelector placeholder);
T visitPseudoSelector(PseudoSelector pseudo);
T visitSelectorList(SelectorList list);
T visitTypeSelector(TypeSelector type);
T visitUniversalSelector(UniversalSelector universal);
}

View File

@ -5,77 +5,20 @@
import '../../ast/sass.dart';
abstract class StatementVisitor<T> {
T visitComment(Comment node) => null;
T visitContent(Content node) => null;
T visitExtendRule(ExtendRule node) => null;
T visitImport(Import node) => null;
T visitPlainImport(PlainImport node) => null;
T visitReturn(Return node) => null;
T visitVariableDeclaration(VariableDeclaration node) => null;
T visitDeclaration(Declaration node) {
if (node.children == null) return null;
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitAtRule(AtRule node) {
if (node.children == null) return null;
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitFunctionDeclaration(FunctionDeclaration node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitIf(If node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitInclude(Include node) {
if (node.children == null) return null;
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitMixinDeclaration(MixinDeclaration node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitMediaRule(MediaRule node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitStyleRule(StyleRule node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitStylesheet(Stylesheet node) {
for (var child in node.children) {
child.accept(this);
}
return null;
}
T visitAtRule(AtRule node);
T visitComment(Comment node);
T visitContent(Content node);
T visitDeclaration(Declaration node);
T visitExtendRule(ExtendRule node);
T visitFunctionDeclaration(FunctionDeclaration node);
T visitIf(If node);
T visitImport(Import node);
T visitInclude(Include node);
T visitMediaRule(MediaRule node);
T visitMixinDeclaration(MixinDeclaration node);
T visitPlainImport(PlainImport node);
T visitReturn(Return node);
T visitStyleRule(StyleRule node);
T visitStylesheet(Stylesheet node);
T visitVariableDeclaration(VariableDeclaration node);
}

View File

@ -5,24 +5,11 @@
import '../../value.dart';
abstract class ValueVisitor<T> {
T visitBoolean(SassBoolean value) => null;
T visitIdentifier(SassIdentifier value) => null;
T visitNumber(SassNumber value) => null;
T visitString(SassString value) => null;
T visitColor(SassColor value) => null;
T visitList(SassList value) {
for (var element in value.contents) {
element.accept(this);
}
return null;
}
T visitMap(SassMap value) {
value.contents.forEach((key, value) {
key.accept(this);
value.accept(this);
});
return null;
}
T visitBoolean(SassBoolean value);
T visitColor(SassColor value);
T visitIdentifier(SassIdentifier value);
T visitList(SassList value);
T visitMap(SassMap value);
T visitNumber(SassNumber value);
T visitString(SassString value);
}

View File

@ -20,8 +20,7 @@ import '../value.dart';
import 'interface/statement.dart';
import 'interface/expression.dart';
class PerformVisitor extends StatementVisitor
implements ExpressionVisitor<Value> {
class PerformVisitor implements StatementVisitor, ExpressionVisitor<Value> {
final List<String> _loadPaths;
Environment _environment;
@ -64,7 +63,9 @@ class PerformVisitor extends StatementVisitor
CssStylesheet visitStylesheet(Stylesheet node) {
_root = new CssStylesheet(node.span);
_parent = _root;
super.visitStylesheet(node);
for (var child in node.children) {
child.accept(this);
}
return _root;
}
@ -101,7 +102,9 @@ class PerformVisitor extends StatementVisitor
if (node.children != null) {
var oldDeclarationName = _declarationName;
_declarationName = name.value;
super.visitDeclaration(node);
for (var child in node.children) {
child.accept(this);
}
_declarationName = oldDeclarationName;
}
}
@ -137,15 +140,19 @@ class PerformVisitor extends StatementVisitor
_withParent(new CssAtRule(node.name, node.span, value: value), () {
if (_selector == null) {
super.visitAtRule(node);
for (var child in node.children) {
child.accept(this);
}
} else {
// If we're in a style rule, copy it into the at-rule so that
// declarations immediately inside it have somewhere to go.
//
// For example, "a {@foo {b: c}}" should produce "@foo {a {b: c}}".
_withParent(new CssStyleRule(_selector, _selector.span),
() => super.visitAtRule(node),
removeIfEmpty: true);
_withParent(new CssStyleRule(_selector, _selector.span), () {
for (var child in node.children) {
child.accept(this);
}
}, removeIfEmpty: true);
}
}, through: (node) => node is CssStyleRule);
}
@ -158,7 +165,11 @@ class PerformVisitor extends StatementVisitor
void visitIf(If node) {
var condition = node.expression.accept(this);
if (!condition.isTruthy) return;
_environment.scope(() => super.visitIf(node), semiGlobal: true);
_environment.scope(() {
for (var child in node.children) {
child.accept(this);
}
}, semiGlobal: true);
}
void visitImport(Import node) {
@ -254,16 +265,20 @@ class PerformVisitor extends StatementVisitor
_withParent(new CssMediaRule(queries, node.span), () {
_withMediaQueries(queries, () {
if (_selector == null) {
super.visitMediaRule(node);
for (var child in node.children) {
child.accept(this);
}
} else {
// If we're in a style rule, copy it into the media query so that
// declarations immediately inside @media have somewhere to go.
//
// For example, "a {@media screen {b: c}}" should produce
// "@media screen {a {b: c}}".
_withParent(new CssStyleRule(_selector, _selector.span),
() => super.visitMediaRule(node),
removeIfEmpty: true);
_withParent(new CssStyleRule(_selector, _selector.span), () {
for (var child in node.children) {
child.accept(this);
}
}, removeIfEmpty: true);
}
});
},
@ -313,9 +328,13 @@ class PerformVisitor extends StatementVisitor
var selector =
new CssValue<SelectorList>(parsedSelector, node.selector.span);
_withParent(_extender.addSelector(selector, node.span),
() => _withSelector(selector, () => super.visitStyleRule(node)),
through: (node) => node is CssStyleRule, removeIfEmpty: true);
_withParent(_extender.addSelector(selector, node.span), () {
_withSelector(selector, () {
for (var child in node.children) {
child.accept(this);
}
});
}, through: (node) => node is CssStyleRule, removeIfEmpty: true);
}
void visitVariableDeclaration(VariableDeclaration node) {

View File

@ -12,6 +12,8 @@ import '../ast/selector.dart';
import '../util/character.dart';
import '../value.dart';
import 'interface/css.dart';
import 'interface/selector.dart';
import 'interface/value.dart';
String toCss(CssNode node) {
var visitor = new _SerializeCssVisitor();
@ -38,7 +40,8 @@ String selectorToCss(Selector selector) {
return visitor._buffer.toString();
}
class _SerializeCssVisitor extends CssVisitor {
class _SerializeCssVisitor
implements CssVisitor, ValueVisitor, SelectorVisitor {
final _buffer = new StringBuffer();
var _indentation = 0;
@ -311,6 +314,12 @@ class _SerializeCssVisitor extends CssVisitor {
});
}
void visitCompoundSelector(CompoundSelector compound) {
for (var simple in compound.components) {
simple.accept(this);
}
}
void visitIDSelector(IDSelector id) {
_buffer.writeCharCode($hash);
_buffer.write(id.name);
@ -326,6 +335,11 @@ class _SerializeCssVisitor extends CssVisitor {
if (parent.suffix != null) _buffer.write(parent.suffix);
}
void visitPlaceholderSelector(PlaceholderSelector placeholder) {
_buffer.writeCharCode($percent);
_buffer.write(placeholder.name);
}
void visitPseudoSelector(PseudoSelector pseudo) {
_buffer.writeCharCode($colon);
if (pseudo.type == PseudoType.element) _buffer.writeCharCode($colon);