| 542 | self._scanner_generated_lines: frozenset[int] = frozenset() |
| 543 | |
| 544 | def node_stack(self) -> PeekStack[Node]: |
| 545 | try: |
| 546 | tree = ast_parse( |
| 547 | self.extractor.contents or "", |
| 548 | filename=self.filepath, |
| 549 | suppress_warnings=False, |
| 550 | ) |
| 551 | return PeekStack(iter(tree.body)) |
| 552 | except SyntaxError: |
| 553 | # File has syntax errors — use scanner to recover individual cells. |
| 554 | # Never re-raise: parse_notebook must return a best-effort result |
| 555 | # so --watch and IPC are never broken by a syntax error. |
| 556 | from marimo._ast.scanner import scan_parse_fallback |
| 557 | |
| 558 | nodes, scanner_lines = scan_parse_fallback( |
| 559 | self.extractor.contents or "", self.filepath |
| 560 | ) |
| 561 | self._scanner_generated_lines = scanner_lines |
| 562 | return PeekStack(iter(nodes)) |
| 563 | |
| 564 | def parse_header(self, body: PeekStack[Node]) -> ParseResult[Header]: |
| 565 | # header? = (docstring | comments)* |