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

Unified Diff: pkg/fasta/lib/src/quote.dart

Issue 2629063005: Fasta builders. (Closed)
Patch Set: Address review comments. Created 3 years, 11 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 | « pkg/fasta/lib/src/modifier.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/fasta/lib/src/quote.dart
diff --git a/pkg/fasta/lib/src/quote.dart b/pkg/fasta/lib/src/quote.dart
new file mode 100644
index 0000000000000000000000000000000000000000..6cf6969edc3ca644089b88e5c4779d45c3170223
--- /dev/null
+++ b/pkg/fasta/lib/src/quote.dart
@@ -0,0 +1,237 @@
+// Copyright (c) 2016, 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 fasta.quote;
+
+import 'errors.dart' show
+ inputError,
+ internalError;
+
+import 'package:dart_scanner/src/characters.dart' show
+ $BACKSLASH,
+ $BS,
+ $CLOSE_CURLY_BRACKET,
+ $CR,
+ $FF,
+ $LF,
+ $OPEN_CURLY_BRACKET,
+ $SPACE,
+ $TAB,
+ $VTAB,
+ $b,
+ $f,
+ $n,
+ $r,
+ $t,
+ $u,
+ $v,
+ $x,
+ hexDigitValue,
+ isHexDigit;
+
+enum Quote {
+ Single,
+ Double,
+ MultiLineSingle,
+ MultiLineDouble,
+ RawSingle,
+ RawDouble,
+ RawMultiLineSingle,
+ RawMultiLineDouble,
+}
+
+Quote analyzeQuote(String first) {
+ if (first.startsWith('"""')) return Quote.MultiLineDouble;
+ if (first.startsWith('r"""')) return Quote.RawMultiLineDouble;
+ if (first.startsWith("'''")) return Quote.MultiLineSingle;
+ if (first.startsWith("r'''")) return Quote.RawMultiLineSingle;
+ if (first.startsWith('"')) return Quote.Double;
+ if (first.startsWith('r"')) return Quote.RawDouble;
+ if (first.startsWith("'")) return Quote.Single;
+ if (first.startsWith("r'")) return Quote.RawSingle;
+ return internalError("Unexpected string literal: $first");
+}
+
+// Note: based on [StringValidator.quotingFromString]
+// (pkg/compiler/lib/src/string_validator.dart).
+int lengthOfOptionalWhitespacePrefix(String first, int start) {
+ List<int> codeUnits = first.codeUnits;
+ for (int i = start; i < codeUnits.length; i++) {
+ int code = codeUnits[i];
+ if (code == $BACKSLASH) {
+ i++;
+ if (i < codeUnits.length) {
+ code = codeUnits[i];
+ } else {
+ break;
+ }
+ }
+ if (code == $TAB || code == $SPACE) continue;
+ if (code == $CR) {
+ if (i + 1 < codeUnits.length && codeUnits[i] == $LF) {
+ i++;
+ }
+ return i + 1;
+ }
+ if (code == $LF) {
+ return i + 1;
+ }
+ break; // Not a white-space character.
+ }
+ return start;
+}
+
+int firstQuoteLength(String first, Quote quote) {
+ switch (quote) {
+ case Quote.Single:
+ case Quote.Double:
+ return 1;
+
+ case Quote.MultiLineSingle:
+ case Quote.MultiLineDouble:
+ return lengthOfOptionalWhitespacePrefix(first, 3);
+
+ case Quote.RawSingle:
+ case Quote.RawDouble:
+ return 2;
+
+ case Quote.RawMultiLineSingle:
+ case Quote.RawMultiLineDouble:
+ return lengthOfOptionalWhitespacePrefix(first, 4);
+ }
+ return internalError("Unhandled string quote: $quote");
+}
+
+int lastQuoteLength(Quote quote) {
+ switch (quote) {
+ case Quote.Single:
+ case Quote.Double:
+ case Quote.RawSingle:
+ case Quote.RawDouble:
+ return 1;
+
+ case Quote.MultiLineSingle:
+ case Quote.MultiLineDouble:
+ case Quote.RawMultiLineSingle:
+ case Quote.RawMultiLineDouble:
+ return 3;
+ }
+ return internalError("Unhandled string quote: $quote");
+}
+
+String unescapeFirstStringPart(String first, Quote quote) {
+ return unescape(first.substring(firstQuoteLength(first, quote)), quote);
+}
+
+String unescapeLastStringPart(String last, Quote quote) {
+ return unescape(last.substring(0, last.length - lastQuoteLength(quote)),
+ quote);
+}
+
+String unescapeString(String string) {
+ Quote quote = analyzeQuote(string);
+ return unescape(string.substring(
+ firstQuoteLength(string, quote), string.length - lastQuoteLength(quote)),
+ quote);
+}
+
+String unescape(String string, Quote quote) {
+ switch (quote) {
+ case Quote.Single:
+ case Quote.Double:
+ case Quote.MultiLineSingle:
+ case Quote.MultiLineDouble:
+ break;
+
+ case Quote.RawSingle:
+ case Quote.RawDouble:
+ case Quote.RawMultiLineSingle:
+ case Quote.RawMultiLineDouble:
+ return string;
+ }
+ return !string.contains("\\") ? string : unescapeCodeUnits(string.codeUnits);
+}
+
+const String incompleteSequence = "Incomplete escape sequence.";
+
+const String invalidCharacter = "Invalid character in escape sequence.";
+
+const String invalidCodePoint = "Invalid code point.";
+
+// Note: based on
+// [StringValidator.validateString](pkg/compiler/lib/src/string_validator.dart).
+String unescapeCodeUnits(List<int> codeUnits) {
+ // Can't use Uint8List or Uint16List here, the code units may be larger.
+ List<int> result = new List<int>(codeUnits.length);
+ int resultOffset = 0;
+ error(int offset, String message) {
+ inputError(null, null, message);
+ }
+ for (int i = 0; i < codeUnits.length; i++) {
+ int code = codeUnits[i];
+ if (code == $BACKSLASH) {
+ if (codeUnits.length == ++i) return error(i, incompleteSequence);
+ code = codeUnits[i];
+ /// `\n` for newline, equivalent to `\x0A`.
+ /// `\r` for carriage return, equivalent to `\x0D`.
+ /// `\f` for form feed, equivalent to `\x0C`.
+ /// `\b` for backspace, equivalent to `\x08`.
+ /// `\t` for tab, equivalent to `\x09`.
+ /// `\v` for vertical tab, equivalent to `\x0B`.
+ /// `\xXX` for hex escape.
+ /// `\uXXXX` or `\u{XX?X?X?X?X?}` for Unicode hex escape.
+ if (code == $n) {
+ code = $LF;
+ } else if (code == $r) {
+ code = $CR;
+ } else if (code == $f) {
+ code = $FF;
+ } else if (code == $b) {
+ code = $BS;
+ } else if (code == $t) {
+ code = $TAB;
+ } else if (code == $v) {
+ code = $VTAB;
+ } else if (code == $x) {
+ // Expect exactly 2 hex digits.
+ if (codeUnits.length <= i + 2) return error(i, incompleteSequence);
+ code = 0;
+ for (int j = 0; j < 2; j++) {
+ int digit = codeUnits[++i];
+ if (!isHexDigit(digit)) return error(i, invalidCharacter);
+ code = (code << 4) + hexDigitValue(digit);
+ }
+ } else if (code == $u) {
+ if (codeUnits.length == i + 1) return error(i, incompleteSequence);
+ code = codeUnits[i + 1];
+ if (code == $OPEN_CURLY_BRACKET) {
+ // Expect 1-6 hex digits followed by '}'.
+ if (codeUnits.length == ++i) return error(i, incompleteSequence);
+ code = 0;
+ for (int j = 0; j < 7; j++) {
+ if (codeUnits.length == ++i) return error(i, incompleteSequence);
+ int digit = codeUnits[i];
+ if (j != 0 && digit == $CLOSE_CURLY_BRACKET) break;
+ if (!isHexDigit(digit)) return error(i, invalidCharacter);
+ code = (code << 4) + hexDigitValue(digit);
+ }
+ } else {
+ // Expect exactly 4 hex digits.
+ if (codeUnits.length < i + 4) return error(i, incompleteSequence);
+ code = 0;
+ for (int j = 0; j < 4; j++) {
+ int digit = codeUnits[i];
+ if (!isHexDigit(digit)) return error(i, invalidCharacter);
+ code = (code << 4) + hexDigitValue(digit);
+ }
+ }
+ } else {
+ // Nothing, escaped character is passed through;
+ }
+ if (code > 0x10FFFF) return error(i, invalidCodePoint);
+ }
+ result[resultOffset++] = code;
+ }
+ return new String.fromCharCodes(result, 0, resultOffset);
+}
« no previous file with comments | « pkg/fasta/lib/src/modifier.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698