( scanner: Scanner, )
| 508 | } |
| 509 | |
| 510 | export function multilineBasicString( |
| 511 | scanner: Scanner, |
| 512 | ): ParseResult<string> { |
| 513 | scanner.skipWhitespaces(); |
| 514 | if (!scanner.startsWith('"""')) return failure(); |
| 515 | scanner.next(3); |
| 516 | if (scanner.char() === "\n") { |
| 517 | // The first newline (LF) is trimmed |
| 518 | scanner.next(); |
| 519 | } else if (scanner.startsWith("\r\n")) { |
| 520 | // The first newline (CRLF) is trimmed |
| 521 | scanner.next(2); |
| 522 | } |
| 523 | const acc: string[] = []; |
| 524 | while (!scanner.startsWith('"""') && !scanner.eof()) { |
| 525 | // line ending backslash |
| 526 | if (scanner.startsWith("\\\n")) { |
| 527 | scanner.next(); |
| 528 | scanner.nextUntilChar({ skipComments: false }); |
| 529 | continue; |
| 530 | } else if (scanner.startsWith("\\\r\n")) { |
| 531 | scanner.next(); |
| 532 | scanner.nextUntilChar({ skipComments: false }); |
| 533 | continue; |
| 534 | } |
| 535 | const escapedChar = escapeSequence(scanner); |
| 536 | if (escapedChar.ok) { |
| 537 | acc.push(escapedChar.body); |
| 538 | } else { |
| 539 | acc.push(scanner.char()); |
| 540 | scanner.next(); |
| 541 | } |
| 542 | } |
| 543 | |
| 544 | if (scanner.eof()) { |
| 545 | throw new SyntaxError( |
| 546 | `Multi-line string is not closed:\n${acc.join("")}`, |
| 547 | ); |
| 548 | } |
| 549 | // if ends with 4 `"`, push the fist `"` to string |
| 550 | if (scanner.char(3) === '"') { |
| 551 | acc.push('"'); |
| 552 | scanner.next(); |
| 553 | } |
| 554 | scanner.next(3); // skip last '"""" |
| 555 | return success(acc.join("")); |
| 556 | } |
| 557 | |
| 558 | export function multilineLiteralString( |
| 559 | scanner: Scanner, |
nothing calls this directly
no test coverage detected