(self)
| 89 | return ParseError(message, token.line, token.column) |
| 90 | |
| 91 | def parse(self) -> ProtoSchema: |
| 92 | syntax = None |
| 93 | package = None |
| 94 | imports: List[str] = [] |
| 95 | enums: List[ProtoEnum] = [] |
| 96 | messages: List[ProtoMessage] = [] |
| 97 | services: List[ProtoService] = [] |
| 98 | options = {} |
| 99 | |
| 100 | while not self.at_end(): |
| 101 | if self.check(TokenType.SYNTAX): |
| 102 | if syntax is not None: |
| 103 | raise self.error("Duplicate syntax declaration") |
| 104 | syntax = self.parse_syntax() |
| 105 | elif self.check(TokenType.PACKAGE): |
| 106 | if package is not None: |
| 107 | raise self.error("Duplicate package declaration") |
| 108 | package = self.parse_package() |
| 109 | elif self.check(TokenType.IMPORT): |
| 110 | path = self.parse_import() |
| 111 | normalized_path = path.lstrip("/") |
| 112 | if not normalized_path.startswith("google/protobuf/"): |
| 113 | imports.append(path) |
| 114 | elif self.check(TokenType.OPTION): |
| 115 | name, value = self.parse_option_statement() |
| 116 | options[name] = value |
| 117 | elif self.check(TokenType.MESSAGE): |
| 118 | messages.append(self.parse_message()) |
| 119 | elif self.check(TokenType.ENUM): |
| 120 | enums.append(self.parse_enum()) |
| 121 | elif self.check(TokenType.SERVICE): |
| 122 | services.append(self.parse_service()) |
| 123 | elif self.check(TokenType.SEMI): |
| 124 | self.advance() |
| 125 | else: |
| 126 | raise self.error(f"Unexpected token: {self.current().value}") |
| 127 | |
| 128 | if syntax is None: |
| 129 | raise self.error('Missing syntax declaration (syntax = "proto3";)') |
| 130 | if syntax != "proto3": |
| 131 | raise self.error(f"Unsupported syntax '{syntax}', only proto3 is supported") |
| 132 | |
| 133 | return ProtoSchema( |
| 134 | syntax=syntax, |
| 135 | package=package, |
| 136 | imports=imports, |
| 137 | enums=enums, |
| 138 | messages=messages, |
| 139 | services=services, |
| 140 | options=options, |
| 141 | source_file=self.filename, |
| 142 | ) |
| 143 | |
| 144 | def parse_syntax(self) -> str: |
| 145 | self.consume(TokenType.SYNTAX, "Expected 'syntax'") |
no test coverage detected