From 1150ae1a09b74b3d22fcc6b3f223335abdeb5823 Mon Sep 17 00:00:00 2001 From: James Westman Date: Wed, 26 Jan 2022 22:55:27 -0600 Subject: [PATCH] reorganization: Move decompilers --- blueprintcompiler/decompiler.py | 154 ++---------------- blueprintcompiler/language/common.py | 2 + blueprintcompiler/language/gobject_object.py | 11 ++ blueprintcompiler/language/gobject_signal.py | 11 ++ blueprintcompiler/language/gtk_a11y.py | 16 ++ blueprintcompiler/language/gtk_file_filter.py | 24 +++ blueprintcompiler/language/gtk_layout.py | 5 + blueprintcompiler/language/gtk_menu.py | 28 ++++ blueprintcompiler/language/gtk_styles.py | 8 + .../language/gtkbuilder_child.py | 9 + .../language/gtkbuilder_template.py | 10 ++ 11 files changed, 138 insertions(+), 140 deletions(-) diff --git a/blueprintcompiler/decompiler.py b/blueprintcompiler/decompiler.py index 58accbc..908d4d5 100644 --- a/blueprintcompiler/decompiler.py +++ b/blueprintcompiler/decompiler.py @@ -22,7 +22,6 @@ from enum import Enum import typing as T from dataclasses import dataclass -from .language import gtk_a11y from .xml_reader import Element, parse from .gir import * from .utils import Colors @@ -126,11 +125,11 @@ class DecompileCtx: def print_attribute(self, name, value, type): if type is None: - self.print(f"{name}: \"{_escape_quote(value)}\";") + self.print(f"{name}: \"{escape_quote(value)}\";") elif type.assignable_to(FloatType()): self.print(f"{name}: {value};") elif type.assignable_to(BoolType()): - val = _truthy(value) + val = truthy(value) self.print(f"{name}: {'true' if val else 'false'};") elif ( type.assignable_to(self.gir.namespaces["Gtk"].lookup_type("Gdk.Pixbuf")) @@ -139,7 +138,7 @@ class DecompileCtx: or type.assignable_to(self.gir.namespaces["Gtk"].lookup_type("Gtk.ShortcutAction")) or type.assignable_to(self.gir.namespaces["Gtk"].lookup_type("Gtk.ShortcutTrigger")) ): - self.print(f"{name}: \"{_escape_quote(value)}\";") + self.print(f"{name}: \"{escape_quote(value)}\";") elif type.assignable_to(self.gir.namespaces["Gtk"].lookup_type("GObject.Object")): self.print(f"{name}: {value};") elif isinstance(type, Enumeration): @@ -153,7 +152,7 @@ class DecompileCtx: flags = re.sub(r"\s*\|\s*", " | ", value).replace("-", "_") self.print(f"{name}: {flags};") else: - self.print(f"{name}: \"{_escape_quote(value)}\";") + self.print(f"{name}: \"{escape_quote(value)}\";") def _decompile_element(ctx: DecompileCtx, gir, xml): @@ -162,7 +161,7 @@ def _decompile_element(ctx: DecompileCtx, gir, xml): if decompiler is None: raise UnsupportedError(f"unsupported XML tag: <{xml.tag}>") - args = {_canon(name): value for name, value in xml.attrs.items()} + args = {canon(name): value for name, value in xml.attrs.items()} if decompiler._cdata: if len(xml.children): args["cdata"] = None @@ -194,19 +193,19 @@ def decompile(data): -def _canon(string: str) -> str: +def canon(string: str) -> str: if string == "class": return "klass" else: return string.replace("-", "_").lower() -def _truthy(string: str) -> bool: +def truthy(string: str) -> bool: return string.lower() in ["yes", "true", "t", "y", "1"] -def _full_name(gir): +def full_name(gir): return gir.name if gir.full_name.startswith("Gtk.") else gir.full_name -def _lookup_by_cname(gir, cname: str): +def lookup_by_cname(gir, cname: str): if isinstance(gir, GirContext): return gir.get_type_by_cname(cname) else: @@ -221,7 +220,7 @@ def decompiler(tag, cdata=False): return decorator -def _escape_quote(string: str) -> str: +def escape_quote(string: str) -> str: return (string .replace("\\", "\\\\") .replace("\'", "\\'") @@ -239,36 +238,6 @@ def decompile_requires(ctx, gir, lib=None, version=None): return gir -@decompiler("template") -def decompile_template(ctx, gir, klass, parent="Widget"): - gir_class = ctx.type_by_cname(parent) - if gir_class is None: - ctx.print(f"template {klass} : .{parent} {{") - else: - ctx.print(f"template {klass} : {_full_name(gir_class)} {{") - return gir_class - - -@decompiler("object") -def decompile_object(ctx, gir, klass, id=None): - gir_class = ctx.type_by_cname(klass) - klass_name = _full_name(gir_class) if gir_class is not None else "." + klass - if id is None: - ctx.print(f"{klass_name} {{") - else: - ctx.print(f"{klass_name} {id} {{") - return gir_class - - -@decompiler("child") -def decompile_child(ctx, gir, type=None, internal_child=None): - if type is not None: - ctx.print(f"[{type}]") - elif internal_child is not None: - ctx.print(f"[internal-child {internal_child}]") - return gir - - @decompiler("property", cdata=True) def decompile_property(ctx, gir, name, cdata, bind_source=None, bind_property=None, bind_flags=None, translatable="false", comments=None, context=None): name = name.replace("_", "-") @@ -288,120 +257,25 @@ def decompile_property(ctx, gir, name, cdata, bind_source=None, bind_property=No if "bidirectional" in bind_flags: flags += " bidirectional" ctx.print(f"{name}: bind {bind_source}.{bind_property}{flags};") - elif _truthy(translatable): + elif truthy(translatable): if context is not None: - ctx.print(f"{name}: C_(\"{_escape_quote(context)}\", \"{_escape_quote(cdata)}\");") + ctx.print(f"{name}: C_(\"{escape_quote(context)}\", \"{escape_quote(cdata)}\");") else: - ctx.print(f"{name}: _(\"{_escape_quote(cdata)}\");") + ctx.print(f"{name}: _(\"{escape_quote(cdata)}\");") elif gir is None or gir.properties.get(name) is None: - ctx.print(f"{name}: \"{_escape_quote(cdata)}\";") + ctx.print(f"{name}: \"{escape_quote(cdata)}\";") else: ctx.print_attribute(name, cdata, gir.properties.get(name).type) return gir - -@decompiler("signal") -def decompile_signal(ctx, gir, name, handler, swapped="false", object=None): - object_name = object or "" - name = name.replace("_", "-") - if _truthy(swapped): - ctx.print(f"{name} => {handler}({object_name}) swapped;") - else: - ctx.print(f"{name} => {handler}({object_name});") - return gir - - -@decompiler("style") -def decompile_style(ctx, gir): - ctx.print(f"styles [") - - -@decompiler("class") -def decompile_class(ctx, gir, name): - ctx.print(f'"{name}",') - - -@decompiler("layout") -def decompile_layout(ctx, gir): - ctx.print("layout {") - - -@decompiler("menu") -def decompile_menu(ctx, gir, id=None): - if id: - ctx.print(f"menu {id} {{") - else: - ctx.print("menu {") - -@decompiler("submenu") -def decompile_submenu(ctx, gir, id=None): - if id: - ctx.print(f"submenu {id} {{") - else: - ctx.print("submenu {") - -@decompiler("item") -def decompile_item(ctx, gir, id=None): - if id: - ctx.print(f"item {id} {{") - else: - ctx.print("item {") - -@decompiler("section") -def decompile_section(ctx, gir, id=None): - if id: - ctx.print(f"section {id} {{") - else: - ctx.print("section {") - @decompiler("attribute", cdata=True) def decompile_attribute(ctx, gir, name, cdata, translatable="false", comments=None, context=None): decompile_property(ctx, gir, name, cdata, translatable=translatable, comments=comments, context=context) -@decompiler("accessibility") -def decompile_accessibility(ctx, gir): - ctx.print("accessibility {") - @decompiler("attributes") def decompile_attributes(ctx, gir): ctx.print("attributes {") -@decompiler("relation", cdata=True) -def decompile_relation(ctx, gir, name, cdata): - ctx.print_attribute(name, cdata, gtk_a11y.get_types(ctx.gir).get(name)) - -@decompiler("state", cdata=True) -def decompile_state(ctx, gir, name, cdata, translatable="false"): - if _truthy(translatable): - ctx.print(f"{name}: _(\"{_escape_quote(cdata)}\");") - else: - ctx.print_attribute(name, cdata, gtk_a11y.get_types(ctx.gir).get(name)) - - -@decompiler("mime-types") -def decompile_mime_types(ctx, gir): - ctx.print("mime-types [") - -@decompiler("mime-type", cdata=True) -def decompile_mime_type(ctx, gir, cdata): - ctx.print(f'"{cdata}",') - -@decompiler("patterns") -def decompile_patterns(ctx, gir): - ctx.print("patterns [") - -@decompiler("pattern", cdata=True) -def decompile_pattern(ctx, gir, cdata): - ctx.print(f'"{cdata}",') - -@decompiler("suffixes") -def decompile_suffixes(ctx, gir): - ctx.print("suffixes [") - -@decompiler("suffix", cdata=True) -def decompile_suffix(ctx, gir, cdata): - ctx.print(f'"{cdata}",') - @dataclass class UnsupportedError(Exception): diff --git a/blueprintcompiler/language/common.py b/blueprintcompiler/language/common.py index ae6ffe1..f6596be 100644 --- a/blueprintcompiler/language/common.py +++ b/blueprintcompiler/language/common.py @@ -21,6 +21,8 @@ from .. import gir from ..ast_utils import AstNode, validate, docs from ..completions_utils import * +from .. import decompiler as decompile +from ..decompiler import DecompileCtx, decompiler from ..gir import StringType, BoolType, IntType, FloatType, GirType from ..lsp_utils import Completion, CompletionItemKind, SemanticToken, SemanticTokenType from ..parse_tree import * diff --git a/blueprintcompiler/language/gobject_object.py b/blueprintcompiler/language/gobject_object.py index e7cf83e..51b34a6 100644 --- a/blueprintcompiler/language/gobject_object.py +++ b/blueprintcompiler/language/gobject_object.py @@ -95,3 +95,14 @@ def validate_parent_type(node, ns: str, name: str, err_msg: str): container_type = node.parent_by_type(Object).gir_class if container_type and not container_type.assignable_to(parent): raise CompileError(f"{container_type.full_name} is not a {parent.full_name}, so it doesn't have {err_msg}") + + +@decompiler("object") +def decompile_object(ctx, gir, klass, id=None): + gir_class = ctx.type_by_cname(klass) + klass_name = decompile.full_name(gir_class) if gir_class is not None else "." + klass + if id is None: + ctx.print(f"{klass_name} {{") + else: + ctx.print(f"{klass_name} {id} {{") + return gir_class diff --git a/blueprintcompiler/language/gobject_signal.py b/blueprintcompiler/language/gobject_signal.py index 453fb1f..a519dee 100644 --- a/blueprintcompiler/language/gobject_signal.py +++ b/blueprintcompiler/language/gobject_signal.py @@ -100,3 +100,14 @@ class Signal(AstNode): swapped="true" if self.tokens["swapped"] else None, object=self.tokens["object"] ) + + +@decompiler("signal") +def decompile_signal(ctx, gir, name, handler, swapped="false", object=None): + object_name = object or "" + name = name.replace("_", "-") + if decompile.truthy(swapped): + ctx.print(f"{name} => {handler}({object_name}) swapped;") + else: + ctx.print(f"{name} => {handler}({object_name});") + return gir diff --git a/blueprintcompiler/language/gtk_a11y.py b/blueprintcompiler/language/gtk_a11y.py index b676126..a0e44e0 100644 --- a/blueprintcompiler/language/gtk_a11y.py +++ b/blueprintcompiler/language/gtk_a11y.py @@ -177,3 +177,19 @@ def a11y_completer(ast_node, match_variables): def a11y_name_completer(ast_node, match_variables): for name, type in get_types(ast_node.root.gir).items(): yield Completion(name, CompletionItemKind.Property, docs=_get_docs(ast_node.root.gir, type)) + + +@decompiler("relation", cdata=True) +def decompile_relation(ctx, gir, name, cdata): + ctx.print_attribute(name, cdata, get_types(ctx.gir).get(name)) + +@decompiler("state", cdata=True) +def decompile_state(ctx, gir, name, cdata, translatable="false"): + if decompile.truthy(translatable): + ctx.print(f"{name}: _(\"{_escape_quote(cdata)}\");") + else: + ctx.print_attribute(name, cdata, get_types(ctx.gir).get(name)) + +@decompiler("accessibility") +def decompile_accessibility(ctx, gir): + ctx.print("accessibility {") diff --git a/blueprintcompiler/language/gtk_file_filter.py b/blueprintcompiler/language/gtk_file_filter.py index a943573..734df47 100644 --- a/blueprintcompiler/language/gtk_file_filter.py +++ b/blueprintcompiler/language/gtk_file_filter.py @@ -78,3 +78,27 @@ def file_filter_completer(ast_node, match_variables): yield Completion("patterns", CompletionItemKind.Snippet, snippet="patterns [\"$0\"]") yield Completion("suffixes", CompletionItemKind.Snippet, snippet="suffixes [\"$0\"]") + +@decompiler("mime-types") +def decompile_mime_types(ctx, gir): + ctx.print("mime-types [") + +@decompiler("mime-type", cdata=True) +def decompile_mime_type(ctx, gir, cdata): + ctx.print(f'"{cdata}",') + +@decompiler("patterns") +def decompile_patterns(ctx, gir): + ctx.print("patterns [") + +@decompiler("pattern", cdata=True) +def decompile_pattern(ctx, gir, cdata): + ctx.print(f'"{cdata}",') + +@decompiler("suffixes") +def decompile_suffixes(ctx, gir): + ctx.print("suffixes [") + +@decompiler("suffix", cdata=True) +def decompile_suffix(ctx, gir, cdata): + ctx.print(f'"{cdata}",') diff --git a/blueprintcompiler/language/gtk_layout.py b/blueprintcompiler/language/gtk_layout.py index f56b8a1..f3b9160 100644 --- a/blueprintcompiler/language/gtk_layout.py +++ b/blueprintcompiler/language/gtk_layout.py @@ -71,3 +71,8 @@ def layout_completer(ast_node, match_variables): "layout", CompletionItemKind.Snippet, snippet="layout {\n $0\n}" ) + + +@decompiler("layout") +def decompile_layout(ctx, gir): + ctx.print("layout {") diff --git a/blueprintcompiler/language/gtk_menu.py b/blueprintcompiler/language/gtk_menu.py index 919b860..a04f5e0 100644 --- a/blueprintcompiler/language/gtk_menu.py +++ b/blueprintcompiler/language/gtk_menu.py @@ -185,3 +185,31 @@ def menu_content_completer(ast_node, match_variables): snippet='icon: "$0";' ) + +@decompiler("menu") +def decompile_menu(ctx, gir, id=None): + if id: + ctx.print(f"menu {id} {{") + else: + ctx.print("menu {") + +@decompiler("submenu") +def decompile_submenu(ctx, gir, id=None): + if id: + ctx.print(f"submenu {id} {{") + else: + ctx.print("submenu {") + +@decompiler("item") +def decompile_item(ctx, gir, id=None): + if id: + ctx.print(f"item {id} {{") + else: + ctx.print("item {") + +@decompiler("section") +def decompile_section(ctx, gir, id=None): + if id: + ctx.print(f"section {id} {{") + else: + ctx.print("section {") diff --git a/blueprintcompiler/language/gtk_styles.py b/blueprintcompiler/language/gtk_styles.py index 23c086f..346f61a 100644 --- a/blueprintcompiler/language/gtk_styles.py +++ b/blueprintcompiler/language/gtk_styles.py @@ -56,3 +56,11 @@ class Styles(AstNode): def style_completer(ast_node, match_variables): yield Completion("styles", CompletionItemKind.Keyword, snippet="styles [\"$0\"]") + +@decompiler("style") +def decompile_style(ctx, gir): + ctx.print(f"styles [") + +@decompiler("class") +def decompile_style_class(ctx, gir, name): + ctx.print(f'"{name}",') diff --git a/blueprintcompiler/language/gtkbuilder_child.py b/blueprintcompiler/language/gtkbuilder_child.py index eb69a1d..68b317f 100644 --- a/blueprintcompiler/language/gtkbuilder_child.py +++ b/blueprintcompiler/language/gtkbuilder_child.py @@ -43,3 +43,12 @@ class Child(AstNode): for child in self.children: child.emit_xml(xml) xml.end_tag() + + +@decompiler("child") +def decompile_child(ctx, gir, type=None, internal_child=None): + if type is not None: + ctx.print(f"[{type}]") + elif internal_child is not None: + ctx.print(f"[internal-child {internal_child}]") + return gir diff --git a/blueprintcompiler/language/gtkbuilder_template.py b/blueprintcompiler/language/gtkbuilder_template.py index 5a28fa9..66e01c5 100644 --- a/blueprintcompiler/language/gtkbuilder_template.py +++ b/blueprintcompiler/language/gtkbuilder_template.py @@ -44,3 +44,13 @@ class Template(Object): for child in self.children: child.emit_xml(xml) xml.end_tag() + + +@decompiler("template") +def decompile_template(ctx: DecompileCtx, gir, klass, parent="Widget"): + gir_class = ctx.type_by_cname(parent) + if gir_class is None: + ctx.print(f"template {klass} : .{parent} {{") + else: + ctx.print(f"template {klass} : {decompile.full_name(gir_class)} {{") + return gir_class