Reorganize the parser/AST code

The code is now organized by syntax: `menu {}` in one file, `style` in
another, etc. This should make it easier to add syntax in the future.
This commit is contained in:
James Westman 2021-10-31 21:41:44 -05:00
parent dc7c0cabd8
commit bfd9daf6a9
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
10 changed files with 486 additions and 344 deletions

View file

@ -0,0 +1,73 @@
# completions_utils.py
#
# Copyright 2021 James Westman <james@jwestman.net>
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 3 of the
# License, or (at your option) any later version.
#
# This file is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: LGPL-3.0-or-later
import typing as T
from . import ast
from .tokenizer import Token, TokenType
from .lsp_utils import Completion
new_statement_patterns = [
[(TokenType.OPEN_BLOCK, None)],
[(TokenType.CLOSE_BLOCK, None)],
[(TokenType.STMT_END, None)],
]
def applies_to(*ast_types):
""" Decorator describing which AST nodes the completer should apply in. """
def decorator(func):
for c in ast_types:
c.completers.append(func)
return func
return decorator
def completer(applies_in: T.List, matches: T.List=[]):
def decorator(func):
def inner(prev_tokens: T.List[Token], ast_node: ast.AstNode):
any_match = len(matches) == 0
match_variables: T.List[str] = []
for pattern in matches:
match_variables = []
if len(pattern) <= len(prev_tokens):
for i in range(0, len(pattern)):
type, value = pattern[i]
token = prev_tokens[i - len(pattern)]
if token.type != type or (value is not None and str(token) != value):
break
if value is None:
match_variables.append(str(token))
else:
any_match = True
break
if not any_match:
return
yield from func(ast_node, match_variables)
for c in applies_in:
c.completers.append(inner)
return inner
return decorator