другая не может вмешаться в её действия (не может её завершить)
def parse_statement(self, tokens: list[token], startpos: int) -> tuple[SyntaxNode, int]:
"""tokens - список токенов из лексера. startpos - номер текущего токена.
Возвращаем собранный синтаксический узел и номер токена, до которого мы продвинулись."""
# перебираем варианты, что может встретиться там, где есть оператор
for variant in (self.parse_if, self.parse_assignment, ...):
try:
node, newpos = variant(tokens, startpos)
except MySyntaxError: # твоё исключение, сигнализирующее об ошибке в синтаксисе
pass # вариант не подошел, пробуем еще один
else:
return node, newpos
# если дошли сюда - ни один вариант не подошёл, нам дали какой-то неправильный код
# К слову, токенизатор должен записать позицию токена в исходном коде в сам токен.
raise MySyntaxError(...) # тут информация об ошибке синтаксиса
def parse_if(self, tokens: list[token], startpos: int) -> tuple[SyntaxNode, int]:
"""Этот метод пытается разобрать ветвление. У всех таких методов одинаковая сигнатура."""
if startpos >= len(tokens) or tokens[startpos]['type'] != 'if': # проверяем что начинается с if
raise MySyntaxError(...) # не начинается - отказ
startpos += 1
condition_node, startpos = self.parse_expression(tokens, startpos) # парсим выражение-условие
# может иметь смысл сделать подпрограмму или что-то подобное для такой проверки
if startpos >= len(tokens) or tokens[startpos]['type'] != ':': # проверяем что дальше двоеточие
raise MySyntaxError(...) # нет - отказ
startpos += 1
then_node, startpos = self.parse_statement(tokens, startpos) # парсим ветку then
# ну и так далее
...
# в конце собираем узел SyntaxNodeIf и возвращаем
return SyntaxNodeIf(condition_node, then_node, else_node), startpos
# далее по аналогии пишем методы parse_expression(), parse_assignment() и другие какие надо