types: Add UncheckedType

This allows us to remember information about an external type, such as
its name, while still marking it as unchecked.
This commit is contained in:
James Westman 2022-12-23 20:13:14 -06:00
parent f7aa7d0be2
commit 2033bd9e16
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
7 changed files with 55 additions and 11 deletions

View file

@ -120,7 +120,7 @@ def gtk_object_completer(ast_node, match_variables):
matches=new_statement_patterns, matches=new_statement_patterns,
) )
def property_completer(ast_node, match_variables): def property_completer(ast_node, match_variables):
if ast_node.gir_class: if ast_node.gir_class and not isinstance(ast_node.gir_class, gir.UncheckedType):
for prop in ast_node.gir_class.properties: for prop in ast_node.gir_class.properties:
yield Completion(prop, CompletionItemKind.Property, snippet=f"{prop}: $0;") yield Completion(prop, CompletionItemKind.Property, snippet=f"{prop}: $0;")
@ -144,7 +144,7 @@ def prop_value_completer(ast_node, match_variables):
matches=new_statement_patterns, matches=new_statement_patterns,
) )
def signal_completer(ast_node, match_variables): def signal_completer(ast_node, match_variables):
if ast_node.gir_class: if ast_node.gir_class and not isinstance(ast_node.gir_class, gir.UncheckedType):
for signal in ast_node.gir_class.signals: for signal in ast_node.gir_class.signals:
if not isinstance(ast_node.parent, language.Object): if not isinstance(ast_node.parent, language.Object):
name = "on" name = "on"

View file

