| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style licenset hat can be found in the LICENSE file. |
| 4 |
| 5 library dart_scanner.error_token; |
| 6 |
| 7 // TODO(ahe): ErrorKind doesn't belong in dart_parser. Move to compiler_util or |
| 8 // this package? |
| 9 import '../parser/error_kind.dart' show |
| 10 ErrorKind; |
| 11 |
| 12 import '../scanner.dart' show |
| 13 BeginGroupToken, |
| 14 Token, |
| 15 unicodeReplacementCharacter; |
| 16 |
| 17 import 'precedence.dart' show |
| 18 BAD_INPUT_INFO, |
| 19 PrecedenceInfo; |
| 20 |
| 21 export '../parser/error_kind.dart' show |
| 22 ErrorKind; |
| 23 |
| 24 ErrorToken buildUnexpectedCharacterToken(int character, int charOffset) { |
| 25 if (character < 0x1f) { |
| 26 return new AsciiControlCharacterToken(character, charOffset); |
| 27 } |
| 28 switch (character) { |
| 29 case unicodeReplacementCharacter: |
| 30 return new EncodingErrorToken(charOffset); |
| 31 |
| 32 /// See [General Punctuation] |
| 33 /// (http://www.unicode.org/charts/PDF/U2000.pdf). |
| 34 case 0x00A0: // No-break space. |
| 35 case 0x1680: // Ogham space mark. |
| 36 case 0x180E: // Mongolian vowel separator. |
| 37 case 0x2000: // En quad. |
| 38 case 0x2001: // Em quad. |
| 39 case 0x2002: // En space. |
| 40 case 0x2003: // Em space. |
| 41 case 0x2004: // Three-per-em space. |
| 42 case 0x2005: // Four-per-em space. |
| 43 case 0x2006: // Six-per-em space. |
| 44 case 0x2007: // Figure space. |
| 45 case 0x2008: // Punctuation space. |
| 46 case 0x2009: // Thin space. |
| 47 case 0x200A: // Hair space. |
| 48 case 0x200B: // Zero width space. |
| 49 case 0x2028: // Line separator. |
| 50 case 0x2029: // Paragraph separator. |
| 51 case 0x202F: // Narrow no-break space. |
| 52 case 0x205F: // Medium mathematical space. |
| 53 case 0x3000: // Ideographic space. |
| 54 case 0xFEFF: // Zero width no-break space. |
| 55 return new NonAsciiWhitespaceToken(character, charOffset); |
| 56 |
| 57 default: |
| 58 return new NonAsciiIdentifierToken(character, charOffset); |
| 59 } |
| 60 } |
| 61 |
| 62 /// Common superclass for all error tokens. |
| 63 /// |
| 64 /// It's considered an implementation error to access [value] of an |
| 65 /// [ErrorToken]. |
| 66 abstract class ErrorToken extends Token { |
| 67 ErrorToken(int charOffset) : super(charOffset); |
| 68 |
| 69 PrecedenceInfo get info => BAD_INPUT_INFO; |
| 70 |
| 71 String get value => throw assertionMessage; |
| 72 |
| 73 String get stringValue => null; |
| 74 |
| 75 bool isIdentifier() => false; |
| 76 |
| 77 String get assertionMessage; |
| 78 |
| 79 ErrorKind get errorCode; |
| 80 |
| 81 int get character => null; |
| 82 |
| 83 String get start => null; |
| 84 |
| 85 int get endOffset => null; |
| 86 |
| 87 BeginGroupToken get begin => null; |
| 88 } |
| 89 |
| 90 /// Represents an encoding error. |
| 91 class EncodingErrorToken extends ErrorToken { |
| 92 EncodingErrorToken(int charOffset) : super(charOffset); |
| 93 |
| 94 String toString() => "EncodingErrorToken()"; |
| 95 |
| 96 String get assertionMessage => "Unable to decode bytes as UTF-8."; |
| 97 |
| 98 ErrorKind get errorCode => ErrorKind.Encoding; |
| 99 } |
| 100 |
| 101 /// Represents a non-ASCII character outside a string or comment. |
| 102 class NonAsciiIdentifierToken extends ErrorToken { |
| 103 final int character; |
| 104 |
| 105 NonAsciiIdentifierToken(this.character, int charOffset) : super(charOffset); |
| 106 |
| 107 String toString() => "NonAsciiIdentifierToken($character)"; |
| 108 |
| 109 String get assertionMessage { |
| 110 String c = new String.fromCharCodes([character]); |
| 111 String hex = character.toRadixString(16); |
| 112 String padding = "0000".substring(hex.length); |
| 113 hex = "$padding$hex"; |
| 114 return |
| 115 "The non-ASCII character '$c' (U+$hex) can't be used in identifiers," |
| 116 " only in strings and comments.\n" |
| 117 "Try using an US-ASCII letter, a digit, '_' (an underscore)," |
| 118 " or '\$' (a dollar sign)."; |
| 119 } |
| 120 |
| 121 ErrorKind get errorCode => ErrorKind.NonAsciiIdentifier; |
| 122 } |
| 123 |
| 124 /// Represents a non-ASCII whitespace outside a string or comment. |
| 125 class NonAsciiWhitespaceToken extends ErrorToken { |
| 126 final int character; |
| 127 |
| 128 NonAsciiWhitespaceToken(this.character, int charOffset) : super(charOffset); |
| 129 |
| 130 String toString() => "NonAsciiWhitespaceToken($character)"; |
| 131 |
| 132 String get assertionMessage { |
| 133 String hex = character.toRadixString(16); |
| 134 return "The non-ASCII space character U+$hex can only be used in strings " |
| 135 "and comments."; |
| 136 } |
| 137 |
| 138 ErrorKind get errorCode => ErrorKind.NonAsciiWhitespace; |
| 139 } |
| 140 |
| 141 /// Represents an ASCII control character outside a string or comment. |
| 142 class AsciiControlCharacterToken extends ErrorToken { |
| 143 final int character; |
| 144 |
| 145 AsciiControlCharacterToken(this.character, int charOffset) |
| 146 : super(charOffset); |
| 147 |
| 148 String toString() => "AsciiControlCharacterToken($character)"; |
| 149 |
| 150 String get assertionMessage { |
| 151 String hex = character.toRadixString(16); |
| 152 return "The control character U+$hex can only be used in strings and " |
| 153 "comments."; |
| 154 } |
| 155 |
| 156 ErrorKind get errorCode => ErrorKind.AsciiControlCharacter; |
| 157 } |
| 158 |
| 159 /// Represents an unterminated string. |
| 160 class UnterminatedToken extends ErrorToken { |
| 161 final String start; |
| 162 final int endOffset; |
| 163 |
| 164 UnterminatedToken(this.start, int charOffset, this.endOffset) |
| 165 : super(charOffset); |
| 166 |
| 167 String toString() => "UnterminatedToken($start)"; |
| 168 |
| 169 String get assertionMessage => "'$start' isn't terminated."; |
| 170 |
| 171 int get charCount => endOffset - charOffset; |
| 172 |
| 173 ErrorKind get errorCode { |
| 174 switch (start) { |
| 175 case '1e': |
| 176 return ErrorKind.MissingExponent; |
| 177 |
| 178 case '"': |
| 179 case "'": |
| 180 case '"""': |
| 181 case "'''": |
| 182 case 'r"': |
| 183 case "r'": |
| 184 case 'r"""': |
| 185 case "r'''": |
| 186 return ErrorKind.UnterminatedString; |
| 187 |
| 188 case '0x': |
| 189 return ErrorKind.ExpectedHexDigit; |
| 190 |
| 191 case r'$': |
| 192 return ErrorKind.UnexpectedDollarInString; |
| 193 |
| 194 case '/*': |
| 195 return ErrorKind.UnterminatedComment; |
| 196 |
| 197 default: |
| 198 return ErrorKind.UnterminatedToken; |
| 199 } |
| 200 } |
| 201 } |
| 202 |
| 203 /// Represents an open brace without a matching close brace. |
| 204 /// |
| 205 /// In this case, brace means any of `(`, `{`, `[`, and `<`, parenthesis, curly |
| 206 /// brace, square brace, and angle brace, respectively. |
| 207 class UnmatchedToken extends ErrorToken { |
| 208 final BeginGroupToken begin; |
| 209 |
| 210 UnmatchedToken(BeginGroupToken begin) |
| 211 : this.begin = begin, |
| 212 super(begin.charOffset); |
| 213 |
| 214 String toString() => "UnmatchedToken(${begin.value})"; |
| 215 |
| 216 String get assertionMessage => "'$begin' isn't closed."; |
| 217 |
| 218 ErrorKind get errorCode => ErrorKind.UnmatchedToken; |
| 219 } |
| OLD | NEW |