mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
Merge branch 'bindings' into 'main'
Draft: decompiler: Implement support for bindings See merge request jwestman/blueprint-compiler!162
This commit is contained in:
commit
179718288f
18 changed files with 208 additions and 10 deletions
|
@ -42,6 +42,19 @@ _NAMESPACES = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TextFragment:
|
||||||
|
text: str
|
||||||
|
newline_after: bool = True
|
||||||
|
indent: bool = True
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BlockInfo:
|
||||||
|
terminator: T.Optional[TextFragment] = None
|
||||||
|
separator: T.Optional[TextFragment] = None
|
||||||
|
|
||||||
|
|
||||||
class LineType(Enum):
|
class LineType(Enum):
|
||||||
NONE = 1
|
NONE = 1
|
||||||
STMT = 2
|
STMT = 2
|
||||||
|
@ -54,7 +67,7 @@ class DecompileCtx:
|
||||||
self._result: str = ""
|
self._result: str = ""
|
||||||
self.gir = GirContext()
|
self.gir = GirContext()
|
||||||
self._indent: int = 0
|
self._indent: int = 0
|
||||||
self._blocks_need_end: T.List[str] = []
|
self._blocks: T.List[BlockInfo] = []
|
||||||
self._last_line_type: LineType = LineType.NONE
|
self._last_line_type: LineType = LineType.NONE
|
||||||
self.template_class: T.Optional[str] = None
|
self.template_class: T.Optional[str] = None
|
||||||
|
|
||||||
|
@ -86,16 +99,25 @@ class DecompileCtx:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def start_block(self) -> None:
|
def start_block(self) -> None:
|
||||||
self._blocks_need_end.append("")
|
self._blocks.append(BlockInfo())
|
||||||
|
|
||||||
def end_block(self) -> None:
|
def end_block(self) -> None:
|
||||||
if close := self._blocks_need_end.pop():
|
block = self._blocks.pop()
|
||||||
self.print(close)
|
if terminator := block.terminator:
|
||||||
|
self.print(terminator.text, terminator.newline_after, terminator.indent)
|
||||||
|
|
||||||
def end_block_with(self, text: str) -> None:
|
def separate_block_elements(self) -> None:
|
||||||
self._blocks_need_end[-1] = text
|
block = self._blocks[-1]
|
||||||
|
if separator := block.separator:
|
||||||
|
self.print(separator.text, separator.newline_after, separator.indent)
|
||||||
|
|
||||||
def print(self, line: str, newline: bool = True) -> None:
|
def end_block_with(self, text: str, newline_after: bool = True, indent: bool = True) -> None:
|
||||||
|
self._blocks[-1].terminator = TextFragment(text, newline_after, indent)
|
||||||
|
|
||||||
|
def separate_block_elements_with(self, text: str, newline_after: bool = False, indent: bool = False) -> None:
|
||||||
|
self._blocks[-1].separator = TextFragment(text, newline_after, indent)
|
||||||
|
|
||||||
|
def print(self, line: str, newline: bool = True, indent: bool = True) -> None:
|
||||||
if line == "}" or line == "]":
|
if line == "}" or line == "]":
|
||||||
self._indent -= 1
|
self._indent -= 1
|
||||||
|
|
||||||
|
@ -117,13 +139,13 @@ class DecompileCtx:
|
||||||
self._result += "\n"
|
self._result += "\n"
|
||||||
self._last_line_type = line_type
|
self._last_line_type = line_type
|
||||||
|
|
||||||
self._result += (" " * self._indent) + line
|
self._result += (" " * self._indent * indent) + line
|
||||||
if newline:
|
if newline:
|
||||||
self._result += "\n"
|
self._result += "\n"
|
||||||
|
|
||||||
if line.endswith("{") or line.endswith("["):
|
if line.endswith("{") or line.endswith("["):
|
||||||
if len(self._blocks_need_end):
|
if len(self._blocks):
|
||||||
self._blocks_need_end[-1] = _CLOSING[line[-1]]
|
self._blocks[-1].terminator = TextFragment(_CLOSING[line[-1]])
|
||||||
self._indent += 1
|
self._indent += 1
|
||||||
|
|
||||||
def print_attribute(self, name: str, value: str, type: GirType) -> None:
|
def print_attribute(self, name: str, value: str, type: GirType) -> None:
|
||||||
|
@ -193,7 +215,11 @@ def _decompile_element(
|
||||||
ctx.start_block()
|
ctx.start_block()
|
||||||
gir = decompiler(ctx, gir, **args)
|
gir = decompiler(ctx, gir, **args)
|
||||||
|
|
||||||
|
first = True
|
||||||
for child in xml.children:
|
for child in xml.children:
|
||||||
|
if not first:
|
||||||
|
ctx.separate_block_elements()
|
||||||
|
first = False
|
||||||
_decompile_element(ctx, gir, child)
|
_decompile_element(ctx, gir, child)
|
||||||
|
|
||||||
ctx.end_block()
|
ctx.end_block()
|
||||||
|
@ -331,6 +357,45 @@ def decompile_property(
|
||||||
return gir
|
return gir
|
||||||
|
|
||||||
|
|
||||||
|
@decompiler("binding")
|
||||||
|
def decompile_binding(ctx: DecompileCtx, gir, name):
|
||||||
|
name = name.replace("_", "-")
|
||||||
|
ctx.print(f"{name}: bind ", newline=False)
|
||||||
|
ctx.end_block_with(";")
|
||||||
|
return gir
|
||||||
|
|
||||||
|
|
||||||
|
@decompiler("lookup", cdata=True)
|
||||||
|
def decompile_lookup(ctx: DecompileCtx, gir, name, cdata, type=None):
|
||||||
|
name = name.replace("_", "-")
|
||||||
|
|
||||||
|
if cdata is not None:
|
||||||
|
ctx.print(cdata, newline=False)
|
||||||
|
|
||||||
|
cast = f" as <{type}>" if type is not None else ""
|
||||||
|
ctx.end_block_with(f"{cast}.{name}", newline_after=False, indent=False)
|
||||||
|
|
||||||
|
return gir
|
||||||
|
|
||||||
|
|
||||||
|
@decompiler("constant", cdata=True)
|
||||||
|
def decompile_constant(ctx: DecompileCtx, gir, cdata, type=None):
|
||||||
|
cast = f" as <{type}>" if type is not None else ""
|
||||||
|
ctx.print(f"{cdata}{cast}", newline=False, indent=False)
|
||||||
|
|
||||||
|
return gir
|
||||||
|
|
||||||
|
|
||||||
|
@decompiler("closure")
|
||||||
|
def decompile_closure(ctx: DecompileCtx, gir, function, type):
|
||||||
|
ctx.print(f"{function}(", newline=False)
|
||||||
|
ctx.separate_block_elements_with(f", ")
|
||||||
|
cast = f" as <{type}>"
|
||||||
|
ctx.end_block_with(f"){cast}", newline_after=False, indent=False)
|
||||||
|
|
||||||
|
return gir
|
||||||
|
|
||||||
|
|
||||||
@decompiler("attribute", cdata=True)
|
@decompiler("attribute", cdata=True)
|
||||||
def decompile_attribute(
|
def decompile_attribute(
|
||||||
ctx, gir, name, cdata, translatable="false", comments=None, context=None
|
ctx, gir, name, cdata, translatable="false", comments=None, context=None
|
||||||
|
|
5
tests/samples/binding1.blp
Normal file
5
tests/samples/binding1.blp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: bla as <gchararray> ;
|
||||||
|
}
|
7
tests/samples/binding1.ui
Normal file
7
tests/samples/binding1.ui
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<constant type="gchararray">bla</constant>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
5
tests/samples/binding2.blp
Normal file
5
tests/samples/binding2.blp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: bla as <gint> ;
|
||||||
|
}
|
7
tests/samples/binding2.ui
Normal file
7
tests/samples/binding2.ui
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<constant type="gint">bla</constant>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
5
tests/samples/binding3.blp
Normal file
5
tests/samples/binding3.blp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: bla ;
|
||||||
|
}
|
7
tests/samples/binding3.ui
Normal file
7
tests/samples/binding3.ui
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<constant>bla</constant>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
5
tests/samples/binding4.blp
Normal file
5
tests/samples/binding4.blp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: bla as <nosuchtype> ;
|
||||||
|
}
|
7
tests/samples/binding4.ui
Normal file
7
tests/samples/binding4.ui
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<constant type="nosuchtype">bla</constant>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
8
tests/samples/binding5.blp
Normal file
8
tests/samples/binding5.blp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
Label bla {
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: bla.label ;
|
||||||
|
}
|
8
tests/samples/binding5.ui
Normal file
8
tests/samples/binding5.ui
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkLabel" id="bla"/>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<lookup name="label">bla</lookup>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
8
tests/samples/binding6.blp
Normal file
8
tests/samples/binding6.blp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
Label bla {
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: bla as <GtkLabel>.label ;
|
||||||
|
}
|
8
tests/samples/binding6.ui
Normal file
8
tests/samples/binding6.ui
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkLabel" id="bla"/>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<lookup name="label" type="GtkLabel">bla</lookup>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
8
tests/samples/binding7.blp
Normal file
8
tests/samples/binding7.blp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
Label bla {
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: bla as <GtkLabel>.label ;
|
||||||
|
}
|
10
tests/samples/binding7.ui
Normal file
10
tests/samples/binding7.ui
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkLabel" id="bla"/>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<lookup name="label">
|
||||||
|
<constant type="GtkLabel">bla</constant>
|
||||||
|
</lookup>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
8
tests/samples/binding8.blp
Normal file
8
tests/samples/binding8.blp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
|
||||||
|
Label bla {
|
||||||
|
}
|
||||||
|
|
||||||
|
DropDown {
|
||||||
|
expression: strcmp('File size:', bla as <GtkLabel>.max-width-chars) as <gchararray>;
|
||||||
|
}
|
11
tests/samples/binding8.ui
Normal file
11
tests/samples/binding8.ui
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<interface>
|
||||||
|
<object class="GtkLabel" id="bla"/>
|
||||||
|
<object class="GtkDropDown">
|
||||||
|
<property name="expression">
|
||||||
|
<closure type='gchararray' function="strcmp">
|
||||||
|
<constant type="gchararray">File size:</constant>
|
||||||
|
<lookup type="GtkLabel" name="max-width-chars">bla</lookup>
|
||||||
|
</closure>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</interface>
|
|
@ -174,6 +174,14 @@ class TestSamples(unittest.TestCase):
|
||||||
REQUIRE_ADW_1_4 = ["adw_breakpoint"]
|
REQUIRE_ADW_1_4 = ["adw_breakpoint"]
|
||||||
|
|
||||||
SKIP_RUN = [
|
SKIP_RUN = [
|
||||||
|
"binding1",
|
||||||
|
"binding2",
|
||||||
|
"binding3",
|
||||||
|
"binding4",
|
||||||
|
"binding5",
|
||||||
|
"binding6",
|
||||||
|
"binding7",
|
||||||
|
"binding8",
|
||||||
"expr_closure",
|
"expr_closure",
|
||||||
"expr_closure_args",
|
"expr_closure_args",
|
||||||
"parseable",
|
"parseable",
|
||||||
|
@ -211,6 +219,14 @@ class TestSamples(unittest.TestCase):
|
||||||
|
|
||||||
def test_decompiler(self):
|
def test_decompiler(self):
|
||||||
self.assert_decompile("accessibility_dec")
|
self.assert_decompile("accessibility_dec")
|
||||||
|
self.assert_decompile("binding1")
|
||||||
|
self.assert_decompile("binding2")
|
||||||
|
self.assert_decompile("binding3")
|
||||||
|
self.assert_decompile("binding4")
|
||||||
|
self.assert_decompile("binding5")
|
||||||
|
self.assert_decompile("binding6")
|
||||||
|
self.assert_decompile("binding7")
|
||||||
|
self.assert_decompile("binding8")
|
||||||
self.assert_decompile("child_type")
|
self.assert_decompile("child_type")
|
||||||
self.assert_decompile("file_filter")
|
self.assert_decompile("file_filter")
|
||||||
self.assert_decompile("flags")
|
self.assert_decompile("flags")
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue