content: // 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 tree;
  
  /**
   * 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.
   */
  abstract class DartString extends IterableBase<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(String source, int length) =>
        new RawSourceDartString(source, length);
    factory DartString.escapedString(String 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();
  
    /**
     * The length of this [DartString], which is the string length after
     * escapes have been resolved.
     */
    int get length;
    bool get isEmpty => length == 0;
  
    Iterator<int> get iterator;
  
    /**
     * The string represented by this [DartString].
     */
    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.moveNext()) {
        if (!it2.moveNext()) return false;
        if (it1.current != it2.current) return false;
      }
      return true;
    }
  
    int get hashCode => throw new UnsupportedError('DartString.hashCode');
  
    /**
     * A textual representation of this [DartString] with some debugging
     * information.
     */
    String toString() => "DartString#${length}:${slowToString()}";
  }
  
  
  /**
   * 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> get iterator => string.codeUnits.iterator;
    String slowToString() => string;
  }
  
  /**
   * A [DartString] whereSource the content comes from a slice of the program
   * source.
   */
  abstract class SourceBasedDartString extends DartString {
    /**
     * The source string containing explicit escapes from which this [DartString]
     * is built.
     */
    final String source;
    final int length;
    SourceBasedDartString(this.source, this.length);
    Iterator<int> get 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> get iterator => source.codeUnits.iterator;
    String slowToString() => source;
  }
  
  /**
   * General case of a [SourceBasedDartString] where the source might contain
   * escapes.
   */
  class EscapedSourceDartString extends SourceBasedDartString {
    String toStringCache;
    EscapedSourceDartString(source, length) : super(source, length);
    Iterator<int> get iterator {
      if (toStringCache != null) return toStringCache.codeUnits.iterator;
      return new StringEscapeIterator(source);
    }
    String slowToString() {
      if (toStringCache != null) return toStringCache;
      StringBuffer buffer = new StringBuffer();
      StringEscapeIterator it = new StringEscapeIterator(source);
      while (it.moveNext()) {
        buffer.writeCharCode(it.current);
      }
      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> get iterator => new ConsDartStringIterator(this);
  
    String slowToString() {
      if (toStringCache != null) return toStringCache;
      toStringCache = left.slowToString() + right.slowToString();
      return toStringCache;
    }
    String get source => slowToString();
  }
  
  class ConsDartStringIterator implements Iterator<int> {
    HasNextIterator<int> currentIterator;
    DartString right;
    bool hasNextLookAhead;
    int _current = null;
  
    ConsDartStringIterator(ConsDartString cons)
        : currentIterator = new HasNextIterator<int>(cons.left.iterator),
          right = cons.right {
      hasNextLookAhead = currentIterator.hasNext;
      if (!hasNextLookAhead) {
        nextPart();
      }
    }
  
    int get current => _current;
  
    bool moveNext() {
      if (!hasNextLookAhead) {
        _current = null;
        return false;
      }
      _current = currentIterator.next();
      hasNextLookAhead = currentIterator.hasNext;
      if (!hasNextLookAhead) {
        nextPart();
      }
      return true;
    }
    void nextPart() {
      if (right != null) {
        currentIterator = new HasNextIterator<int>(right.iterator);
        right = null;
        hasNextLookAhead = currentIterator.hasNext;
      }
    }
  }
  
  /**
   *Iterator that returns the actual string contents of a string with escapes.
   */
  class StringEscapeIterator implements Iterator<int>{
    final Iterator<int> source;
    int _current = null;
  
    StringEscapeIterator(String source) : this.source = source.codeUnits.iterator;
  
    int get current => _current;
  
    bool moveNext() {
      if (!source.moveNext()) {
        _current = null;
        return false;
      }
      int code = source.current;
      if (code != $BACKSLASH) {
        _current = code;
        return true;
      }
      source.moveNext();
      code = source.current;
      switch (code) {
        case $n: _current = $LF; break;
        case $r: _current = $CR; break;
        case $t: _current = $TAB; break;
        case $b: _current = $BS; break;
        case $f: _current = $FF; break;
        case $v: _current = $VTAB; break;
        case $x:
          source.moveNext();
          int value = hexDigitValue(source.current);
          source.moveNext();
          value = value * 16 + hexDigitValue(source.current);
          _current = value;
          break;
        case $u:
          int value = 0;
          source.moveNext();
          code = source.current;
          if (code == $OPEN_CURLY_BRACKET) {
            source.moveNext();
            while (source.current != $CLOSE_CURLY_BRACKET) {
              value = value * 16 + hexDigitValue(source.current);
              source.moveNext();
            }
            _current = value;
            break;
          }
          // Four digit hex value.
          value = hexDigitValue(code);
          for (int i = 0; i < 3; i++) {
            source.moveNext();
            value = value * 16 + hexDigitValue(source.current);
          }
          _current = value;
          break;
        default:
          _current = code;
      }
      return true;
    }
  }
  
  