Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(828)

Unified Diff: frog/leg/tree/nodes.dart

Issue 9642001: Make string juxtaposition combine properly with string interpolations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments. Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « frog/leg/ssa/nodes.dart ('k') | frog/leg/tree/tree.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/tree/nodes.dart
diff --git a/frog/leg/tree/nodes.dart b/frog/leg/tree/nodes.dart
index 3062f660c771e04fcd9d24ca42e9f979a7e8457d..4b4b74cbcdac1ca0dafc32525eb80ddc8a445254 100644
--- a/frog/leg/tree/nodes.dart
+++ b/frog/leg/tree/nodes.dart
@@ -27,7 +27,7 @@ interface Visitor<R> {
R visitLiteralMapEntry(LiteralMapEntry node);
R visitLiteralNull(LiteralNull node);
R visitLiteralString(LiteralString node);
- R visitLiteralStringJuxtaposition(LiteralStringJuxtaposition node);
+ R visitStringJuxtaposition(StringJuxtaposition node);
R visitModifiers(Modifiers node);
R visitNamedArgument(NamedArgument node);
R visitNewExpression(NewExpression node);
@@ -57,6 +57,12 @@ Token firstBeginToken(Node first, Node second) {
return null;
}
+class NodeAssertionFailure implements Exception {
+ final Node node;
+ final String message;
+ NodeAssertionFailure(this.node, this.message);
+}
+
/**
* A node in a syntax tree.
*
@@ -137,6 +143,7 @@ class Node implements Hashable {
Statement asStatement() => null;
StringInterpolation asStringInterpolation() => null;
StringInterpolationPart asStringInterpolationPart() => null;
+ StringJuxtaposition asStringJuxtaposition() => null;
SwitchCase asSwitchCase() => null;
SwitchStatement asSwitchStatement() => null;
Throw asThrow() => null;
@@ -731,193 +738,30 @@ class StringQuoting {
}
}
-class DartString implements Iterable<int> {
- // This is a convenience constructor. If you need a const literal DartString,
- // use [const LiteralDartString(string)] directly.
- factory DartString.literal(String string) => new LiteralDartString(string);
- factory DartString.rawString(SourceString source, int length) =>
- new RawSourceDartString(source, length);
- factory DartString.escapedString(SourceString source, int length) =>
- new EscapedSourceDartString(source, length);
- const DartString();
- abstract int get length();
- bool isEmpty() => length == 0;
- abstract Iterator<int> iterator();
- abstract String slowToString();
-
- bool operator ==(var other) {
- if (other is !DartString) return false;
- DartString otherString = other;
- if (length != otherString.length) return false;
- Iterator it1 = iterator();
- Iterator it2 = otherString.iterator();
- while (it1.hasNext()) {
- if (it1.next() != it2.next()) return false;
- }
- return true;
- }
- String toString() => "DartString#${length}:${slowToString()}";
- abstract SourceString get source();
-}
-
-class LiteralDartString extends DartString {
- final String string;
- const LiteralDartString(this.string);
- int get length() => string.length;
- Iterator<int> iterator() => new StringCodeIterator(string);
- String slowToString() => string;
- SourceString get source() => new StringWrapper(string);
-}
-
-class SourceBasedDartString extends DartString {
- String toStringCache = null;
- final SourceString source;
- final int length;
- SourceBasedDartString(this.source, this.length);
- abstract Iterator<int> iterator();
-}
-
-class RawSourceDartString extends SourceBasedDartString {
- RawSourceDartString(source, length) : super(source, length);
- Iterator<int> iterator() => source.iterator();
- String slowToString() {
- if (toStringCache !== null) return toStringCache;
- toStringCache = source.slowToString();
- return toStringCache;
- }
-}
-
-class EscapedSourceDartString extends SourceBasedDartString {
- EscapedSourceDartString(source, length) : super(source, length);
- Iterator<int> iterator() {
- if (toStringCache !== null) return new StringCodeIterator(toStringCache);
- return new StringEscapeIterator(source);
- }
- String slowToString() {
- if (toStringCache !== null) return toStringCache;
- StringBuffer buffer = new StringBuffer();
- StringEscapeIterator it = new StringEscapeIterator(source);
- while (it.hasNext()) {
- buffer.addCharCode(it.next());
- }
- toStringCache = buffer.toString();
- return toStringCache;
- }
-}
-
-class ConsDartString extends DartString {
- final DartString left;
- final DartString right;
- final int length;
- int hashCache = null;
- String toStringCache;
- ConsDartString(DartString left, DartString right)
- : this.left = left,
- this.right = right,
- length = left.length + right.length;
-
- Iterator<int> iterator() => new ConsDartStringIterator(this);
-
- String slowToString() {
- if (toStringCache !== null) return toStringCache;
- toStringCache = left.slowToString().concat(right.slowToString());
- return toStringCache;
- }
- SourceString get source() => new StringWrapper(slowToString());
-}
-
-class ConsDartStringIterator implements Iterator<int> {
- Iterator<int> current;
- DartString right;
- bool hasNextLookAhead;
- ConsDartStringIterator(ConsDartString cons)
- : current = cons.left.iterator(),
- right = cons.right {
- hasNextLookAhead = current.hasNext();
- if (!hasNextLookAhead) {
- nextPart();
- }
- }
- bool hasNext() {
- return hasNextLookAhead;
- }
- int next() {
- assert(hasNextLookAhead);
- int result = current.next();
- hasNextLookAhead = current.hasNext();
- if (!hasNextLookAhead) {
- nextPart();
- }
- return result;
- }
- void nextPart() {
- if (right !== null) {
- current = right.iterator();
- right = null;
- hasNextLookAhead = current.hasNext();
- }
- }
-}
-
/**
- *Iterator that returns the actual string contents of a string with escapes.
- */
-class StringEscapeIterator implements Iterator<int>{
- final Iterator<int> source;
- StringEscapeIterator(SourceString source) : this.source = source.iterator();
- bool hasNext() => source.hasNext();
- int next() {
- int code = source.next();
- if (code !== $BACKSLASH) {
- return code;
- }
- code = source.next();
- if (code === $n) return $LF;
- if (code === $r) return $CR;
- if (code === $t) return $TAB;
- if (code === $b) return $BS;
- if (code === $f) return $FF;
- if (code === $v) return $VTAB;
- if (code === $x) {
- int value = hexDigitValue(source.next());
- value = value * 16 + hexDigitValue(source.next());
- return value;
- }
- if (code === $u) {
- int value = 0;
- code = source.next();
- if (code === $OPEN_CURLY_BRACKET) {
- for (code = source.next();
- code != $CLOSE_CURLY_BRACKET;
- code = source.next()) {
- value = value * 16 + hexDigitValue(code);
- }
- return value;
- }
- // Four digit hex value.
- value = hexDigitValue(code);
- for (int i = 0; i < 3; i++) {
- code = source.next();
- value = value * 16 + hexDigitValue(code);
- }
- return value;
- }
- return code;
- }
+ * Superclass for classes representing string literals.
+ */
+class StringNode extends Expression {
+ abstract DartString get dartString();
+ abstract bool get isInterpolation();
}
+class LiteralString extends StringNode {
+ final Token token;
+ /** Non-null on validated string literals. */
+ final DartString dartString;
-class LiteralString extends Literal<SourceString> {
- /** Set on validated string literals. */
- final DartString dartString = null;
-
- LiteralString(Token token, this.dartString) : super(token, null);
+ LiteralString(this.token, this.dartString);
LiteralString asLiteralString() => this;
+ void visitChildren(Visitor visitor) {}
+
+ bool get isInterpolation() => false;
bool isValidated() => dartString !== null;
- SourceString get value() => token.value;
+ Token getBeginToken() => token;
+ Token getEndToken() => token;
accept(Visitor visitor) => visitor.visitLiteralString(this);
}
@@ -1248,7 +1092,7 @@ class Modifiers extends Node {
bool isFactory() => (flags & FLAG_FACTORY) != 0;
}
-class StringInterpolation extends Expression {
+class StringInterpolation extends StringNode {
final LiteralString string;
final NodeList parts;
@@ -1256,6 +1100,9 @@ class StringInterpolation extends Expression {
StringInterpolation asStringInterpolation() => this;
+ DartString get dartString() => null;
+ bool get isInterpolation() => true;
+
accept(Visitor visitor) => visitor.visitStringInterpolation(this);
visitChildren(Visitor visitor) {
@@ -1264,7 +1111,6 @@ class StringInterpolation extends Expression {
}
Token getBeginToken() => string.getBeginToken();
-
Token getEndToken() => parts.getEndToken();
}
@@ -1288,45 +1134,70 @@ class StringInterpolationPart extends Node {
Token getEndToken() => string.getEndToken();
}
-class LiteralStringJuxtaposition extends LiteralString {
- // List of either StringLiteral or StringInterpolation.
- final Link<Expression> literals;
+/**
+ * A class representing juxtaposed string literals.
+ * The string literals can be both plain literals and string interpolations.
+ */
+class StringJuxtaposition extends StringNode {
+ final Expression first;
+ final Expression second;
- LiteralStringJuxtaposition(Link<Expression> literals)
- : this.literals = literals,
- super(literals.head.getBeginToken(), concatenateLiterals(literals));
+ /**
+ * Caches the check for whether this juxtaposition contains a string
+ * interpolation
+ */
+ bool isInterpolationCache = null;
- static DartString concatenateLiterals(Link<Expression> literals) {
- assert(!literals.isEmpty());
- LiteralString literal = literals.head;
- if (literals.tail.isEmpty()) {
- return literal.dartString;
- }
- return new ConsDartString(literal.dartString,
- concatenateLiterals(literals.tail));
- }
+ /**
+ * Caches a Dart string representation of the entire juxtaposition's
+ * content. Only juxtapositions that don't (transitively) contains
+ * interpolations have a static representation.
+ */
+ DartString dartStringCache = null;
- SourceString get value() => null;
+ StringJuxtaposition(this.first, this.second);
- accept(Visitor visitor) => visitor.visitLiteralStringJuxtaposition(this);
+ StringJuxtaposition asStringJuxtaposition() => this;
- visitChildren(Visitor visitor) {
- for (Expression literal in literals) {
- literal.accept(visitor);
+ bool get isInterpolation() {
+ if (isInterpolationCache === null) {
+ isInterpolationCache = (first.accept(const IsInterpolationVisitor()) ||
+ second.accept(const IsInterpolationVisitor()));
}
+ return isInterpolationCache;
}
- Token getBeginToken() => literals.head.getBeginToken();
-
- Token getEndToken() {
- Link<Expression> current = literals;
- Expression lastExpression = null;
- while (!current.isEmpty()) {
- lastExpression = current.head;
- current = current.tail;
+ /**
+ * Retrieve a single DartString that represents this entire juxtaposition
+ * of string literals.
+ * Should only be called if [isInterpolation] returns false.
+ */
+ DartString get dartString() {
+ if (isInterpolation) {
+ throw new NodeAssertionFailure(this,
+ "Getting dartString on interpolation;");
+ }
+ if (dartStringCache === null) {
+ DartString firstString = first.accept(const GetDartStringVisitor());
+ DartString secondString = second.accept(const GetDartStringVisitor());
+ if (firstString === null || secondString === null) {
+ return null;
+ }
+ dartStringCache = new DartString.concat(firstString, secondString);
}
- return lastExpression.getEndToken();
+ return dartStringCache;
}
+
+ accept(Visitor visitor) => visitor.visitStringJuxtaposition(this);
+
+ void visitChildren(Visitor visitor) {
+ first.accept(visitor);
+ second.accept(visitor);
+ }
+
+ Token getBeginToken() => first.getBeginToken();
+
+ Token getEndToken() => second.getEndToken();
}
class EmptyStatement extends Statement {
@@ -1596,9 +1467,9 @@ class LabeledStatement extends Statement {
class ScriptTag extends Node {
final Identifier tag;
- final LiteralString argument;
+ final StringNode argument;
final Identifier prefixIdentifier;
- final LiteralString prefix;
+ final StringNode prefix;
final Token beginToken;
final Token endToken;
@@ -1741,3 +1612,19 @@ class Initializers {
node.selector.asIdentifier() !== null);
}
}
+
+class GetDartStringVisitor extends AbstractVisitor<DartString> {
+ const GetDartStringVisitor();
+ DartString visitNode(Node node) => null;
+ DartString visitStringJuxtaposition(StringJuxtaposition node)
+ => node.dartString;
+ DartString visitLiteralString(LiteralString node) => node.dartString;
+}
+
+class IsInterpolationVisitor extends AbstractVisitor<bool> {
+ const IsInterpolationVisitor();
+ bool visitNode(Node node) => false;
+ bool visitStringInterpolation(StringInterpolation node) => true;
+ bool visitStringJuxtaposition(StringJuxtaposition node)
+ => node.isInterpolation;
+}
« no previous file with comments | « frog/leg/ssa/nodes.dart ('k') | frog/leg/tree/tree.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698