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

Unified Diff: frog/leg/tree/dartstring.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: Fix typo 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
Index: frog/leg/tree/dartstring.dart
diff --git a/frog/leg/tree/dartstring.dart b/frog/leg/tree/dartstring.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e46a03af67be8f698e67962c378fdbb8ebda5e8b
--- /dev/null
+++ b/frog/leg/tree/dartstring.dart
@@ -0,0 +1,209 @@
+// 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.
+
+/**
+ * The [DartString] type represents a Dart string value as a sequence of Unicode
+ * Scalar Values.
+ * After parsing, any valid [LiteralString] will contain a [DartString]
+ * representing its content after removing quotes and resolving escapes in
+ * its source.
+ */
+class DartString implements Iterable<int> {
+ factory DartString.empty() => const LiteralDartString("");
+ // 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);
+ factory DartString.concat(DartString first, DartString second) {
+ if (first.isEmpty()) return second;
+ if (second.isEmpty()) return first;
+ return new ConsDartString(first, second);
+ }
+ 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();
+}
+
+
+/**
+ * A [DartString] where the content is represented by an actual [String].
+ */
+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);
+}
+
+/**
+ * A [DartString] where the content comes from a slice of the program source.
+ */
+class SourceBasedDartString extends DartString {
+ String toStringCache = null;
+ final SourceString source;
+ final int length;
+ SourceBasedDartString(this.source, this.length);
+ abstract Iterator<int> iterator();
+}
+
+/**
+ * Special case of a [SourceBasedDartString] where we know the source doesn't
+ * contain any escapes.
+ */
+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;
+ }
+}
+
+/**
+ * General case of a [SourceBasedDartString] where the source might contain
+ * escapes.
+ */
+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;
+ }
+}
+
+/**
+ * The concatenation of two [DartString]s.
+ */
+class ConsDartString extends DartString {
+ final DartString left;
+ final DartString right;
+ final int length;
+ 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;
+ }
+}
+

Powered by Google App Engine
This is Rietveld 408576698