Add an explicit distinction between statements and expressions.

This commit is contained in:
Natalie Weizenbaum 2016-05-24 11:07:31 -07:00
parent 7cc74b7c17
commit f8cfb305a9
16 changed files with 131 additions and 72 deletions

View File

@ -4,10 +4,10 @@
import 'package:source_span/source_span.dart';
import '../visitor.dart';
import 'node.dart';
import '../visitor/statement.dart';
import 'statement.dart';
class CommentNode implements AstNode {
class CommentNode implements Statement {
final String text;
final bool isSilent;
@ -18,7 +18,7 @@ class CommentNode implements AstNode {
CommentNode(this.text, {bool silent, this.span})
: isSilent = silent;
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
visitor.visitComment(this);
String toString() => text;

View File

@ -4,12 +4,12 @@
import 'package:source_span/source_span.dart';
import '../visitor.dart';
import '../visitor/statement.dart';
import 'expression.dart';
import 'expression/interpolation.dart';
import 'node.dart';
import 'statement.dart';
class DeclarationNode implements AstNode {
class DeclarationNode implements Statement {
final InterpolationExpression name;
final Expression value;
@ -18,7 +18,7 @@ class DeclarationNode implements AstNode {
DeclarationNode(this.name, this.value, {this.span});
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
visitor.visitDeclaration(this);
String toString() => "$name: $value;";

View File

@ -2,6 +2,9 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import '../visitor/expression.dart';
import 'node.dart';
abstract class Expression implements AstNode {}
abstract class Expression implements AstNode {
/*=T*/ visit/*<T>*/(ExpressionVisitor/*<T>*/ visitor);
}

View File

@ -4,7 +4,7 @@
import 'package:source_span/source_span.dart';
import '../../visitor.dart';
import '../../visitor/expression.dart';
import '../expression.dart';
import 'interpolation.dart';
@ -15,7 +15,7 @@ class IdentifierExpression implements Expression {
IdentifierExpression(this.text);
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(ExpressionVisitor/*<T>*/ visitor) =>
visitor.visitIdentifierExpression(this);
String toString() => text.toString();

View File

@ -4,7 +4,7 @@
import 'package:source_span/source_span.dart';
import '../../visitor.dart';
import '../../visitor/expression.dart';
import '../expression.dart';
class InterpolationExpression implements Expression {
@ -40,7 +40,7 @@ class InterpolationExpression implements Expression {
}
}
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(ExpressionVisitor/*<T>*/ visitor) =>
visitor.visitInterpolationExpression(this);
String toString() =>

View File

@ -5,7 +5,7 @@
import 'package:source_span/source_span.dart';
import '../../utils.dart';
import '../../visitor.dart';
import '../../visitor/expression.dart';
import '../expression.dart';
class ListExpression implements Expression {
@ -23,7 +23,7 @@ class ListExpression implements Expression {
: contents = contents,
span = span ?? spanForList(contents);
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(ExpressionVisitor/*<T>*/ visitor) =>
visitor.visitListExpression(this);
// TODO: parenthesize nested lists if necessary

View File

@ -4,7 +4,7 @@
import 'package:source_span/source_span.dart';
import '../../visitor.dart';
import '../../visitor/expression.dart';
import '../expression.dart';
import 'interpolation.dart';
@ -23,7 +23,7 @@ class StringExpression implements Expression {
/// Unlike [text], his doesn't resolve escapes and does include quotes.
InterpolationExpression get asInterpolation => throw new UnimplementedError();
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(ExpressionVisitor/*<T>*/ visitor) =>
visitor.visitStringExpression(this);
StringExpression(this.text);

View File

@ -4,10 +4,6 @@
import 'package:source_span/source_span.dart';
import '../visitor.dart';
abstract class AstNode {
SourceSpan get span;
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor);
}

View File

@ -0,0 +1,10 @@
// Copyright 2016 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import '../visitor/statement.dart';
import 'node.dart';
abstract class Statement implements AstNode {
/*=T*/ visit/*<T>*/(StatementVisitor/*<T>*/ visitor);
}

View File

@ -4,23 +4,23 @@
import 'package:source_span/source_span.dart';
import '../visitor.dart';
import '../visitor/statement.dart';
import 'expression/interpolation.dart';
import 'node.dart';
import 'statement.dart';
class StyleRuleNode implements AstNode {
class StyleRuleNode implements Statement {
final InterpolationExpression selector;
final List<AstNode> children;
final List<Statement> children;
final SourceSpan span;
// TODO: validate that children only contains variable, at-rule, declaration,
// or style nodes?
StyleRuleNode(this.selector, Iterable<AstNode> children, {this.span})
StyleRuleNode(this.selector, Iterable<Statement> children, {this.span})
: children = new List.unmodifiable(children);
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
visitor.visitStyleRule(this);
String toString() => "$selector {${children.join(" ")}}";

View File

@ -4,18 +4,18 @@
import 'package:source_span/source_span.dart';
import '../visitor.dart';
import 'node.dart';
import '../visitor/statement.dart';
import 'statement.dart';
class StylesheetNode implements AstNode {
final List<AstNode> children;
class StylesheetNode implements Statement {
final List<Statement> children;
final SourceSpan span;
StylesheetNode(Iterable<AstNode> children, {this.span})
StylesheetNode(Iterable<Statement> children, {this.span})
: children = new List.unmodifiable(children);
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
visitor.visitStylesheet(this);
String toString() => children.map((child) => "$child").join(" ");

View File

@ -4,11 +4,11 @@
import 'package:source_span/source_span.dart';
import '../visitor.dart';
import '../visitor/statement.dart';
import 'expression.dart';
import 'node.dart';
import 'statement.dart';
class VariableDeclarationNode implements AstNode {
class VariableDeclarationNode implements Statement {
final String name;
final Expression expression;
@ -24,7 +24,7 @@ class VariableDeclarationNode implements AstNode {
: isGuarded = guarded,
isGlobal = global;
/*=T*/ visit/*<T>*/(AstVisitor/*<T>*/ visitor) =>
/*=T*/ visit/*<T>*/(StatementVisitor/*<T>*/ visitor) =>
visitor.visitVariableDeclaration(this);
String toString() => "\$$name: $expression;";

View File

@ -5,7 +5,6 @@
import 'package:charcode/charcode.dart';
import 'package:string_scanner/string_scanner.dart';
import 'ast/node.dart';
import 'ast/comment.dart';
import 'ast/declaration.dart';
import 'ast/expression.dart';
@ -13,6 +12,8 @@ import 'ast/expression/identifier.dart';
import 'ast/expression/interpolation.dart';
import 'ast/expression/list.dart';
import 'ast/expression/string.dart';
import 'ast/node.dart';
import 'ast/statement.dart';
import 'ast/style_rule.dart';
import 'ast/stylesheet.dart';
import 'ast/variable_declaration.dart';
@ -36,7 +37,7 @@ class Parser {
StylesheetNode parse() {
var start = _scanner.state;
var children = <AstNode>[];
var children = <Statement>[];
do {
children.addAll(_comments());
switch (_scanner.peekChar()) {
@ -103,9 +104,9 @@ class Parser {
span: _scanner.spanFrom(start));
}
List<AstNode> _styleRuleChildren() {
List<Statement> _styleRuleChildren() {
_expectChar($lbrace);
var children = <AstNode>[];
var children = <Statement>[];
do {
children.addAll(_comments());
switch (_scanner.peekChar()) {

View File

@ -2,20 +2,24 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'ast/node.dart';
import 'ast/comment.dart';
import 'ast/declaration.dart';
import 'ast/expression.dart';
import 'ast/expression/identifier.dart';
import 'ast/expression/interpolation.dart';
import 'ast/expression/list.dart';
import 'ast/expression/string.dart';
import 'ast/node.dart';
import 'ast/statement.dart';
import 'ast/style_rule.dart';
import 'ast/stylesheet.dart';
import 'ast/variable_declaration.dart';
import 'visitor/expression.dart';
import 'visitor/statement.dart';
class AstVisitor<T> {
T visit(AstNode node) => node.visit(this);
class AstVisitor<T> extends ExpressionVisitor<T>
implements StatementVisitor<T> {
T visit(AstNode node) {
if (node is Statement) return node.visit(this);
if (node is Expression) return node.visit(this);
throw new ArgumentError("Unknown node type $node.");
}
T visitComment(CommentNode node) => null;
@ -44,28 +48,4 @@ class AstVisitor<T> {
node.expression.visit(this);
return null;
}
T visitIdentifierExpression(IdentifierExpression node) {
visitInterpolationExpression(node.text);
return null;
}
T visitInterpolationExpression(InterpolationExpression node) {
for (var value in node.contents) {
if (value is Expression) value.visit(this);
}
return null;
}
T visitListExpression(ListExpression node) {
for (var expression in node.contents) {
expression.visit(this);
}
return null;
}
T visitStringExpression(StringExpression node) {
visitInterpolationExpression(node.text);
return null;
}
}

View File

@ -0,0 +1,37 @@
// Copyright 2016 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import '../ast/expression.dart';
import '../ast/expression/identifier.dart';
import '../ast/expression/interpolation.dart';
import '../ast/expression/list.dart';
import '../ast/expression/string.dart';
class ExpressionVisitor<T> {
T visit(Expression expression) => expression.visit(this);
T visitIdentifierExpression(IdentifierExpression node) {
visitInterpolationExpression(node.text);
return null;
}
T visitInterpolationExpression(InterpolationExpression node) {
for (var value in node.contents) {
if (value is Expression) value.visit(this);
}
return null;
}
T visitListExpression(ListExpression node) {
for (var expression in node.contents) {
expression.visit(this);
}
return null;
}
T visitStringExpression(StringExpression node) {
visitInterpolationExpression(node.text);
return null;
}
}

View File

@ -0,0 +1,32 @@
// Copyright 2016 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import '../ast/comment.dart';
import '../ast/declaration.dart';
import '../ast/statement.dart';
import '../ast/style_rule.dart';
import '../ast/stylesheet.dart';
import '../ast/variable_declaration.dart';
class StatementVisitor<T> {
T visit(Statement node) => node.visit(this);
T visitComment(CommentNode node) => null;
T visitDeclaration(DeclarationNode node) => null;
T visitVariableDeclaration(VariableDeclarationNode node) => null;
T visitStyleRule(StyleRuleNode node) {
for (var child in node.children) {
child.visit(this);
}
return null;
}
T visitStylesheet(StylesheetNode node) {
for (var child in node.children) {
child.visit(this);
}
return null;
}
}