afdb87e2cf
Change-Id: I8299a49425188c9864fc47532243cede2cf16b1f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/353960 Reviewed-by: Chloe Stefantsova <cstefantsova@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com> Commit-Queue: Jens Johansen <jensj@google.com>
100 lines
2.7 KiB
Dart
100 lines
2.7 KiB
Dart
// Copyright (c) 2018, 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.
|
|
|
|
library kernel.text_reader;
|
|
|
|
// S-expressions
|
|
//
|
|
// An S-expression is an atom or an S-list, an atom is a string that does not
|
|
// contain the delimiters '(', ')', or ' ', and an S-list is a space delimited
|
|
// sequence of S-expressions enclosed in parentheses:
|
|
//
|
|
// <S-expression> ::= <Atom>
|
|
// | <S-list>
|
|
// <S-list> ::= '(' ')'
|
|
// | '(' <S-expression> {' ' <S-expression>}* ')'
|
|
//
|
|
// We use an iterator to read S-expressions. The iterator produces a stream
|
|
// of atoms (strings) and nested iterators (S-lists).
|
|
class TextIterator implements Iterator<Object? /* String? | TextIterator? */ > {
|
|
static final int space = ' '.codeUnitAt(0);
|
|
static final int lparen = '('.codeUnitAt(0);
|
|
static final int rparen = ')'.codeUnitAt(0);
|
|
static final int dquote = '"'.codeUnitAt(0);
|
|
static final int bslash = '\\'.codeUnitAt(0);
|
|
|
|
final String input;
|
|
int index;
|
|
|
|
TextIterator(this.input, this.index);
|
|
|
|
// Consume spaces.
|
|
void skipWhitespace() {
|
|
while (index < input.length && input.codeUnitAt(index) == space) {
|
|
++index;
|
|
}
|
|
}
|
|
|
|
// Consume the rest of a nested S-expression and the closing delimiter.
|
|
void skipToEndOfNested() {
|
|
if (current is TextIterator) {
|
|
TextIterator it = current as TextIterator;
|
|
while (it.moveNext()) {}
|
|
index = it.index + 1;
|
|
}
|
|
}
|
|
|
|
void skipToEndOfAtom() {
|
|
bool isQuoted = false;
|
|
if (index < input.length && input.codeUnitAt(index) == dquote) {
|
|
++index;
|
|
isQuoted = true;
|
|
}
|
|
do {
|
|
if (index >= input.length) return;
|
|
int codeUnit = input.codeUnitAt(index);
|
|
if (isQuoted) {
|
|
// Terminator.
|
|
if (codeUnit == dquote) {
|
|
++index;
|
|
return;
|
|
}
|
|
// Escaped double quote.
|
|
if (codeUnit == bslash &&
|
|
index < input.length + 1 &&
|
|
input.codeUnitAt(index + 1) == dquote) {
|
|
index += 2;
|
|
} else {
|
|
++index;
|
|
}
|
|
} else {
|
|
// Terminator.
|
|
if (codeUnit == space || codeUnit == rparen) return;
|
|
++index;
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
@override
|
|
Object? current = null;
|
|
|
|
@override
|
|
bool moveNext() {
|
|
skipToEndOfNested();
|
|
skipWhitespace();
|
|
if (index >= input.length || input.codeUnitAt(index) == rparen) {
|
|
current = null;
|
|
return false;
|
|
}
|
|
if (input.codeUnitAt(index) == lparen) {
|
|
current = new TextIterator(input, index + 1);
|
|
return true;
|
|
}
|
|
int start = index;
|
|
skipToEndOfAtom();
|
|
current = input.substring(start, index);
|
|
return true;
|
|
}
|
|
}
|