Appearance
| 1 | namespace Syntax.Parsers.Definitions is | |
| 2 | use Source | |
| 3 | ||
| 4 | // Where a definition list picks up again after a definition it could | |
| 5 | // not parse. The tokens between the mistake and the next definition | |
| 6 | // belong to the definition that went wrong, so reading each of them as | |
| 7 | // a definition of its own reports the one mistake once per token and | |
| 8 | // takes whatever it can make of the rest - a damaged header's body read | |
| 9 | // as members, say. | |
| 10 | // | |
| 11 | // So the list skips them, reporting nothing, and resumes at: | |
| 12 | // | |
| 13 | // a token some construct still being parsed would end at, read from | |
| 14 | // those parsers as the statement layer reads it (see | |
| 15 | // CONTEXT._awaited_enders) - the `si` of the enclosing type or | |
| 16 | // namespace, which the list itself must see; | |
| 17 | // a keyword that can only begin a definition, wherever it stands; | |
| 18 | // the start of a line, since the rest of the line the mistake is on | |
| 19 | // belongs to the definition that went wrong, and a later line is | |
| 20 | // read as whatever it is. | |
| 21 | // | |
| 22 | // Nothing is counted: the source being recovered from is | |
| 23 | // incomplete, so a count taken from its brackets is a count of the | |
| 24 | // mistake. | |
| 25 | class DEFINITION_RESYNC is | |
| 26 | init() is si | |
| 27 | ||
| 28 | // After a definition attempt that started at `attempt_start` with | |
| 29 | // `errors_before` errors logged. | |
| 30 | recover(context: CONTEXT, attempt_start: LOCATION, errors_before: int) is | |
| 31 | if context.logger.error_count == errors_before then | |
| 32 | return | |
| 33 | fi | |
| 34 | ||
| 35 | // An attempt that consumed nothing has to be moved past, or the | |
| 36 | // list would try the same parse at the same place again. | |
| 37 | let consumed mut = context.location.start != attempt_start.start | |
| 38 | ||
| 39 | while !context.is_end_of_file do | |
| 40 | if context.is_awaited_ender(context.current_token) then | |
| 41 | break | |
| 42 | fi | |
| 43 | ||
| 44 | if consumed /\ _at_resync_point(context) then | |
| 45 | break | |
| 46 | fi | |
| 47 | ||
| 48 | context.next_token() | |
| 49 | ||
| 50 | consumed = true | |
| 51 | od | |
| 52 | si | |
| 53 | ||
| 54 | _at_resync_point(context: CONTEXT) -> bool => | |
| 55 | _starts_only_a_definition(context.current_token) \/ context.current.first_on_line | |
| 56 | ||
| 57 | _starts_only_a_definition(token: Lexical.TOKEN) -> bool => | |
| 58 | token == Lexical.TOKEN.NAMESPACE \/ | |
| 59 | token == Lexical.TOKEN.USE \/ | |
| 60 | token == Lexical.TOKEN.CLASS \/ | |
| 61 | token == Lexical.TOKEN.TRAIT \/ | |
| 62 | token == Lexical.TOKEN.STRUCT \/ | |
| 63 | token == Lexical.TOKEN.PARTIAL \/ | |
| 64 | token == Lexical.TOKEN.IMPL \/ | |
| 65 | token == Lexical.TOKEN.UNION \/ | |
| 66 | token == Lexical.TOKEN.ENUM \/ | |
| 67 | token == Lexical.TOKEN.AT | |
| 68 | si | |
| 69 | si |