More errors for duplicates

This commit is contained in:
James Westman 2023-05-17 10:25:25 -05:00
parent 2ca71de061
commit 6ac798ea6f
No known key found for this signature in database
GPG key ID: CE2DBA0ADB654EA6
13 changed files with 105 additions and 9 deletions

View file

@ -175,7 +175,9 @@ class AstNode:
for child in self.children:
yield from child.get_semantic_tokens()
def validate_unique_in_parent(self, error, check=None):
def validate_unique_in_parent(
self, error: str, check: T.Optional[T.Callable[["AstNode"], bool]] = None
):
for child in self.parent.children:
if child is self:
break

View file

@ -24,6 +24,23 @@ from .contexts import ScopeCtx
from .common import *
class SignalFlag(AstNode):
grammar = AnyOf(
UseExact("flag", "swapped"),
UseExact("flag", "after"),
)
@property
def flag(self) -> str:
return self.tokens["flag"]
@validate()
def unique(self):
self.validate_unique_in_parent(
f"Duplicate flag '{self.flag}'", lambda x: x.flag == self.flag
)
class Signal(AstNode):
grammar = Statement(
UseIdent("name"),
@ -39,12 +56,7 @@ class Signal(AstNode):
Match("(").expected("argument list"),
Optional(UseIdent("object")).expected("object identifier"),
Match(")").expected(),
ZeroOrMore(
AnyOf(
[Keyword("swapped"), UseLiteral("swapped", True)],
[Keyword("after"), UseLiteral("after", True)],
)
),
ZeroOrMore(SignalFlag),
)
@property
@ -55,6 +67,13 @@ class Signal(AstNode):
def detail_name(self) -> T.Optional[str]:
return self.tokens["detail_name"]
@property
def full_name(self) -> str:
if self.detail_name is None:
return self.name
else:
return self.name + "::" + self.detail_name
@property
def handler(self) -> str:
return self.tokens["handler"]
@ -63,13 +82,17 @@ class Signal(AstNode):
def object_id(self) -> T.Optional[str]:
return self.tokens["object"]
@property
def flags(self) -> T.List[SignalFlag]:
return self.children[SignalFlag]
@property
def is_swapped(self) -> bool:
return self.tokens["swapped"] or False
return any(x.flag == "swapped" for x in self.flags)
@property
def is_after(self) -> bool:
return self.tokens["after"] or False
return any(x.flag == "after" for x in self.flags)
@property
def gir_signal(self):

View file

@ -38,6 +38,13 @@ class Item(AstNode):
def value(self) -> StringValue:
return self.children[StringValue][0]
@validate("name")
def unique_in_parent(self):
if self.name is not None:
self.validate_unique_in_parent(
f"Duplicate item '{self.name}'", lambda x: x.name == self.name
)
class ExtComboBoxItems(AstNode):
grammar = [

View file

@ -46,6 +46,13 @@ class FilterString(AstNode):
def item(self) -> str:
return self.tokens["name"]
@validate()
def unique_in_parent(self):
self.validate_unique_in_parent(
f"Duplicate {self.tokens['tag_name']} '{self.item}'",
check=lambda child: child.item == self.item,
)
def create_node(tag_name: str, singular: str):
return Group(

View file

@ -29,6 +29,10 @@ class ExtListItemFactory(AstNode):
"sub-templates",
)
@validate("template")
def unique_in_parent(self):
self.validate_unique_in_parent("Duplicate template block")
@validate()
def type_is_list_item(self):
if self.type_name is not None:

View file

@ -69,6 +69,12 @@ class MenuAttribute(AstNode):
def value_type(self) -> ValueTypeCtx:
return ValueTypeCtx(None)
@validate("name")
def unique(self):
self.validate_unique_in_parent(
f"Duplicate attribute '{self.name}'", lambda x: x.name == self.name
)
menu_child = AnyOf()

View file

@ -47,6 +47,12 @@ class Widget(AstNode):
f"Cannot assign {object.gir_class.full_name} to {type.full_name}"
)
@validate("name")
def unique_in_parent(self):
self.validate_unique_in_parent(
f"Object '{self.name}' is listed twice", lambda x: x.name == self.name
)
class ExtSizeGroupWidgets(AstNode):
grammar = [

View file

@ -29,6 +29,12 @@ class StyleClass(AstNode):
def name(self) -> str:
return self.tokens["name"]
@validate("name")
def unique_in_parent(self):
self.validate_unique_in_parent(
f"Duplicate style class '{self.name}'", lambda x: x.name == self.name
)
class ExtStyles(AstNode):
grammar = [

View file

@ -112,6 +112,20 @@ class Child(AstNode):
else:
return None
@validate()
def internal_child_unique(self):
if self.annotation is not None:
if isinstance(self.annotation.child, ChildInternal):
internal_child = self.annotation.child.internal_child
self.validate_unique_in_parent(
f"Duplicate internal child '{internal_child}'",
lambda x: (
x.annotation
and isinstance(x.annotation.child, ChildInternal)
and x.annotation.child.internal_child == internal_child
),
)
@decompiler("child")
def decompile_child(ctx, gir, type=None, internal_child=None):

View file

@ -44,6 +44,12 @@ class PropertyBindingFlag(AstNode):
actions=[CodeAction("remove 'sync-create'", "")],
)
@validate()
def unique(self):
self.validate_unique_in_parent(
f"Duplicate flag '{self.flag}'", lambda x: x.flag == self.flag
)
class PropertyBinding(AstNode):
grammar = AnyOf(

View file

@ -229,6 +229,12 @@ class Flag(AstNode):
did_you_mean=(self.tokens["value"], expected_type.members.keys()),
)
@validate()
def unique(self):
self.validate_unique_in_parent(
f"Duplicate flag '{self.name}'", lambda x: x.name == self.name
)
class Flags(AstNode):
grammar = [Flag, "|", Flag, ZeroOrMore(["|", Flag])]