[Auto-Sync] LLVM 18 update (#2296)

Refactor auto-sync updater

This refactors the auto-sync updater scripts, adds multiple tests and some other smaller things:

- Converts the updater in a proper Python package.
- Renaming was done to fit this new package structure.
- Format code with usort and black and enforce it with the CI.
- Add license information to auto-sync scripts.
- Update tree-sitter-cpp to v20.0.5
- Fix py-tree-sitter version to `< 0.22.0` due to https://github.com/tree-sitter/tree-sitter-cpp/issues/250
- Allow file/dir creation of non existing paths.
- Add CI tests for Patch, inc gen, translation and diff persistence testing.
- Implement editing of diffs with an editor.
- Fix: Add Namespace id also to anonymous enumeration members.
This commit is contained in:
Rot127 2024-04-22 03:55:44 +00:00 committed by GitHub
parent 24d99a907b
commit 7746648f0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
104 changed files with 2393 additions and 547 deletions

66
.github/workflows/auto-sync.yml vendored Normal file
View File

@ -0,0 +1,66 @@
name: Auto-Sync
on:
push:
paths:
- "suite/auto-sync/**"
pull_request:
jobs:
check:
runs-on: ubuntu-latest
defaults:
run:
working-directory: suite/auto-sync/
steps:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Check out repository
uses: actions/checkout@v4
with:
submodules: true
- name: Install auto-sync package
run: |
pip install .
- name: Check formatting
run: |
python3.11 -m black --check src/autosync
- name: Build llvm-tblgen
run: |
git clone https://github.com/capstone-engine/llvm-capstone.git vendor/llvm_root
cd vendor/llvm_root
mkdir build
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../llvm
cmake --build . --target llvm-tblgen --config Debug
cd ../../../
- name: Test generation of inc files
run: |
./src/autosync/ASUpdater.py -d -a AArch64 -s IncGen
./src/autosync/ASUpdater.py -d -a Alpha -s IncGen
./src/autosync/ASUpdater.py -d -a ARM -s IncGen
./src/autosync/ASUpdater.py -d -a PPC -s IncGen
- name: CppTranslator - Patch tests
run: |
python -m unittest src/autosync/cpptranslator/Tests/test_patches.py
- name: CppTranslator - Differ tests
run: |
python -m unittest src/autosync/cpptranslator/Tests/test_differ.py
- name: CppTranslator - Test translation
run: |
./src/autosync/ASUpdater.py --ci -d -a AArch64 -s Translate
./src/autosync/ASUpdater.py --ci -d -a ARM -s Translate
./src/autosync/ASUpdater.py --ci -d -a PPC -s Translate
- name: Test Header patcher
run: |
python -m unittest src/autosync/Tests/test_header_patcher.py

3
.gitignore vendored
View File

@ -143,3 +143,6 @@ android-ndk-*
# python virtual env
.venv/
# Auto-sync files
suite/auto-sync/src/autosync.egg-info

20
.reuse/dep5 Normal file
View File

@ -0,0 +1,20 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: CapstoneEngine
Source: https://github.com/capstone-engine/capstone
Files: src/autosync/cpptranslator/Tests/test_config.json
Copyright: 2022 Rot127 <unisono@quyllur.org>
License: BSD-3
Files: src/autosync/cpptranslator/arch_config.json
Copyright: 2022 Rot127 <unisono@quyllur.org>
License: BSD-3
Files: src/autosync/cpptranslator/saved_patches.json
Copyright: 2022 Rot127 <unisono@quyllur.org>
License: BSD-3
Files: src/autosync/path_vars.json
Copyright: 2022 Rot127 <unisono@quyllur.org>
License: BSD-3

View File

@ -0,0 +1,9 @@
{% for copyright_line in copyright_lines %}
{{ copyright_line }}
{% endfor %}
{% for contributor_line in contributor_lines %}
SPDX-FileContributor: {{ contributor_line }}
{% endfor %}
{% for expression in spdx_expressions %}
SPDX-License-Identifier: {{ expression }}
{% endfor %}

View File

@ -0,0 +1,11 @@
Copyright (c) <year> <owner>.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -96,7 +96,7 @@ def copy_sources():
src.extend(glob.glob(os.path.join(BUILD_DIR, "*.mk")))
src.extend(glob.glob(os.path.join(BUILD_DIR, "Makefile")))
src.extend(glob.glob(os.path.join(BUILD_DIR, "LICENSE*")))
src.extend(glob.glob(os.path.join(BUILD_DIR, "LICENSES/*")))
src.extend(glob.glob(os.path.join(BUILD_DIR, "README")))
src.extend(glob.glob(os.path.join(BUILD_DIR, "*.TXT")))
src.extend(glob.glob(os.path.join(BUILD_DIR, "RELEASE_NOTES")))

View File

@ -1,4 +0,0 @@
tree-sitter==0.20.1
termcolor==2.2.0
cmake==3.27.9
ninja==1.11.1.1

View File

@ -1,5 +1,7 @@
build/
vendor/llvm_root
*/.idea
Updater/config.json
src/auto-sync/config.json
src/autosync/cpptranslator/Tests/Differ/test_saved_patches.json
src/autosync.egg-info

View File

@ -1,3 +1,9 @@
<!--
Copyright © 2022 Rot127 <unisono@quyllur.org>
Copyright © 2024 2022 Rot127 <unisono@quyllur.org>
SPDX-License-Identifier: BSD-3
-->
# Architecture updater
This is Capstones updater for some architectures.
@ -5,12 +11,6 @@ Unfortunately not all architectures are supported yet.
## Install dependencies
Install clang-format
```
sudo apt install clang-format-18
```
Setup Python environment and Tree-sitter
```
@ -20,7 +20,6 @@ sudo apt install python3-venv
# Setup virtual environment in Capstone root dir
python3 -m venv ./.venv
source ./.venv/bin/activate
pip3 install -r dev_requirements.txt
```
Clone C++ grammar
@ -28,6 +27,7 @@ Clone C++ grammar
```
cd suite/auto-sync/
git submodule update --init --recursive ./vendor/
pip install -e .
```
## Update
@ -35,13 +35,13 @@ git submodule update --init --recursive ./vendor/
Check if your architecture is supported.
```
./Updater/ASUpdater.py -h
./src/autosync/ASUpdater.py -h
```
Clone Capstones LLVM fork and build `llvm-tblgen`
```
git clone https://github.com/capstone-engine/llvm-capstone
git clone https://github.com/capstone-engine/llvm-capstone vendor/llvm_root/
cd llvm-capstone
git checkout auto-sync
mkdir build
@ -55,7 +55,7 @@ cd ../../
Run the updater
```
./Updater/ASUpdater.py -a <ARCH>
./src/autosync/ASUpdater.py -a <ARCH>
```
## Post-processing steps

View File

@ -1,2 +0,0 @@
*/.idea/

View File

@ -1,67 +0,0 @@
import json
import logging as log
import re
import subprocess
from pathlib import Path
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class PathVarHandler(metaclass=Singleton):
paths = {}
def __init__(self) -> None:
try:
res = subprocess.run(["git", "rev-parse", "--show-toplevel"], check=True, stdout=subprocess.PIPE)
except subprocess.CalledProcessError:
log.fatal("Could not get repository top level directory.")
exit(1)
repo_root = res.stdout.decode("utf8").strip("\n")
# The main directories
self.paths["{CS_ROOT}"] = Path(repo_root)
self.paths["{AUTO_SYNC_ROOT}"] = Path(repo_root).joinpath("suite/auto-sync/")
self.paths["{AUTO_SYNC_UPDATER_DIR}"] = self.paths["{AUTO_SYNC_ROOT}"].joinpath("Updater/")
path_config_file = self.paths["{AUTO_SYNC_UPDATER_DIR}"].joinpath("path_vars.json")
# Load variables
with open(path_config_file) as f:
vars = json.load(f)
missing = list()
for p_name, path in vars.items():
resolved = path
for var_id in re.findall(r"\{.+}", resolved):
if var_id not in self.paths:
log.fatal(
f"{var_id} hasn't been added to the PathVarsHandler, yet. The var must be defined in a previous entry."
)
exit(1)
resolved = re.sub(var_id, str(self.paths[var_id]), resolved)
log.debug(f"Set {p_name} = {resolved}")
if not Path(resolved).exists():
missing.append(resolved)
self.paths[p_name] = resolved
if len(missing) > 0:
log.fatal(f"Some paths from config file are missing!")
for m in missing:
log.fatal(f"\t{m}")
exit(1)
def get_path(self, name: str) -> Path:
if name not in self.paths:
raise ValueError(f"Path variable {name} has no path saved.")
return self.paths[name]
def complete_path(self, path_str: str) -> Path:
resolved = path_str
for p_name in re.findall(r"\{.+}", path_str):
resolved = re.sub(p_name, self.get_path(p_name), resolved)
return Path(resolved)

View File

@ -1,7 +0,0 @@
# The update scripts for auto-sync
## Updating only the `inc` files
```cmd
> ./IncGenerator.py ...
```

View File

@ -1,22 +0,0 @@
{
"{LLVM_ROOT}": "{AUTO_SYNC_ROOT}/llvm-capstone/",
"{LLVM_TARGET_DIR}": "{AUTO_SYNC_ROOT}/llvm-capstone/llvm/lib/Target/",
"{LLVM_TBLGEN_BIN}": "{AUTO_SYNC_ROOT}/llvm-capstone/build/bin/llvm-tblgen",
"{LLVM_INCLUDE_DIR}": "{AUTO_SYNC_ROOT}/llvm-capstone/llvm/include",
"{VENDOR_DIR}": "{AUTO_SYNC_ROOT}/vendor/",
"{AUTO_SYNC_UPDATER_DIR}": "{AUTO_SYNC_ROOT}/Updater/",
"{CPP_TRANSLATOR_DIR}": "{AUTO_SYNC_ROOT}/Updater/CppTranslator/",
"{CPP_TRANSLATOR_CONFIG}": "{CPP_TRANSLATOR_DIR}/arch_config.json",
"{INC_PATCH_DIR}": "{AUTO_SYNC_ROOT}/inc_patches/",
"{CS_INCLUDE_DIR}": "{CS_ROOT}/include/capstone/",
"{CS_ARCH_MODULE_DIR}": "{CS_ROOT}/arch/",
"{CS_CLANG_FORMAT_FILE}": "{CS_ROOT}/.clang-format",
"{BUILD_DIR}": "{AUTO_SYNC_ROOT}/build/",
"{C_INC_OUT_DIR}": "{BUILD_DIR}/llvm_c_inc/",
"{CPP_INC_OUT_DIR}": "{BUILD_DIR}/llvm_cpp_inc/"
}

View File

@ -1,2 +0,0 @@
termcolor>=2.3.0
tree_sitter>=0.20.2

4
suite/auto-sync/format_py.sh Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/bash
python3.11 -m usort format src/autosync
python3.11 -m black src/autosync

View File

@ -0,0 +1,23 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# Copyright © 2024 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
[project]
name = "autosync"
version = "0.1.0"
dependencies = [
"termcolor >= 2.3.0",
"tree_sitter < 0.22.0",
"black >= 24.3.0",
"usort >= 1.0.8",
"setuptools >= 69.2.0",
"ninja >= 1.11.1.1",
"cmake >= 3.28.3",
"reuse >= 3.0.1",
"clang-format >= 18.1.1",
]
requires-python = ">= 3.11"
[tool.setuptools]
packages = ["autosync", "autosync.cpptranslator", "autosync.cpptranslator.patches"]
package-dir = {"" = "src"}

View File

@ -1,21 +1,25 @@
#!/usr/bin/env python3
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import argparse
import logging as log
import os
import shutil
import subprocess
import sys
import logging as log
from enum import StrEnum
from CppTranslator.Configurator import Configurator
from CppTranslator.CppTranslator import Translator
from IncGenerator import IncGenerator
from Helper import get_path, convert_loglevel, check_py_version, fail_exit
from HeaderPatcher import HeaderPatcher
from pathlib import Path
from autosync.cpptranslator.Configurator import Configurator
from autosync.cpptranslator.CppTranslator import Translator
from autosync.HeaderPatcher import HeaderPatcher
from autosync.Helper import check_py_version, convert_loglevel, fail_exit, get_path
from autosync.IncGenerator import IncGenerator
class USteps(StrEnum):
INC_GEN = "IncGen"
@ -38,11 +42,13 @@ class ASUpdater:
no_clean: bool,
refactor: bool,
differ_no_auto_apply: bool,
wait_for_user: bool = True,
) -> None:
self.arch = arch
self.write = write
self.no_clean_build = no_clean
self.inc_list = inc_list
self.wait_for_user = wait_for_user
if USteps.ALL in steps:
self.steps = [USteps.INC_GEN, USteps.TRANS, USteps.DIFF]
else:
@ -108,20 +114,22 @@ class ASUpdater:
ts_dir = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
if not ts_dir.exists():
log.info("tree-sitter was not fetched. Cloning it now...")
subprocess.run(["git", "submodule", "update", "--init", "--recursive"], check=True)
subprocess.run(
["git", "submodule", "update", "--init", "--recursive"], check=True
)
def translate(self) -> None:
self.check_tree_sitter()
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
configurator = Configurator(self.arch, translator_config)
translator = Translator(configurator)
translator = Translator(configurator, self.wait_for_user)
translator.translate()
translator.remark_manual_files()
def diff(self) -> None:
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
configurator = Configurator(self.arch, translator_config)
from CppTranslator.Differ import Differ
from autosync.cpptranslator.Differ import Differ
differ = Differ(configurator, self.differ_no_auto_apply)
differ.diff()
@ -151,11 +159,23 @@ def parse_args() -> argparse.Namespace:
description="Capstones architecture module updater.",
)
parser.add_argument(
"-a", dest="arch", help="Name of target architecture.", choices=["ARM", "PPC", "AArch64", "Alpha"], required=True
"-a",
dest="arch",
help="Name of target architecture.",
choices=["ARM", "PPC", "AArch64", "Alpha"],
required=True,
)
parser.add_argument("-d", dest="no_clean", help="Don't clean build dir before updating.", action="store_true")
parser.add_argument(
"-w", dest="write", help="Write generated/translated files to arch/<ARCH>/", action="store_true"
"-d",
dest="no_clean",
help="Don't clean build dir before updating.",
action="store_true",
)
parser.add_argument(
"-w",
dest="write",
help="Write generated/translated files to arch/<ARCH>/",
action="store_true",
)
parser.add_argument(
"-v",
@ -205,9 +225,15 @@ def parse_args() -> argparse.Namespace:
parser.add_argument(
"--refactor",
dest="refactor",
help="Sets change update behavior to ease refacotring and new implementations.",
help="Sets change update behavior to ease refactoring and new implementations.",
action="store_true",
)
parser.add_argument(
"--ci",
dest="wait_for_user",
help="The translator will not wait for user input when printing important logs.",
action="store_false",
)
arguments = parser.parse_args()
return arguments
@ -223,6 +249,13 @@ if __name__ == "__main__":
)
Updater = ASUpdater(
args.arch, args.write, args.steps, args.inc_list, args.no_clean, args.refactor, args.no_auto_apply
args.arch,
args.write,
args.steps,
args.inc_list,
args.no_clean,
args.refactor,
args.no_auto_apply,
args.wait_for_user,
)
Updater.update()

View File

@ -1,5 +1,8 @@
#!/usr/bin/env python3
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import argparse
import logging as log
import re
@ -12,8 +15,12 @@ def parse_args() -> argparse.Namespace:
prog="PatchHeaders",
description="Patches generated enums into the main arch header file.",
)
parser.add_argument("--header", dest="header", help="Path header file.", type=Path, required=True)
parser.add_argument("--inc", dest="inc", help="Path inc file.", type=Path, required=True)
parser.add_argument(
"--header", dest="header", help="Path header file.", type=Path, required=True
)
parser.add_argument(
"--inc", dest="inc", help="Path inc file.", type=Path, required=True
)
arguments = parser.parse_args()
return arguments
@ -24,9 +31,13 @@ def error_exit(msg: str) -> None:
class HeaderPatcher:
def __init__(self, header: Path, inc: Path) -> None:
def __init__(self, header: Path, inc: Path, write_file: bool = True) -> None:
self.header = header
self.inc = inc
self.inc_content: str = ""
self.write_file = write_file
# Gets set to the patched file content if writing to the file is disabled.
self.patched_header_content: str = ""
def patch_header(self) -> bool:
if not (self.header.exists() or self.header.is_file()):
@ -69,7 +80,7 @@ class HeaderPatcher:
header_enum_id = f":{ev_id}" if ev_id != "NOTGIVEN" else ""
regex = (
rf"\s*// generated content <{self.inc.name}{header_enum_id}> begin.*(\n)"
rf"(.*\n)+"
rf"(.*\n)*"
rf"\s*// generated content <{self.inc.name}{header_enum_id}> end.*(\n)"
)
if not re.search(regex, header_content):
@ -84,8 +95,11 @@ class HeaderPatcher:
)
header_content = re.sub(regex, new_content, header_content)
if self.write_file:
with open(self.header, "w") as f:
f.write(header_content)
else:
self.patched_header_content = header_content
log.info(f"Patched {self.inc.name} into {self.header.name}")
return True

View File

@ -1,3 +1,6 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import hashlib
import logging as log
import shutil
@ -6,10 +9,10 @@ import sys
from pathlib import Path
import termcolor
from PathVarHandler import PathVarHandler
from tree_sitter import Node
from autosync.PathVarHandler import PathVarHandler
def convert_loglevel(level: str) -> int:
if level == "debug":
@ -79,11 +82,12 @@ def find_id_by_type(node: Node, node_types: [str], type_must_match: bool) -> byt
return b""
def print_prominent_warning(msg: str) -> None:
def print_prominent_warning(msg: str, wait_for_user: bool = True) -> None:
print("\n" + separator_line_1("yellow"))
print(termcolor.colored("WARNING", "yellow", attrs=["bold"]) + "\n")
print(msg)
print(separator_line_1("yellow"))
if wait_for_user:
input("Press enter to continue...\n")
@ -91,10 +95,11 @@ def term_width() -> int:
return shutil.get_terminal_size()[0]
def print_prominent_info(msg: str) -> None:
def print_prominent_info(msg: str, wait_for_user: bool = True) -> None:
print("\n" + separator_line_1("blue"))
print(msg)
print(separator_line_1("blue"))
if wait_for_user:
input("Press enter to continue...\n")
@ -140,7 +145,14 @@ def get_header() -> str:
def run_clang_format(out_paths: list[Path]):
for out_file in out_paths:
log.info(f"Format {out_file}")
subprocess.run(["clang-format-18", f"-style=file:{get_path('{CS_CLANG_FORMAT_FILE}')}", "-i", out_file])
subprocess.run(
[
"clang-format",
f"-style=file:{get_path('{CS_CLANG_FORMAT_FILE}')}",
"-i",
out_file,
]
)
def get_path(config_path: str) -> Path:

View File

@ -1,15 +1,17 @@
#!/usr/bin/env python3
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
import os
import re
import shutil
import subprocess
import logging as log
from Helper import fail_exit, get_path
from pathlib import Path
from autosync.Helper import fail_exit, get_path
inc_tables = [
{
"name": "Disassembler",
@ -71,7 +73,9 @@ class IncGenerator:
self.patches_dir_path: Path = get_path("{INC_PATCH_DIR}")
self.llvm_include_dir: Path = get_path("{LLVM_INCLUDE_DIR}")
self.output_dir: Path = get_path("{BUILD_DIR}")
self.llvm_target_dir: Path = get_path("{LLVM_TARGET_DIR}").joinpath(f"{self.arch_dir_name}")
self.llvm_target_dir: Path = get_path("{LLVM_TARGET_DIR}").joinpath(
f"{self.arch_dir_name}"
)
self.llvm_tblgen: Path = get_path("{LLVM_TBLGEN_BIN}")
self.output_dir_c_inc = get_path("{C_INC_OUT_DIR}")
self.output_dir_cpp_inc = get_path("{CPP_INC_OUT_DIR}")
@ -106,16 +110,26 @@ class IncGenerator:
for file in Path.cwd().iterdir():
if re.search(rf"{self.arch}Gen.*\.inc", file.name):
log.debug(f"Move {file} to {self.output_dir_c_inc}")
if self.output_dir_c_inc.joinpath(file.name).exists():
os.remove(self.output_dir_c_inc.joinpath(file.name))
shutil.move(file, self.output_dir_c_inc)
if self.arch == "AArch64":
# We have to rename the file SystemRegister -> SystemOperands
sys_ops_table_file = self.output_dir_c_inc.joinpath("AArch64GenSystemRegister.inc")
new_sys_ops_file = self.output_dir_c_inc.joinpath("AArch64GenSystemOperands.inc")
sys_ops_table_file = self.output_dir_c_inc.joinpath(
"AArch64GenSystemRegister.inc"
)
new_sys_ops_file = self.output_dir_c_inc.joinpath(
"AArch64GenSystemOperands.inc"
)
if "SystemOperand" not in self.inc_list:
return
elif not sys_ops_table_file.exists():
fail_exit(f"{sys_ops_table_file} does not exist. But it should have been generated.")
fail_exit(
f"{sys_ops_table_file} does not exist. But it should have been generated."
)
if new_sys_ops_file.exists():
os.remove(new_sys_ops_file)
shutil.move(sys_ops_table_file, new_sys_ops_file)
def gen_incs(self) -> None:
@ -178,6 +192,6 @@ class IncGenerator:
check=True,
)
except subprocess.CalledProcessError as e:
log.warn(f"Patch {patch.name} did not apply correctly!")
log.warn(f"git apply returned: {e}")
log.warning(f"Patch {patch.name} did not apply correctly!")
log.warning(f"git apply returned: {e}")
return

View File

@ -0,0 +1,106 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import json
import logging as log
import re
import subprocess
from pathlib import Path
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class PathVarHandler(metaclass=Singleton):
def __init__(self) -> None:
try:
res = subprocess.run(
["git", "rev-parse", "--show-toplevel"],
check=True,
stdout=subprocess.PIPE,
)
except subprocess.CalledProcessError:
log.fatal("Could not get repository top level directory.")
exit(1)
repo_root = res.stdout.decode("utf8").strip("\n")
# The main directories
self.paths: dict[str:Path] = dict()
self.paths["{CS_ROOT}"] = Path(repo_root)
self.paths["{AUTO_SYNC_ROOT}"] = Path(repo_root).joinpath("suite/auto-sync/")
self.paths["{AUTO_SYNC_SRC}"] = self.paths["{AUTO_SYNC_ROOT}"].joinpath(
"src/autosync/"
)
path_config_file = self.paths["{AUTO_SYNC_SRC}"].joinpath("path_vars.json")
# Load variables
with open(path_config_file) as f:
vars = json.load(f)
paths = vars["paths"]
self.create_during_runtime = vars["create_during_runtime"]
missing = list()
for p_name, path in paths.items():
resolved = path
for var_id in re.findall(r"\{.+}", resolved):
if var_id not in self.paths:
log.fatal(
f"{var_id} hasn't been added to the PathVarsHandler, yet. The var must be defined in a previous entry."
)
exit(1)
resolved: str = re.sub(var_id, str(self.paths[var_id]), resolved)
log.debug(f"Set {p_name} = {resolved}")
if not Path(resolved).exists() and (
p_name not in self.create_during_runtime
and p_name not in vars["ignore_missing"]
):
missing.append(resolved)
elif var_id in self.create_during_runtime:
self.create_path(var_id, resolved)
self.paths[p_name] = Path(resolved)
if len(missing) > 0:
log.fatal(f"Some paths from config file are missing!")
for m in missing:
log.fatal(f"\t{m}")
exit(1)
def get_path(self, name: str) -> Path:
if name not in self.paths:
raise ValueError(f"Path variable {name} has no path saved.")
if name in self.create_during_runtime:
self.create_path(name, self.paths[name])
return self.paths[name]
def complete_path(self, path_str: str) -> Path:
resolved = path_str
for p_name in re.findall(r"\{.+}", path_str):
resolved = re.sub(p_name, str(self.get_path(p_name)), resolved)
return Path(resolved)
@staticmethod
def create_path(var_id: str, path: str):
pp = Path(path)
if pp.exists():
return
log.debug(f"Create path {var_id} @ {path}")
postfix = var_id.strip("}").split("_")[-1]
if postfix == "FILE":
if not pp.parent.exists():
pp.parent.mkdir(parents=True)
pp.touch()
elif postfix == "DIR":
pp.mkdir(parents=True)
else:
from autosync.Helper import fail_exit
fail_exit(
f"The var_id: {var_id} must end in _FILE or _DIR. It ends in '{postfix}'"
)

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
// SPDX-License-Identifier: BSD-3
// Include the whole file
// generated content <test_include.inc> begin
// generated content <test_include.inc> end
// Include only a part of the file.
// generated content <test_include.inc:GUARD> begin
// generated content <test_include.inc:GUARD> end

View File

@ -0,0 +1,47 @@
# SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import unittest
from autosync.HeaderPatcher import HeaderPatcher
from autosync.Helper import get_path
class TestHeaderPatcher(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.hpatcher = HeaderPatcher(
get_path("{HEADER_PATCHER_TEST_HEADER_FILE}"),
get_path("{HEADER_PATCHER_TEST_INC_FILE}"),
write_file=False,
)
def test_header_patching(self):
self.hpatcher.patch_header()
self.assertEqual(
self.hpatcher.patched_header_content,
(
"// SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>\n"
"// SPDX-License-Identifier: BSD-3\n"
"\n"
"\n"
" // Include the whole file\n"
" // generated content <test_include.inc> begin\n"
" // clang-format off\n"
"\n"
"This part should be included if the whole file is included.\n"
"\n"
" // clang-format on\n"
" // generated content <test_include.inc> end\n"
"\n"
" // Include only a part of the file.\n"
" // generated content <test_include.inc:GUARD> begin\n"
" // clang-format off\n"
"\n"
" Partial include of something\n"
"\n"
" // clang-format on\n"
" // generated content <test_include.inc:GUARD> end\n"
"\n"
),
)

View File

@ -0,0 +1,11 @@
// SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
// SPDX-License-Identifier: BSD-3
#ifdef GUARD
#undef GUARD
Partial include of something
#endif
This part should be included if the whole file is included.

View File

@ -1,9 +1,13 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import json
import logging as log
from pathlib import Path
from Helper import get_path, fail_exit
from tree_sitter import Language, Parser
import logging as log
from autosync.Helper import fail_exit, get_path
class Configurator:
@ -60,7 +64,9 @@ class Configurator:
with open(self.config_path) as f:
conf = json.loads(f.read())
if self.arch not in conf:
fail_exit(f"{self.arch} has no configuration. Please add them in {self.config_path}!")
fail_exit(
f"{self.arch} has no configuration. Please add them in {self.config_path}!"
)
self.config = conf
def ts_compile_cpp(self) -> None:
@ -68,13 +74,17 @@ class Configurator:
ts_grammar_path = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
if not Path.exists(ts_grammar_path):
fail_exit(f"Could not load the tree-sitter grammar at '{ts_grammar_path}'")
Language.build_library(str(self.ts_shared_object), [ts_grammar_path])
# build_library wll be deprecated in 0.22.0. But CPP tree-sitter doesn't have Python bindings.
# So we stick with it.
Language.build_library(str(self.ts_shared_object), [str(ts_grammar_path)])
def ts_set_cpp_language(self) -> None:
log.info(f"Load language '{self.ts_shared_object}'")
if not Path.exists(self.ts_shared_object):
fail_exit(f"Could not load the tree-sitter language shared object at '{self.ts_shared_object}'")
self.ts_cpp_lang = Language(self.ts_shared_object, "cpp")
fail_exit(
f"Could not load the tree-sitter language shared object at '{self.ts_shared_object}'"
)
self.ts_cpp_lang = Language(str(self.ts_shared_object), "cpp")
def init_parser(self) -> None:
log.debug("Init parser")

View File

@ -1,77 +1,89 @@
#!/usr/bin/env python3
from pathlib import Path
import termcolor
from tree_sitter import Language, Parser, Tree, Node
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import argparse
import logging as log
import sys
from pathlib import Path
from tree_sitter.binding import Query
import termcolor
from tree_sitter import Language, Node, Parser, Query, Tree
from CppTranslator.Configurator import Configurator
from Helper import convert_loglevel, print_prominent_warning, get_header, run_clang_format, get_path
from CppTranslator.Patches.GetRegFromClass import GetRegFromClass
from CppTranslator.Patches.AddCSDetail import AddCSDetail
from CppTranslator.Patches.AddOperand import AddOperand
from CppTranslator.Patches.Assert import Assert
from CppTranslator.Patches.BitCastStdArray import BitCastStdArray
from CppTranslator.Patches.CheckDecoderStatus import CheckDecoderStatus
from CppTranslator.Patches.ClassConstructorDef import ClassConstructorDef
from CppTranslator.Patches.ClassesDef import ClassesDef
from CppTranslator.Patches.ConstMCInstParameter import ConstMCInstParameter
from CppTranslator.Patches.ConstMCOperand import ConstMCOperand
from CppTranslator.Patches.CppInitCast import CppInitCast
from CppTranslator.Patches.CreateOperand0 import CreateOperand0
from CppTranslator.Patches.CreateOperand1 import CreateOperand1
from CppTranslator.Patches.DeclarationInConditionClause import DeclarationInConditionalClause
from CppTranslator.Patches.DecodeInstruction import DecodeInstruction
from CppTranslator.Patches.DecoderCast import DecoderCast
from CppTranslator.Patches.DecoderParameter import DecoderParameter
from CppTranslator.Patches.FallThrough import FallThrough
from CppTranslator.Patches.FeatureBits import FeatureBits
from CppTranslator.Patches.FeatureBitsDecl import FeatureBitsDecl
from CppTranslator.Patches.FieldFromInstr import FieldFromInstr
from CppTranslator.Patches.GetNumOperands import GetNumOperands
from CppTranslator.Patches.GetOpcode import GetOpcode
from CppTranslator.Patches.GetOperandRegImm import GetOperandRegImm
from CppTranslator.Patches.GetOperand import GetOperand
from CppTranslator.Patches.GetRegClass import GetRegClass
from CppTranslator.Patches.GetSubReg import GetSubReg
from CppTranslator.Patches.Includes import Includes
from CppTranslator.Patches.InlineToStaticInline import InlineToStaticInline
from CppTranslator.Patches.IsRegImm import IsOperandRegImm
from CppTranslator.Patches.IsOptionalDef import IsOptionalDef
from CppTranslator.Patches.IsPredicate import IsPredicate
from CppTranslator.Patches.LLVMFallThrough import LLVMFallThrough
from CppTranslator.Patches.LLVMunreachable import LLVMUnreachable
from CppTranslator.Patches.MethodToFunctions import MethodToFunction
from CppTranslator.Patches.MethodTypeQualifier import MethodTypeQualifier
from CppTranslator.Patches.NamespaceLLVM import NamespaceLLVM
from CppTranslator.Patches.NamespaceAnon import NamespaceAnon
from CppTranslator.Patches.NamespaceArch import NamespaceArch
from CppTranslator.Patches.OutStreamParam import OutStreamParam
from CppTranslator.Patches.PredicateBlockFunctions import PredicateBlockFunctions
from CppTranslator.Patches.PrintAnnotation import PrintAnnotation
from CppTranslator.Patches.PrintRegImmShift import PrintRegImmShift
from CppTranslator.Patches.QualifiedIdentifier import QualifiedIdentifier
from CppTranslator.Patches.Patch import Patch
from CppTranslator.Patches.ReferencesDecl import ReferencesDecl
from CppTranslator.Patches.RegClassContains import RegClassContains
from CppTranslator.Patches.STIArgument import STIArgument
from CppTranslator.Patches.STIFeatureBits import STIFeatureBits
from CppTranslator.Patches.STParameter import SubtargetInfoParam
from CppTranslator.Patches.SetOpcode import SetOpcode
from CppTranslator.Patches.SignExtend import SignExtend
from CppTranslator.Patches.SizeAssignments import SizeAssignment
from CppTranslator.Patches.StreamOperation import StreamOperations
from CppTranslator.Patches.TemplateDeclaration import TemplateDeclaration
from CppTranslator.Patches.TemplateDefinition import TemplateDefinition
from CppTranslator.Patches.TemplateParamDecl import TemplateParamDecl
from CppTranslator.Patches.TemplateRefs import TemplateRefs
from CppTranslator.Patches.UseMarkup import UseMarkup
from CppTranslator.Patches.UsingDeclaration import UsingDeclaration
from CppTranslator.TemplateCollector import TemplateCollector
from autosync.cpptranslator.Configurator import Configurator
from autosync.cpptranslator.patches.AddCSDetail import AddCSDetail
from autosync.cpptranslator.patches.AddOperand import AddOperand
from autosync.cpptranslator.patches.Assert import Assert
from autosync.cpptranslator.patches.BitCastStdArray import BitCastStdArray
from autosync.cpptranslator.patches.CheckDecoderStatus import CheckDecoderStatus
from autosync.cpptranslator.patches.ClassConstructorDef import ClassConstructorDef
from autosync.cpptranslator.patches.ClassesDef import ClassesDef
from autosync.cpptranslator.patches.ConstMCInstParameter import ConstMCInstParameter
from autosync.cpptranslator.patches.ConstMCOperand import ConstMCOperand
from autosync.cpptranslator.patches.CppInitCast import CppInitCast
from autosync.cpptranslator.patches.CreateOperand0 import CreateOperand0
from autosync.cpptranslator.patches.CreateOperand1 import CreateOperand1
from autosync.cpptranslator.patches.DeclarationInConditionClause import (
DeclarationInConditionalClause,
)
from autosync.cpptranslator.patches.DecodeInstruction import DecodeInstruction
from autosync.cpptranslator.patches.DecoderCast import DecoderCast
from autosync.cpptranslator.patches.DecoderParameter import DecoderParameter
from autosync.cpptranslator.patches.FallThrough import FallThrough
from autosync.cpptranslator.patches.FeatureBits import FeatureBits
from autosync.cpptranslator.patches.FeatureBitsDecl import FeatureBitsDecl
from autosync.cpptranslator.patches.FieldFromInstr import FieldFromInstr
from autosync.cpptranslator.patches.GetNumOperands import GetNumOperands
from autosync.cpptranslator.patches.GetOpcode import GetOpcode
from autosync.cpptranslator.patches.GetOperand import GetOperand
from autosync.cpptranslator.patches.GetOperandRegImm import GetOperandRegImm
from autosync.cpptranslator.patches.GetRegClass import GetRegClass
from autosync.cpptranslator.patches.GetRegFromClass import GetRegFromClass
from autosync.cpptranslator.patches.GetSubReg import GetSubReg
from autosync.cpptranslator.patches.Includes import Includes
from autosync.cpptranslator.patches.InlineToStaticInline import InlineToStaticInline
from autosync.cpptranslator.patches.IsOptionalDef import IsOptionalDef
from autosync.cpptranslator.patches.IsPredicate import IsPredicate
from autosync.cpptranslator.patches.IsRegImm import IsOperandRegImm
from autosync.cpptranslator.patches.LLVMFallThrough import LLVMFallThrough
from autosync.cpptranslator.patches.LLVMunreachable import LLVMUnreachable
from autosync.cpptranslator.patches.MethodToFunctions import MethodToFunction
from autosync.cpptranslator.patches.MethodTypeQualifier import MethodTypeQualifier
from autosync.cpptranslator.patches.NamespaceAnon import NamespaceAnon
from autosync.cpptranslator.patches.NamespaceArch import NamespaceArch
from autosync.cpptranslator.patches.NamespaceLLVM import NamespaceLLVM
from autosync.cpptranslator.patches.OutStreamParam import OutStreamParam
from autosync.cpptranslator.patches.Patch import Patch
from autosync.cpptranslator.patches.PredicateBlockFunctions import (
PredicateBlockFunctions,
)
from autosync.cpptranslator.patches.PrintAnnotation import PrintAnnotation
from autosync.cpptranslator.patches.PrintRegImmShift import PrintRegImmShift
from autosync.cpptranslator.patches.QualifiedIdentifier import QualifiedIdentifier
from autosync.cpptranslator.patches.ReferencesDecl import ReferencesDecl
from autosync.cpptranslator.patches.RegClassContains import RegClassContains
from autosync.cpptranslator.patches.SetOpcode import SetOpcode
from autosync.cpptranslator.patches.SignExtend import SignExtend
from autosync.cpptranslator.patches.SizeAssignments import SizeAssignment
from autosync.cpptranslator.patches.STIArgument import STIArgument
from autosync.cpptranslator.patches.STIFeatureBits import STIFeatureBits
from autosync.cpptranslator.patches.STParameter import SubtargetInfoParam
from autosync.cpptranslator.patches.StreamOperation import StreamOperations
from autosync.cpptranslator.patches.TemplateDeclaration import TemplateDeclaration
from autosync.cpptranslator.patches.TemplateDefinition import TemplateDefinition
from autosync.cpptranslator.patches.TemplateParamDecl import TemplateParamDecl
from autosync.cpptranslator.patches.TemplateRefs import TemplateRefs
from autosync.cpptranslator.patches.UseMarkup import UseMarkup
from autosync.cpptranslator.patches.UsingDeclaration import UsingDeclaration
from autosync.cpptranslator.TemplateCollector import TemplateCollector
from autosync.Helper import (
convert_loglevel,
get_header,
get_path,
print_prominent_warning,
run_clang_format,
)
class Translator:
@ -162,17 +174,22 @@ class Translator:
TemplateDefinition.__name__: 6,
}
def __init__(self, configure: Configurator):
def __init__(self, configure: Configurator, wait_for_user: bool = False):
self.configurator = configure
self.wait_for_user = wait_for_user
self.arch = self.configurator.get_arch()
self.conf = self.configurator.get_arch_config()
self.conf_general = self.configurator.get_general_config()
self.ts_cpp_lang = self.configurator.get_cpp_lang()
self.parser = self.configurator.get_parser()
self.src_paths: [Path] = [get_path(sp["in"]) for sp in self.conf["files_to_translate"]]
t_out_dir: Path = get_path(self.conf_general["translation_out_dir"])
self.out_paths: [Path] = [t_out_dir.joinpath(sp["out"]) for sp in self.conf["files_to_translate"]]
self.src_paths: [Path] = [
get_path(sp["in"]) for sp in self.conf["files_to_translate"]
]
t_out_dir: Path = get_path("{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}")
self.out_paths: [Path] = [
t_out_dir.joinpath(sp["out"]) for sp in self.conf["files_to_translate"]
]
self.collect_template_instances()
self.init_patches()
@ -188,7 +205,9 @@ class Translator:
def init_patches(self):
log.debug("Init patches")
priorities = dict(sorted(self.patch_priorities.items(), key=lambda item: item[1]))
priorities = dict(
sorted(self.patch_priorities.items(), key=lambda item: item[1])
)
for ptype, p in priorities.items():
match ptype:
case RegClassContains.__name__:
@ -351,8 +370,13 @@ class Translator:
def apply_patch(self, patch: Patch) -> bool:
"""Tests if the given patch should be applied for the current architecture or file."""
has_apply_only = len(patch.apply_only_to["files"]) > 0 or len(patch.apply_only_to["archs"]) > 0
has_do_not_apply = len(patch.do_not_apply["files"]) > 0 or len(patch.do_not_apply["archs"]) > 0
has_apply_only = (
len(patch.apply_only_to["files"]) > 0
or len(patch.apply_only_to["archs"]) > 0
)
has_do_not_apply = (
len(patch.do_not_apply["files"]) > 0 or len(patch.do_not_apply["archs"]) > 0
)
if not (has_apply_only or has_do_not_apply):
# Lists empty.
@ -374,7 +398,9 @@ class Translator:
exit(1)
def translate(self) -> None:
for self.current_src_path_in, self.current_src_path_out in zip(self.src_paths, self.out_paths):
for self.current_src_path_in, self.current_src_path_out in zip(
self.src_paths, self.out_paths
):
log.info(f"Translate '{self.current_src_path_in}'")
self.parse(self.current_src_path_in)
patch: Patch
@ -398,7 +424,9 @@ class Translator:
# Add it to the bundle.
captures_bundle[-1].append(q)
log.debug(f"Patch {patch.__class__.__name__} (to patch: {len(captures_bundle)}).")
log.debug(
f"Patch {patch.__class__.__name__} (to patch: {len(captures_bundle)})."
)
p_list: (bytes, Node) = list()
cb: [(Node, str)]
@ -420,8 +448,12 @@ class Translator:
def collect_template_instances(self):
search_paths = [get_path(p) for p in self.conf["files_for_template_search"]]
temp_arg_deduction = [p.encode("utf8") for p in self.conf["templates_with_arg_deduction"]]
self.template_collector = TemplateCollector(self.parser, self.ts_cpp_lang, search_paths, temp_arg_deduction)
temp_arg_deduction = [
p.encode("utf8") for p in self.conf["templates_with_arg_deduction"]
]
self.template_collector = TemplateCollector(
self.parser, self.ts_cpp_lang, search_paths, temp_arg_deduction
)
self.template_collector.collect()
def get_patch_kwargs(self, patch):
@ -435,7 +467,8 @@ class Translator:
if len(manual_edited) > 0:
msg += (
termcolor.colored(
"The following files are too complex to translate! Please check them by hand.", attrs=["bold"]
"The following files are too complex to translate! Please check them by hand.",
attrs=["bold"],
)
+ "\n"
)
@ -443,7 +476,7 @@ class Translator:
return
for f in manual_edited:
msg += get_path(f).name + "\n"
print_prominent_warning(msg)
print_prominent_warning(msg, self.wait_for_user)
def parse_args() -> argparse.Namespace:
@ -452,7 +485,11 @@ def parse_args() -> argparse.Namespace:
description="Capstones C++ to C translator for LLVM source files",
)
parser.add_argument(
"-a", dest="arch", help="Name of target architecture.", choices=["ARM", "PPC", "AArch64", "Alpha"], required=True
"-a",
dest="arch",
help="Name of target architecture.",
choices=["ARM", "PPC", "AArch64", "Alpha"],
required=True,
)
parser.add_argument(
"-v",
@ -462,7 +499,11 @@ def parse_args() -> argparse.Namespace:
default="info",
)
parser.add_argument(
"-c", dest="config_path", help="Config file for architectures.", default="arch_config.json", type=Path
"-c",
dest="config_path",
help="Config file for architectures.",
default="arch_config.json",
type=Path,
)
arguments = parser.parse_args()
return arguments

View File

@ -1,29 +1,34 @@
#!/usr/bin/env python3
import json
from enum import StrEnum
from pathlib import Path
from typing import Iterator
from tree_sitter import Language, Parser, Tree, Node
from shutil import copy2
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import argparse
import difflib as dl
import json
import logging as log
import subprocess
import sys
import tempfile
from enum import StrEnum
from pathlib import Path
from shutil import copy2
from CppTranslator.Configurator import Configurator
from Helper import (
convert_loglevel,
find_id_by_type,
print_prominent_info,
from tree_sitter import Language, Node, Parser, Tree
from autosync.cpptranslator.Configurator import Configurator
from autosync.Helper import (
bold,
colored,
convert_loglevel,
find_id_by_type,
get_path,
get_sha256,
print_prominent_info,
print_prominent_warning,
run_clang_format,
separator_line_1,
separator_line_2,
print_prominent_warning,
get_sha256,
run_clang_format,
get_path,
)
@ -35,7 +40,13 @@ class PatchCoord:
start_point: tuple[int, int]
end_point: tuple[int, int]
def __init__(self, start_byte: int, end_byte: int, start_point: tuple[int, int], end_point: tuple[int, int]):
def __init__(
self,
start_byte: int,
end_byte: int,
start_point: tuple[int, int],
end_point: tuple[int, int],
):
self.start_byte = start_byte
self.end_byte = end_byte
self.start_point = start_point
@ -58,7 +69,9 @@ class PatchCoord:
@staticmethod
def get_coordinates_from_node(node: Node):
return PatchCoord(node.start_byte, node.end_byte, node.start_point, node.end_point)
return PatchCoord(
node.start_byte, node.end_byte, node.start_point, node.end_point
)
class ApplyType(StrEnum):
@ -66,6 +79,7 @@ class ApplyType(StrEnum):
NEW = "NEW" # Apply version from new file (leave unchanged)
SAVED = "SAVED" # Use saved resolution
EDIT = "EDIT" # Edit patch and apply
SHOW_EDIT = "SHOW_EDIT" # Show the saved edited text.
OLD_ALL = "OLD_ALL" # Apply all versions from old file.
PREVIOUS = "PREVIOUS" # Ignore diff and go to previous
@ -81,7 +95,13 @@ class Patch:
new_hash: str
def __init__(
self, node_id: str, old: bytes, new: bytes, coord: PatchCoord, apply: ApplyType, edit: bytes = None
self,
node_id: str,
old: bytes,
new: bytes,
coord: PatchCoord,
apply: ApplyType,
edit: bytes = None,
) -> None:
if apply == ApplyType.SAVED:
raise NotImplementedError("Not yet implemented.")
@ -133,6 +153,41 @@ class Patch:
class Differ:
"""
Diffs the newly translated C++ files against the old version.
The general diffing works like this:
The old and the new file get parsed with tree sitter into an AST.
Then, we extract all nodes of a specific type out of this AST.
Which nodes specifically is defined in "arch_config.json::General::nodes_to_diff".
These nodes (old and new separately) are than sorted descending by their coordinates.
Meaning, nodes at the end in the file come first.
The identifiers of those nodes are saved in a single list.
Now we iterate over this list of identifiers. Now we make decisions:
The node id is present as:
old node & new node => Text matches?
yes => Continue
no => Add new node as Patch (see below)
only old node => We save all consecutive old nodes, which have _no_ equivalent new node
and add them as single patch
only new node => Add patch
Now we have the patch. We have a persistence file which saved previous decisions, on which patch to choose.
We take the node text of the old and new node (or only from a single one) and compare them to our previous decision.
If the text of the nodes didn't change since the last run, we auto-apply the patch.
Otherwise, the user decides:
- Choose the old node text
- Choose the new node text
- Open the editor to edit the patch and apply it.
- Use the stored previous decision.
- Select always the old nodes.
- Go back and decide on node before.
Each decision is saved to the persistence file for later.
Last (optional) step is to write the patches to the new file.
Please note that we always write to the new file in the current version.
"""
ts_cpp_lang: Language = None
@ -148,11 +203,13 @@ class Differ:
patches: list[Patch]
current_patch: Patch
cur_old_node: Node = None
cur_new_node: Node = None
cur_old_node: Node | None = None
cur_new_node: Node | None = None
cur_nid: str = None
def __init__(self, configurator: Configurator, no_auto_apply: bool):
def __init__(
self, configurator: Configurator, no_auto_apply: bool, testing: bool = False
):
self.configurator = configurator
self.no_auto_apply = no_auto_apply
self.arch = self.configurator.get_arch()
@ -161,18 +218,41 @@ class Differ:
self.ts_cpp_lang = self.configurator.get_cpp_lang()
self.parser = self.configurator.get_parser()
self.differ = dl.Differ()
self.testing = testing
t_out_dir: Path = get_path(self.conf_general["translation_out_dir"])
self.translated_files = [t_out_dir.joinpath(sp["out"]) for sp in self.conf_arch["files_to_translate"]]
cs_arch_src: Path = get_path("{CS_ARCH_MODULE_DIR}")
cs_arch_src = cs_arch_src.joinpath(self.arch if self.arch != "PPC" else "PowerPC")
self.diff_out_dir = get_path("{CPP_TRANSLATOR_DIFF_OUT_DIR}")
if self.testing:
t_out_dir: Path = get_path("{DIFFER_TEST_NEW_SRC_DIR}")
self.translated_files = [
t_out_dir.joinpath(sp["out"])
for sp in self.conf_arch["files_to_translate"]
]
self.old_files = [
cs_arch_src.joinpath(f"{cs_arch_src}/" + sp["out"]) for sp in self.conf_arch["files_to_translate"]
get_path("{DIFFER_TEST_OLD_SRC_DIR}").joinpath(sp["out"])
for sp in self.conf_arch["files_to_translate"]
]
self.load_persistence_file()
else:
t_out_dir: Path = get_path("{CPP_TRANSLATOR_TRANSLATION_OUT_DIR}")
self.translated_files = [
t_out_dir.joinpath(sp["out"])
for sp in self.conf_arch["files_to_translate"]
]
cs_arch_src: Path = get_path("{CS_ARCH_MODULE_DIR}")
cs_arch_src = cs_arch_src.joinpath(
self.arch if self.arch != "PPC" else "PowerPC"
)
self.old_files = [
cs_arch_src.joinpath(f"{cs_arch_src}/" + sp["out"])
for sp in self.conf_arch["files_to_translate"]
]
self.load_persistence_file()
def load_persistence_file(self) -> None:
self.persistence_filepath = get_path(self.conf_general["patch_persistence_file"])
if self.testing:
self.persistence_filepath = get_path("{DIFFER_TEST_PERSISTENCE_FILE}")
else:
self.persistence_filepath = get_path("{DIFFER_PERSISTENCE_FILE}")
if not self.persistence_filepath.exists():
self.saved_patches = dict()
return
@ -181,7 +261,9 @@ class Differ:
try:
self.saved_patches = json.load(f)
except json.decoder.JSONDecodeError as e:
log.fatal(f"Persistence file {bold(self.persistence_filepath.name)} corrupt.")
log.fatal(
f"Persistence file {bold(self.persistence_filepath.name)} corrupt."
)
log.fatal("Delete it or fix it by hand.")
log.fatal(f"JSON Exception: {e}")
exit(1)
@ -191,6 +273,10 @@ class Differ:
json.dump(self.saved_patches, f, indent=2)
def persist_patch(self, filename: Path, patch: Patch) -> None:
"""
:param filename: The filename this patch is saved for.
:param patch: The patch to apply.
"""
if filename.name not in self.saved_patches:
self.saved_patches[filename.name] = dict()
log.debug(f"Save: {patch.get_persist_info()}")
@ -201,14 +287,19 @@ class Differ:
Copy translated files to diff directory for editing.
"""
log.info("Copy files for editing")
diff_dir: Path = get_path(self.conf_general["diff_out_dir"])
diff_dir: Path = self.diff_out_dir
for f in self.translated_files:
dest = diff_dir.joinpath(f.name)
copy2(f, dest)
self.diff_dest_files.append(dest)
def get_diff_intro_msg(
self, old_filename: Path, new_filename: Path, current: int, total: int, num_diffs: int
self,
old_filename: Path,
new_filename: Path,
current: int,
total: int,
num_diffs: int,
) -> str:
color_new = self.conf_general["diff_color_new"]
color_old = self.conf_general["diff_color_old"]
@ -229,7 +320,9 @@ class Differ:
if n["node_type"] == node.type:
id_types = n["identifier_node_type"]
if not id_types:
log.fatal(f"Diffing: Node of type {node.type} has not identifier type specified.")
log.fatal(
f"Diffing: Node of type {node.type} has not identifier type specified."
)
exit(1)
identifier = ""
for id_type in id_types:
@ -241,7 +334,7 @@ class Differ:
exit(1)
return identifier
def parse_file(self, file: Path) -> dict:
def parse_file(self, file: Path) -> dict[str:Node]:
"""
Parse a files and return all nodes which should be diffed.
Nodes are indexed by a unique identifier.
@ -251,7 +344,9 @@ class Differ:
tree: Tree = self.parser.parse(content, keep_text=True)
node_types_to_diff = [n["node_type"] for n in self.conf_general["nodes_to_diff"]]
node_types_to_diff = [
n["node_type"] for n in self.conf_general["nodes_to_diff"]
]
content = None
if file.suffix == ".h":
# Header file. Get the content in between the include guard
@ -283,11 +378,13 @@ class Differ:
def print_diff(self, diff_lines: list[str], node_id: str, current: int, total: int):
new_color = self.conf_general["diff_color_new"]
old_color = self.conf_general["diff_color_old"]
print(separator_line_1())
print(separator_line_2())
print(f"{bold('Patch:')} {current}/{total}\n")
print(f"{bold('Node:')} {node_id}")
print(f"{bold('Color:')} {colored('NEW FILE - (Just translated)', new_color)}")
print(f"{bold('Color:')} {colored('OLD FILE - (Currently in Capstone)', old_color)}\n")
print(
f"{bold('Color:')} {colored('OLD FILE - (Currently in Capstone)', old_color)}\n"
)
print(separator_line_1())
for line in diff_lines:
if line[0] == "+":
@ -301,13 +398,15 @@ class Differ:
print(separator_line_2())
@staticmethod
def no_difference(diff_lines: Iterator[str]) -> bool:
def no_difference(diff_lines: list[str]) -> bool:
for line in diff_lines:
if line[0] != " ":
return False
return True
def print_prompt(self, saved_diff_present: bool = False, saved_choice: ApplyType = None) -> str:
def print_prompt(
self, saved_diff_present: bool = False, saved_choice: ApplyType = None
) -> str:
new_color = self.conf_general["diff_color_new"]
old_color = self.conf_general["diff_color_old"]
edited_color = self.conf_general["diff_color_edited"]
@ -315,15 +414,19 @@ class Differ:
choice = input(
f"Choice: {colored('O', old_color)}, {bold('o', old_color)}, {bold('n', new_color)}, "
f"{saved_selection}, {colored('e', edited_color)}, p, q, ? > "
f"{saved_selection}, {colored('e', edited_color)}, {colored('E', edited_color)}, p, q, ? > "
)
return choice
def get_saved_choice_prompt(self, saved_diff_present: bool = False, saved_choice: ApplyType = None):
def get_saved_choice_prompt(
self, saved_diff_present: bool = False, saved_choice: ApplyType = None
):
new_color = self.conf_general["diff_color_new"]
old_color = self.conf_general["diff_color_old"]
edited_color = self.conf_general["diff_color_edited"]
saved_color = self.conf_general["diff_color_saved"] if saved_diff_present else "dark_grey"
saved_color = (
self.conf_general["diff_color_saved"] if saved_diff_present else "dark_grey"
)
saved_selection = f"{bold('s', saved_color)}"
if saved_choice == ApplyType.OLD:
saved_selection += f" ({colored('old', old_color)}) "
@ -335,7 +438,9 @@ class Differ:
saved_selection += f" ({colored('none', 'dark_grey')}) "
return saved_selection
def print_prompt_help(self, saved_diff_present: bool = False, saved_choice: ApplyType = None) -> None:
def print_prompt_help(
self, saved_diff_present: bool = False, saved_choice: ApplyType = None
) -> None:
new_color = self.conf_general["diff_color_new"]
old_color = self.conf_general["diff_color_old"]
edited_color = self.conf_general["diff_color_edited"]
@ -352,10 +457,12 @@ class Differ:
f"?\t\t- Show this help\n\n"
)
def get_user_choice(self, saved_diff_present: bool, saved_choice: ApplyType) -> ApplyType:
def get_user_choice(
self, saved_diff_present: bool, saved_choice: ApplyType
) -> ApplyType:
while True:
choice = self.print_prompt(saved_diff_present, saved_choice)
if choice not in ["O", "o", "n", "e", "s", "p", "q", "?", "help"]:
if choice not in ["O", "o", "n", "e", "E", "s", "p", "q", "?", "help"]:
print(f"{bold(choice)} is not valid.")
self.print_prompt_help(saved_diff_present, saved_choice)
continue
@ -372,6 +479,8 @@ class Differ:
return ApplyType.OLD_ALL
elif choice == "e":
return ApplyType.EDIT
elif choice == "E":
return ApplyType.SHOW_EDIT
elif choice == "s":
return ApplyType.SAVED
elif choice in ["?", "help"]:
@ -391,10 +500,23 @@ class Differ:
new_hash = ""
return saved["old_hash"] == old_hash and saved["new_hash"] == new_hash
def create_patch(self, coord: PatchCoord, choice: ApplyType, saved_patch: dict = None):
def create_patch(
self,
coord: PatchCoord,
choice: ApplyType,
saved_patch: dict = None,
edited_text: bytes = None,
):
old = self.cur_old_node.text if self.cur_old_node else b""
new = self.cur_new_node.text if self.cur_new_node else b""
return Patch(self.cur_nid, old, new, coord, saved_patch["apply_type"] if saved_patch else choice)
return Patch(
self.cur_nid,
old,
new,
coord,
saved_patch["apply_type"] if saved_patch else choice,
edit=edited_text,
)
def add_patch(
self,
@ -402,8 +524,12 @@ class Differ:
consec_old: int,
old_filepath: Path,
patch_coord: PatchCoord,
saved_patch: dict | None = None,
edited_text: bytes | None = None,
) -> None:
self.current_patch = self.create_patch(patch_coord, apply_type)
self.current_patch = self.create_patch(
patch_coord, apply_type, saved_patch, edited_text
)
self.persist_patch(old_filepath, self.current_patch)
if consec_old > 1:
# Two or more old nodes are not present in the new file.
@ -412,18 +538,34 @@ class Differ:
else:
self.patches.append(self.current_patch)
def diff_nodes(self, old_filepath: Path, new_nodes: dict[bytes, Node], old_nodes: dict[bytes, Node]) -> list[Patch]:
def diff_nodes(
self,
old_filepath: Path,
new_nodes: dict[bytes, Node],
old_nodes: dict[bytes, Node],
) -> list[Patch]:
"""
Asks the user for each different node, which version should be written.
It writes the choice to a file, so the previous choice can be applied again if nothing changed.
"""
# Sort list of nodes descending.
# This is necessary because
# a) we need to apply the patches backwards (so the coordinates in the file don't change.
# a) we need to apply the patches backwards (starting from the end of the file,
# so the coordinates in the file don't change, when replace text).
# b) If there is an old node, which is not present in the new file, we search for
# a node which is adjacent (random node order wouldn't allow this).
new_nodes = {k: v for k, v in sorted(new_nodes.items(), key=lambda item: item[1].start_byte, reverse=True)}
old_nodes = {k: v for k, v in sorted(old_nodes.items(), key=lambda item: item[1].start_byte, reverse=True)}
new_nodes = {
k: v
for k, v in sorted(
new_nodes.items(), key=lambda item: item[1].start_byte, reverse=True
)
}
old_nodes = {
k: v
for k, v in sorted(
old_nodes.items(), key=lambda item: item[1].start_byte, reverse=True
)
}
# Collect all node ids of this file
node_ids = set()
@ -433,36 +575,48 @@ class Differ:
# The initial patch coordinates point after the last node in the file.
n0 = new_nodes[list(new_nodes.keys())[0]]
patch_coord = PatchCoord(n0.end_byte, n0.end_byte, n0.end_point, n0.end_point)
PatchCoord(n0.end_byte, n0.end_byte, n0.end_point, n0.end_point)
node_ids = sorted(node_ids)
self.patches = list()
matching_nodes_count = 0
# Counts the number of old nodes which have no equivalent new node.
# Counts the number of _consecutive_ old nodes which have no equivalent new node.
# They will be merged to a single patch later
consec_old = 0
choice: ApplyType = None
i = 0
while i < len(node_ids):
self.cur_nid = node_ids[i]
self.cur_new_node = None
if self.cur_nid in new_nodes:
self.cur_new_node = new_nodes[self.cur_nid]
self.cur_old_node = None
if self.cur_nid in old_nodes:
self.cur_old_node = old_nodes[self.cur_nid]
choice: ApplyType | None = None
idx = 0
while idx < len(node_ids):
self.cur_nid = node_ids[idx]
self.cur_new_node = (
None if self.cur_nid not in new_nodes else new_nodes[self.cur_nid]
)
self.cur_old_node = (
None if self.cur_nid not in old_nodes else old_nodes[self.cur_nid]
)
n = self.cur_new_node.text.decode("utf8").splitlines() if self.cur_new_node else [""]
o = self.cur_old_node.text.decode("utf8").splitlines() if self.cur_old_node else [""]
n = (
self.cur_new_node.text.decode("utf8").splitlines()
if self.cur_new_node
else [""]
)
o = (
self.cur_old_node.text.decode("utf8").splitlines()
if self.cur_old_node
else [""]
)
diff_lines = list(self.differ.compare(o, n))
if self.no_difference(diff_lines):
log.debug(f"Nodes {bold(self.cur_nid)} match.")
log.info(
f"{bold('Patch:')} {idx + 1}/{len(node_ids)} - Nodes {bold(self.cur_nid)} match."
)
matching_nodes_count += 1
i += 1
idx += 1
continue
if self.cur_new_node:
consec_old = 0
# We always write to the new file. So we always take he coordinates form it.
patch_coord = PatchCoord.get_coordinates_from_node(self.cur_new_node)
else:
consec_old += 1
@ -473,38 +627,50 @@ class Differ:
j = old_node_ids.index(self.cur_nid)
while j >= 0 and (old_node_ids[j] not in new_nodes.keys()):
j -= 1
ref_new: Node = new_nodes[old_node_ids[j]] if old_node_ids[j] in new_nodes.keys() else new_nodes[0]
ref_new: Node = (
new_nodes[old_node_ids[j]]
if old_node_ids[j] in new_nodes.keys()
else new_nodes[0]
)
ref_end_byte = ref_new.start_byte
# We always write to the new file. So we always take he coordinates form it.
patch_coord = PatchCoord(
ref_end_byte - 1,
ref_end_byte - 1,
ref_end_byte,
ref_end_byte,
ref_new.start_point,
ref_new.start_point,
)
save_exists = False
saved = None
if old_filepath.name in self.saved_patches and self.cur_nid in self.saved_patches[old_filepath.name]:
saved: dict = self.saved_patches[old_filepath.name][self.cur_nid]
saved: dict | None = None
if (
old_filepath.name in self.saved_patches
and self.cur_nid in self.saved_patches[old_filepath.name]
):
saved = self.saved_patches[old_filepath.name][self.cur_nid]
save_exists = True
if self.saved_patch_matches(saved) and not self.no_auto_apply:
apply_type = ApplyType(saved["apply_type"])
self.add_patch(apply_type, consec_old, old_filepath, patch_coord)
log.info(f"Auto apply patch for {bold(self.cur_nid)}")
i += 1
log.info(
f"{bold('Patch:')} {idx + 1}/{len(node_ids)} - Auto apply patch for {bold(self.cur_nid)}"
)
idx += 1
continue
if choice == ApplyType.OLD_ALL:
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
i += 1
idx += 1
continue
self.print_diff(diff_lines, self.cur_nid, i + 1, len(node_ids))
choice = self.get_user_choice(save_exists, None if not saved else saved["apply_type"])
self.print_diff(diff_lines, self.cur_nid, idx + 1, len(node_ids))
choice = self.get_user_choice(
save_exists, None if not saved else saved["apply_type"]
)
if choice == ApplyType.OLD:
if not self.cur_old_node:
# No data in old node. Skip
i += 1
idx += 1
continue
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
elif choice == ApplyType.NEW:
@ -514,20 +680,43 @@ class Differ:
if not save_exists:
print(bold("Save does not exist."))
continue
self.add_patch(saved["apply_type"], consec_old, old_filepath, patch_coord)
self.add_patch(
saved["apply_type"],
consec_old,
old_filepath,
patch_coord,
saved_patch=saved,
edited_text=saved["edit"].encode(),
)
elif choice == ApplyType.SHOW_EDIT:
if not saved or not saved["edit"]:
print(bold("No edited text was saved before."))
input("Press enter to continue...\n")
continue
saved_edited_text = colored(
f'\n{saved["edit"]}\n', self.conf_general["diff_color_edited"]
)
print(saved_edited_text)
input("Press enter to continue...\n")
continue
elif choice == ApplyType.OLD_ALL:
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
elif choice == ApplyType.EDIT:
print(f"{bold('Editing not yet implemented.', 'light_red')}")
edited_text = self.edit_patch(diff_lines)
if not edited_text:
continue
self.persist_patch(
old_filepath,
self.create_patch(patch_coord, choice, edited_text=edited_text),
)
elif choice == ApplyType.PREVIOUS:
if i == 0:
if idx == 0:
print(bold(f"There is no previous diff for {old_filepath.name}!"))
input("Press enter...")
continue
i -= 1
idx -= 1
continue
i += 1
idx += 1
log.info(f"Number of matching nodes = {matching_nodes_count}")
return self.patches
@ -558,10 +747,16 @@ class Differ:
old_filepath = old_file[k]["filepath"]
new_filepath = new_file[k]["filepath"]
diffs_to_process = max(len(new_file[k]["nodes"]), len(old_file[k]["nodes"]))
print_prominent_info(self.get_diff_intro_msg(old_filepath, new_filepath, k + 1, i, diffs_to_process))
print_prominent_info(
self.get_diff_intro_msg(
old_filepath, new_filepath, k + 1, i, diffs_to_process
)
)
if diffs_to_process == 0:
continue
patches[new_filepath] = self.diff_nodes(old_filepath, new_file[k]["nodes"], old_file[k]["nodes"])
patches[new_filepath] = self.diff_nodes(
old_filepath, new_file[k]["nodes"], old_file[k]["nodes"]
)
self.patch_files(patches)
log.info("Done")
@ -590,6 +785,38 @@ class Differ:
run_clang_format(list(file_patches.keys()))
return
def edit_patch(self, diff_lines: list[str]) -> bytes | None:
tmp_file = tempfile.NamedTemporaryFile(suffix="c", delete=False)
tmp_file_name = tmp_file.name
tmp_file.writelines([line.encode() + b"\n" for line in diff_lines])
tmp_file.write(self.get_edit_explanation())
tmp_file.close()
editor = self.conf_general["patch_editor"]
try:
subprocess.run([editor, tmp_file_name])
except FileNotFoundError:
log.error(f"Could not find editor '{editor}'")
return None
edited_text = b""
with open(tmp_file_name, "rb") as tmp_file:
for line in tmp_file.readlines():
if self.get_separator_line() in line:
break
edited_text += line
tmp_file.close()
return edited_text
@staticmethod
def get_separator_line() -> bytes:
return f"// {'=' * 50}".encode()
def get_edit_explanation(self) -> bytes:
return (
f"{self.get_separator_line().decode('utf8')}\n"
"// Everything below this line will be deleted\n"
"// Edit the file to your liking. The result will be written 'as is' to the source file.\n"
).encode()
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
@ -603,7 +830,11 @@ def parse_args() -> argparse.Namespace:
action="store_true",
)
parser.add_argument(
"-a", dest="arch", help="Name of target architecture.", choices=["ARM", "PPC, AArch64", "Alpha"], required=True
"-a",
dest="arch",
help="Name of target architecture (ignored with -t option)",
choices=["ARM", "PPC, AArch64", "Alpha"],
required=True,
)
parser.add_argument(
"-v",
@ -613,7 +844,7 @@ def parse_args() -> argparse.Namespace:
default="info",
)
parser.add_argument(
"-c", dest="config_path", help="Config file for architectures.", default="arch_config.json", type=Path
"-t", dest="testing", help="Run with test configuration.", action="store_true"
)
arguments = parser.parse_args()
return arguments
@ -629,9 +860,12 @@ if __name__ == "__main__":
stream=sys.stdout,
format="%(levelname)-5s - %(message)s",
)
cfg = Configurator(args.arch, args.config_path)
if args.testing:
cfg = Configurator("ARCH", get_path("{DIFFER_TEST_CONFIG_FILE}"))
else:
cfg = Configurator(args.arch, get_path("{CPP_TRANSLATOR_CONFIG}"))
differ = Differ(cfg, args.no_auto_apply)
differ = Differ(cfg, args.no_auto_apply, testing=args.testing)
try:
differ.diff()
except Exception as e:

View File

@ -1,3 +1,8 @@
<!--
Copyright © 2022 Rot127 <unisono@quyllur.org>
SPDX-License-Identifier: BSD-3
-->
# C++ Translator
Capstone uses source files from LLVM to disassemble opcodes.
@ -13,16 +18,14 @@ The configuration for each architecture is set in `arch_config.json`.
The config values have the following meaning:
- `General`: Settings valid for all architectures.
- `patch_persistent_file`: Path to the file which saves the selections from the `Differ`.
- `translation_out_dir`: Path to the directory where the `CppTranslator` stores its files.
- `diff_out_dir`: Path to the directory where the `Differ` stores its files.
- `diff_color_new`: Color in the `Differ` for translated content.
- `diff_color_old`: Color in the `Differ` for old/current Capstone content.
- `diff_color_saved`: Color in the `Differ` for saved content.
- `diff_color_edited`: Color in the `Differ` for edited content.
- `patch_editor`: Editor to open for patch editing.
- `nodes_to_diff`: List of parse tree nodes which get diffed - *Mind the note below*.
- `node_type`: The `type` of the node to be diffed.
- `identifier_node_type`: Types of child nodes which identify the node during diffing (the identifier must be the same in the translated and the old file!).
- `identifier_node_type`: Types of child nodes which identify the node during diffing (the identifier must be the same in the translated and the old file!). Types can be of the form `<parent-type>/<child type>`.
- `<ARCH>`: Settings valid for a specific architecture
- `files_to_translate`: A list of file paths to translate.
- `in`: *Path* to a specific source file.

View File

@ -1,11 +1,13 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
import re
from pathlib import Path
from tree_sitter import Language, Parser
import logging as log
from tree_sitter import Language, Node, Parser, Query
from tree_sitter.binding import Query, Node
from CppTranslator.Patches.HelperMethods import get_text
from autosync.cpptranslator.patches.Helper import get_text
class TemplateRefInstance:
@ -27,7 +29,9 @@ class TemplateRefInstance:
# (parameters are set by the template parameters of the calling function).
caller_param_indices: [{str: int}] = list()
def __init__(self, name: bytes, args: bytes, start_point, start_byte, end_point, end_byte):
def __init__(
self, name: bytes, args: bytes, start_point, start_byte, end_point, end_byte
):
self.name = name
self.args = args
self.start_point = start_point
@ -41,7 +45,14 @@ class TemplateRefInstance:
return (
self.name == other.name
and self.args == other.args
and any([a == b for a, b in zip(self.caller_param_indices, other.caller_param_indices)])
and any(
[
a == b
for a, b in zip(
self.caller_param_indices, other.caller_param_indices
)
]
)
and self.start_byte == other.start_byte
and self.start_point == other.start_point
and self.end_byte == other.end_byte
@ -75,7 +86,13 @@ class TemplateCollector:
incomplete_template_refs: {bytes: [TemplateRefInstance]} = dict()
sources: [{str: bytes}] = list()
def __init__(self, ts_parser: Parser, ts_cpp: Language, searchable_files: [Path], temp_arg_deduction: [bytes]):
def __init__(
self,
ts_parser: Parser,
ts_cpp: Language,
searchable_files: [Path],
temp_arg_deduction: [bytes],
):
self.parser = ts_parser
self.lang_cpp = ts_cpp
self.searchable_files = searchable_files
@ -100,10 +117,17 @@ class TemplateCollector:
args = get_text(src, templ_args.start_byte, templ_args.end_byte)
ti = TemplateRefInstance(
name, args, cb[0][0].start_point, cb[0][0].start_byte, cb[0][0].end_point, cb[0][0].end_byte
name,
args,
cb[0][0].start_point,
cb[0][0].start_byte,
cb[0][0].end_point,
cb[0][0].end_byte,
)
log.debug(f"Found new template ref: {name.decode('utf8')}{args.decode('utf8')}")
log.debug(
f"Found new template ref: {name.decode('utf8')}{args.decode('utf8')}"
)
if not self.contains_template_dependent_param(src, ti, cb[0]):
if name not in self.template_refs:
@ -118,7 +142,10 @@ class TemplateCollector:
def resolve_dependencies(self):
# Resolve dependencies of templates until nothing new was resolved.
prev_len = 0
while len(self.incomplete_template_refs) > 0 and len(self.incomplete_template_refs) != prev_len:
while (
len(self.incomplete_template_refs) > 0
and len(self.incomplete_template_refs) != prev_len
):
# Dict with new template calls which were previously incomplete
# because one or more parameters were unknown.
new_completed_tcs: {str: list} = dict()
@ -134,7 +161,9 @@ class TemplateCollector:
for caller_template in tc_instance_list:
incomplete_tc: TemplateRefInstance
for incomplete_tc in self.incomplete_template_refs[caller_name]:
new_tc: TemplateRefInstance = self.get_completed_tc(caller_template, incomplete_tc)
new_tc: TemplateRefInstance = self.get_completed_tc(
caller_template, incomplete_tc
)
callee_name = new_tc.name
if callee_name not in new_completed_tcs:
new_completed_tcs[callee_name] = list()
@ -149,11 +178,22 @@ class TemplateCollector:
self.template_refs[templ_name] = tc_list
prev_len = len(self.incomplete_template_refs)
if prev_len > 0:
log.info(f"Unresolved template calls: {self.incomplete_template_refs.keys()}. Patch them by hand!")
log.info(
f"Unresolved template calls: {self.incomplete_template_refs.keys()}. Patch them by hand!"
)
@staticmethod
def get_completed_tc(tc: TemplateRefInstance, itc: TemplateRefInstance) -> TemplateRefInstance:
new_tc = TemplateRefInstance(itc.name, itc.args, itc.start_byte, itc.start_byte, itc.end_point, itc.end_byte)
def get_completed_tc(
tc: TemplateRefInstance, itc: TemplateRefInstance
) -> TemplateRefInstance:
new_tc = TemplateRefInstance(
itc.name,
itc.args,
itc.start_byte,
itc.start_byte,
itc.end_point,
itc.end_byte,
)
for indices in itc.caller_param_indices:
if tc.name not in indices:
# Index of other caller function. Skip.
@ -165,7 +205,9 @@ class TemplateCollector:
new_tc.templ_name = new_tc.name + new_tc.args
return new_tc
def contains_template_dependent_param(self, src, ti: TemplateRefInstance, parse_tree: (Node, str)) -> bool:
def contains_template_dependent_param(
self, src, ti: TemplateRefInstance, parse_tree: (Node, str)
) -> bool:
"""Here we check if one of the template parameters of the given template call,
is a parameter of the callers template definition.
@ -201,14 +243,20 @@ class TemplateCollector:
return False
caller_fcn_id = node.named_children[2].named_children[0]
caller_fcn_name = get_text(src, caller_fcn_id.start_byte, caller_fcn_id.end_byte)
caller_templ_params = get_text(src, node.prev_sibling.start_byte, node.prev_sibling.end_byte)
caller_fcn_name = get_text(
src, caller_fcn_id.start_byte, caller_fcn_id.end_byte
)
caller_templ_params = get_text(
src, node.prev_sibling.start_byte, node.prev_sibling.end_byte
)
pl = TemplateCollector.templ_params_to_list(caller_templ_params)
has_parameter_dependency = False
for i, param in enumerate(pl):
if param in ti.args_list:
has_parameter_dependency = True
ti.caller_param_indices.append({caller_fcn_name: i, "self_i": ti.args_list.index(param)})
ti.caller_param_indices.append(
{caller_fcn_name: i, "self_i": ti.args_list.index(param)}
)
if not has_parameter_dependency:
return False

View File

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
// SPDX-License-Identifier: BSD-3
#include "some_header_I.h"
#include <some_system_header.h>
#define MACRO_A 0
#define MACRO_B 0
#define FCN_MACRO_A(x) function_a(x)
#define FCN_MACRO_B(x) \
function_b(x + 1)
int main() {
int x = 10000 * 71;
return x;
}
void function_a(int x) {
return;
}
void function_b(unsigned x) {
return;
}
void only_in_new() {}

View File

@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
// SPDX-License-Identifier: BSD-3
#include "some_header_I.h"
#include <some_system_header.h>
#define MACRO_A 0
#define MACRO_B 0
#define FCN_MACRO_A(x) function_a(x)
#define FCN_MACRO_B(x) \
function_b(x)
int main() {
int x = 71;
return x;
}
void function_a(int x) {
return;
}
void function_b(int x) {
return;
}
void only_in_old_I() {}
void only_in_old_II() {}

View File

@ -0,0 +1,35 @@
{
"General": {
"diff_color_new": "green",
"diff_color_old": "light_blue",
"diff_color_saved": "yellow",
"diff_color_edited": "light_magenta",
"patch_editor": "vim",
"nodes_to_diff": [
{
"node_type": "function_definition",
"identifier_node_type": ["function_declarator/identifier"]
},{
"node_type": "preproc_function_def",
"identifier_node_type": ["identifier"]
},{
"node_type": "preproc_include",
"identifier_node_type": ["string_literal", "system_lib_string"]
},{
"node_type": "preproc_define",
"identifier_node_type": ["identifier"]
}
]
},
"ARCH": {
"files_to_translate": [
{
"in": "{DIFFER_TEST_OLD_SRC_DIR}/diff_test_file.c",
"out": "diff_test_file.c"
}
],
"files_for_template_search": [],
"templates_with_arg_deduction": [],
"manually_edited_files": []
}
}

View File

@ -0,0 +1,7 @@
// SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
// SPDX-License-Identifier: BSD-3
int main() {
tfunction<int, int>();
tfunction<int, char>();
}

View File

@ -0,0 +1,16 @@
{
"General": {
"diff_color_new": "green",
"diff_color_old": "light_blue",
"diff_color_saved": "yellow",
"diff_color_edited": "light_magenta",
"patch_editor": "vim",
"nodes_to_diff": []
},
"ARCH": {
"files_to_translate": [],
"files_for_template_search": ["{PATCHES_TEST_DIR}/template_src.c"],
"templates_with_arg_deduction": [],
"manually_edited_files": []
}
}

View File

@ -0,0 +1,106 @@
# SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import unittest
from tree_sitter import Node
from autosync.cpptranslator.Configurator import Configurator
from autosync.cpptranslator.Differ import ApplyType, Differ, Patch, PatchCoord
from autosync.cpptranslator.TemplateCollector import TemplateCollector
from autosync.Helper import get_path
class TestHeaderPatcher(unittest.TestCase):
@classmethod
def setUpClass(cls):
configurator = Configurator("ARCH", get_path("{DIFFER_TEST_CONFIG_FILE}"))
cls.ts_cpp_lang = configurator.get_cpp_lang()
cls.parser = configurator.get_parser()
cls.template_collector = TemplateCollector(
configurator.get_parser(), configurator.get_cpp_lang(), [], []
)
cls.differ = Differ(configurator, testing=True, no_auto_apply=True)
def check_persistence(self, nid, expected, apply_type, edited_text):
new_node: Node = self.new_nodes[nid] if nid in self.new_nodes else None
old_node: Node = self.old_nodes[nid] if nid in self.old_nodes else None
if not new_node:
before_old_node = old_node.start_byte - 1
coord = PatchCoord(
before_old_node,
before_old_node,
(before_old_node, before_old_node),
(before_old_node, before_old_node),
)
else:
coord = PatchCoord(
new_node.start_byte,
new_node.end_byte,
new_node.start_point,
new_node.end_point,
)
patch = Patch(
node_id=nid,
old=old_node.text if old_node else b"",
new=new_node.text if new_node else b"",
coord=coord,
apply=apply_type,
edit=edited_text,
)
self.assertEqual(patch.get_persist_info(), expected)
def parse_files(self, filename: str):
self.old_nodes = self.differ.parse_file(
get_path("{DIFFER_TEST_OLD_SRC_DIR}").joinpath(filename)
)
self.new_nodes = self.differ.parse_file(
get_path("{DIFFER_TEST_NEW_SRC_DIR}").joinpath(filename)
)
def test_patch_persistence(self):
self.parse_files("diff_test_file.c")
nid = "function_b"
expected = {
f"{nid}": {
"apply_type": "OLD",
"edit": "aaaaaaa",
"new_hash": "e5b3e0e5c6fb1f5f39e5725e464e6dfa3c6a7f1a8a5d104801e1fc10b6f1cc2b",
"old_hash": "8fc2b2123209c37534bb60c8e38564ed773430b9fc5bca37a0ae73a64b2883ab",
}
}
edited_text: bytes = b"aaaaaaa"
self.check_persistence(nid, expected, ApplyType.OLD, edited_text)
nid = "only_in_old_I"
expected = {
f"{nid}": {
"apply_type": "NEW",
"edit": "",
"new_hash": "",
"old_hash": "37431b6fe6707794a8e07902bef6510fc1d10b833db9b1dccc70b1530997b2b1",
}
}
self.check_persistence(nid, expected, ApplyType.NEW, b"")
self.assertRaises(
NotImplementedError,
self.check_persistence,
nid=nid,
expected=expected,
apply_type=ApplyType.SAVED,
edited_text=b"",
)
nid = "function_b"
expected = {
f"{nid}": {
"apply_type": "EDIT",
"edit": "aaaaaaa\n\n\n\n\n91928",
"new_hash": "e5b3e0e5c6fb1f5f39e5725e464e6dfa3c6a7f1a8a5d104801e1fc10b6f1cc2b",
"old_hash": "8fc2b2123209c37534bb60c8e38564ed773430b9fc5bca37a0ae73a64b2883ab",
}
}
edited_text: bytes = b"aaaaaaa\n\n\n\n\n91928"
self.check_persistence(nid, expected, ApplyType.EDIT, edited_text)

View File

@ -0,0 +1,563 @@
#!/usr/bin/env python3
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import unittest
from tree_sitter import Node, Query
from autosync.cpptranslator import CppTranslator
from autosync.cpptranslator.Configurator import Configurator
from autosync.cpptranslator.patches.AddCSDetail import AddCSDetail
from autosync.cpptranslator.patches.AddOperand import AddOperand
from autosync.cpptranslator.patches.Assert import Assert
from autosync.cpptranslator.patches.BitCastStdArray import BitCastStdArray
from autosync.cpptranslator.patches.CheckDecoderStatus import CheckDecoderStatus
from autosync.cpptranslator.patches.ClassesDef import ClassesDef
from autosync.cpptranslator.patches.ConstMCInstParameter import ConstMCInstParameter
from autosync.cpptranslator.patches.ConstMCOperand import ConstMCOperand
from autosync.cpptranslator.patches.CppInitCast import CppInitCast
from autosync.cpptranslator.patches.CreateOperand0 import CreateOperand0
from autosync.cpptranslator.patches.CreateOperand1 import CreateOperand1
from autosync.cpptranslator.patches.DeclarationInConditionClause import (
DeclarationInConditionalClause,
)
from autosync.cpptranslator.patches.DecodeInstruction import DecodeInstruction
from autosync.cpptranslator.patches.DecoderCast import DecoderCast
from autosync.cpptranslator.patches.DecoderParameter import DecoderParameter
from autosync.cpptranslator.patches.FallThrough import FallThrough
from autosync.cpptranslator.patches.FeatureBits import FeatureBits
from autosync.cpptranslator.patches.FeatureBitsDecl import FeatureBitsDecl
from autosync.cpptranslator.patches.FieldFromInstr import FieldFromInstr
from autosync.cpptranslator.patches.GetNumOperands import GetNumOperands
from autosync.cpptranslator.patches.GetOpcode import GetOpcode
from autosync.cpptranslator.patches.GetOperand import GetOperand
from autosync.cpptranslator.patches.GetOperandRegImm import GetOperandRegImm
from autosync.cpptranslator.patches.GetRegClass import GetRegClass
from autosync.cpptranslator.patches.GetRegFromClass import GetRegFromClass
from autosync.cpptranslator.patches.GetSubReg import GetSubReg
from autosync.cpptranslator.patches.Includes import Includes
from autosync.cpptranslator.patches.InlineToStaticInline import InlineToStaticInline
from autosync.cpptranslator.patches.IsOptionalDef import IsOptionalDef
from autosync.cpptranslator.patches.IsPredicate import IsPredicate
from autosync.cpptranslator.patches.IsRegImm import IsOperandRegImm
from autosync.cpptranslator.patches.LLVMFallThrough import LLVMFallThrough
from autosync.cpptranslator.patches.LLVMunreachable import LLVMUnreachable
from autosync.cpptranslator.patches.MethodToFunctions import MethodToFunction
from autosync.cpptranslator.patches.MethodTypeQualifier import MethodTypeQualifier
from autosync.cpptranslator.patches.NamespaceAnon import NamespaceAnon
from autosync.cpptranslator.patches.NamespaceArch import NamespaceArch
from autosync.cpptranslator.patches.NamespaceLLVM import NamespaceLLVM
from autosync.cpptranslator.patches.OutStreamParam import OutStreamParam
from autosync.cpptranslator.patches.PredicateBlockFunctions import (
PredicateBlockFunctions,
)
from autosync.cpptranslator.patches.PrintAnnotation import PrintAnnotation
from autosync.cpptranslator.patches.PrintRegImmShift import PrintRegImmShift
from autosync.cpptranslator.patches.QualifiedIdentifier import QualifiedIdentifier
from autosync.cpptranslator.patches.ReferencesDecl import ReferencesDecl
from autosync.cpptranslator.patches.RegClassContains import RegClassContains
from autosync.cpptranslator.patches.SetOpcode import SetOpcode
from autosync.cpptranslator.patches.SignExtend import SignExtend
from autosync.cpptranslator.patches.SizeAssignments import SizeAssignment
from autosync.cpptranslator.patches.STIArgument import STIArgument
from autosync.cpptranslator.patches.STIFeatureBits import STIFeatureBits
from autosync.cpptranslator.patches.STParameter import SubtargetInfoParam
from autosync.cpptranslator.patches.StreamOperation import StreamOperations
from autosync.cpptranslator.patches.TemplateDeclaration import TemplateDeclaration
from autosync.cpptranslator.patches.TemplateDefinition import TemplateDefinition
from autosync.cpptranslator.patches.TemplateParamDecl import TemplateParamDecl
from autosync.cpptranslator.patches.TemplateRefs import TemplateRefs
from autosync.cpptranslator.patches.UseMarkup import UseMarkup
from autosync.cpptranslator.patches.UsingDeclaration import UsingDeclaration
from autosync.cpptranslator.TemplateCollector import TemplateCollector
from autosync.Helper import get_path
class TestPatches(unittest.TestCase):
@classmethod
def setUpClass(cls):
configurator = Configurator("ARCH", get_path("{PATCHES_TEST_CONFIG}"))
cls.translator = CppTranslator.Translator(configurator, False)
cls.ts_cpp_lang = configurator.get_cpp_lang()
cls.parser = configurator.get_parser()
cls.template_collector = TemplateCollector(
configurator.get_parser(), configurator.get_cpp_lang(), [], []
)
def check_patching_result(self, patch, syntax, expected, filename=""):
if filename:
kwargs = {"filename": filename}
else:
kwargs = self.translator.get_patch_kwargs(patch)
query: Query = self.ts_cpp_lang.query(patch.get_search_pattern())
captures_bundle: [[(Node, str)]] = list()
for q in query.captures(self.parser.parse(syntax, keep_text=True).root_node):
if q[1] == patch.get_main_capture_name():
captures_bundle.append([q])
else:
captures_bundle[-1].append(q)
self.assertGreater(len(captures_bundle), 0)
for cb in captures_bundle:
self.assertEqual(patch.get_patch(cb, syntax, **kwargs), expected)
def test_addcsdetail(self):
patch = AddCSDetail(0, "ARCH")
syntax = b"int i = x; void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNo, SStream *O) { int i = OpNo; }"
self.check_patching_result(
patch,
syntax,
b"void printThumbLdrLabelOperand(MCInst *MI, unsigned OpNo, SStream *O){ "
b"add_cs_detail(MI, ARCH_OP_GROUP_ThumbLdrLabelOperand, OpNo); "
b"int i = OpNo; "
b"}",
)
def test_addoperand(self):
patch = AddOperand(0)
syntax = b"MI.addOperand(OPERAND)"
self.check_patching_result(
patch,
syntax,
b"MCInst_addOperand2(MI, (OPERAND))",
)
def test_assert(self):
patch = Assert(0)
syntax = b"assert(0 == 0)"
self.check_patching_result(patch, syntax, b"")
def test_bitcaststdarray(self):
patch = BitCastStdArray(0)
syntax = b"auto S = bit_cast<std::array<int32_t, 2>>(Imm);"
self.check_patching_result(
patch,
syntax,
b"union {\n"
b" typeof(Imm) In;\n"
b" int32_t Out[ 2];\n"
b"} U_S;\n"
b"U_S.In = Imm"
b";\n"
b"int32_t *S = U_S.Out;",
)
def test_checkdecoderstatus(self):
patch = CheckDecoderStatus(0)
syntax = b"Check(S, functions())"
self.check_patching_result(patch, syntax, b"Check(&S, functions())")
def test_classesdef(self):
patch = ClassesDef(0)
syntax = b"""class AArch64Disassembler : public MCDisassembler {
std::unique_ptr<const MCInstrInfo> const MCII;
public:
AArch64Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx,
MCInstrInfo const *MCII)
: MCDisassembler(STI, Ctx), MCII(MCII) {}
~AArch64Disassembler() override = default;
MCDisassembler::DecodeStatus
getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes,
uint64_t Address, raw_ostream &CStream) const override;
uint64_t suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
uint64_t Address) const override;
};
"""
self.check_patching_result(
patch,
syntax,
b"MCDisassembler::DecodeStatus\n"
b" getInstruction(MCInst &Instr, uint64_t &Size, ArrayRef<uint8_t> Bytes,\n"
b" uint64_t Address, raw_ostream &CStream) const override;\n"
b"uint64_t suggestBytesToSkip(ArrayRef<uint8_t> Bytes,\n"
b" uint64_t Address) const override;\n",
)
def test_constmcinstparameter(self):
patch = ConstMCInstParameter(0)
syntax = b"void function(const MCInst *MI);"
expected = b"MCInst *MI"
self.check_patching_result(patch, syntax, expected)
def test_constmcoperand(self):
patch = ConstMCOperand(0)
syntax = b"const MCOperand op = { 0 };"
self.check_patching_result(patch, syntax, b"MCOperand op = { 0 };")
def test_cppinitcast(self):
patch = CppInitCast(0)
syntax = b"int(0x0000)"
self.check_patching_result(patch, syntax, b"((int)(0x0000))")
def test_createoperand0(self):
patch = CreateOperand0(0)
syntax = b"Inst.addOperand(MCOperand::createReg(REGISTER));"
self.check_patching_result(
patch,
syntax,
b"MCOperand_CreateReg0(Inst, (REGISTER))",
)
def test_createoperand1(self):
patch = CreateOperand1(0)
syntax = b"MI.insert(I, MCOperand::createReg(REGISTER));"
self.check_patching_result(
patch,
syntax,
b"MCInst_insert0(MI, I, MCOperand_CreateReg1(MI, (REGISTER)))",
)
def test_declarationinconditionclause(self):
patch = DeclarationInConditionalClause(0)
syntax = b"if (int i = 0) {}"
self.check_patching_result(patch, syntax, b"int i = 0;\nif (i)\n{}")
def test_decodeinstruction(self):
patch = DecodeInstruction(0)
syntax = (
b"decodeInstruction(DecoderTableThumb16, MI, Insn16, Address, this, STI);"
)
self.check_patching_result(
patch,
syntax,
b"decodeInstruction_2(DecoderTableThumb16, MI, Insn16, Address)",
)
syntax = b"decodeInstruction(Table[i], MI, Insn16, Address, this, STI);"
self.check_patching_result(
patch,
syntax,
b"decodeInstruction_2(Table[i], MI, Insn16, Address)",
)
def test_decodercast(self):
patch = DecoderCast(0)
syntax = (
b"const MCDisassembler *Dis = static_cast<const MCDisassembler*>(Decoder);"
)
self.check_patching_result(patch, syntax, b"")
def test_decoderparameter(self):
patch = DecoderParameter(0)
syntax = b"void function(const MCDisassembler *Decoder);"
self.check_patching_result(patch, syntax, b"const void *Decoder")
def test_fallthrough(self):
patch = FallThrough(0)
syntax = b"[[fallthrough]]"
self.check_patching_result(patch, syntax, b"// fall through")
def test_featurebitsdecl(self):
patch = FeatureBitsDecl(0)
syntax = b"const FeatureBitset &FeatureBits = ((const MCDisassembler*)Decoder)->getSubtargetInfo().getFeatureBits();"
self.check_patching_result(patch, syntax, b"")
def test_featurebits(self):
patch = FeatureBits(0, b"ARCH")
syntax = b"bool hasD32 = featureBits[ARCH::HasV8Ops];"
self.check_patching_result(
patch,
syntax,
b"ARCH_getFeatureBits(Inst->csh->mode, ARCH::HasV8Ops)",
)
def test_fieldfrominstr(self):
patch = FieldFromInstr(0)
syntax = b"unsigned Rm = fieldFromInstruction(Inst16, 0, 4);"
self.check_patching_result(
patch,
syntax,
b"fieldFromInstruction_2(Inst16, 0, 4)",
)
syntax = b"void function(MCInst *MI, unsigned Val) { unsigned Rm = fieldFromInstruction(Val, 0, 4); }"
self.check_patching_result(
patch,
syntax,
b"fieldFromInstruction_4(Val, 0, 4)",
)
def test_getnumoperands(self):
patch = GetNumOperands(0)
syntax = b"MI.getNumOperands();"
self.check_patching_result(patch, syntax, b"MCInst_getNumOperands(MI)")
def test_getopcode(self):
patch = GetOpcode(0)
syntax = b"Inst.getOpcode();"
self.check_patching_result(patch, syntax, b"MCInst_getOpcode(Inst)")
def test_getoperand(self):
patch = GetOperand(0)
syntax = b"MI.getOperand(0);"
self.check_patching_result(patch, syntax, b"MCInst_getOperand(MI, (0))")
def test_getoperandregimm(self):
patch = GetOperandRegImm(0)
syntax = b"OPERAND.getReg()"
self.check_patching_result(patch, syntax, b"MCOperand_getReg(OPERAND)")
def test_getregclass(self):
patch = GetRegClass(0)
syntax = b"MRI.getRegClass(RegClass);"
expected = b"MCRegisterInfo_getRegClass(Inst->MRI, RegClass)"
self.check_patching_result(patch, syntax, expected)
def test_getregfromclass(self):
patch = GetRegFromClass(0)
syntax = b"ARCHMCRegisterClasses[ARCH::FPR128RegClassID].getRegister(RegNo);"
self.check_patching_result(
patch,
syntax,
b"ARCHMCRegisterClasses[ARCH::FPR128RegClassID].RegsBegin[RegNo]",
)
def test_getsubreg(self):
patch = GetSubReg(0)
syntax = b"MRI.getSubReg(REGISTER);"
self.check_patching_result(
patch,
syntax,
b"MCRegisterInfo_getSubReg(Inst->MRI, REGISTER)",
)
def test_includes(self):
patch = Includes(0, "TEST_ARCH")
syntax = b'#include "some_llvm_header.h"'
self.check_patching_result(
patch,
syntax,
b"#include <stdio.h>\n"
b"#include <string.h>\n"
b"#include <stdlib.h>\n"
b"#include <capstone/platform.h>\n\n"
b"test_output",
"filename",
)
def test_inlinetostaticinline(self):
patch = InlineToStaticInline(0)
syntax = b"inline void FUNCTION() {}"
self.check_patching_result(
patch,
syntax,
b"static inline void FUNCTION() {}",
)
def test_isoptionaldef(self):
patch = IsOptionalDef(0)
syntax = b"OpInfo[i].isOptionalDef()"
self.check_patching_result(
patch,
syntax,
b"MCOperandInfo_isOptionalDef(&OpInfo[i])",
)
def test_ispredicate(self):
patch = IsPredicate(0)
syntax = b"OpInfo[i].isPredicate()"
self.check_patching_result(
patch,
syntax,
b"MCOperandInfo_isPredicate(&OpInfo[i])",
)
def test_isregimm(self):
patch = IsOperandRegImm(0)
syntax = b"OPERAND.isReg()"
self.check_patching_result(patch, syntax, b"MCOperand_isReg(OPERAND)")
def test_llvmfallthrough(self):
patch = LLVMFallThrough(0)
syntax = b"LLVM_FALLTHROUGH;"
self.check_patching_result(patch, syntax, b"")
def test_llvmunreachable(self):
patch = LLVMUnreachable(0)
syntax = b'llvm_unreachable("Error msg")'
self.check_patching_result(patch, syntax, b'assert(0 && "Error msg")')
def test_methodtofunctions(self):
patch = MethodToFunction(0)
syntax = b"void CLASS::METHOD_NAME(int a) {}"
self.check_patching_result(patch, syntax, b"METHOD_NAME(int a)")
def test_methodtypequalifier(self):
patch = MethodTypeQualifier(0)
syntax = b"void a_const_method() const {}"
self.check_patching_result(patch, syntax, b"a_const_method()")
def test_namespaceanon(self):
patch = NamespaceAnon(0)
syntax = b"namespace { int a = 0; }"
self.check_patching_result(patch, syntax, b" int a = 0; ")
def test_namespacearch(self):
patch = NamespaceArch(0)
syntax = b"namespace ArchSpecificNamespace { int a = 0; }"
self.check_patching_result(
patch,
syntax,
b"// CS namespace begin: ArchSpecificNamespace\n\n"
b"int a = 0;\n\n"
b"// CS namespace end: ArchSpecificNamespace\n\n",
)
def test_namespacellvm(self):
patch = NamespaceLLVM(0)
syntax = b"namespace llvm {int a = 0}"
self.check_patching_result(patch, syntax, b"int a = 0")
def test_outstreamparam(self):
patch = OutStreamParam(0)
syntax = b"void function(int a, raw_ostream &OS);"
self.check_patching_result(patch, syntax, b"(int a, SStream *OS)")
def test_predicateblockfunctions(self):
patch = PredicateBlockFunctions(0)
syntax = b"void function(MCInst *MI) { VPTBlock.instrInVPTBlock(); }"
self.check_patching_result(
patch,
syntax,
b"VPTBlock_instrInVPTBlock(&(MI->csh->VPTBlock))",
)
def test_predicateblockfunctions(self):
patch = PrintAnnotation(0)
syntax = b"printAnnotation();"
self.check_patching_result(patch, syntax, b"")
def test_printregimmshift(self):
patch = PrintRegImmShift(0)
syntax = b"printRegImmShift(0)"
self.check_patching_result(patch, syntax, b"printRegImmShift(Inst, 0)")
def test_qualifiedidentifier(self):
patch = QualifiedIdentifier(0)
syntax = b"NAMESPACE::ID"
self.check_patching_result(patch, syntax, b"NAMESPACE_ID")
def test_referencesdecl(self):
patch = ReferencesDecl(0)
syntax = b"int &Param = 0;"
self.check_patching_result(patch, syntax, b"*Param")
def test_regclasscontains(self):
patch = RegClassContains(0)
syntax = b"if (MRI.getRegClass(AArch64::GPR32RegClassID).contains(Reg)) {}"
self.check_patching_result(
patch,
syntax,
b"MCRegisterClass_contains(MRI.getRegClass(AArch64::GPR32RegClassID), Reg)",
)
def test_setopcode(self):
patch = SetOpcode(0)
syntax = b"Inst.setOpcode(0)"
self.check_patching_result(patch, syntax, b"MCInst_setOpcode(Inst, (0))")
def test_signextend(self):
patch = SignExtend(0)
syntax = b"SignExtend32<A>(0)"
self.check_patching_result(patch, syntax, b"SignExtend32((0), A)")
def test_sizeassignments(self):
patch = SizeAssignment(0)
syntax = b"void function(int &Size) { Size = 0; }"
self.check_patching_result(patch, syntax, b"*Size = 0")
def test_stiargument(self):
patch = STIArgument(0)
syntax = b"printSomeOperand(MI, NUM, STI, NUM)"
self.check_patching_result(patch, syntax, b"(MI, NUM, NUM)")
def test_stifeaturebits(self):
patch = STIFeatureBits(0, b"ARCH")
syntax = b"STI.getFeatureBits()[ARCH::FLAG];"
self.check_patching_result(
patch,
syntax,
b"ARCH_getFeatureBits(Inst->csh->mode, ARCH::FLAG)",
)
def test_stifeaturebits(self):
patch = SubtargetInfoParam(0)
syntax = b"void function(MCSubtargetInfo &STI);"
self.check_patching_result(patch, syntax, b"()")
def test_streamoperation(self):
patch = StreamOperations(0)
syntax = b"{ OS << 'a'; }"
self.check_patching_result(patch, syntax, b'SStream_concat0(OS, "a");\n')
syntax = b'{ OS << "aaaa" << "bbbb" << "cccc"; }'
self.check_patching_result(
patch,
syntax,
b'SStream_concat(OS, "%s%s", "aaaa", "bbbb");\nSStream_concat0(OS, "cccc");',
)
syntax = b'{ OS << "aaaa" << \'a\' << "cccc"; }'
self.check_patching_result(
patch,
syntax,
b'SStream_concat(OS, "%s", "aaaa");\n'
b"SStream_concat1(OS, 'a');\n"
b'SStream_concat0(OS, "cccc");',
)
def test_templatedeclaration(self):
patch = TemplateDeclaration(0, self.template_collector)
syntax = b"template<A, B> void tfunction();"
self.check_patching_result(
patch,
syntax,
b"#define DECLARE_tfunction(A, B) \\\n"
b" void CONCAT(tfunction, CONCAT(A, B))();\n"
b"DECLARE_tfunction(int, int);\n"
b"DECLARE_tfunction(int, char);\n",
)
def test_templatedefinition(self):
patch = TemplateDefinition(0, self.template_collector)
syntax = b"template<A, B> void tfunction() {}"
self.check_patching_result(
patch,
syntax,
b"#define DEFINE_tfunction(A, B) \\\n"
b" void CONCAT(tfunction, CONCAT(A, B))(){}\n"
b"DEFINE_tfunction(int, int);\n"
b"DEFINE_tfunction(int, char);\n",
)
def test_templateparamdecl(self):
patch = TemplateParamDecl(0)
syntax = b"void function(ArrayRef<uint8_t> x);"
self.check_patching_result(patch, syntax, b"const uint8_t *x")
def test_templaterefs(self):
patch = TemplateRefs(0)
syntax = b"TemplateFunction<A, B>();"
self.check_patching_result(
patch,
syntax,
b"CONCAT(TemplateFunction, CONCAT(A, B))",
)
def test_usemarkup(self):
patch = UseMarkup(0)
syntax = b"UseMarkup()"
self.check_patching_result(patch, syntax, b"getUseMarkup()")
def test_usingdecl(self):
patch = UsingDeclaration(0)
syntax = b"using namespace llvm;"
self.check_patching_result(patch, syntax, b"")

View File

@ -1,12 +1,10 @@
{
"General": {
"patch_persistence_file": "{CPP_TRANSLATOR_DIR}/saved_patches.json",
"translation_out_dir": "{BUILD_DIR}/translate_out/",
"diff_out_dir": "{BUILD_DIR}/diff_out/",
"diff_color_new": "green",
"diff_color_old": "light_blue",
"diff_color_saved": "yellow",
"diff_color_edited": "light_magenta",
"patch_editor": "vim",
"nodes_to_diff": [
{
"node_type": "function_definition",
@ -116,7 +114,8 @@
"printImmSVE",
"printAMIndexedWB",
"isSVECpyImm",
"isSVEAddSubImm"
"isSVEAddSubImm",
"printVectorIndex"
],
"manually_edited_files": []
},

View File

@ -1,10 +1,17 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name, template_param_list_to_dict
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import (
get_MCInst_var_name,
get_text,
template_param_list_to_dict,
)
from autosync.cpptranslator.patches.Patch import Patch
class AddCSDetail(Patch):
@ -33,7 +40,11 @@ class AddCSDetail(Patch):
super().__init__(priority)
self.arch = arch
self.apply_only_to = {
"files": ["ARMInstPrinter.cpp", "PPCInstPrinter.cpp", "AArch64InstPrinter.cpp"],
"files": [
"ARMInstPrinter.cpp",
"PPCInstPrinter.cpp",
"AArch64InstPrinter.cpp",
],
"archs": list(),
}
@ -68,15 +79,31 @@ class AddCSDetail(Patch):
comp = get_text(src, comp.start_byte, comp.end_byte)
return b"void " + fcn_id + params + b"{ " + add_cs_detail + comp.strip(b"{")
def get_add_cs_detail(self, src: bytes, fcn_def: Node, fcn_id: bytes, params: bytes) -> bytes:
op_group_enum = self.arch.encode("utf8") + b"_OP_GROUP_" + fcn_id[5:] # Remove "print" from function id
def get_add_cs_detail(
self, src: bytes, fcn_def: Node, fcn_id: bytes, params: bytes
) -> bytes:
op_group_enum = (
self.arch.encode("utf8") + b"_OP_GROUP_" + fcn_id[5:]
) # Remove "print" from function id
is_template = fcn_def.prev_sibling.type == "template_parameter_list"
op_num_var_name = b"OpNum" if b"OpNum" in params else (b"OpNo" if b"OpNo" in params else b"-.-")
op_num_var_name = (
b"OpNum"
if b"OpNum" in params
else (b"OpNo" if b"OpNo" in params else b"-.-")
)
if not is_template and op_num_var_name in params:
# Standard printOperand() parameters
mcinst_var = get_MCInst_var_name(src, fcn_def)
return b"add_cs_detail(" + mcinst_var + b", " + op_group_enum + b", " + op_num_var_name + b");"
return (
b"add_cs_detail("
+ mcinst_var
+ b", "
+ op_group_enum
+ b", "
+ op_num_var_name
+ b");"
)
elif op_group_enum == b"ARM_OP_GROUP_RegImmShift":
return b"add_cs_detail(MI, " + op_group_enum + b", ShOpc, ShImm);"
elif is_template and op_num_var_name in params:
@ -84,7 +111,9 @@ class AddCSDetail(Patch):
templ_p = template_param_list_to_dict(fcn_def.prev_sibling)
cs_args = b""
for tp in templ_p:
op_group_enum = b"CONCAT(" + op_group_enum + b", " + tp["identifier"] + b")"
op_group_enum = (
b"CONCAT(" + op_group_enum + b", " + tp["identifier"] + b")"
)
cs_args += b", " + tp["identifier"]
return (
b"add_cs_detail("

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class AddOperand(Patch):

View File

@ -1,5 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class Assert(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class BitCastStdArray(Patch):
@ -46,14 +49,36 @@ class BitCastStdArray(Patch):
arr_name: bytes = captures[1][0].text
array_type: Node = captures[3][0]
cast_target: bytes = captures[4][0].text.strip(b"()")
array_templ_args: bytes = array_type.named_children[0].named_children[1].named_children[1].text.strip(b"<>")
array_templ_args: bytes = (
array_type.named_children[0]
.named_children[1]
.named_children[1]
.text.strip(b"<>")
)
arr_type = array_templ_args.split(b",")[0]
arr_len = array_templ_args.split(b",")[1]
return (
b"union {\n"
+ b" typeof(" + cast_target + b") In;\n"
+ b" " + arr_type + b" Out[" + arr_len + b"];\n"
+ b"} U_" + arr_name + b";\n"
+ b"U_" + arr_name + b".In = " + cast_target + b";\n"
+ arr_type + b" *" + arr_name + b" = U_" + arr_name + b".Out;"
+ b" typeof("
+ cast_target
+ b") In;\n"
+ b" "
+ arr_type
+ b" Out["
+ arr_len
+ b"];\n"
+ b"} U_"
+ arr_name
+ b";\n"
+ b"U_"
+ arr_name
+ b".In = "
+ cast_target
+ b";\n"
+ arr_type
+ b" *"
+ arr_name
+ b" = U_"
+ arr_name
+ b".Out;"
)

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class CheckDecoderStatus(Patch):

View File

@ -1,5 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class ClassConstructorDef(Patch):

View File

@ -1,10 +1,13 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class ClassesDef(Patch):
@ -31,7 +34,9 @@ class ClassesDef(Patch):
for field_decl in field_decl_list.named_children:
if (
field_decl.type in "field_declaration"
and ("function_declarator" in [t.type for t in field_decl.named_children])
and (
"function_declarator" in [t.type for t in field_decl.named_children]
)
) or field_decl.type == "template_declaration":
# Keep comments
sibling = field_decl.prev_named_sibling

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class ConstMCInstParameter(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class ConstMCOperand(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class CppInitCast(Patch):
@ -14,7 +17,12 @@ class CppInitCast(Patch):
super().__init__(priority)
def get_search_pattern(self) -> str:
return "(call_expression" " (primitive_type) @cast_type" " (argument_list) @cast_target" ") @cast"
return (
"(call_expression"
" (primitive_type) @cast_type"
" (argument_list) @cast_target"
") @cast"
)
def get_main_capture_name(self) -> str:
return "cast"

View File

@ -1,9 +1,12 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class CreateOperand0(Patch):
@ -44,7 +47,11 @@ class CreateOperand0(Patch):
op_create_args: Node = captures[4][0]
# Capstone spells the function with capital letter 'C' for whatever reason.
fcn = re.sub(b"create", b"Create", get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte))
fcn = re.sub(
b"create",
b"Create",
get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte),
)
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
if args[0] == b"(" and args[-1] == b")":

View File

@ -1,9 +1,12 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
from autosync.cpptranslator.patches.Patch import Patch
class CreateOperand1(Patch):
@ -50,7 +53,11 @@ class CreateOperand1(Patch):
insert_arg_t = get_text(src, insert_arg.start_byte, insert_arg.end_byte)
# Capstone spells the function with capital letter 'C' for whatever reason.
fcn = re.sub(b"create", b"Create", get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte))
fcn = re.sub(
b"create",
b"Create",
get_text(src, op_create_fcn.start_byte, op_create_fcn.end_byte),
)
inst = get_text(src, inst_var.start_byte, inst_var.end_byte)
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
return (
@ -62,7 +69,7 @@ class CreateOperand1(Patch):
+ b"MCOperand_"
+ fcn
+ b"1("
+ get_MCInst_var_name(src, inst_var)
+ inst
+ b", "
+ args
+ b"))"

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
from autosync.cpptranslator.patches.Patch import Patch
class DeclarationInConditionalClause(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class DecodeInstruction(Patch):
@ -31,8 +34,12 @@ class DecodeInstruction(Patch):
args_text = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
table, mi_inst, opcode_var, address, this, sti = args_text.split(b",")
is_32bit = table[-2:].decode("utf8") == "32" or opcode_var[-2:].decode("utf8") == "32"
is_16bit = table[-2:].decode("utf8") == "16" or opcode_var[-2:].decode("utf8") == "16"
is_32bit = (
table[-2:].decode("utf8") == "32" or opcode_var[-2:].decode("utf8") == "32"
)
is_16bit = (
table[-2:].decode("utf8") == "16" or opcode_var[-2:].decode("utf8") == "16"
)
args = table + b", " + mi_inst + b", " + opcode_var + b", " + address
if is_16bit and not is_32bit:

View File

@ -1,6 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class DecoderCast(Patch):

View File

@ -1,6 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class DecoderParameter(Patch):

View File

@ -1,5 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class FallThrough(Patch):

View File

@ -1,12 +1,16 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
from autosync.cpptranslator.patches.Patch import Patch
class FeatureBits(Patch):
"""
Patch featureBits[FLAG]
to ARCH_getFeatureBits(Inst->csh->mode, ...)
to ARCH_getFeatureBits(Inst->csh->mode, FLAG)
"""
def __init__(self, priority: int, arch: bytes):
@ -30,4 +34,11 @@ class FeatureBits(Patch):
qualified_id: Node = captures[2][0]
flag = get_text(src, qualified_id.start_byte, qualified_id.end_byte)
mcinst_var_name = get_MCInst_var_name(src, qualified_id)
return self.arch + b"_getFeatureBits(" + mcinst_var_name + b"->csh->mode, " + flag + b")"
return (
self.arch
+ b"_getFeatureBits("
+ mcinst_var_name
+ b"->csh->mode, "
+ flag
+ b")"
)

View File

@ -1,6 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class FeatureBitsDecl(Patch):

View File

@ -1,16 +1,19 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_function_params_of_node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
from autosync.cpptranslator.patches.Patch import Patch
class FieldFromInstr(Patch):
"""
Patch fieldFromInstr(...)
to fieldFromInstr_<instr_width>(...)
Patch fieldFromInstruction(...)
to fieldFromInstruction_<instr_width>(...)
"""
def __init__(self, priority: int):
@ -32,7 +35,9 @@ class FieldFromInstr(Patch):
ffi_call: Node = captures[0][0]
ffi_first_arg: Node = captures[2][0]
param_list_caller = get_function_params_of_node(ffi_call)
ffi_first_arg_text = get_text(src, ffi_first_arg.start_byte, ffi_first_arg.end_byte).decode("utf8")
ffi_first_arg_text = get_text(
src, ffi_first_arg.start_byte, ffi_first_arg.end_byte
).decode("utf8")
# Determine width of instruction by the variable name.
if ffi_first_arg_text[-2:] == "32":

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class GetNumOperands(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class GetOpcode(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class GetOperand(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
from autosync.cpptranslator.patches.Patch import Patch
class GetOperandRegImm(Patch):

View File

@ -1,13 +1,20 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node, get_MCInst_var_name
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import (
get_capture_node,
get_MCInst_var_name,
get_text,
)
from autosync.cpptranslator.patches.Patch import Patch
class GetRegClass(Patch):
"""
Patch MRI.getRegClass(...)
to MCRegisterClass_getRegClass(MI->MRI, ...)
to MCRegisterInfo_getRegClass(Inst->MRI, ...)
"""
def __init__(self, priority: int):
@ -31,6 +38,8 @@ class GetRegClass(Patch):
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
arg_list: Node = get_capture_node(captures, "arg_list")
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
mcinst_var = get_MCInst_var_name(src, get_capture_node(captures, "get_reg_class"))
mcinst_var = get_MCInst_var_name(
src, get_capture_node(captures, "get_reg_class")
)
res = b"MCRegisterInfo_getRegClass(" + mcinst_var + b"->MRI, " + args + b")"
return res

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
from autosync.cpptranslator.patches.Patch import Patch
class GetRegFromClass(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
from autosync.cpptranslator.patches.Patch import Patch
class GetSubReg(Patch):
@ -31,6 +34,8 @@ class GetSubReg(Patch):
# Get arg list
op_create_args: Node = captures[2][0]
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte).strip(b"()")
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte).strip(
b"()"
)
mcinst_var_name = get_MCInst_var_name(src, op_create_args)
return b"MCRegisterInfo_getSubReg(" + mcinst_var_name + b"->MRI, " + args + b")"

View File

@ -1,9 +1,12 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
import re
from tree_sitter import Node
import logging as log
from Helper import fail_exit
from autosync.Helper import fail_exit
def get_function_params_of_node(n: Node) -> Node:
@ -33,9 +36,12 @@ def get_MCInst_var_name(src: bytes, n: Node) -> bytes:
"""Searches for the name of the parameter of type MCInst and returns it."""
params = get_function_params_of_node(n)
mcinst_var_name = b""
if params:
for p in params.named_children:
p_text = get_text(src, p.start_byte, p.end_byte)
if b"MCInst" in p_text:
if b"MCInst" not in p_text:
continue
mcinst_var_name = p_text.split((b"&" if b"&" in p_text else b"*"))[1]
break
if mcinst_var_name == b"":
@ -46,7 +52,9 @@ def get_MCInst_var_name(src: bytes, n: Node) -> bytes:
def template_param_list_to_dict(param_list: Node) -> [dict]:
if param_list.type != "template_parameter_list":
log.fatal(f"Wrong node type '{param_list.type}'. Not 'template_parameter_list'.")
log.fatal(
f"Wrong node type '{param_list.type}'. Not 'template_parameter_list'."
)
exit(1)
pl = list()
for c in param_list.named_children:
@ -64,7 +72,9 @@ def template_param_list_to_dict(param_list: Node) -> [dict]:
def parameter_declaration_to_dict(param_decl: Node) -> dict:
if param_decl.type != "parameter_declaration":
log.fatal(f"Wrong node type '{param_decl.type}'. Should be 'parameter_declaration'.")
log.fatal(
f"Wrong node type '{param_decl.type}'. Should be 'parameter_declaration'."
)
exit(1)
return {
"prim_type": param_decl.children[0].type == "primitive_type",
@ -95,18 +105,21 @@ def namespace_enum(src: bytes, ns_id: bytes, enum: Node) -> bytes:
type_id = c
primary_tid_set = True
if not (enumerator_list and type_id):
if not enumerator_list and not type_id:
log.fatal("Could not find enumerator_list or enum type_identifier.")
exit(1)
tid = get_text(src, type_id.start_byte, type_id.end_byte)
tid = get_text(src, type_id.start_byte, type_id.end_byte) if type_id else None
elist = get_text(src, enumerator_list.start_byte, enumerator_list.end_byte)
for e in enumerator_list.named_children:
if e.type == "enumerator":
enum_entry_text = get_text(src, e.start_byte, e.end_byte)
elist = elist.replace(enum_entry_text, ns_id + b"_" + enum_entry_text)
if tid:
new_enum = b"typedef enum " + tid + b" " + elist + b"\n " + ns_id + b"_" + tid
else:
new_enum = b"enum " + b" " + elist + b"\n"
return new_enum
@ -152,7 +165,9 @@ def namespace_struct(src: bytes, ns_id: bytes, struct: Node) -> bytes:
tid = get_text(src, type_id.start_byte, type_id.end_byte)
fields = get_text(src, field_list.start_byte, field_list.end_byte)
typed_struct = b"typedef struct " + tid + b" " + fields + b"\n " + ns_id + b"_" + tid
typed_struct = (
b"typedef struct " + tid + b" " + fields + b"\n " + ns_id + b"_" + tid
)
return typed_struct
@ -193,9 +208,16 @@ def parse_function_capture(
case _:
raise NotImplementedError(f"Node type {node.type} not handled.")
from CppTranslator.TemplateCollector import TemplateCollector
from autosync.cpptranslator.TemplateCollector import TemplateCollector
return TemplateCollector.templ_params_to_list(temp_args), st_class_ids, ret_type, func_name, func_params, comp_stmt
return (
TemplateCollector.templ_params_to_list(temp_args),
st_class_ids,
ret_type,
func_name,
func_params,
comp_stmt,
)
def get_capture_node(captures: [(Node, str)], name: str) -> Node:

View File

@ -1,9 +1,12 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class Includes(Patch):
@ -34,11 +37,17 @@ class Includes(Patch):
include_text = get_text(src, captures[0][0].start_byte, captures[0][0].end_byte)
# Special cases, which appear somewhere in the code.
if b"GenDisassemblerTables.inc" in include_text:
return b'#include "' + bytes(self.arch, "utf8") + b'GenDisassemblerTables.inc"\n\n'
return (
b'#include "'
+ bytes(self.arch, "utf8")
+ b'GenDisassemblerTables.inc"\n\n'
)
elif b"GenAsmWriter.inc" in include_text:
return b'#include "' + bytes(self.arch, "utf8") + b'GenAsmWriter.inc"\n\n'
elif b"GenSystemOperands.inc" in include_text:
return b'#include "' + bytes(self.arch, "utf8") + b'GenSystemOperands.inc"\n\n'
return (
b'#include "' + bytes(self.arch, "utf8") + b'GenSystemOperands.inc"\n\n'
)
if self.include_count[filename] > 1:
# Only the first include is replaced with all CS includes.
@ -53,6 +62,8 @@ class Includes(Patch):
return res + get_PPC_includes(filename) + get_general_macros()
case "AArch64":
return res + get_AArch64_includes(filename) + get_general_macros()
case "TEST_ARCH":
return res + b"test_output"
case _:
log.fatal(f"Includes of {self.arch} not handled.")
exit(1)
@ -245,4 +256,6 @@ def get_AArch64_includes(filename: str) -> bytes:
def get_general_macros():
return b"#define CONCAT(a, b) CONCAT_(a, b)\n" b"#define CONCAT_(a, b) a ## _ ## b\n"
return (
b"#define CONCAT(a, b) CONCAT_(a, b)\n" b"#define CONCAT_(a, b) a ## _ ## b\n"
)

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class InlineToStaticInline(Patch):
@ -20,7 +23,10 @@ class InlineToStaticInline(Patch):
def get_search_pattern(self) -> str:
return (
"(function_definition" ' ((storage_class_specifier) @scs (#eq? @scs "inline"))' " (_)+" ") @inline_def"
"(function_definition"
' ((storage_class_specifier) @scs (#eq? @scs "inline"))'
" (_)+"
") @inline_def"
)
def get_main_capture_name(self) -> str:

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class IsOptionalDef(Patch):
@ -34,4 +37,4 @@ class IsOptionalDef(Patch):
index = captures[2][0]
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
index = get_text(src, index.start_byte, index.end_byte)
return b"MCOperandInfo_isOptionalDef(&" + op_info_var + b"[" + index + b"])"
return b"MCOperandInfo_isOptionalDef(&" + op_info_var + index + b")"

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class IsPredicate(Patch):
@ -34,4 +37,4 @@ class IsPredicate(Patch):
index = captures[2][0]
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
index = get_text(src, index.start_byte, index.end_byte)
return b"MCOperandInfo_isPredicate(&" + op_info_var + b"[" + index + b"])"
return b"MCOperandInfo_isPredicate(&" + op_info_var + index + b")"

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class IsOperandRegImm(Patch):

View File

@ -1,6 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class LLVMFallThrough(Patch):
@ -12,7 +15,11 @@ class LLVMFallThrough(Patch):
super().__init__(priority)
def get_search_pattern(self) -> str:
return "(expression_statement" ' ((identifier) @id (#eq? @id "LLVM_FALLTHROUGH"))' ") @llvm_fall_through"
return (
"(expression_statement"
' ((identifier) @id (#eq? @id "LLVM_FALLTHROUGH"))'
") @llvm_fall_through"
)
def get_main_capture_name(self) -> str:
return "llvm_fall_through"

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class LLVMUnreachable(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class MethodToFunction(Patch):
@ -35,6 +38,8 @@ class MethodToFunction(Patch):
name = captures[1][0]
parameter_list = captures[2][0]
name = get_text(src, name.start_byte, name.end_byte)
parameter_list = get_text(src, parameter_list.start_byte, parameter_list.end_byte)
parameter_list = get_text(
src, parameter_list.start_byte, parameter_list.end_byte
)
res = name + parameter_list
return res

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class MethodTypeQualifier(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class NamespaceAnon(Patch):
@ -16,7 +19,11 @@ class NamespaceAnon(Patch):
super().__init__(priority)
def get_search_pattern(self) -> str:
return "(namespace_definition" " (declaration_list) @decl_list" ") @namespace_def"
return (
"(namespace_definition"
" (declaration_list) @decl_list"
") @namespace_def"
)
def get_main_capture_name(self) -> str:
return "namespace_def"

View File

@ -1,7 +1,15 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, namespace_enum, namespace_fcn_def, namespace_struct
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import (
get_text,
namespace_enum,
namespace_fcn_def,
namespace_struct,
)
from autosync.cpptranslator.patches.Patch import Patch
class NamespaceArch(Patch):
@ -16,7 +24,12 @@ class NamespaceArch(Patch):
super().__init__(priority)
def get_search_pattern(self) -> str:
return "(namespace_definition" " (namespace_identifier)" " (declaration_list) @decl_list" ") @namespace_def"
return (
"(namespace_definition"
" (namespace_identifier)"
" (declaration_list) @decl_list"
") @namespace_def"
)
def get_main_capture_name(self) -> str:
return "namespace_def"
@ -24,7 +37,11 @@ class NamespaceArch(Patch):
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
namespace = captures[0][0]
decl_list = captures[1][0]
namespace_id = get_text(src, namespace.named_children[0].start_byte, namespace.named_children[0].end_byte)
namespace_id = get_text(
src,
namespace.named_children[0].start_byte,
namespace.named_children[0].end_byte,
)
# We need to prepend the namespace id to all enum members, function declarators and struct types.
# Because in the generated files they are accessed via NAMESPACE::X which becomes NAMESPACE_X.

View File

@ -1,12 +1,15 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class NamespaceLLVM(Patch):
"""
Patch namespace {CONTENT}
Patch namespace llvm {CONTENT}
to CONTENT
Only for anonymous or llvm namespaces

View File

@ -1,13 +1,18 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class OutStreamParam(Patch):
"""
Patch raw_ostream &OS
to SStream *OS
Patches the parameter list only:
Patch void function(int a, raw_ostream &OS)
to void function(int a, SStream *OS)
"""
def __init__(self, priority: int):

View File

@ -1,6 +1,10 @@
from tree_sitter import Node
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
from tree_sitter import Node
class Patch:
priority: int = None

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
from autosync.cpptranslator.patches.Patch import Patch
class PredicateBlockFunctions(Patch):

View File

@ -1,5 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class PrintAnnotation(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
from autosync.cpptranslator.patches.Patch import Patch
class PrintRegImmShift(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class QualifiedIdentifier(Patch):

View File

@ -1,9 +1,12 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class ReferencesDecl(Patch):
@ -18,7 +21,12 @@ class ReferencesDecl(Patch):
super().__init__(priority)
def get_search_pattern(self) -> str:
return "[" "(reference_declarator)" "(type_identifier) (abstract_reference_declarator)" "] @reference_decl"
return (
"["
"(reference_declarator)"
"(type_identifier) (abstract_reference_declarator)"
"] @reference_decl"
)
def get_main_capture_name(self) -> str:
return "reference_decl"

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
from autosync.cpptranslator.patches.Patch import Patch
class RegClassContains(Patch):
@ -32,6 +35,8 @@ class RegClassContains(Patch):
reg_class_getter: Node = get_capture_node(captures, "reg_class")
arg_list: Node = get_capture_node(captures, "arg_list")
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
reg_class = get_text(src, reg_class_getter.start_byte, reg_class_getter.end_byte)
reg_class = get_text(
src, reg_class_getter.start_byte, reg_class_getter.end_byte
)
res = b"MCRegisterClass_contains(" + reg_class + b", " + args + b")"
return res

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class STIArgument(Patch):

View File

@ -1,13 +1,16 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class STIFeatureBits(Patch):
"""
Patch STI.getFeatureBits()[FLAG]
to ARCH_getFeatureBits(Inst->csh->mode, ...)
Patch STI.getFeatureBits()[ARCH::FLAG]
to ARCH_getFeatureBits(Inst->csh->mode, ARCH::FLAG)
"""
def __init__(self, priority: int, arch: bytes):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class SubtargetInfoParam(Patch):

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class SetOpcode(Patch):

View File

@ -1,7 +1,11 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from CppTranslator.TemplateCollector import TemplateCollector
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
from autosync.cpptranslator.TemplateCollector import TemplateCollector
class SignExtend(Patch):

View File

@ -1,9 +1,12 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text, get_function_params_of_node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
from autosync.cpptranslator.patches.Patch import Patch
class SizeAssignment(Patch):
@ -18,7 +21,11 @@ class SizeAssignment(Patch):
super().__init__(priority)
def get_search_pattern(self) -> str:
return "(assignment_expression" ' ((identifier) @id (#eq? @id "Size"))' ") @assign"
return (
"(assignment_expression"
' ((identifier) @id (#eq? @id "Size"))'
") @assign"
)
def get_main_capture_name(self) -> str:
return "assign"

View File

@ -1,7 +1,10 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class StreamOperations(Patch):
@ -58,11 +61,22 @@ class StreamOperations(Patch):
+ b', "'
+ b"%s" * len(string_ops)
+ b'", '
+ b", ".join([get_text(src, o.start_byte, o.end_byte) for o in string_ops])
+ b", ".join(
[
get_text(src, o.start_byte, o.end_byte)
for o in string_ops
]
)
+ b");\n"
)
string_ops.clear()
res += b"SStream_concat1(" + s_name + b", " + get_text(src, op.start_byte, op.end_byte) + b");\n"
res += (
b"SStream_concat1("
+ s_name
+ b", "
+ get_text(src, op.start_byte, op.end_byte)
+ b");\n"
)
else:
string_ops.append(op)
i += 1
@ -75,14 +89,22 @@ class StreamOperations(Patch):
+ b', "'
+ b"%s" * len(string_ops)
+ b'", '
+ b", ".join([get_text(src, o.start_byte, o.end_byte) for o in string_ops])
+ b", ".join(
[get_text(src, o.start_byte, o.end_byte) for o in string_ops]
)
+ b");\n"
)
string_ops.clear()
last_op_text = get_text(src, last_op.start_byte, last_op.end_byte)
if last_op.type == "char_literal":
res += b"SStream_concat0(" + s_name + b", " + last_op_text.replace(b"'", b'"') + b");\n"
res += (
b"SStream_concat0("
+ s_name
+ b", "
+ last_op_text.replace(b"'", b'"')
+ b");\n"
)
else:
res += b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
stream = captures[0][0]

View File

@ -1,9 +1,16 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import parse_function_capture
from CppTranslator.Patches.Patch import Patch
from CppTranslator.TemplateCollector import TemplateCollector, TemplateRefInstance
from autosync.cpptranslator.patches.Helper import parse_function_capture
from autosync.cpptranslator.patches.Patch import Patch
from autosync.cpptranslator.TemplateCollector import (
TemplateCollector,
TemplateRefInstance,
)
class TemplateDeclaration(Patch):
@ -37,13 +44,24 @@ class TemplateDeclaration(Patch):
def get_main_capture_name(self) -> str:
return "template_decl"
def get_patch(self, captures: list[tuple[Node, str]], src: bytes, **kwargs) -> bytes:
def get_patch(
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
) -> bytes:
t_params, sc, tid, f_name, f_params, _ = parse_function_capture(captures, src)
if f_name in self.collector.templates_with_arg_deduction:
return sc + tid + b" " + f_name + f_params + b";"
declaration = b"#define DECLARE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
declaration += sc + b" " + tid + b" " + TemplateCollector.get_macro_c_call(f_name, t_params, f_params) + b";"
declaration = (
b"#define DECLARE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
)
declaration += (
sc
+ b" "
+ tid
+ b" "
+ TemplateCollector.get_macro_c_call(f_name, t_params, f_params)
+ b";"
)
declaration = declaration.replace(b"\n", b" \\\n") + b"\n"
template_instance: TemplateRefInstance
@ -52,7 +70,13 @@ class TemplateDeclaration(Patch):
self.collector.log_missing_ref_and_exit(f_name)
for template_instance in self.collector.template_refs[f_name]:
d = b"DECLARE_" + f_name + b"(" + b", ".join(template_instance.get_args_for_decl()) + b");\n"
d = (
b"DECLARE_"
+ f_name
+ b"("
+ b", ".join(template_instance.get_args_for_decl())
+ b");\n"
)
if d in declared_implementations:
continue
declared_implementations.append(d)

View File

@ -1,11 +1,17 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
import re
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import parse_function_capture
from CppTranslator.Patches.Patch import Patch
from CppTranslator.TemplateCollector import TemplateCollector, TemplateRefInstance
from autosync.cpptranslator.patches.Helper import parse_function_capture
from autosync.cpptranslator.patches.Patch import Patch
from autosync.cpptranslator.TemplateCollector import (
TemplateCollector,
TemplateRefInstance,
)
class TemplateDefinition(Patch):
@ -40,14 +46,23 @@ class TemplateDefinition(Patch):
def get_main_capture_name(self) -> str:
return "template_def"
def get_patch(self, captures: list[tuple[Node, str]], src: bytes, **kwargs) -> bytes:
t_params, sc, tid, f_name, f_params, f_compound = parse_function_capture(captures, src)
def get_patch(
self, captures: list[tuple[Node, str]], src: bytes, **kwargs
) -> bytes:
t_params, sc, tid, f_name, f_params, f_compound = parse_function_capture(
captures, src
)
if f_name in self.collector.templates_with_arg_deduction:
return sc + tid + b" " + f_name + f_params + f_compound
definition = b"#define DEFINE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
definition += (
sc + b" " + tid + b" " + TemplateCollector.get_macro_c_call(f_name, t_params, f_params) + f_compound
sc
+ b" "
+ tid
+ b" "
+ TemplateCollector.get_macro_c_call(f_name, t_params, f_params)
+ f_compound
)
# Remove // comments
definition = re.sub(b" *//.*", b"", definition)
@ -59,7 +74,13 @@ class TemplateDefinition(Patch):
self.collector.log_missing_ref_and_exit(f_name)
for template_instance in self.collector.template_refs[f_name]:
d = b"DEFINE_" + f_name + b"(" + b", ".join(template_instance.get_args_for_decl()) + b");\n"
d = (
b"DEFINE_"
+ f_name
+ b"("
+ b", ".join(template_instance.get_args_for_decl())
+ b");\n"
)
if d in declared_implementations:
continue
declared_implementations.append(d)

View File

@ -1,9 +1,12 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
import logging as log
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
class TemplateParamDecl(Patch):

View File

@ -1,8 +1,11 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.HelperMethods import get_text
from CppTranslator.Patches.Patch import Patch
from CppTranslator.TemplateCollector import TemplateCollector
from autosync.cpptranslator.patches.Helper import get_text
from autosync.cpptranslator.patches.Patch import Patch
from autosync.cpptranslator.TemplateCollector import TemplateCollector
class TemplateRefs(Patch):

View File

@ -1,5 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class UseMarkup(Patch):

View File

@ -1,6 +1,9 @@
# Copyright © 2022 Rot127 <unisono@quyllur.org>
# SPDX-License-Identifier: BSD-3
from tree_sitter import Node
from CppTranslator.Patches.Patch import Patch
from autosync.cpptranslator.patches.Patch import Patch
class UsingDeclaration(Patch):

Some files were not shown because too many files have changed in this diff Show More