start: root_path path* root_path: (literal | index_path | append_path) literal: TEXT | NUMBER path: key_path | index_path | append_path key_path: LEFT_BRACKET TEXT RIGHT_BRACKET index_path: LEFT_BRACKET NUMBER RIGHT_BRACKET append_path: LEFT_BRAC
(source: str)
| 21 | |
| 22 | |
| 23 | def parse(source: str) -> Iterator[Path]: |
| 24 | """ |
| 25 | start: root_path path* |
| 26 | root_path: (literal | index_path | append_path) |
| 27 | literal: TEXT | NUMBER |
| 28 | |
| 29 | path: |
| 30 | key_path |
| 31 | | index_path |
| 32 | | append_path |
| 33 | key_path: LEFT_BRACKET TEXT RIGHT_BRACKET |
| 34 | index_path: LEFT_BRACKET NUMBER RIGHT_BRACKET |
| 35 | append_path: LEFT_BRACKET RIGHT_BRACKET |
| 36 | |
| 37 | """ |
| 38 | |
| 39 | tokens = list(tokenize(source)) |
| 40 | cursor = 0 |
| 41 | |
| 42 | def can_advance(): |
| 43 | return cursor < len(tokens) |
| 44 | |
| 45 | # noinspection PyShadowingNames |
| 46 | def expect(*kinds): |
| 47 | nonlocal cursor |
| 48 | assert kinds |
| 49 | if can_advance(): |
| 50 | token = tokens[cursor] |
| 51 | cursor += 1 |
| 52 | if token.kind in kinds: |
| 53 | return token |
| 54 | elif tokens: |
| 55 | token = tokens[-1]._replace( |
| 56 | start=tokens[-1].end + 0, |
| 57 | end=tokens[-1].end + 1, |
| 58 | ) |
| 59 | else: |
| 60 | token = None |
| 61 | if len(kinds) == 1: |
| 62 | suffix = kinds[0].to_name() |
| 63 | else: |
| 64 | suffix = ', '.join(kind.to_name() for kind in kinds[:-1]) |
| 65 | suffix += ' or ' + kinds[-1].to_name() |
| 66 | message = f'Expecting {suffix}' |
| 67 | raise NestedJSONSyntaxError(source, token, message) |
| 68 | |
| 69 | # noinspection PyShadowingNames |
| 70 | def parse_root(): |
| 71 | tokens = [] |
| 72 | if not can_advance(): |
| 73 | return Path( |
| 74 | kind=PathAction.KEY, |
| 75 | accessor=EMPTY_STRING, |
| 76 | is_root=True |
| 77 | ) |
| 78 | # (literal | index_path | append_path)? |
| 79 | token = expect(*LITERAL_TOKENS, TokenKind.LEFT_BRACKET) |
| 80 | tokens.append(token) |