diff --git a/gtkblueprinttool/extensions/gtk_a11y.py b/gtkblueprinttool/extensions/gtk_a11y.py index d9bc57c..6fb834b 100644 --- a/gtkblueprinttool/extensions/gtk_a11y.py +++ b/gtkblueprinttool/extensions/gtk_a11y.py @@ -106,6 +106,14 @@ def _get_docs(gir, name): class A11y(AstNode): + @validate("accessibility") + def container_is_widget(self): + widget = self.root.gir.get_type("Widget", "Gtk") + container_type = self.parent_by_type(ast.Object).gir_class + if container_type and not container_type.assignable_to(widget): + raise CompileError(f"{container_type.full_name} is not a {widget.full_name}, so it doesn't have accessibility properties") + + def emit_xml(self, xml: XmlEmitter): xml.start_tag("accessibility") for child in self.children: @@ -158,7 +166,7 @@ a11y_prop = Group( a11y = Group( A11y, Sequence( - Keyword("accessibility"), + Keyword("accessibility", True), OpenBlock().expected("`{`"), Until(a11y_prop, CloseBlock()), ) diff --git a/gtkblueprinttool/extensions/gtk_layout.py b/gtkblueprinttool/extensions/gtk_layout.py index 9a821ca..9ef05e5 100644 --- a/gtkblueprinttool/extensions/gtk_layout.py +++ b/gtkblueprinttool/extensions/gtk_layout.py @@ -19,7 +19,7 @@ from ..ast import BaseAttribute -from ..ast_utils import AstNode +from ..ast_utils import AstNode, validate from ..completions_utils import * from ..lsp_utils import Completion, CompletionItemKind from ..parse_tree import * @@ -28,6 +28,14 @@ from ..xml_emitter import XmlEmitter class Layout(AstNode): + @validate("layout") + def container_is_widget(self): + widget = self.root.gir.get_type("Widget", "Gtk") + container_type = self.parent_by_type(ast.Object).gir_class + if container_type and not container_type.assignable_to(widget): + raise CompileError(f"{container_type.full_name} is not a {widget.full_name}, so it doesn't have layout properties") + + def emit_xml(self, xml: XmlEmitter): xml.start_tag("layout") for child in self.children: @@ -56,7 +64,7 @@ layout_prop = Group( layout = Group( Layout, Sequence( - Keyword("layout"), + Keyword("layout", True), OpenBlock().expected("`{`"), Until(layout_prop, CloseBlock()), ) diff --git a/gtkblueprinttool/parse_tree.py b/gtkblueprinttool/parse_tree.py index 2288dfa..551f403 100644 --- a/gtkblueprinttool/parse_tree.py +++ b/gtkblueprinttool/parse_tree.py @@ -514,12 +514,16 @@ class UseLiteral(ParseNode): class Keyword(ParseNode): """ Matches the given identifier. """ - def __init__(self, kw): + def __init__(self, kw, set_token=False): self.kw = kw + self.set_token = True def _parse(self, ctx: ParseContext): token = ctx.next_token() if token.type != TokenType.IDENT: return False + if self.set_token: + ctx.set_group_val(self.kw, True, token) + return str(token) == self.kw diff --git a/tests/sample_errors/a11y_in_non_widget.blp b/tests/sample_errors/a11y_in_non_widget.blp new file mode 100644 index 0000000..9609a0c --- /dev/null +++ b/tests/sample_errors/a11y_in_non_widget.blp @@ -0,0 +1,6 @@ +using Gtk 4.0; +using GObject 2.0; + +GObject.Object { + accessibility {} +} diff --git a/tests/sample_errors/a11y_in_non_widget.err b/tests/sample_errors/a11y_in_non_widget.err new file mode 100644 index 0000000..68d43dc --- /dev/null +++ b/tests/sample_errors/a11y_in_non_widget.err @@ -0,0 +1 @@ +5,3,13,GObject.Object is not a Gtk.Widget, so it doesn't have accessibility properties diff --git a/tests/sample_errors/layout_in_non_widget.blp b/tests/sample_errors/layout_in_non_widget.blp new file mode 100644 index 0000000..26c27c3 --- /dev/null +++ b/tests/sample_errors/layout_in_non_widget.blp @@ -0,0 +1,6 @@ +using Gtk 4.0; +using GObject 2.0; + +GObject.Object { + layout {} +} diff --git a/tests/sample_errors/layout_in_non_widget.err b/tests/sample_errors/layout_in_non_widget.err new file mode 100644 index 0000000..3dccc2d --- /dev/null +++ b/tests/sample_errors/layout_in_non_widget.err @@ -0,0 +1 @@ +5,3,6,GObject.Object is not a Gtk.Widget, so it doesn't have layout properties diff --git a/tests/test_samples.py b/tests/test_samples.py index d987584..ebf415a 100644 --- a/tests/test_samples.py +++ b/tests/test_samples.py @@ -112,6 +112,7 @@ class TestSamples(unittest.TestCase): def test_sample_errors(self): + self.assert_sample_error("a11y_in_non_widget") self.assert_sample_error("a11y_prop_dne") self.assert_sample_error("a11y_prop_obj_dne") self.assert_sample_error("a11y_prop_type") @@ -120,6 +121,7 @@ class TestSamples(unittest.TestCase): self.assert_sample_error("duplicate_obj_id") self.assert_sample_error("enum_member_dne") self.assert_sample_error("invalid_bool") + self.assert_sample_error("layout_in_non_widget") self.assert_sample_error("ns_not_imported") self.assert_sample_error("not_a_class") self.assert_sample_error("object_dne")