mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
Fix type checker errors
This commit is contained in:
parent
b387d4114f
commit
b9068e24ab
7 changed files with 35 additions and 18 deletions
|
@ -88,6 +88,8 @@ class AstNode:
|
||||||
if docs is not None:
|
if docs is not None:
|
||||||
return docs
|
return docs
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class UI(AstNode):
|
class UI(AstNode):
|
||||||
""" The AST node for the entire file """
|
""" The AST node for the entire file """
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
|
import typing as T
|
||||||
import sys, traceback
|
import sys, traceback
|
||||||
from . import utils
|
from . import utils
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ class CompileError(PrintableError):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
def _did_you_mean(self, word: str, options: [str]):
|
def _did_you_mean(self, word: str, options: T.List[str]):
|
||||||
if word.replace("_", "-") in options:
|
if word.replace("_", "-") in options:
|
||||||
self.hint(f"use '-', not '_': `{word.replace('_', '-')}`")
|
self.hint(f"use '-', not '_': `{word.replace('_', '-')}`")
|
||||||
return
|
return
|
||||||
|
@ -98,11 +99,11 @@ class MultipleErrors(PrintableError):
|
||||||
a list and re-thrown using the MultipleErrors exception. It will
|
a list and re-thrown using the MultipleErrors exception. It will
|
||||||
pretty-print all of the errors and a count of how many errors there are. """
|
pretty-print all of the errors and a count of how many errors there are. """
|
||||||
|
|
||||||
def __init__(self, errors: [CompileError]):
|
def __init__(self, errors: T.List[CompileError]):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.errors = errors
|
self.errors = errors
|
||||||
|
|
||||||
def pretty_print(self, filename, code) -> str:
|
def pretty_print(self, filename, code) -> None:
|
||||||
for error in self.errors:
|
for error in self.errors:
|
||||||
error.pretty_print(filename, code)
|
error.pretty_print(filename, code)
|
||||||
if len(self.errors) != 1:
|
if len(self.errors) != 1:
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
import typing as T
|
||||||
import os, sys
|
import os, sys
|
||||||
|
|
||||||
from .errors import CompileError, CompilerBugError
|
from .errors import CompileError, CompilerBugError
|
||||||
|
@ -24,7 +25,7 @@ from .utils import lazy_prop
|
||||||
from . import xml_reader
|
from . import xml_reader
|
||||||
|
|
||||||
|
|
||||||
extra_search_paths = []
|
extra_search_paths: T.List[str] = []
|
||||||
_namespace_cache = {}
|
_namespace_cache = {}
|
||||||
|
|
||||||
_search_paths = []
|
_search_paths = []
|
||||||
|
@ -71,7 +72,7 @@ class GirNode:
|
||||||
return self.xml.get("version")
|
return self.xml.get("version")
|
||||||
|
|
||||||
@lazy_prop
|
@lazy_prop
|
||||||
def doc(self) -> str:
|
def doc(self) -> T.Optional[str]:
|
||||||
el = self.xml.get_elements("doc")
|
el = self.xml.get_elements("doc")
|
||||||
if len(el) != 1:
|
if len(el) != 1:
|
||||||
return None
|
return None
|
||||||
|
@ -175,7 +176,7 @@ class Repository(GirNode):
|
||||||
try:
|
try:
|
||||||
self.includes = { include["name"]: get_namespace(include["name"], include["version"]) for include in xml.get_elements("include") }
|
self.includes = { include["name"]: get_namespace(include["name"], include["version"]) for include in xml.get_elements("include") }
|
||||||
except:
|
except:
|
||||||
raise CompilerBugError(f"Failed to load dependencies of {namespace}-{version}")
|
raise CompilerBugError(f"Failed to load dependencies.")
|
||||||
|
|
||||||
def lookup_namespace(self, name: str):
|
def lookup_namespace(self, name: str):
|
||||||
ns = self.namespaces.get(name)
|
ns = self.namespaces.get(name)
|
||||||
|
@ -195,7 +196,7 @@ class GirContext:
|
||||||
def add_namespace(self, namespace: Namespace):
|
def add_namespace(self, namespace: Namespace):
|
||||||
other = self.namespaces.get(namespace.name)
|
other = self.namespaces.get(namespace.name)
|
||||||
if other is not None and other.version != namespace.version:
|
if other is not None and other.version != namespace.version:
|
||||||
raise CompileError(f"Namespace {namespace}-{version} can't be imported because version {other.version} was imported earlier")
|
raise CompileError(f"Namespace {namespace.name}-{namespace.version} can't be imported because version {other.version} was imported earlier")
|
||||||
|
|
||||||
self.namespaces[namespace.name] = namespace
|
self.namespaces[namespace.name] = namespace
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
|
import typing as T
|
||||||
import json, sys, traceback
|
import json, sys, traceback
|
||||||
|
|
||||||
from .errors import PrintableError, CompileError, MultipleErrors
|
from .errors import PrintableError, CompileError, MultipleErrors
|
||||||
|
@ -33,7 +34,7 @@ def command(json_method):
|
||||||
|
|
||||||
|
|
||||||
class LanguageServer:
|
class LanguageServer:
|
||||||
commands = {}
|
commands: T.Dict[str, T.Callable[[LanguageServer, T.Union[str, int], T.Any], None]] = {}
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.client_capabilities = {}
|
self.client_capabilities = {}
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
|
|
||||||
""" Utilities for parsing an AST from a token stream. """
|
""" Utilities for parsing an AST from a token stream. """
|
||||||
|
|
||||||
|
import typing as T
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from .ast import AstNode
|
from .ast import AstNode
|
||||||
|
@ -27,7 +30,12 @@ from .tokenizer import Token, TokenType
|
||||||
|
|
||||||
|
|
||||||
_SKIP_TOKENS = [TokenType.COMMENT, TokenType.WHITESPACE]
|
_SKIP_TOKENS = [TokenType.COMMENT, TokenType.WHITESPACE]
|
||||||
_RECOVER_TOKENS = [TokenType.COMMENT, TokenType.STMT_END, TokenType.CLOSE_BLOCK, TokenType.EOF]
|
_RECOVER_TOKENS = [
|
||||||
|
TokenType.COMMENT,
|
||||||
|
TokenType.STMT_END,
|
||||||
|
TokenType.CLOSE_BLOCK,
|
||||||
|
TokenType.EOF,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ParseResult(Enum):
|
class ParseResult(Enum):
|
||||||
|
@ -59,9 +67,9 @@ class ParseGroup:
|
||||||
|
|
||||||
def __init__(self, ast_type, start: int):
|
def __init__(self, ast_type, start: int):
|
||||||
self.ast_type = ast_type
|
self.ast_type = ast_type
|
||||||
self.children = {}
|
self.children: T.Dict[str, T.List[ParseGroup]] = defaultdict()
|
||||||
self.keys = {}
|
self.keys: T.Dict[str, T.Any] = {}
|
||||||
self.tokens = {}
|
self.tokens: T.Dict[str, Token] = {}
|
||||||
self.start = start
|
self.start = start
|
||||||
self.end = None
|
self.end = None
|
||||||
|
|
||||||
|
@ -195,6 +203,9 @@ class ParseNode:
|
||||||
else:
|
else:
|
||||||
return ParseResult.FAILURE
|
return ParseResult.FAILURE
|
||||||
|
|
||||||
|
def _parse(self, ctx: ParseContext) -> bool:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
def err(self, message):
|
def err(self, message):
|
||||||
""" Causes this ParseNode to raise an exception if it fails to parse.
|
""" Causes this ParseNode to raise an exception if it fails to parse.
|
||||||
This prevents the parser from backtracking, so you should understand
|
This prevents the parser from backtracking, so you should understand
|
||||||
|
@ -346,7 +357,7 @@ class Optional(ParseNode):
|
||||||
class StaticToken(ParseNode):
|
class StaticToken(ParseNode):
|
||||||
""" Base class for ParseNodes that match a token type without inspecting
|
""" Base class for ParseNodes that match a token type without inspecting
|
||||||
the token's contents. """
|
the token's contents. """
|
||||||
token_type = None
|
token_type: T.Optional[TokenType] = None
|
||||||
|
|
||||||
def _parse(self, ctx: ParseContext) -> bool:
|
def _parse(self, ctx: ParseContext) -> bool:
|
||||||
return ctx.next_token().type == self.token_type
|
return ctx.next_token().type == self.token_type
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
|
||||||
|
import typing as T
|
||||||
import re
|
import re
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ class TokenType(Enum):
|
||||||
COMMA = 15
|
COMMA = 15
|
||||||
|
|
||||||
|
|
||||||
_TOKENS = [
|
_tokens = [
|
||||||
(TokenType.DIRECTIVE, r"@[\d\w\-_]+"),
|
(TokenType.DIRECTIVE, r"@[\d\w\-_]+"),
|
||||||
(TokenType.IDENT, r"[A-Za-z_][\d\w\-_]*"),
|
(TokenType.IDENT, r"[A-Za-z_][\d\w\-_]*"),
|
||||||
(TokenType.QUOTED, r'"(\\"|[^"\n])+"'),
|
(TokenType.QUOTED, r'"(\\"|[^"\n])+"'),
|
||||||
|
@ -63,7 +64,7 @@ _TOKENS = [
|
||||||
(TokenType.OP, r"[:=\.=\|<>\+\-/\*]+"),
|
(TokenType.OP, r"[:=\.=\|<>\+\-/\*]+"),
|
||||||
(TokenType.COMMA, r"\,"),
|
(TokenType.COMMA, r"\,"),
|
||||||
]
|
]
|
||||||
_TOKENS = [(type, re.compile(regex)) for (type, regex) in _TOKENS]
|
_TOKENS = [(type, re.compile(regex)) for (type, regex) in _tokens]
|
||||||
|
|
||||||
|
|
||||||
class Token:
|
class Token:
|
||||||
|
@ -111,5 +112,5 @@ def _tokenize(ui_ml: str):
|
||||||
yield Token(TokenType.EOF, i, i, ui_ml)
|
yield Token(TokenType.EOF, i, i, ui_ml)
|
||||||
|
|
||||||
|
|
||||||
def tokenize(data: str) -> [Token]:
|
def tokenize(data: str) -> T.List[Token]:
|
||||||
return list(_tokenize(data))
|
return list(_tokenize(data))
|
||||||
|
|
|
@ -32,7 +32,7 @@ def lazy_prop(func):
|
||||||
return real_func
|
return real_func
|
||||||
|
|
||||||
|
|
||||||
def did_you_mean(word: str, options: [str]) -> T.Optional[str]:
|
def did_you_mean(word: str, options: T.List[str]) -> T.Optional[str]:
|
||||||
if len(options) == 0:
|
if len(options) == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ def did_you_mean(word: str, options: [str]) -> T.Optional[str]:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def idx_to_pos(idx: int, text: str) -> (int, int):
|
def idx_to_pos(idx: int, text: str) -> T.Tuple[int, int]:
|
||||||
if idx == 0:
|
if idx == 0:
|
||||||
return (0, 0)
|
return (0, 0)
|
||||||
sp = text[:idx].splitlines(keepends=True)
|
sp = text[:idx].splitlines(keepends=True)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue