* Return the next token, or null.
()
| 189 | re.lastIndex = this.pos; |
| 190 | } else { |
| 191 | re.lastIndex = |
| 192 | this.offsets![this.pos < this.s.length ? this.pos : this.s.length]; |
| 193 | } |
| 194 | const execResult = re.exec(this.joined); |
| 195 | if (execResult?.[0]) { |
| 196 | this.pos += execResult[0].length; |
| 197 | return execResult[0]; |
| 198 | } |
| 199 | return null; |
| 200 | } |
| 201 | /** |
| 202 | * Return the next token, or null. |
| 203 | */ |
| 204 | next(): Token | null { |
| 205 | // If we've reached the end, exit |
| 206 | if (this.end()) return null; |
| 207 | // Handle white space |
| 208 | // In text mode, spaces are significant, |
| 209 | // however they are coalesced unless \obeyspaces |
| 210 | if (!this.obeyspaces && this.match(/^[ \f\n\r\t\v\xA0\u2028\u2029]+/)) { |
| 211 | // Note that browsers are inconsistent in their definitions of the |
| 212 | // `\s` metacharacter, so we use an explicit pattern instead. |
| 213 | |
| 214 | // - IE: `[ \f\n\r\t\v]` |
| 215 | // - Chrome: `[ \f\n\r\t\v\u00A0]` |
| 216 | // - Firefox: `[ \f\n\r\t\v\u00A0\u2028\u2029]` |
| 217 | // - \f \u000C: form feed (FORM FEED) |
| 218 | // - \n \u000A: linefeed (LINE FEED) |
| 219 | // - \r \u000D: carriage return |
| 220 | // - \t \u0009: tab (CHARACTER TABULATION) |
| 221 | // - \v \u000B: vertical tab (LINE TABULATION) |
| 222 | // - \u00A0: NON-BREAKING SPACE |
| 223 | // - \u2028: LINE SEPARATOR |
| 224 | // - \u2029: PARAGRAPH SEPARATOR |
| 225 | return '<space>'; |
| 226 | } else if ( |
| 227 | this.obeyspaces && |
| 228 | this.match(/^[ \f\n\r\t\v\xA0\u2028\u2029]/) |
| 229 | ) { |
| 230 | // Don't coalesce when this.obeyspaces is true (different regex from above) |
| 231 | return '<space>'; |
| 232 | } |
| 233 | const next = this.get(); |
| 234 | // Is it a command? |
| 235 | if (next === '\\') { |
| 236 | if (!this.end()) { |
| 237 | // A command is either a string of letters (control word)... |
| 238 | let command = this.match(/^[a-zA-Z]+/); |
| 239 | if (command) { |
| 240 | // Spaces after a 'control word' are ignored |
| 241 | // (but not after a 'control symbol' (single char) |
| 242 | this.match(/^[ \f\n\r\t\v\xA0\u2028\u2029]*/); |
| 243 | } else { |
| 244 | // ... or a single non-letter character (control char) |
| 245 | command = this.get(); |
| 246 | if (command === ' ') { |
| 247 | // The `\ ` command is equivalent to a single space |
| 248 | return '<space>'; |
no test coverage detected