@ -93,13 +93,36 @@ class GirType:
def doc(self): def doc(self):
return None return None
def assignable_to(self, other) -> bool: def assignable_to(self, other: "GirType") -> bool:
raise NotImplementedError() raise NotImplementedError()
@property @property
def full_name(self) -> str: def full_name(self) -> str:
"""The GIR name of the type to use in diagnostics"""
raise NotImplementedError() raise NotImplementedError()
@property
def glib_type_name(self) -> str:
"""The name of the type in the GObject type system, suitable to pass to `g_type_from_name()`."""
raise NotImplementedError()
class UncheckedType(GirType):
def __init__(self, name) -> None:
super().__init__()
self._name = name
def assignable_to(self, other: GirType) -> bool:
return True
@property
def full_name(self) -> str:
return self._name
@property
def glib_type_name(self) -> str:
return self._name
class BasicType(GirType): class BasicType(GirType):
name: str = "unknown type" name: str = "unknown type"
@ -111,6 +134,7 @@ class BasicType(GirType):
class BoolType(BasicType): class BoolType(BasicType):
name = "bool" name = "bool"
glib_type_name: str = "gboolean"
def assignable_to(self, other) -> bool: def assignable_to(self, other) -> bool:
return isinstance(other, BoolType) return isinstance(other, BoolType)
@ -118,6 +142,7 @@ class BoolType(BasicType):
class IntType(BasicType): class IntType(BasicType):
name = "int" name = "int"
glib_type_name: str = "gint"
def assignable_to(self, other) -> bool: def assignable_to(self, other) -> bool:
return ( return (
@ -129,6 +154,7 @@ class IntType(BasicType):
class UIntType(BasicType): class UIntType(BasicType):
name = "uint" name = "uint"
glib_type_name: str = "guint"
def assignable_to(self, other) -> bool: def assignable_to(self, other) -> bool:
return ( return (
@ -140,6 +166,7 @@ class UIntType(BasicType):
class FloatType(BasicType): class FloatType(BasicType):
name = "float" name = "float"
glib_type_name: str = "gfloat"
def assignable_to(self, other) -> bool: def assignable_to(self, other) -> bool:
return isinstance(other, FloatType) return isinstance(other, FloatType)
@ -147,6 +174,7 @@ class FloatType(BasicType):
class StringType(BasicType): class StringType(BasicType):
name = "string" name = "string"
glib_type_name: str = "gchararray"
def assignable_to(self, other) -> bool: def assignable_to(self, other) -> bool:
return isinstance(other, StringType) return isinstance(other, StringType)
@ -154,6 +182,7 @@ class StringType(BasicType):
class TypeType(BasicType): class TypeType(BasicType):
name = "GType" name = "GType"
glib_type_name: str = "GType"
def assignable_to(self, other) -> bool: def assignable_to(self, other) -> bool:
return isinstance(other, TypeType) return isinstance(other, TypeType)

View file

@ -24,7 +24,15 @@ from ..errors import CompileError, MultipleErrors
from ..completions_utils import * from ..completions_utils import *
from .. import decompiler as decompile from .. import decompiler as decompile
from ..decompiler import DecompileCtx, decompiler from ..decompiler import DecompileCtx, decompiler
from ..gir import StringType, BoolType, IntType, FloatType, GirType, Enumeration from ..gir import (
StringType,
BoolType,
IntType,
FloatType,
GirType,
Enumeration,
UncheckedType,
)
from ..lsp_utils import Completion, CompletionItemKind, SemanticToken, SemanticTokenType from ..lsp_utils import Completion, CompletionItemKind, SemanticToken, SemanticTokenType
from ..parse_tree import * from ..parse_tree import *

View file

@ -69,7 +69,7 @@ class Property(AstNode):
@property @property
def gir_property(self): def gir_property(self):
if self.gir_class is not None: if self.gir_class is not None and not isinstance(self.gir_class, UncheckedType):
return self.gir_class.properties.get(self.tokens["name"]) return self.gir_class.properties.get(self.tokens["name"])
@property @property
@ -79,7 +79,7 @@ class Property(AstNode):
@validate("name") @validate("name")
def property_exists(self): def property_exists(self):
if self.gir_class is None: if self.gir_class is None or isinstance(self.gir_class, UncheckedType):
# Objects that we have no gir data on should not be validated # Objects that we have no gir data on should not be validated
# This happens for classes defined by the app itself # This happens for classes defined by the app itself
return return

View file

@ -71,7 +71,7 @@ class Signal(AstNode):
@property @property
def gir_signal(self): def gir_signal(self):
if self.gir_class is not None: if self.gir_class is not None and not isinstance(self.gir_class, UncheckedType):
return self.gir_class.signals.get(self.tokens["name"]) return self.gir_class.signals.get(self.tokens["name"])
@property @property
@ -80,7 +80,7 @@ class Signal(AstNode):
@validate("name") @validate("name")
def signal_exists(self): def signal_exists(self):
if self.gir_class is None: if self.gir_class is None or isinstance(self.gir_class, UncheckedType):
# Objects that we have no gir data on should not be validated # Objects that we have no gir data on should not be validated
# This happens for classes defined by the app itself # This happens for classes defined by the app itself
return return

View file

@ -53,6 +53,8 @@ class Template(Object):
# Templates might not have a parent class defined # Templates might not have a parent class defined
if class_name := self.class_name: if class_name := self.class_name:
return class_name.gir_type return class_name.gir_type
else:
return gir.UncheckedType(self.id)
@validate("id") @validate("id")
def unique_in_parent(self): def unique_in_parent(self):

View file

@ -56,12 +56,13 @@ class TypeName(AstNode):
return self.root.gir.namespaces.get(self.tokens["namespace"] or "Gtk") return self.root.gir.namespaces.get(self.tokens["namespace"] or "Gtk")
@property @property
def gir_type(self) -> T.Optional[gir.Class]: def gir_type(self) -> gir.GirType:
if self.tokens["class_name"] and not self.tokens["ignore_gir"]: if self.tokens["class_name"] and not self.tokens["ignore_gir"]:
return self.root.gir.get_type( return self.root.gir.get_type(
self.tokens["class_name"], self.tokens["namespace"] self.tokens["class_name"], self.tokens["namespace"]
) )
return None
return gir.UncheckedType(self.tokens["class_name"])
@property @property
def glib_type_name(self) -> str: def glib_type_name(self) -> str:
@ -84,7 +85,11 @@ class TypeName(AstNode):
class ClassName(TypeName): class ClassName(TypeName):
@validate("namespace", "class_name") @validate("namespace", "class_name")
def gir_class_exists(self): def gir_class_exists(self):
if self.gir_type is not None and not isinstance(self.gir_type, Class): if (
self.gir_type
and not isinstance(self.gir_type, UncheckedType)
and not isinstance(self.gir_type, Class)
):
if isinstance(self.gir_type, Interface): if isinstance(self.gir_type, Interface):
raise CompileError( raise CompileError(
f"{self.gir_type.full_name} is an interface, not a class" f"{self.gir_type.full_name} is an interface, not a class"