mirror of
https://github.com/capstone-engine/capstone.git
synced 2024-11-23 05:29:53 +00:00
[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:
parent
24d99a907b
commit
7746648f0b
66
.github/workflows/auto-sync.yml
vendored
Normal file
66
.github/workflows/auto-sync.yml
vendored
Normal 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
3
.gitignore
vendored
@ -143,3 +143,6 @@ android-ndk-*
|
|||||||
|
|
||||||
# python virtual env
|
# python virtual env
|
||||||
.venv/
|
.venv/
|
||||||
|
|
||||||
|
# Auto-sync files
|
||||||
|
suite/auto-sync/src/autosync.egg-info
|
||||||
|
20
.reuse/dep5
Normal file
20
.reuse/dep5
Normal 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
|
||||||
|
|
9
.reuse/templates/license-template.jinja2
Normal file
9
.reuse/templates/license-template.jinja2
Normal 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 %}
|
11
LICENSES/LICENSE_BSD_3_CLAUSE.txt
Normal file
11
LICENSES/LICENSE_BSD_3_CLAUSE.txt
Normal 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.
|
@ -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, "*.mk")))
|
||||||
|
|
||||||
src.extend(glob.glob(os.path.join(BUILD_DIR, "Makefile")))
|
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, "README")))
|
||||||
src.extend(glob.glob(os.path.join(BUILD_DIR, "*.TXT")))
|
src.extend(glob.glob(os.path.join(BUILD_DIR, "*.TXT")))
|
||||||
src.extend(glob.glob(os.path.join(BUILD_DIR, "RELEASE_NOTES")))
|
src.extend(glob.glob(os.path.join(BUILD_DIR, "RELEASE_NOTES")))
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
tree-sitter==0.20.1
|
|
||||||
termcolor==2.2.0
|
|
||||||
cmake==3.27.9
|
|
||||||
ninja==1.11.1.1
|
|
4
suite/auto-sync/.gitignore
vendored
4
suite/auto-sync/.gitignore
vendored
@ -1,5 +1,7 @@
|
|||||||
build/
|
build/
|
||||||
vendor/llvm_root
|
vendor/llvm_root
|
||||||
*/.idea
|
*/.idea
|
||||||
Updater/config.json
|
src/auto-sync/config.json
|
||||||
|
src/autosync/cpptranslator/Tests/Differ/test_saved_patches.json
|
||||||
|
src/autosync.egg-info
|
||||||
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
<!--
|
||||||
|
Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
Copyright © 2024 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
SPDX-License-Identifier: BSD-3
|
||||||
|
-->
|
||||||
|
|
||||||
# Architecture updater
|
# Architecture updater
|
||||||
|
|
||||||
This is Capstones updater for some architectures.
|
This is Capstones updater for some architectures.
|
||||||
@ -5,12 +11,6 @@ Unfortunately not all architectures are supported yet.
|
|||||||
|
|
||||||
## Install dependencies
|
## Install dependencies
|
||||||
|
|
||||||
Install clang-format
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt install clang-format-18
|
|
||||||
```
|
|
||||||
|
|
||||||
Setup Python environment and Tree-sitter
|
Setup Python environment and Tree-sitter
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -20,7 +20,6 @@ sudo apt install python3-venv
|
|||||||
# Setup virtual environment in Capstone root dir
|
# Setup virtual environment in Capstone root dir
|
||||||
python3 -m venv ./.venv
|
python3 -m venv ./.venv
|
||||||
source ./.venv/bin/activate
|
source ./.venv/bin/activate
|
||||||
pip3 install -r dev_requirements.txt
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Clone C++ grammar
|
Clone C++ grammar
|
||||||
@ -28,6 +27,7 @@ Clone C++ grammar
|
|||||||
```
|
```
|
||||||
cd suite/auto-sync/
|
cd suite/auto-sync/
|
||||||
git submodule update --init --recursive ./vendor/
|
git submodule update --init --recursive ./vendor/
|
||||||
|
pip install -e .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Update
|
## Update
|
||||||
@ -35,13 +35,13 @@ git submodule update --init --recursive ./vendor/
|
|||||||
Check if your architecture is supported.
|
Check if your architecture is supported.
|
||||||
|
|
||||||
```
|
```
|
||||||
./Updater/ASUpdater.py -h
|
./src/autosync/ASUpdater.py -h
|
||||||
```
|
```
|
||||||
|
|
||||||
Clone Capstones LLVM fork and build `llvm-tblgen`
|
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
|
cd llvm-capstone
|
||||||
git checkout auto-sync
|
git checkout auto-sync
|
||||||
mkdir build
|
mkdir build
|
||||||
@ -55,7 +55,7 @@ cd ../../
|
|||||||
Run the updater
|
Run the updater
|
||||||
|
|
||||||
```
|
```
|
||||||
./Updater/ASUpdater.py -a <ARCH>
|
./src/autosync/ASUpdater.py -a <ARCH>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Post-processing steps
|
## Post-processing steps
|
||||||
|
2
suite/auto-sync/Updater/.gitignore
vendored
2
suite/auto-sync/Updater/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
*/.idea/
|
|
||||||
|
|
@ -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)
|
|
@ -1,7 +0,0 @@
|
|||||||
# The update scripts for auto-sync
|
|
||||||
|
|
||||||
## Updating only the `inc` files
|
|
||||||
|
|
||||||
```cmd
|
|
||||||
> ./IncGenerator.py ...
|
|
||||||
```
|
|
@ -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/"
|
|
||||||
}
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
termcolor>=2.3.0
|
|
||||||
tree_sitter>=0.20.2
|
|
4
suite/auto-sync/format_py.sh
Executable file
4
suite/auto-sync/format_py.sh
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
python3.11 -m usort format src/autosync
|
||||||
|
python3.11 -m black src/autosync
|
23
suite/auto-sync/pyproject.toml
Normal file
23
suite/auto-sync/pyproject.toml
Normal 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"}
|
@ -1,21 +1,25 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
import logging as log
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import logging as log
|
|
||||||
from enum import StrEnum
|
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 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):
|
class USteps(StrEnum):
|
||||||
INC_GEN = "IncGen"
|
INC_GEN = "IncGen"
|
||||||
@ -38,11 +42,13 @@ class ASUpdater:
|
|||||||
no_clean: bool,
|
no_clean: bool,
|
||||||
refactor: bool,
|
refactor: bool,
|
||||||
differ_no_auto_apply: bool,
|
differ_no_auto_apply: bool,
|
||||||
|
wait_for_user: bool = True,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.arch = arch
|
self.arch = arch
|
||||||
self.write = write
|
self.write = write
|
||||||
self.no_clean_build = no_clean
|
self.no_clean_build = no_clean
|
||||||
self.inc_list = inc_list
|
self.inc_list = inc_list
|
||||||
|
self.wait_for_user = wait_for_user
|
||||||
if USteps.ALL in steps:
|
if USteps.ALL in steps:
|
||||||
self.steps = [USteps.INC_GEN, USteps.TRANS, USteps.DIFF]
|
self.steps = [USteps.INC_GEN, USteps.TRANS, USteps.DIFF]
|
||||||
else:
|
else:
|
||||||
@ -108,20 +114,22 @@ class ASUpdater:
|
|||||||
ts_dir = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
|
ts_dir = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
|
||||||
if not ts_dir.exists():
|
if not ts_dir.exists():
|
||||||
log.info("tree-sitter was not fetched. Cloning it now...")
|
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:
|
def translate(self) -> None:
|
||||||
self.check_tree_sitter()
|
self.check_tree_sitter()
|
||||||
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
|
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
|
||||||
configurator = Configurator(self.arch, translator_config)
|
configurator = Configurator(self.arch, translator_config)
|
||||||
translator = Translator(configurator)
|
translator = Translator(configurator, self.wait_for_user)
|
||||||
translator.translate()
|
translator.translate()
|
||||||
translator.remark_manual_files()
|
translator.remark_manual_files()
|
||||||
|
|
||||||
def diff(self) -> None:
|
def diff(self) -> None:
|
||||||
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
|
translator_config = get_path("{CPP_TRANSLATOR_CONFIG}")
|
||||||
configurator = Configurator(self.arch, 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 = Differ(configurator, self.differ_no_auto_apply)
|
||||||
differ.diff()
|
differ.diff()
|
||||||
@ -151,11 +159,23 @@ def parse_args() -> argparse.Namespace:
|
|||||||
description="Capstones architecture module updater.",
|
description="Capstones architecture module updater.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
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(
|
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(
|
parser.add_argument(
|
||||||
"-v",
|
"-v",
|
||||||
@ -205,9 +225,15 @@ def parse_args() -> argparse.Namespace:
|
|||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--refactor",
|
"--refactor",
|
||||||
dest="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",
|
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()
|
arguments = parser.parse_args()
|
||||||
return arguments
|
return arguments
|
||||||
|
|
||||||
@ -223,6 +249,13 @@ if __name__ == "__main__":
|
|||||||
)
|
)
|
||||||
|
|
||||||
Updater = ASUpdater(
|
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()
|
Updater.update()
|
@ -1,5 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging as log
|
import logging as log
|
||||||
import re
|
import re
|
||||||
@ -12,8 +15,12 @@ def parse_args() -> argparse.Namespace:
|
|||||||
prog="PatchHeaders",
|
prog="PatchHeaders",
|
||||||
description="Patches generated enums into the main arch header file.",
|
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(
|
||||||
parser.add_argument("--inc", dest="inc", help="Path inc file.", type=Path, required=True)
|
"--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()
|
arguments = parser.parse_args()
|
||||||
return arguments
|
return arguments
|
||||||
|
|
||||||
@ -24,9 +31,13 @@ def error_exit(msg: str) -> None:
|
|||||||
|
|
||||||
|
|
||||||
class HeaderPatcher:
|
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.header = header
|
||||||
self.inc = inc
|
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:
|
def patch_header(self) -> bool:
|
||||||
if not (self.header.exists() or self.header.is_file()):
|
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 ""
|
header_enum_id = f":{ev_id}" if ev_id != "NOTGIVEN" else ""
|
||||||
regex = (
|
regex = (
|
||||||
rf"\s*// generated content <{self.inc.name}{header_enum_id}> begin.*(\n)"
|
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)"
|
rf"\s*// generated content <{self.inc.name}{header_enum_id}> end.*(\n)"
|
||||||
)
|
)
|
||||||
if not re.search(regex, header_content):
|
if not re.search(regex, header_content):
|
||||||
@ -84,8 +95,11 @@ class HeaderPatcher:
|
|||||||
)
|
)
|
||||||
|
|
||||||
header_content = re.sub(regex, new_content, header_content)
|
header_content = re.sub(regex, new_content, header_content)
|
||||||
|
if self.write_file:
|
||||||
with open(self.header, "w") as f:
|
with open(self.header, "w") as f:
|
||||||
f.write(header_content)
|
f.write(header_content)
|
||||||
|
else:
|
||||||
|
self.patched_header_content = header_content
|
||||||
log.info(f"Patched {self.inc.name} into {self.header.name}")
|
log.info(f"Patched {self.inc.name} into {self.header.name}")
|
||||||
return True
|
return True
|
||||||
|
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging as log
|
import logging as log
|
||||||
import shutil
|
import shutil
|
||||||
@ -6,10 +9,10 @@ import sys
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import termcolor
|
import termcolor
|
||||||
|
|
||||||
from PathVarHandler import PathVarHandler
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
|
from autosync.PathVarHandler import PathVarHandler
|
||||||
|
|
||||||
|
|
||||||
def convert_loglevel(level: str) -> int:
|
def convert_loglevel(level: str) -> int:
|
||||||
if level == "debug":
|
if level == "debug":
|
||||||
@ -79,11 +82,12 @@ def find_id_by_type(node: Node, node_types: [str], type_must_match: bool) -> byt
|
|||||||
return b""
|
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("\n" + separator_line_1("yellow"))
|
||||||
print(termcolor.colored("WARNING", "yellow", attrs=["bold"]) + "\n")
|
print(termcolor.colored("WARNING", "yellow", attrs=["bold"]) + "\n")
|
||||||
print(msg)
|
print(msg)
|
||||||
print(separator_line_1("yellow"))
|
print(separator_line_1("yellow"))
|
||||||
|
if wait_for_user:
|
||||||
input("Press enter to continue...\n")
|
input("Press enter to continue...\n")
|
||||||
|
|
||||||
|
|
||||||
@ -91,10 +95,11 @@ def term_width() -> int:
|
|||||||
return shutil.get_terminal_size()[0]
|
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("\n" + separator_line_1("blue"))
|
||||||
print(msg)
|
print(msg)
|
||||||
print(separator_line_1("blue"))
|
print(separator_line_1("blue"))
|
||||||
|
if wait_for_user:
|
||||||
input("Press enter to continue...\n")
|
input("Press enter to continue...\n")
|
||||||
|
|
||||||
|
|
||||||
@ -140,7 +145,14 @@ def get_header() -> str:
|
|||||||
def run_clang_format(out_paths: list[Path]):
|
def run_clang_format(out_paths: list[Path]):
|
||||||
for out_file in out_paths:
|
for out_file in out_paths:
|
||||||
log.info(f"Format {out_file}")
|
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:
|
def get_path(config_path: str) -> Path:
|
@ -1,15 +1,17 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
|
import logging as log
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
import logging as log
|
|
||||||
|
|
||||||
from Helper import fail_exit, get_path
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from autosync.Helper import fail_exit, get_path
|
||||||
|
|
||||||
inc_tables = [
|
inc_tables = [
|
||||||
{
|
{
|
||||||
"name": "Disassembler",
|
"name": "Disassembler",
|
||||||
@ -71,7 +73,9 @@ class IncGenerator:
|
|||||||
self.patches_dir_path: Path = get_path("{INC_PATCH_DIR}")
|
self.patches_dir_path: Path = get_path("{INC_PATCH_DIR}")
|
||||||
self.llvm_include_dir: Path = get_path("{LLVM_INCLUDE_DIR}")
|
self.llvm_include_dir: Path = get_path("{LLVM_INCLUDE_DIR}")
|
||||||
self.output_dir: Path = get_path("{BUILD_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.llvm_tblgen: Path = get_path("{LLVM_TBLGEN_BIN}")
|
||||||
self.output_dir_c_inc = get_path("{C_INC_OUT_DIR}")
|
self.output_dir_c_inc = get_path("{C_INC_OUT_DIR}")
|
||||||
self.output_dir_cpp_inc = get_path("{CPP_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():
|
for file in Path.cwd().iterdir():
|
||||||
if re.search(rf"{self.arch}Gen.*\.inc", file.name):
|
if re.search(rf"{self.arch}Gen.*\.inc", file.name):
|
||||||
log.debug(f"Move {file} to {self.output_dir_c_inc}")
|
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)
|
shutil.move(file, self.output_dir_c_inc)
|
||||||
|
|
||||||
if self.arch == "AArch64":
|
if self.arch == "AArch64":
|
||||||
# We have to rename the file SystemRegister -> SystemOperands
|
# We have to rename the file SystemRegister -> SystemOperands
|
||||||
sys_ops_table_file = self.output_dir_c_inc.joinpath("AArch64GenSystemRegister.inc")
|
sys_ops_table_file = self.output_dir_c_inc.joinpath(
|
||||||
new_sys_ops_file = self.output_dir_c_inc.joinpath("AArch64GenSystemOperands.inc")
|
"AArch64GenSystemRegister.inc"
|
||||||
|
)
|
||||||
|
new_sys_ops_file = self.output_dir_c_inc.joinpath(
|
||||||
|
"AArch64GenSystemOperands.inc"
|
||||||
|
)
|
||||||
if "SystemOperand" not in self.inc_list:
|
if "SystemOperand" not in self.inc_list:
|
||||||
return
|
return
|
||||||
elif not sys_ops_table_file.exists():
|
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)
|
shutil.move(sys_ops_table_file, new_sys_ops_file)
|
||||||
|
|
||||||
def gen_incs(self) -> None:
|
def gen_incs(self) -> None:
|
||||||
@ -178,6 +192,6 @@ class IncGenerator:
|
|||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
log.warn(f"Patch {patch.name} did not apply correctly!")
|
log.warning(f"Patch {patch.name} did not apply correctly!")
|
||||||
log.warn(f"git apply returned: {e}")
|
log.warning(f"git apply returned: {e}")
|
||||||
return
|
return
|
106
suite/auto-sync/src/autosync/PathVarHandler.py
Normal file
106
suite/auto-sync/src/autosync/PathVarHandler.py
Normal 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}'"
|
||||||
|
)
|
12
suite/auto-sync/src/autosync/Tests/test_header.h
Normal file
12
suite/auto-sync/src/autosync/Tests/test_header.h
Normal 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
|
||||||
|
|
47
suite/auto-sync/src/autosync/Tests/test_header_patcher.py
Normal file
47
suite/auto-sync/src/autosync/Tests/test_header_patcher.py
Normal 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"
|
||||||
|
),
|
||||||
|
)
|
11
suite/auto-sync/src/autosync/Tests/test_include.inc
Normal file
11
suite/auto-sync/src/autosync/Tests/test_include.inc
Normal 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.
|
@ -1,9 +1,13 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import logging as log
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from Helper import get_path, fail_exit
|
|
||||||
from tree_sitter import Language, Parser
|
from tree_sitter import Language, Parser
|
||||||
import logging as log
|
|
||||||
|
from autosync.Helper import fail_exit, get_path
|
||||||
|
|
||||||
|
|
||||||
class Configurator:
|
class Configurator:
|
||||||
@ -60,7 +64,9 @@ class Configurator:
|
|||||||
with open(self.config_path) as f:
|
with open(self.config_path) as f:
|
||||||
conf = json.loads(f.read())
|
conf = json.loads(f.read())
|
||||||
if self.arch not in conf:
|
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
|
self.config = conf
|
||||||
|
|
||||||
def ts_compile_cpp(self) -> None:
|
def ts_compile_cpp(self) -> None:
|
||||||
@ -68,13 +74,17 @@ class Configurator:
|
|||||||
ts_grammar_path = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
|
ts_grammar_path = get_path("{VENDOR_DIR}").joinpath("tree-sitter-cpp")
|
||||||
if not Path.exists(ts_grammar_path):
|
if not Path.exists(ts_grammar_path):
|
||||||
fail_exit(f"Could not load the tree-sitter grammar at '{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:
|
def ts_set_cpp_language(self) -> None:
|
||||||
log.info(f"Load language '{self.ts_shared_object}'")
|
log.info(f"Load language '{self.ts_shared_object}'")
|
||||||
if not Path.exists(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}'")
|
fail_exit(
|
||||||
self.ts_cpp_lang = Language(self.ts_shared_object, "cpp")
|
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:
|
def init_parser(self) -> None:
|
||||||
log.debug("Init parser")
|
log.debug("Init parser")
|
@ -1,77 +1,89 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import termcolor
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
from tree_sitter import Language, Parser, Tree, Node
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging as log
|
import logging as log
|
||||||
import sys
|
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 autosync.cpptranslator.Configurator import Configurator
|
||||||
from Helper import convert_loglevel, print_prominent_warning, get_header, run_clang_format, get_path
|
from autosync.cpptranslator.patches.AddCSDetail import AddCSDetail
|
||||||
from CppTranslator.Patches.GetRegFromClass import GetRegFromClass
|
from autosync.cpptranslator.patches.AddOperand import AddOperand
|
||||||
from CppTranslator.Patches.AddCSDetail import AddCSDetail
|
from autosync.cpptranslator.patches.Assert import Assert
|
||||||
from CppTranslator.Patches.AddOperand import AddOperand
|
from autosync.cpptranslator.patches.BitCastStdArray import BitCastStdArray
|
||||||
from CppTranslator.Patches.Assert import Assert
|
from autosync.cpptranslator.patches.CheckDecoderStatus import CheckDecoderStatus
|
||||||
from CppTranslator.Patches.BitCastStdArray import BitCastStdArray
|
from autosync.cpptranslator.patches.ClassConstructorDef import ClassConstructorDef
|
||||||
from CppTranslator.Patches.CheckDecoderStatus import CheckDecoderStatus
|
from autosync.cpptranslator.patches.ClassesDef import ClassesDef
|
||||||
from CppTranslator.Patches.ClassConstructorDef import ClassConstructorDef
|
from autosync.cpptranslator.patches.ConstMCInstParameter import ConstMCInstParameter
|
||||||
from CppTranslator.Patches.ClassesDef import ClassesDef
|
from autosync.cpptranslator.patches.ConstMCOperand import ConstMCOperand
|
||||||
from CppTranslator.Patches.ConstMCInstParameter import ConstMCInstParameter
|
from autosync.cpptranslator.patches.CppInitCast import CppInitCast
|
||||||
from CppTranslator.Patches.ConstMCOperand import ConstMCOperand
|
from autosync.cpptranslator.patches.CreateOperand0 import CreateOperand0
|
||||||
from CppTranslator.Patches.CppInitCast import CppInitCast
|
from autosync.cpptranslator.patches.CreateOperand1 import CreateOperand1
|
||||||
from CppTranslator.Patches.CreateOperand0 import CreateOperand0
|
from autosync.cpptranslator.patches.DeclarationInConditionClause import (
|
||||||
from CppTranslator.Patches.CreateOperand1 import CreateOperand1
|
DeclarationInConditionalClause,
|
||||||
from CppTranslator.Patches.DeclarationInConditionClause import DeclarationInConditionalClause
|
)
|
||||||
from CppTranslator.Patches.DecodeInstruction import DecodeInstruction
|
from autosync.cpptranslator.patches.DecodeInstruction import DecodeInstruction
|
||||||
from CppTranslator.Patches.DecoderCast import DecoderCast
|
from autosync.cpptranslator.patches.DecoderCast import DecoderCast
|
||||||
from CppTranslator.Patches.DecoderParameter import DecoderParameter
|
from autosync.cpptranslator.patches.DecoderParameter import DecoderParameter
|
||||||
from CppTranslator.Patches.FallThrough import FallThrough
|
from autosync.cpptranslator.patches.FallThrough import FallThrough
|
||||||
from CppTranslator.Patches.FeatureBits import FeatureBits
|
from autosync.cpptranslator.patches.FeatureBits import FeatureBits
|
||||||
from CppTranslator.Patches.FeatureBitsDecl import FeatureBitsDecl
|
from autosync.cpptranslator.patches.FeatureBitsDecl import FeatureBitsDecl
|
||||||
from CppTranslator.Patches.FieldFromInstr import FieldFromInstr
|
from autosync.cpptranslator.patches.FieldFromInstr import FieldFromInstr
|
||||||
from CppTranslator.Patches.GetNumOperands import GetNumOperands
|
from autosync.cpptranslator.patches.GetNumOperands import GetNumOperands
|
||||||
from CppTranslator.Patches.GetOpcode import GetOpcode
|
from autosync.cpptranslator.patches.GetOpcode import GetOpcode
|
||||||
from CppTranslator.Patches.GetOperandRegImm import GetOperandRegImm
|
from autosync.cpptranslator.patches.GetOperand import GetOperand
|
||||||
from CppTranslator.Patches.GetOperand import GetOperand
|
from autosync.cpptranslator.patches.GetOperandRegImm import GetOperandRegImm
|
||||||
from CppTranslator.Patches.GetRegClass import GetRegClass
|
from autosync.cpptranslator.patches.GetRegClass import GetRegClass
|
||||||
from CppTranslator.Patches.GetSubReg import GetSubReg
|
from autosync.cpptranslator.patches.GetRegFromClass import GetRegFromClass
|
||||||
from CppTranslator.Patches.Includes import Includes
|
from autosync.cpptranslator.patches.GetSubReg import GetSubReg
|
||||||
from CppTranslator.Patches.InlineToStaticInline import InlineToStaticInline
|
from autosync.cpptranslator.patches.Includes import Includes
|
||||||
from CppTranslator.Patches.IsRegImm import IsOperandRegImm
|
from autosync.cpptranslator.patches.InlineToStaticInline import InlineToStaticInline
|
||||||
from CppTranslator.Patches.IsOptionalDef import IsOptionalDef
|
from autosync.cpptranslator.patches.IsOptionalDef import IsOptionalDef
|
||||||
from CppTranslator.Patches.IsPredicate import IsPredicate
|
from autosync.cpptranslator.patches.IsPredicate import IsPredicate
|
||||||
from CppTranslator.Patches.LLVMFallThrough import LLVMFallThrough
|
from autosync.cpptranslator.patches.IsRegImm import IsOperandRegImm
|
||||||
from CppTranslator.Patches.LLVMunreachable import LLVMUnreachable
|
from autosync.cpptranslator.patches.LLVMFallThrough import LLVMFallThrough
|
||||||
from CppTranslator.Patches.MethodToFunctions import MethodToFunction
|
from autosync.cpptranslator.patches.LLVMunreachable import LLVMUnreachable
|
||||||
from CppTranslator.Patches.MethodTypeQualifier import MethodTypeQualifier
|
from autosync.cpptranslator.patches.MethodToFunctions import MethodToFunction
|
||||||
from CppTranslator.Patches.NamespaceLLVM import NamespaceLLVM
|
from autosync.cpptranslator.patches.MethodTypeQualifier import MethodTypeQualifier
|
||||||
from CppTranslator.Patches.NamespaceAnon import NamespaceAnon
|
from autosync.cpptranslator.patches.NamespaceAnon import NamespaceAnon
|
||||||
from CppTranslator.Patches.NamespaceArch import NamespaceArch
|
from autosync.cpptranslator.patches.NamespaceArch import NamespaceArch
|
||||||
from CppTranslator.Patches.OutStreamParam import OutStreamParam
|
from autosync.cpptranslator.patches.NamespaceLLVM import NamespaceLLVM
|
||||||
from CppTranslator.Patches.PredicateBlockFunctions import PredicateBlockFunctions
|
from autosync.cpptranslator.patches.OutStreamParam import OutStreamParam
|
||||||
from CppTranslator.Patches.PrintAnnotation import PrintAnnotation
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
from CppTranslator.Patches.PrintRegImmShift import PrintRegImmShift
|
from autosync.cpptranslator.patches.PredicateBlockFunctions import (
|
||||||
from CppTranslator.Patches.QualifiedIdentifier import QualifiedIdentifier
|
PredicateBlockFunctions,
|
||||||
from CppTranslator.Patches.Patch import Patch
|
)
|
||||||
from CppTranslator.Patches.ReferencesDecl import ReferencesDecl
|
from autosync.cpptranslator.patches.PrintAnnotation import PrintAnnotation
|
||||||
from CppTranslator.Patches.RegClassContains import RegClassContains
|
from autosync.cpptranslator.patches.PrintRegImmShift import PrintRegImmShift
|
||||||
from CppTranslator.Patches.STIArgument import STIArgument
|
from autosync.cpptranslator.patches.QualifiedIdentifier import QualifiedIdentifier
|
||||||
from CppTranslator.Patches.STIFeatureBits import STIFeatureBits
|
from autosync.cpptranslator.patches.ReferencesDecl import ReferencesDecl
|
||||||
from CppTranslator.Patches.STParameter import SubtargetInfoParam
|
from autosync.cpptranslator.patches.RegClassContains import RegClassContains
|
||||||
from CppTranslator.Patches.SetOpcode import SetOpcode
|
from autosync.cpptranslator.patches.SetOpcode import SetOpcode
|
||||||
from CppTranslator.Patches.SignExtend import SignExtend
|
from autosync.cpptranslator.patches.SignExtend import SignExtend
|
||||||
from CppTranslator.Patches.SizeAssignments import SizeAssignment
|
from autosync.cpptranslator.patches.SizeAssignments import SizeAssignment
|
||||||
from CppTranslator.Patches.StreamOperation import StreamOperations
|
from autosync.cpptranslator.patches.STIArgument import STIArgument
|
||||||
from CppTranslator.Patches.TemplateDeclaration import TemplateDeclaration
|
from autosync.cpptranslator.patches.STIFeatureBits import STIFeatureBits
|
||||||
from CppTranslator.Patches.TemplateDefinition import TemplateDefinition
|
from autosync.cpptranslator.patches.STParameter import SubtargetInfoParam
|
||||||
from CppTranslator.Patches.TemplateParamDecl import TemplateParamDecl
|
from autosync.cpptranslator.patches.StreamOperation import StreamOperations
|
||||||
from CppTranslator.Patches.TemplateRefs import TemplateRefs
|
from autosync.cpptranslator.patches.TemplateDeclaration import TemplateDeclaration
|
||||||
from CppTranslator.Patches.UseMarkup import UseMarkup
|
from autosync.cpptranslator.patches.TemplateDefinition import TemplateDefinition
|
||||||
from CppTranslator.Patches.UsingDeclaration import UsingDeclaration
|
from autosync.cpptranslator.patches.TemplateParamDecl import TemplateParamDecl
|
||||||
from CppTranslator.TemplateCollector import TemplateCollector
|
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:
|
class Translator:
|
||||||
@ -162,17 +174,22 @@ class Translator:
|
|||||||
TemplateDefinition.__name__: 6,
|
TemplateDefinition.__name__: 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, configure: Configurator):
|
def __init__(self, configure: Configurator, wait_for_user: bool = False):
|
||||||
self.configurator = configure
|
self.configurator = configure
|
||||||
|
self.wait_for_user = wait_for_user
|
||||||
self.arch = self.configurator.get_arch()
|
self.arch = self.configurator.get_arch()
|
||||||
self.conf = self.configurator.get_arch_config()
|
self.conf = self.configurator.get_arch_config()
|
||||||
self.conf_general = self.configurator.get_general_config()
|
self.conf_general = self.configurator.get_general_config()
|
||||||
self.ts_cpp_lang = self.configurator.get_cpp_lang()
|
self.ts_cpp_lang = self.configurator.get_cpp_lang()
|
||||||
self.parser = self.configurator.get_parser()
|
self.parser = self.configurator.get_parser()
|
||||||
|
|
||||||
self.src_paths: [Path] = [get_path(sp["in"]) for sp in self.conf["files_to_translate"]]
|
self.src_paths: [Path] = [
|
||||||
t_out_dir: Path = get_path(self.conf_general["translation_out_dir"])
|
get_path(sp["in"]) for sp in self.conf["files_to_translate"]
|
||||||
self.out_paths: [Path] = [t_out_dir.joinpath(sp["out"]) 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.collect_template_instances()
|
||||||
self.init_patches()
|
self.init_patches()
|
||||||
@ -188,7 +205,9 @@ class Translator:
|
|||||||
|
|
||||||
def init_patches(self):
|
def init_patches(self):
|
||||||
log.debug("Init patches")
|
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():
|
for ptype, p in priorities.items():
|
||||||
match ptype:
|
match ptype:
|
||||||
case RegClassContains.__name__:
|
case RegClassContains.__name__:
|
||||||
@ -351,8 +370,13 @@ class Translator:
|
|||||||
|
|
||||||
def apply_patch(self, patch: Patch) -> bool:
|
def apply_patch(self, patch: Patch) -> bool:
|
||||||
"""Tests if the given patch should be applied for the current architecture or file."""
|
"""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_apply_only = (
|
||||||
has_do_not_apply = len(patch.do_not_apply["files"]) > 0 or len(patch.do_not_apply["archs"]) > 0
|
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):
|
if not (has_apply_only or has_do_not_apply):
|
||||||
# Lists empty.
|
# Lists empty.
|
||||||
@ -374,7 +398,9 @@ class Translator:
|
|||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
def translate(self) -> None:
|
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}'")
|
log.info(f"Translate '{self.current_src_path_in}'")
|
||||||
self.parse(self.current_src_path_in)
|
self.parse(self.current_src_path_in)
|
||||||
patch: Patch
|
patch: Patch
|
||||||
@ -398,7 +424,9 @@ class Translator:
|
|||||||
# Add it to the bundle.
|
# Add it to the bundle.
|
||||||
captures_bundle[-1].append(q)
|
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()
|
p_list: (bytes, Node) = list()
|
||||||
cb: [(Node, str)]
|
cb: [(Node, str)]
|
||||||
@ -420,8 +448,12 @@ class Translator:
|
|||||||
|
|
||||||
def collect_template_instances(self):
|
def collect_template_instances(self):
|
||||||
search_paths = [get_path(p) for p in self.conf["files_for_template_search"]]
|
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"]]
|
temp_arg_deduction = [
|
||||||
self.template_collector = TemplateCollector(self.parser, self.ts_cpp_lang, search_paths, 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()
|
self.template_collector.collect()
|
||||||
|
|
||||||
def get_patch_kwargs(self, patch):
|
def get_patch_kwargs(self, patch):
|
||||||
@ -435,7 +467,8 @@ class Translator:
|
|||||||
if len(manual_edited) > 0:
|
if len(manual_edited) > 0:
|
||||||
msg += (
|
msg += (
|
||||||
termcolor.colored(
|
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"
|
+ "\n"
|
||||||
)
|
)
|
||||||
@ -443,7 +476,7 @@ class Translator:
|
|||||||
return
|
return
|
||||||
for f in manual_edited:
|
for f in manual_edited:
|
||||||
msg += get_path(f).name + "\n"
|
msg += get_path(f).name + "\n"
|
||||||
print_prominent_warning(msg)
|
print_prominent_warning(msg, self.wait_for_user)
|
||||||
|
|
||||||
|
|
||||||
def parse_args() -> argparse.Namespace:
|
def parse_args() -> argparse.Namespace:
|
||||||
@ -452,7 +485,11 @@ def parse_args() -> argparse.Namespace:
|
|||||||
description="Capstones C++ to C translator for LLVM source files",
|
description="Capstones C++ to C translator for LLVM source files",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
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(
|
parser.add_argument(
|
||||||
"-v",
|
"-v",
|
||||||
@ -462,7 +499,11 @@ def parse_args() -> argparse.Namespace:
|
|||||||
default="info",
|
default="info",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
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()
|
arguments = parser.parse_args()
|
||||||
return arguments
|
return arguments
|
@ -1,29 +1,34 @@
|
|||||||
#!/usr/bin/env python3
|
#!/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
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
from shutil import copy2
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import difflib as dl
|
import difflib as dl
|
||||||
|
import json
|
||||||
import logging as log
|
import logging as log
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
|
from enum import StrEnum
|
||||||
|
from pathlib import Path
|
||||||
|
from shutil import copy2
|
||||||
|
|
||||||
from CppTranslator.Configurator import Configurator
|
from tree_sitter import Language, Node, Parser, Tree
|
||||||
from Helper import (
|
|
||||||
convert_loglevel,
|
from autosync.cpptranslator.Configurator import Configurator
|
||||||
find_id_by_type,
|
from autosync.Helper import (
|
||||||
print_prominent_info,
|
|
||||||
bold,
|
bold,
|
||||||
colored,
|
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_1,
|
||||||
separator_line_2,
|
separator_line_2,
|
||||||
print_prominent_warning,
|
|
||||||
get_sha256,
|
|
||||||
run_clang_format,
|
|
||||||
get_path,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -35,7 +40,13 @@ class PatchCoord:
|
|||||||
start_point: tuple[int, int]
|
start_point: tuple[int, int]
|
||||||
end_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.start_byte = start_byte
|
||||||
self.end_byte = end_byte
|
self.end_byte = end_byte
|
||||||
self.start_point = start_point
|
self.start_point = start_point
|
||||||
@ -58,7 +69,9 @@ class PatchCoord:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_coordinates_from_node(node: Node):
|
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):
|
class ApplyType(StrEnum):
|
||||||
@ -66,6 +79,7 @@ class ApplyType(StrEnum):
|
|||||||
NEW = "NEW" # Apply version from new file (leave unchanged)
|
NEW = "NEW" # Apply version from new file (leave unchanged)
|
||||||
SAVED = "SAVED" # Use saved resolution
|
SAVED = "SAVED" # Use saved resolution
|
||||||
EDIT = "EDIT" # Edit patch and apply
|
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.
|
OLD_ALL = "OLD_ALL" # Apply all versions from old file.
|
||||||
PREVIOUS = "PREVIOUS" # Ignore diff and go to previous
|
PREVIOUS = "PREVIOUS" # Ignore diff and go to previous
|
||||||
|
|
||||||
@ -81,7 +95,13 @@ class Patch:
|
|||||||
new_hash: str
|
new_hash: str
|
||||||
|
|
||||||
def __init__(
|
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:
|
) -> None:
|
||||||
if apply == ApplyType.SAVED:
|
if apply == ApplyType.SAVED:
|
||||||
raise NotImplementedError("Not yet implemented.")
|
raise NotImplementedError("Not yet implemented.")
|
||||||
@ -133,6 +153,41 @@ class Patch:
|
|||||||
class Differ:
|
class Differ:
|
||||||
"""
|
"""
|
||||||
Diffs the newly translated C++ files against the old version.
|
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
|
ts_cpp_lang: Language = None
|
||||||
@ -148,11 +203,13 @@ class Differ:
|
|||||||
patches: list[Patch]
|
patches: list[Patch]
|
||||||
|
|
||||||
current_patch: Patch
|
current_patch: Patch
|
||||||
cur_old_node: Node = None
|
cur_old_node: Node | None = None
|
||||||
cur_new_node: Node = None
|
cur_new_node: Node | None = None
|
||||||
cur_nid: str = 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.configurator = configurator
|
||||||
self.no_auto_apply = no_auto_apply
|
self.no_auto_apply = no_auto_apply
|
||||||
self.arch = self.configurator.get_arch()
|
self.arch = self.configurator.get_arch()
|
||||||
@ -161,18 +218,41 @@ class Differ:
|
|||||||
self.ts_cpp_lang = self.configurator.get_cpp_lang()
|
self.ts_cpp_lang = self.configurator.get_cpp_lang()
|
||||||
self.parser = self.configurator.get_parser()
|
self.parser = self.configurator.get_parser()
|
||||||
self.differ = dl.Differ()
|
self.differ = dl.Differ()
|
||||||
|
self.testing = testing
|
||||||
|
|
||||||
t_out_dir: Path = get_path(self.conf_general["translation_out_dir"])
|
self.diff_out_dir = get_path("{CPP_TRANSLATOR_DIFF_OUT_DIR}")
|
||||||
self.translated_files = [t_out_dir.joinpath(sp["out"]) for sp in self.conf_arch["files_to_translate"]]
|
if self.testing:
|
||||||
cs_arch_src: Path = get_path("{CS_ARCH_MODULE_DIR}")
|
t_out_dir: Path = get_path("{DIFFER_TEST_NEW_SRC_DIR}")
|
||||||
cs_arch_src = cs_arch_src.joinpath(self.arch if self.arch != "PPC" else "PowerPC")
|
self.translated_files = [
|
||||||
|
t_out_dir.joinpath(sp["out"])
|
||||||
|
for sp in self.conf_arch["files_to_translate"]
|
||||||
|
]
|
||||||
self.old_files = [
|
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()
|
self.load_persistence_file()
|
||||||
|
|
||||||
def load_persistence_file(self) -> None:
|
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():
|
if not self.persistence_filepath.exists():
|
||||||
self.saved_patches = dict()
|
self.saved_patches = dict()
|
||||||
return
|
return
|
||||||
@ -181,7 +261,9 @@ class Differ:
|
|||||||
try:
|
try:
|
||||||
self.saved_patches = json.load(f)
|
self.saved_patches = json.load(f)
|
||||||
except json.decoder.JSONDecodeError as e:
|
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("Delete it or fix it by hand.")
|
||||||
log.fatal(f"JSON Exception: {e}")
|
log.fatal(f"JSON Exception: {e}")
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -191,6 +273,10 @@ class Differ:
|
|||||||
json.dump(self.saved_patches, f, indent=2)
|
json.dump(self.saved_patches, f, indent=2)
|
||||||
|
|
||||||
def persist_patch(self, filename: Path, patch: Patch) -> None:
|
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:
|
if filename.name not in self.saved_patches:
|
||||||
self.saved_patches[filename.name] = dict()
|
self.saved_patches[filename.name] = dict()
|
||||||
log.debug(f"Save: {patch.get_persist_info()}")
|
log.debug(f"Save: {patch.get_persist_info()}")
|
||||||
@ -201,14 +287,19 @@ class Differ:
|
|||||||
Copy translated files to diff directory for editing.
|
Copy translated files to diff directory for editing.
|
||||||
"""
|
"""
|
||||||
log.info("Copy files 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:
|
for f in self.translated_files:
|
||||||
dest = diff_dir.joinpath(f.name)
|
dest = diff_dir.joinpath(f.name)
|
||||||
copy2(f, dest)
|
copy2(f, dest)
|
||||||
self.diff_dest_files.append(dest)
|
self.diff_dest_files.append(dest)
|
||||||
|
|
||||||
def get_diff_intro_msg(
|
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:
|
) -> str:
|
||||||
color_new = self.conf_general["diff_color_new"]
|
color_new = self.conf_general["diff_color_new"]
|
||||||
color_old = self.conf_general["diff_color_old"]
|
color_old = self.conf_general["diff_color_old"]
|
||||||
@ -229,7 +320,9 @@ class Differ:
|
|||||||
if n["node_type"] == node.type:
|
if n["node_type"] == node.type:
|
||||||
id_types = n["identifier_node_type"]
|
id_types = n["identifier_node_type"]
|
||||||
if not id_types:
|
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)
|
exit(1)
|
||||||
identifier = ""
|
identifier = ""
|
||||||
for id_type in id_types:
|
for id_type in id_types:
|
||||||
@ -241,7 +334,7 @@ class Differ:
|
|||||||
exit(1)
|
exit(1)
|
||||||
return identifier
|
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.
|
Parse a files and return all nodes which should be diffed.
|
||||||
Nodes are indexed by a unique identifier.
|
Nodes are indexed by a unique identifier.
|
||||||
@ -251,7 +344,9 @@ class Differ:
|
|||||||
|
|
||||||
tree: Tree = self.parser.parse(content, keep_text=True)
|
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
|
content = None
|
||||||
if file.suffix == ".h":
|
if file.suffix == ".h":
|
||||||
# Header file. Get the content in between the include guard
|
# 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):
|
def print_diff(self, diff_lines: list[str], node_id: str, current: int, total: int):
|
||||||
new_color = self.conf_general["diff_color_new"]
|
new_color = self.conf_general["diff_color_new"]
|
||||||
old_color = self.conf_general["diff_color_old"]
|
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('Patch:')} {current}/{total}\n")
|
||||||
print(f"{bold('Node:')} {node_id}")
|
print(f"{bold('Node:')} {node_id}")
|
||||||
print(f"{bold('Color:')} {colored('NEW FILE - (Just translated)', new_color)}")
|
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())
|
print(separator_line_1())
|
||||||
for line in diff_lines:
|
for line in diff_lines:
|
||||||
if line[0] == "+":
|
if line[0] == "+":
|
||||||
@ -301,13 +398,15 @@ class Differ:
|
|||||||
print(separator_line_2())
|
print(separator_line_2())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def no_difference(diff_lines: Iterator[str]) -> bool:
|
def no_difference(diff_lines: list[str]) -> bool:
|
||||||
for line in diff_lines:
|
for line in diff_lines:
|
||||||
if line[0] != " ":
|
if line[0] != " ":
|
||||||
return False
|
return False
|
||||||
return True
|
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"]
|
new_color = self.conf_general["diff_color_new"]
|
||||||
old_color = self.conf_general["diff_color_old"]
|
old_color = self.conf_general["diff_color_old"]
|
||||||
edited_color = self.conf_general["diff_color_edited"]
|
edited_color = self.conf_general["diff_color_edited"]
|
||||||
@ -315,15 +414,19 @@ class Differ:
|
|||||||
|
|
||||||
choice = input(
|
choice = input(
|
||||||
f"Choice: {colored('O', old_color)}, {bold('o', old_color)}, {bold('n', new_color)}, "
|
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
|
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"]
|
new_color = self.conf_general["diff_color_new"]
|
||||||
old_color = self.conf_general["diff_color_old"]
|
old_color = self.conf_general["diff_color_old"]
|
||||||
edited_color = self.conf_general["diff_color_edited"]
|
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)}"
|
saved_selection = f"{bold('s', saved_color)}"
|
||||||
if saved_choice == ApplyType.OLD:
|
if saved_choice == ApplyType.OLD:
|
||||||
saved_selection += f" ({colored('old', old_color)}) "
|
saved_selection += f" ({colored('old', old_color)}) "
|
||||||
@ -335,7 +438,9 @@ class Differ:
|
|||||||
saved_selection += f" ({colored('none', 'dark_grey')}) "
|
saved_selection += f" ({colored('none', 'dark_grey')}) "
|
||||||
return saved_selection
|
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"]
|
new_color = self.conf_general["diff_color_new"]
|
||||||
old_color = self.conf_general["diff_color_old"]
|
old_color = self.conf_general["diff_color_old"]
|
||||||
edited_color = self.conf_general["diff_color_edited"]
|
edited_color = self.conf_general["diff_color_edited"]
|
||||||
@ -352,10 +457,12 @@ class Differ:
|
|||||||
f"?\t\t- Show this help\n\n"
|
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:
|
while True:
|
||||||
choice = self.print_prompt(saved_diff_present, saved_choice)
|
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.")
|
print(f"{bold(choice)} is not valid.")
|
||||||
self.print_prompt_help(saved_diff_present, saved_choice)
|
self.print_prompt_help(saved_diff_present, saved_choice)
|
||||||
continue
|
continue
|
||||||
@ -372,6 +479,8 @@ class Differ:
|
|||||||
return ApplyType.OLD_ALL
|
return ApplyType.OLD_ALL
|
||||||
elif choice == "e":
|
elif choice == "e":
|
||||||
return ApplyType.EDIT
|
return ApplyType.EDIT
|
||||||
|
elif choice == "E":
|
||||||
|
return ApplyType.SHOW_EDIT
|
||||||
elif choice == "s":
|
elif choice == "s":
|
||||||
return ApplyType.SAVED
|
return ApplyType.SAVED
|
||||||
elif choice in ["?", "help"]:
|
elif choice in ["?", "help"]:
|
||||||
@ -391,10 +500,23 @@ class Differ:
|
|||||||
new_hash = ""
|
new_hash = ""
|
||||||
return saved["old_hash"] == old_hash and saved["new_hash"] == 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""
|
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""
|
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(
|
def add_patch(
|
||||||
self,
|
self,
|
||||||
@ -402,8 +524,12 @@ class Differ:
|
|||||||
consec_old: int,
|
consec_old: int,
|
||||||
old_filepath: Path,
|
old_filepath: Path,
|
||||||
patch_coord: PatchCoord,
|
patch_coord: PatchCoord,
|
||||||
|
saved_patch: dict | None = None,
|
||||||
|
edited_text: bytes | None = 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)
|
self.persist_patch(old_filepath, self.current_patch)
|
||||||
if consec_old > 1:
|
if consec_old > 1:
|
||||||
# Two or more old nodes are not present in the new file.
|
# Two or more old nodes are not present in the new file.
|
||||||
@ -412,18 +538,34 @@ class Differ:
|
|||||||
else:
|
else:
|
||||||
self.patches.append(self.current_patch)
|
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.
|
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.
|
It writes the choice to a file, so the previous choice can be applied again if nothing changed.
|
||||||
"""
|
"""
|
||||||
# Sort list of nodes descending.
|
# Sort list of nodes descending.
|
||||||
# This is necessary because
|
# 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
|
# 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).
|
# 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)}
|
new_nodes = {
|
||||||
old_nodes = {k: v for k, v in sorted(old_nodes.items(), key=lambda item: item[1].start_byte, reverse=True)}
|
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
|
# Collect all node ids of this file
|
||||||
node_ids = set()
|
node_ids = set()
|
||||||
@ -433,36 +575,48 @@ class Differ:
|
|||||||
|
|
||||||
# The initial patch coordinates point after the last node in the file.
|
# The initial patch coordinates point after the last node in the file.
|
||||||
n0 = new_nodes[list(new_nodes.keys())[0]]
|
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)
|
node_ids = sorted(node_ids)
|
||||||
self.patches = list()
|
self.patches = list()
|
||||||
matching_nodes_count = 0
|
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
|
consec_old = 0
|
||||||
choice: ApplyType = None
|
choice: ApplyType | None = None
|
||||||
i = 0
|
idx = 0
|
||||||
while i < len(node_ids):
|
while idx < len(node_ids):
|
||||||
self.cur_nid = node_ids[i]
|
self.cur_nid = node_ids[idx]
|
||||||
self.cur_new_node = None
|
self.cur_new_node = (
|
||||||
if self.cur_nid in new_nodes:
|
None if self.cur_nid not in new_nodes else new_nodes[self.cur_nid]
|
||||||
self.cur_new_node = new_nodes[self.cur_nid]
|
)
|
||||||
self.cur_old_node = None
|
self.cur_old_node = (
|
||||||
if self.cur_nid in old_nodes:
|
None if self.cur_nid not in old_nodes else old_nodes[self.cur_nid]
|
||||||
self.cur_old_node = old_nodes[self.cur_nid]
|
)
|
||||||
|
|
||||||
n = self.cur_new_node.text.decode("utf8").splitlines() if self.cur_new_node else [""]
|
n = (
|
||||||
o = self.cur_old_node.text.decode("utf8").splitlines() if self.cur_old_node else [""]
|
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))
|
diff_lines = list(self.differ.compare(o, n))
|
||||||
if self.no_difference(diff_lines):
|
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
|
matching_nodes_count += 1
|
||||||
i += 1
|
idx += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self.cur_new_node:
|
if self.cur_new_node:
|
||||||
consec_old = 0
|
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)
|
patch_coord = PatchCoord.get_coordinates_from_node(self.cur_new_node)
|
||||||
else:
|
else:
|
||||||
consec_old += 1
|
consec_old += 1
|
||||||
@ -473,38 +627,50 @@ class Differ:
|
|||||||
j = old_node_ids.index(self.cur_nid)
|
j = old_node_ids.index(self.cur_nid)
|
||||||
while j >= 0 and (old_node_ids[j] not in new_nodes.keys()):
|
while j >= 0 and (old_node_ids[j] not in new_nodes.keys()):
|
||||||
j -= 1
|
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
|
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(
|
patch_coord = PatchCoord(
|
||||||
ref_end_byte - 1,
|
ref_end_byte - 1,
|
||||||
ref_end_byte - 1,
|
ref_end_byte - 1,
|
||||||
ref_end_byte,
|
ref_new.start_point,
|
||||||
ref_end_byte,
|
ref_new.start_point,
|
||||||
)
|
)
|
||||||
|
|
||||||
save_exists = False
|
save_exists = False
|
||||||
saved = None
|
saved: dict | None = None
|
||||||
if old_filepath.name in self.saved_patches and self.cur_nid in self.saved_patches[old_filepath.name]:
|
if (
|
||||||
saved: dict = self.saved_patches[old_filepath.name][self.cur_nid]
|
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
|
save_exists = True
|
||||||
if self.saved_patch_matches(saved) and not self.no_auto_apply:
|
if self.saved_patch_matches(saved) and not self.no_auto_apply:
|
||||||
apply_type = ApplyType(saved["apply_type"])
|
apply_type = ApplyType(saved["apply_type"])
|
||||||
self.add_patch(apply_type, consec_old, old_filepath, patch_coord)
|
self.add_patch(apply_type, consec_old, old_filepath, patch_coord)
|
||||||
log.info(f"Auto apply patch for {bold(self.cur_nid)}")
|
log.info(
|
||||||
i += 1
|
f"{bold('Patch:')} {idx + 1}/{len(node_ids)} - Auto apply patch for {bold(self.cur_nid)}"
|
||||||
|
)
|
||||||
|
idx += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if choice == ApplyType.OLD_ALL:
|
if choice == ApplyType.OLD_ALL:
|
||||||
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
|
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
|
||||||
i += 1
|
idx += 1
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.print_diff(diff_lines, self.cur_nid, i + 1, len(node_ids))
|
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"])
|
choice = self.get_user_choice(
|
||||||
|
save_exists, None if not saved else saved["apply_type"]
|
||||||
|
)
|
||||||
if choice == ApplyType.OLD:
|
if choice == ApplyType.OLD:
|
||||||
if not self.cur_old_node:
|
if not self.cur_old_node:
|
||||||
# No data in old node. Skip
|
# No data in old node. Skip
|
||||||
i += 1
|
idx += 1
|
||||||
continue
|
continue
|
||||||
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
|
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
|
||||||
elif choice == ApplyType.NEW:
|
elif choice == ApplyType.NEW:
|
||||||
@ -514,20 +680,43 @@ class Differ:
|
|||||||
if not save_exists:
|
if not save_exists:
|
||||||
print(bold("Save does not exist."))
|
print(bold("Save does not exist."))
|
||||||
continue
|
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:
|
elif choice == ApplyType.OLD_ALL:
|
||||||
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
|
self.add_patch(ApplyType.OLD, consec_old, old_filepath, patch_coord)
|
||||||
elif choice == ApplyType.EDIT:
|
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
|
continue
|
||||||
|
self.persist_patch(
|
||||||
|
old_filepath,
|
||||||
|
self.create_patch(patch_coord, choice, edited_text=edited_text),
|
||||||
|
)
|
||||||
elif choice == ApplyType.PREVIOUS:
|
elif choice == ApplyType.PREVIOUS:
|
||||||
if i == 0:
|
if idx == 0:
|
||||||
print(bold(f"There is no previous diff for {old_filepath.name}!"))
|
print(bold(f"There is no previous diff for {old_filepath.name}!"))
|
||||||
input("Press enter...")
|
input("Press enter...")
|
||||||
continue
|
continue
|
||||||
i -= 1
|
idx -= 1
|
||||||
continue
|
continue
|
||||||
i += 1
|
idx += 1
|
||||||
log.info(f"Number of matching nodes = {matching_nodes_count}")
|
log.info(f"Number of matching nodes = {matching_nodes_count}")
|
||||||
return self.patches
|
return self.patches
|
||||||
|
|
||||||
@ -558,10 +747,16 @@ class Differ:
|
|||||||
old_filepath = old_file[k]["filepath"]
|
old_filepath = old_file[k]["filepath"]
|
||||||
new_filepath = new_file[k]["filepath"]
|
new_filepath = new_file[k]["filepath"]
|
||||||
diffs_to_process = max(len(new_file[k]["nodes"]), len(old_file[k]["nodes"]))
|
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:
|
if diffs_to_process == 0:
|
||||||
continue
|
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)
|
self.patch_files(patches)
|
||||||
log.info("Done")
|
log.info("Done")
|
||||||
|
|
||||||
@ -590,6 +785,38 @@ class Differ:
|
|||||||
run_clang_format(list(file_patches.keys()))
|
run_clang_format(list(file_patches.keys()))
|
||||||
return
|
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:
|
def parse_args() -> argparse.Namespace:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
@ -603,7 +830,11 @@ def parse_args() -> argparse.Namespace:
|
|||||||
action="store_true",
|
action="store_true",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
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(
|
parser.add_argument(
|
||||||
"-v",
|
"-v",
|
||||||
@ -613,7 +844,7 @@ def parse_args() -> argparse.Namespace:
|
|||||||
default="info",
|
default="info",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
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()
|
arguments = parser.parse_args()
|
||||||
return arguments
|
return arguments
|
||||||
@ -629,9 +860,12 @@ if __name__ == "__main__":
|
|||||||
stream=sys.stdout,
|
stream=sys.stdout,
|
||||||
format="%(levelname)-5s - %(message)s",
|
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:
|
try:
|
||||||
differ.diff()
|
differ.diff()
|
||||||
except Exception as e:
|
except Exception as e:
|
@ -1,3 +1,8 @@
|
|||||||
|
<!--
|
||||||
|
Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
SPDX-License-Identifier: BSD-3
|
||||||
|
-->
|
||||||
|
|
||||||
# C++ Translator
|
# C++ Translator
|
||||||
|
|
||||||
Capstone uses source files from LLVM to disassemble opcodes.
|
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:
|
The config values have the following meaning:
|
||||||
|
|
||||||
- `General`: Settings valid for all architectures.
|
- `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_new`: Color in the `Differ` for translated content.
|
||||||
- `diff_color_old`: Color in the `Differ` for old/current Capstone 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_saved`: Color in the `Differ` for saved content.
|
||||||
- `diff_color_edited`: Color in the `Differ` for edited 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*.
|
- `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.
|
- `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
|
- `<ARCH>`: Settings valid for a specific architecture
|
||||||
- `files_to_translate`: A list of file paths to translate.
|
- `files_to_translate`: A list of file paths to translate.
|
||||||
- `in`: *Path* to a specific source file.
|
- `in`: *Path* to a specific source file.
|
@ -1,11 +1,13 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
|
import logging as log
|
||||||
import re
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from tree_sitter import Language, Parser
|
from tree_sitter import Language, Node, Parser, Query
|
||||||
import logging as log
|
|
||||||
|
|
||||||
from tree_sitter.binding import Query, Node
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateRefInstance:
|
class TemplateRefInstance:
|
||||||
@ -27,7 +29,9 @@ class TemplateRefInstance:
|
|||||||
# (parameters are set by the template parameters of the calling function).
|
# (parameters are set by the template parameters of the calling function).
|
||||||
caller_param_indices: [{str: int}] = list()
|
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.name = name
|
||||||
self.args = args
|
self.args = args
|
||||||
self.start_point = start_point
|
self.start_point = start_point
|
||||||
@ -41,7 +45,14 @@ class TemplateRefInstance:
|
|||||||
return (
|
return (
|
||||||
self.name == other.name
|
self.name == other.name
|
||||||
and self.args == other.args
|
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_byte == other.start_byte
|
||||||
and self.start_point == other.start_point
|
and self.start_point == other.start_point
|
||||||
and self.end_byte == other.end_byte
|
and self.end_byte == other.end_byte
|
||||||
@ -75,7 +86,13 @@ class TemplateCollector:
|
|||||||
incomplete_template_refs: {bytes: [TemplateRefInstance]} = dict()
|
incomplete_template_refs: {bytes: [TemplateRefInstance]} = dict()
|
||||||
sources: [{str: bytes}] = list()
|
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.parser = ts_parser
|
||||||
self.lang_cpp = ts_cpp
|
self.lang_cpp = ts_cpp
|
||||||
self.searchable_files = searchable_files
|
self.searchable_files = searchable_files
|
||||||
@ -100,10 +117,17 @@ class TemplateCollector:
|
|||||||
args = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
args = get_text(src, templ_args.start_byte, templ_args.end_byte)
|
||||||
|
|
||||||
ti = TemplateRefInstance(
|
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 not self.contains_template_dependent_param(src, ti, cb[0]):
|
||||||
if name not in self.template_refs:
|
if name not in self.template_refs:
|
||||||
@ -118,7 +142,10 @@ class TemplateCollector:
|
|||||||
def resolve_dependencies(self):
|
def resolve_dependencies(self):
|
||||||
# Resolve dependencies of templates until nothing new was resolved.
|
# Resolve dependencies of templates until nothing new was resolved.
|
||||||
prev_len = 0
|
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
|
# Dict with new template calls which were previously incomplete
|
||||||
# because one or more parameters were unknown.
|
# because one or more parameters were unknown.
|
||||||
new_completed_tcs: {str: list} = dict()
|
new_completed_tcs: {str: list} = dict()
|
||||||
@ -134,7 +161,9 @@ class TemplateCollector:
|
|||||||
for caller_template in tc_instance_list:
|
for caller_template in tc_instance_list:
|
||||||
incomplete_tc: TemplateRefInstance
|
incomplete_tc: TemplateRefInstance
|
||||||
for incomplete_tc in self.incomplete_template_refs[caller_name]:
|
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
|
callee_name = new_tc.name
|
||||||
if callee_name not in new_completed_tcs:
|
if callee_name not in new_completed_tcs:
|
||||||
new_completed_tcs[callee_name] = list()
|
new_completed_tcs[callee_name] = list()
|
||||||
@ -149,11 +178,22 @@ class TemplateCollector:
|
|||||||
self.template_refs[templ_name] = tc_list
|
self.template_refs[templ_name] = tc_list
|
||||||
prev_len = len(self.incomplete_template_refs)
|
prev_len = len(self.incomplete_template_refs)
|
||||||
if prev_len > 0:
|
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
|
@staticmethod
|
||||||
def get_completed_tc(tc: TemplateRefInstance, itc: TemplateRefInstance) -> TemplateRefInstance:
|
def get_completed_tc(
|
||||||
new_tc = TemplateRefInstance(itc.name, itc.args, itc.start_byte, itc.start_byte, itc.end_point, itc.end_byte)
|
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:
|
for indices in itc.caller_param_indices:
|
||||||
if tc.name not in indices:
|
if tc.name not in indices:
|
||||||
# Index of other caller function. Skip.
|
# Index of other caller function. Skip.
|
||||||
@ -165,7 +205,9 @@ class TemplateCollector:
|
|||||||
new_tc.templ_name = new_tc.name + new_tc.args
|
new_tc.templ_name = new_tc.name + new_tc.args
|
||||||
return new_tc
|
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,
|
"""Here we check if one of the template parameters of the given template call,
|
||||||
is a parameter of the callers template definition.
|
is a parameter of the callers template definition.
|
||||||
|
|
||||||
@ -201,14 +243,20 @@ class TemplateCollector:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
caller_fcn_id = node.named_children[2].named_children[0]
|
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_fcn_name = get_text(
|
||||||
caller_templ_params = get_text(src, node.prev_sibling.start_byte, node.prev_sibling.end_byte)
|
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)
|
pl = TemplateCollector.templ_params_to_list(caller_templ_params)
|
||||||
has_parameter_dependency = False
|
has_parameter_dependency = False
|
||||||
for i, param in enumerate(pl):
|
for i, param in enumerate(pl):
|
||||||
if param in ti.args_list:
|
if param in ti.args_list:
|
||||||
has_parameter_dependency = True
|
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:
|
if not has_parameter_dependency:
|
||||||
return False
|
return False
|
@ -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() {}
|
@ -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() {}
|
@ -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": []
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Rot127 <unisono@quyllur.org>
|
||||||
|
// SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
tfunction<int, int>();
|
||||||
|
tfunction<int, char>();
|
||||||
|
}
|
@ -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": []
|
||||||
|
}
|
||||||
|
}
|
106
suite/auto-sync/src/autosync/cpptranslator/Tests/test_differ.py
Normal file
106
suite/auto-sync/src/autosync/cpptranslator/Tests/test_differ.py
Normal 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)
|
563
suite/auto-sync/src/autosync/cpptranslator/Tests/test_patches.py
Normal file
563
suite/auto-sync/src/autosync/cpptranslator/Tests/test_patches.py
Normal 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"")
|
@ -1,12 +1,10 @@
|
|||||||
{
|
{
|
||||||
"General": {
|
"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_new": "green",
|
||||||
"diff_color_old": "light_blue",
|
"diff_color_old": "light_blue",
|
||||||
"diff_color_saved": "yellow",
|
"diff_color_saved": "yellow",
|
||||||
"diff_color_edited": "light_magenta",
|
"diff_color_edited": "light_magenta",
|
||||||
|
"patch_editor": "vim",
|
||||||
"nodes_to_diff": [
|
"nodes_to_diff": [
|
||||||
{
|
{
|
||||||
"node_type": "function_definition",
|
"node_type": "function_definition",
|
||||||
@ -116,7 +114,8 @@
|
|||||||
"printImmSVE",
|
"printImmSVE",
|
||||||
"printAMIndexedWB",
|
"printAMIndexedWB",
|
||||||
"isSVECpyImm",
|
"isSVECpyImm",
|
||||||
"isSVEAddSubImm"
|
"isSVEAddSubImm",
|
||||||
|
"printVectorIndex"
|
||||||
],
|
],
|
||||||
"manually_edited_files": []
|
"manually_edited_files": []
|
||||||
},
|
},
|
@ -1,10 +1,17 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name, template_param_list_to_dict
|
from autosync.cpptranslator.patches.Helper import (
|
||||||
from CppTranslator.Patches.Patch import Patch
|
get_MCInst_var_name,
|
||||||
|
get_text,
|
||||||
|
template_param_list_to_dict,
|
||||||
|
)
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class AddCSDetail(Patch):
|
class AddCSDetail(Patch):
|
||||||
@ -33,7 +40,11 @@ class AddCSDetail(Patch):
|
|||||||
super().__init__(priority)
|
super().__init__(priority)
|
||||||
self.arch = arch
|
self.arch = arch
|
||||||
self.apply_only_to = {
|
self.apply_only_to = {
|
||||||
"files": ["ARMInstPrinter.cpp", "PPCInstPrinter.cpp", "AArch64InstPrinter.cpp"],
|
"files": [
|
||||||
|
"ARMInstPrinter.cpp",
|
||||||
|
"PPCInstPrinter.cpp",
|
||||||
|
"AArch64InstPrinter.cpp",
|
||||||
|
],
|
||||||
"archs": list(),
|
"archs": list(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,15 +79,31 @@ class AddCSDetail(Patch):
|
|||||||
comp = get_text(src, comp.start_byte, comp.end_byte)
|
comp = get_text(src, comp.start_byte, comp.end_byte)
|
||||||
return b"void " + fcn_id + params + b"{ " + add_cs_detail + comp.strip(b"{")
|
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:
|
def get_add_cs_detail(
|
||||||
op_group_enum = self.arch.encode("utf8") + b"_OP_GROUP_" + fcn_id[5:] # Remove "print" from function id
|
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"
|
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:
|
if not is_template and op_num_var_name in params:
|
||||||
# Standard printOperand() parameters
|
# Standard printOperand() parameters
|
||||||
mcinst_var = get_MCInst_var_name(src, fcn_def)
|
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":
|
elif op_group_enum == b"ARM_OP_GROUP_RegImmShift":
|
||||||
return b"add_cs_detail(MI, " + op_group_enum + b", ShOpc, ShImm);"
|
return b"add_cs_detail(MI, " + op_group_enum + b", ShOpc, ShImm);"
|
||||||
elif is_template and op_num_var_name in params:
|
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)
|
templ_p = template_param_list_to_dict(fcn_def.prev_sibling)
|
||||||
cs_args = b""
|
cs_args = b""
|
||||||
for tp in templ_p:
|
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"]
|
cs_args += b", " + tp["identifier"]
|
||||||
return (
|
return (
|
||||||
b"add_cs_detail("
|
b"add_cs_detail("
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class AddOperand(Patch):
|
class AddOperand(Patch):
|
@ -1,5 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
from CppTranslator.Patches.Patch import Patch
|
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class Assert(Patch):
|
class Assert(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class BitCastStdArray(Patch):
|
class BitCastStdArray(Patch):
|
||||||
@ -46,14 +49,36 @@ class BitCastStdArray(Patch):
|
|||||||
arr_name: bytes = captures[1][0].text
|
arr_name: bytes = captures[1][0].text
|
||||||
array_type: Node = captures[3][0]
|
array_type: Node = captures[3][0]
|
||||||
cast_target: bytes = captures[4][0].text.strip(b"()")
|
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_type = array_templ_args.split(b",")[0]
|
||||||
arr_len = array_templ_args.split(b",")[1]
|
arr_len = array_templ_args.split(b",")[1]
|
||||||
return (
|
return (
|
||||||
b"union {\n"
|
b"union {\n"
|
||||||
+ b" typeof(" + cast_target + b") In;\n"
|
+ b" typeof("
|
||||||
+ b" " + arr_type + b" Out[" + arr_len + b"];\n"
|
+ cast_target
|
||||||
+ b"} U_" + arr_name + b";\n"
|
+ b") In;\n"
|
||||||
+ b"U_" + arr_name + b".In = " + cast_target + b";\n"
|
+ b" "
|
||||||
+ arr_type + b" *" + arr_name + b" = U_" + arr_name + b".Out;"
|
+ 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;"
|
||||||
)
|
)
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class CheckDecoderStatus(Patch):
|
class CheckDecoderStatus(Patch):
|
@ -1,5 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
from CppTranslator.Patches.Patch import Patch
|
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class ClassConstructorDef(Patch):
|
class ClassConstructorDef(Patch):
|
@ -1,10 +1,13 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class ClassesDef(Patch):
|
class ClassesDef(Patch):
|
||||||
@ -31,7 +34,9 @@ class ClassesDef(Patch):
|
|||||||
for field_decl in field_decl_list.named_children:
|
for field_decl in field_decl_list.named_children:
|
||||||
if (
|
if (
|
||||||
field_decl.type in "field_declaration"
|
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":
|
) or field_decl.type == "template_declaration":
|
||||||
# Keep comments
|
# Keep comments
|
||||||
sibling = field_decl.prev_named_sibling
|
sibling = field_decl.prev_named_sibling
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class ConstMCInstParameter(Patch):
|
class ConstMCInstParameter(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class ConstMCOperand(Patch):
|
class ConstMCOperand(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class CppInitCast(Patch):
|
class CppInitCast(Patch):
|
||||||
@ -14,7 +17,12 @@ class CppInitCast(Patch):
|
|||||||
super().__init__(priority)
|
super().__init__(priority)
|
||||||
|
|
||||||
def get_search_pattern(self) -> str:
|
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:
|
def get_main_capture_name(self) -> str:
|
||||||
return "cast"
|
return "cast"
|
@ -1,9 +1,12 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class CreateOperand0(Patch):
|
class CreateOperand0(Patch):
|
||||||
@ -44,7 +47,11 @@ class CreateOperand0(Patch):
|
|||||||
op_create_args: Node = captures[4][0]
|
op_create_args: Node = captures[4][0]
|
||||||
|
|
||||||
# Capstone spells the function with capital letter 'C' for whatever reason.
|
# 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)
|
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)
|
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
|
||||||
if args[0] == b"(" and args[-1] == b")":
|
if args[0] == b"(" and args[-1] == b")":
|
@ -1,9 +1,12 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
|
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class CreateOperand1(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)
|
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.
|
# 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)
|
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)
|
args = get_text(src, op_create_args.start_byte, op_create_args.end_byte)
|
||||||
return (
|
return (
|
||||||
@ -62,7 +69,7 @@ class CreateOperand1(Patch):
|
|||||||
+ b"MCOperand_"
|
+ b"MCOperand_"
|
||||||
+ fcn
|
+ fcn
|
||||||
+ b"1("
|
+ b"1("
|
||||||
+ get_MCInst_var_name(src, inst_var)
|
+ inst
|
||||||
+ b", "
|
+ b", "
|
||||||
+ args
|
+ args
|
||||||
+ b"))"
|
+ b"))"
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
|
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class DeclarationInConditionalClause(Patch):
|
class DeclarationInConditionalClause(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class DecodeInstruction(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"()")
|
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",")
|
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_32bit = (
|
||||||
is_16bit = table[-2:].decode("utf8") == "16" or opcode_var[-2:].decode("utf8") == "16"
|
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
|
args = table + b", " + mi_inst + b", " + opcode_var + b", " + address
|
||||||
|
|
||||||
if is_16bit and not is_32bit:
|
if is_16bit and not is_32bit:
|
@ -1,6 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class DecoderCast(Patch):
|
class DecoderCast(Patch):
|
@ -1,6 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class DecoderParameter(Patch):
|
class DecoderParameter(Patch):
|
@ -1,5 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
from CppTranslator.Patches.Patch import Patch
|
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class FallThrough(Patch):
|
class FallThrough(Patch):
|
@ -1,12 +1,16 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
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):
|
class FeatureBits(Patch):
|
||||||
"""
|
"""
|
||||||
Patch featureBits[FLAG]
|
Patch featureBits[FLAG]
|
||||||
to ARCH_getFeatureBits(Inst->csh->mode, ...)
|
to ARCH_getFeatureBits(Inst->csh->mode, FLAG)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, priority: int, arch: bytes):
|
def __init__(self, priority: int, arch: bytes):
|
||||||
@ -30,4 +34,11 @@ class FeatureBits(Patch):
|
|||||||
qualified_id: Node = captures[2][0]
|
qualified_id: Node = captures[2][0]
|
||||||
flag = get_text(src, qualified_id.start_byte, qualified_id.end_byte)
|
flag = get_text(src, qualified_id.start_byte, qualified_id.end_byte)
|
||||||
mcinst_var_name = get_MCInst_var_name(src, qualified_id)
|
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")"
|
||||||
|
)
|
@ -1,6 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class FeatureBitsDecl(Patch):
|
class FeatureBitsDecl(Patch):
|
@ -1,16 +1,19 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_function_params_of_node
|
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class FieldFromInstr(Patch):
|
class FieldFromInstr(Patch):
|
||||||
"""
|
"""
|
||||||
Patch fieldFromInstr(...)
|
Patch fieldFromInstruction(...)
|
||||||
to fieldFromInstr_<instr_width>(...)
|
to fieldFromInstruction_<instr_width>(...)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, priority: int):
|
def __init__(self, priority: int):
|
||||||
@ -32,7 +35,9 @@ class FieldFromInstr(Patch):
|
|||||||
ffi_call: Node = captures[0][0]
|
ffi_call: Node = captures[0][0]
|
||||||
ffi_first_arg: Node = captures[2][0]
|
ffi_first_arg: Node = captures[2][0]
|
||||||
param_list_caller = get_function_params_of_node(ffi_call)
|
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.
|
# Determine width of instruction by the variable name.
|
||||||
if ffi_first_arg_text[-2:] == "32":
|
if ffi_first_arg_text[-2:] == "32":
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class GetNumOperands(Patch):
|
class GetNumOperands(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class GetOpcode(Patch):
|
class GetOpcode(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class GetOperand(Patch):
|
class GetOperand(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
|
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class GetOperandRegImm(Patch):
|
class GetOperandRegImm(Patch):
|
@ -1,13 +1,20 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node, get_MCInst_var_name
|
from autosync.cpptranslator.patches.Helper import (
|
||||||
from CppTranslator.Patches.Patch import Patch
|
get_capture_node,
|
||||||
|
get_MCInst_var_name,
|
||||||
|
get_text,
|
||||||
|
)
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class GetRegClass(Patch):
|
class GetRegClass(Patch):
|
||||||
"""
|
"""
|
||||||
Patch MRI.getRegClass(...)
|
Patch MRI.getRegClass(...)
|
||||||
to MCRegisterClass_getRegClass(MI->MRI, ...)
|
to MCRegisterInfo_getRegClass(Inst->MRI, ...)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, priority: int):
|
def __init__(self, priority: int):
|
||||||
@ -31,6 +38,8 @@ class GetRegClass(Patch):
|
|||||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||||
arg_list: Node = get_capture_node(captures, "arg_list")
|
arg_list: Node = get_capture_node(captures, "arg_list")
|
||||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
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")"
|
res = b"MCRegisterInfo_getRegClass(" + mcinst_var + b"->MRI, " + args + b")"
|
||||||
return res
|
return res
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
|
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class GetRegFromClass(Patch):
|
class GetRegFromClass(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
|
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class GetSubReg(Patch):
|
class GetSubReg(Patch):
|
||||||
@ -31,6 +34,8 @@ class GetSubReg(Patch):
|
|||||||
# Get arg list
|
# Get arg list
|
||||||
op_create_args: Node = captures[2][0]
|
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)
|
mcinst_var_name = get_MCInst_var_name(src, op_create_args)
|
||||||
return b"MCRegisterInfo_getSubReg(" + mcinst_var_name + b"->MRI, " + args + b")"
|
return b"MCRegisterInfo_getSubReg(" + mcinst_var_name + b"->MRI, " + args + b")"
|
@ -1,9 +1,12 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
|
import logging as log
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
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:
|
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."""
|
"""Searches for the name of the parameter of type MCInst and returns it."""
|
||||||
params = get_function_params_of_node(n)
|
params = get_function_params_of_node(n)
|
||||||
mcinst_var_name = b""
|
mcinst_var_name = b""
|
||||||
|
|
||||||
|
if params:
|
||||||
for p in params.named_children:
|
for p in params.named_children:
|
||||||
p_text = get_text(src, p.start_byte, p.end_byte)
|
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]
|
mcinst_var_name = p_text.split((b"&" if b"&" in p_text else b"*"))[1]
|
||||||
break
|
break
|
||||||
if mcinst_var_name == b"":
|
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]:
|
def template_param_list_to_dict(param_list: Node) -> [dict]:
|
||||||
if param_list.type != "template_parameter_list":
|
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)
|
exit(1)
|
||||||
pl = list()
|
pl = list()
|
||||||
for c in param_list.named_children:
|
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:
|
def parameter_declaration_to_dict(param_decl: Node) -> dict:
|
||||||
if param_decl.type != "parameter_declaration":
|
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)
|
exit(1)
|
||||||
return {
|
return {
|
||||||
"prim_type": param_decl.children[0].type == "primitive_type",
|
"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
|
type_id = c
|
||||||
primary_tid_set = True
|
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.")
|
log.fatal("Could not find enumerator_list or enum type_identifier.")
|
||||||
exit(1)
|
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)
|
elist = get_text(src, enumerator_list.start_byte, enumerator_list.end_byte)
|
||||||
for e in enumerator_list.named_children:
|
for e in enumerator_list.named_children:
|
||||||
if e.type == "enumerator":
|
if e.type == "enumerator":
|
||||||
enum_entry_text = get_text(src, e.start_byte, e.end_byte)
|
enum_entry_text = get_text(src, e.start_byte, e.end_byte)
|
||||||
elist = elist.replace(enum_entry_text, ns_id + b"_" + enum_entry_text)
|
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
|
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
|
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)
|
tid = get_text(src, type_id.start_byte, type_id.end_byte)
|
||||||
fields = get_text(src, field_list.start_byte, field_list.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
|
return typed_struct
|
||||||
|
|
||||||
|
|
||||||
@ -193,9 +208,16 @@ def parse_function_capture(
|
|||||||
case _:
|
case _:
|
||||||
raise NotImplementedError(f"Node type {node.type} not handled.")
|
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:
|
def get_capture_node(captures: [(Node, str)], name: str) -> Node:
|
@ -1,9 +1,12 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class Includes(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)
|
include_text = get_text(src, captures[0][0].start_byte, captures[0][0].end_byte)
|
||||||
# Special cases, which appear somewhere in the code.
|
# Special cases, which appear somewhere in the code.
|
||||||
if b"GenDisassemblerTables.inc" in include_text:
|
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:
|
elif b"GenAsmWriter.inc" in include_text:
|
||||||
return b'#include "' + bytes(self.arch, "utf8") + b'GenAsmWriter.inc"\n\n'
|
return b'#include "' + bytes(self.arch, "utf8") + b'GenAsmWriter.inc"\n\n'
|
||||||
elif b"GenSystemOperands.inc" in include_text:
|
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:
|
if self.include_count[filename] > 1:
|
||||||
# Only the first include is replaced with all CS includes.
|
# 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()
|
return res + get_PPC_includes(filename) + get_general_macros()
|
||||||
case "AArch64":
|
case "AArch64":
|
||||||
return res + get_AArch64_includes(filename) + get_general_macros()
|
return res + get_AArch64_includes(filename) + get_general_macros()
|
||||||
|
case "TEST_ARCH":
|
||||||
|
return res + b"test_output"
|
||||||
case _:
|
case _:
|
||||||
log.fatal(f"Includes of {self.arch} not handled.")
|
log.fatal(f"Includes of {self.arch} not handled.")
|
||||||
exit(1)
|
exit(1)
|
||||||
@ -245,4 +256,6 @@ def get_AArch64_includes(filename: str) -> bytes:
|
|||||||
|
|
||||||
|
|
||||||
def get_general_macros():
|
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"
|
||||||
|
)
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class InlineToStaticInline(Patch):
|
class InlineToStaticInline(Patch):
|
||||||
@ -20,7 +23,10 @@ class InlineToStaticInline(Patch):
|
|||||||
|
|
||||||
def get_search_pattern(self) -> str:
|
def get_search_pattern(self) -> str:
|
||||||
return (
|
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:
|
def get_main_capture_name(self) -> str:
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class IsOptionalDef(Patch):
|
class IsOptionalDef(Patch):
|
||||||
@ -34,4 +37,4 @@ class IsOptionalDef(Patch):
|
|||||||
index = captures[2][0]
|
index = captures[2][0]
|
||||||
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
|
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)
|
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")"
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class IsPredicate(Patch):
|
class IsPredicate(Patch):
|
||||||
@ -34,4 +37,4 @@ class IsPredicate(Patch):
|
|||||||
index = captures[2][0]
|
index = captures[2][0]
|
||||||
op_info_var = get_text(src, op_info_var.start_byte, op_info_var.end_byte)
|
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)
|
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")"
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class IsOperandRegImm(Patch):
|
class IsOperandRegImm(Patch):
|
@ -1,6 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class LLVMFallThrough(Patch):
|
class LLVMFallThrough(Patch):
|
||||||
@ -12,7 +15,11 @@ class LLVMFallThrough(Patch):
|
|||||||
super().__init__(priority)
|
super().__init__(priority)
|
||||||
|
|
||||||
def get_search_pattern(self) -> str:
|
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:
|
def get_main_capture_name(self) -> str:
|
||||||
return "llvm_fall_through"
|
return "llvm_fall_through"
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class LLVMUnreachable(Patch):
|
class LLVMUnreachable(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class MethodToFunction(Patch):
|
class MethodToFunction(Patch):
|
||||||
@ -35,6 +38,8 @@ class MethodToFunction(Patch):
|
|||||||
name = captures[1][0]
|
name = captures[1][0]
|
||||||
parameter_list = captures[2][0]
|
parameter_list = captures[2][0]
|
||||||
name = get_text(src, name.start_byte, name.end_byte)
|
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
|
res = name + parameter_list
|
||||||
return res
|
return res
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class MethodTypeQualifier(Patch):
|
class MethodTypeQualifier(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class NamespaceAnon(Patch):
|
class NamespaceAnon(Patch):
|
||||||
@ -16,7 +19,11 @@ class NamespaceAnon(Patch):
|
|||||||
super().__init__(priority)
|
super().__init__(priority)
|
||||||
|
|
||||||
def get_search_pattern(self) -> str:
|
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:
|
def get_main_capture_name(self) -> str:
|
||||||
return "namespace_def"
|
return "namespace_def"
|
@ -1,7 +1,15 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, namespace_enum, namespace_fcn_def, namespace_struct
|
from autosync.cpptranslator.patches.Helper import (
|
||||||
from CppTranslator.Patches.Patch import Patch
|
get_text,
|
||||||
|
namespace_enum,
|
||||||
|
namespace_fcn_def,
|
||||||
|
namespace_struct,
|
||||||
|
)
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class NamespaceArch(Patch):
|
class NamespaceArch(Patch):
|
||||||
@ -16,7 +24,12 @@ class NamespaceArch(Patch):
|
|||||||
super().__init__(priority)
|
super().__init__(priority)
|
||||||
|
|
||||||
def get_search_pattern(self) -> str:
|
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:
|
def get_main_capture_name(self) -> str:
|
||||||
return "namespace_def"
|
return "namespace_def"
|
||||||
@ -24,7 +37,11 @@ class NamespaceArch(Patch):
|
|||||||
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
def get_patch(self, captures: [(Node, str)], src: bytes, **kwargs) -> bytes:
|
||||||
namespace = captures[0][0]
|
namespace = captures[0][0]
|
||||||
decl_list = captures[1][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.
|
# 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.
|
# Because in the generated files they are accessed via NAMESPACE::X which becomes NAMESPACE_X.
|
@ -1,12 +1,15 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class NamespaceLLVM(Patch):
|
class NamespaceLLVM(Patch):
|
||||||
"""
|
"""
|
||||||
Patch namespace {CONTENT}
|
Patch namespace llvm {CONTENT}
|
||||||
to CONTENT
|
to CONTENT
|
||||||
|
|
||||||
Only for anonymous or llvm namespaces
|
Only for anonymous or llvm namespaces
|
@ -1,13 +1,18 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class OutStreamParam(Patch):
|
class OutStreamParam(Patch):
|
||||||
"""
|
"""
|
||||||
Patch raw_ostream &OS
|
Patches the parameter list only:
|
||||||
to SStream *OS
|
|
||||||
|
Patch void function(int a, raw_ostream &OS)
|
||||||
|
to void function(int a, SStream *OS)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, priority: int):
|
def __init__(self, priority: int):
|
@ -1,6 +1,10 @@
|
|||||||
from tree_sitter import Node
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
|
|
||||||
|
from tree_sitter import Node
|
||||||
|
|
||||||
|
|
||||||
class Patch:
|
class Patch:
|
||||||
priority: int = None
|
priority: int = None
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
|
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class PredicateBlockFunctions(Patch):
|
class PredicateBlockFunctions(Patch):
|
@ -1,5 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
from CppTranslator.Patches.Patch import Patch
|
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class PrintAnnotation(Patch):
|
class PrintAnnotation(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_MCInst_var_name
|
from autosync.cpptranslator.patches.Helper import get_MCInst_var_name, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class PrintRegImmShift(Patch):
|
class PrintRegImmShift(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class QualifiedIdentifier(Patch):
|
class QualifiedIdentifier(Patch):
|
@ -1,9 +1,12 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class ReferencesDecl(Patch):
|
class ReferencesDecl(Patch):
|
||||||
@ -18,7 +21,12 @@ class ReferencesDecl(Patch):
|
|||||||
super().__init__(priority)
|
super().__init__(priority)
|
||||||
|
|
||||||
def get_search_pattern(self) -> str:
|
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:
|
def get_main_capture_name(self) -> str:
|
||||||
return "reference_decl"
|
return "reference_decl"
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_capture_node
|
from autosync.cpptranslator.patches.Helper import get_capture_node, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class RegClassContains(Patch):
|
class RegClassContains(Patch):
|
||||||
@ -32,6 +35,8 @@ class RegClassContains(Patch):
|
|||||||
reg_class_getter: Node = get_capture_node(captures, "reg_class")
|
reg_class_getter: Node = get_capture_node(captures, "reg_class")
|
||||||
arg_list: Node = get_capture_node(captures, "arg_list")
|
arg_list: Node = get_capture_node(captures, "arg_list")
|
||||||
args = get_text(src, arg_list.start_byte, arg_list.end_byte).strip(b"()")
|
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")"
|
res = b"MCRegisterClass_contains(" + reg_class + b", " + args + b")"
|
||||||
return res
|
return res
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class STIArgument(Patch):
|
class STIArgument(Patch):
|
@ -1,13 +1,16 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class STIFeatureBits(Patch):
|
class STIFeatureBits(Patch):
|
||||||
"""
|
"""
|
||||||
Patch STI.getFeatureBits()[FLAG]
|
Patch STI.getFeatureBits()[ARCH::FLAG]
|
||||||
to ARCH_getFeatureBits(Inst->csh->mode, ...)
|
to ARCH_getFeatureBits(Inst->csh->mode, ARCH::FLAG)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, priority: int, arch: bytes):
|
def __init__(self, priority: int, arch: bytes):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class SubtargetInfoParam(Patch):
|
class SubtargetInfoParam(Patch):
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class SetOpcode(Patch):
|
class SetOpcode(Patch):
|
@ -1,7 +1,11 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
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 CppTranslator.TemplateCollector import TemplateCollector
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||||
|
|
||||||
|
|
||||||
class SignExtend(Patch):
|
class SignExtend(Patch):
|
@ -1,9 +1,12 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text, get_function_params_of_node
|
from autosync.cpptranslator.patches.Helper import get_function_params_of_node, get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class SizeAssignment(Patch):
|
class SizeAssignment(Patch):
|
||||||
@ -18,7 +21,11 @@ class SizeAssignment(Patch):
|
|||||||
super().__init__(priority)
|
super().__init__(priority)
|
||||||
|
|
||||||
def get_search_pattern(self) -> str:
|
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:
|
def get_main_capture_name(self) -> str:
|
||||||
return "assign"
|
return "assign"
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class StreamOperations(Patch):
|
class StreamOperations(Patch):
|
||||||
@ -58,11 +61,22 @@ class StreamOperations(Patch):
|
|||||||
+ b', "'
|
+ b', "'
|
||||||
+ b"%s" * len(string_ops)
|
+ b"%s" * len(string_ops)
|
||||||
+ b'", '
|
+ 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"
|
+ b");\n"
|
||||||
)
|
)
|
||||||
string_ops.clear()
|
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:
|
else:
|
||||||
string_ops.append(op)
|
string_ops.append(op)
|
||||||
i += 1
|
i += 1
|
||||||
@ -75,14 +89,22 @@ class StreamOperations(Patch):
|
|||||||
+ b', "'
|
+ b', "'
|
||||||
+ b"%s" * len(string_ops)
|
+ b"%s" * len(string_ops)
|
||||||
+ b'", '
|
+ 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"
|
+ b");\n"
|
||||||
)
|
)
|
||||||
string_ops.clear()
|
string_ops.clear()
|
||||||
|
|
||||||
last_op_text = get_text(src, last_op.start_byte, last_op.end_byte)
|
last_op_text = get_text(src, last_op.start_byte, last_op.end_byte)
|
||||||
if last_op.type == "char_literal":
|
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:
|
else:
|
||||||
res += b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
res += b"SStream_concat0(" + s_name + b", " + last_op_text + b");"
|
||||||
stream = captures[0][0]
|
stream = captures[0][0]
|
@ -1,9 +1,16 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import parse_function_capture
|
from autosync.cpptranslator.patches.Helper import parse_function_capture
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
from CppTranslator.TemplateCollector import TemplateCollector, TemplateRefInstance
|
from autosync.cpptranslator.TemplateCollector import (
|
||||||
|
TemplateCollector,
|
||||||
|
TemplateRefInstance,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TemplateDeclaration(Patch):
|
class TemplateDeclaration(Patch):
|
||||||
@ -37,13 +44,24 @@ class TemplateDeclaration(Patch):
|
|||||||
def get_main_capture_name(self) -> str:
|
def get_main_capture_name(self) -> str:
|
||||||
return "template_decl"
|
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)
|
t_params, sc, tid, f_name, f_params, _ = parse_function_capture(captures, src)
|
||||||
if f_name in self.collector.templates_with_arg_deduction:
|
if f_name in self.collector.templates_with_arg_deduction:
|
||||||
return sc + tid + b" " + f_name + f_params + b";"
|
return sc + tid + b" " + f_name + f_params + b";"
|
||||||
|
|
||||||
declaration = b"#define DECLARE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
|
declaration = (
|
||||||
declaration += sc + b" " + tid + b" " + TemplateCollector.get_macro_c_call(f_name, t_params, f_params) + b";"
|
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"
|
declaration = declaration.replace(b"\n", b" \\\n") + b"\n"
|
||||||
|
|
||||||
template_instance: TemplateRefInstance
|
template_instance: TemplateRefInstance
|
||||||
@ -52,7 +70,13 @@ class TemplateDeclaration(Patch):
|
|||||||
self.collector.log_missing_ref_and_exit(f_name)
|
self.collector.log_missing_ref_and_exit(f_name)
|
||||||
|
|
||||||
for template_instance in self.collector.template_refs[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:
|
if d in declared_implementations:
|
||||||
continue
|
continue
|
||||||
declared_implementations.append(d)
|
declared_implementations.append(d)
|
@ -1,11 +1,17 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import parse_function_capture
|
from autosync.cpptranslator.patches.Helper import parse_function_capture
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
from CppTranslator.TemplateCollector import TemplateCollector, TemplateRefInstance
|
from autosync.cpptranslator.TemplateCollector import (
|
||||||
|
TemplateCollector,
|
||||||
|
TemplateRefInstance,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TemplateDefinition(Patch):
|
class TemplateDefinition(Patch):
|
||||||
@ -40,14 +46,23 @@ class TemplateDefinition(Patch):
|
|||||||
def get_main_capture_name(self) -> str:
|
def get_main_capture_name(self) -> str:
|
||||||
return "template_def"
|
return "template_def"
|
||||||
|
|
||||||
def get_patch(self, captures: list[tuple[Node, str]], src: bytes, **kwargs) -> bytes:
|
def get_patch(
|
||||||
t_params, sc, tid, f_name, f_params, f_compound = parse_function_capture(captures, src)
|
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:
|
if f_name in self.collector.templates_with_arg_deduction:
|
||||||
return sc + tid + b" " + f_name + f_params + f_compound
|
return sc + tid + b" " + f_name + f_params + f_compound
|
||||||
|
|
||||||
definition = b"#define DEFINE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
|
definition = b"#define DEFINE_" + f_name + b"(" + b", ".join(t_params) + b")\n"
|
||||||
definition += (
|
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
|
# Remove // comments
|
||||||
definition = re.sub(b" *//.*", b"", definition)
|
definition = re.sub(b" *//.*", b"", definition)
|
||||||
@ -59,7 +74,13 @@ class TemplateDefinition(Patch):
|
|||||||
self.collector.log_missing_ref_and_exit(f_name)
|
self.collector.log_missing_ref_and_exit(f_name)
|
||||||
|
|
||||||
for template_instance in self.collector.template_refs[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:
|
if d in declared_implementations:
|
||||||
continue
|
continue
|
||||||
declared_implementations.append(d)
|
declared_implementations.append(d)
|
@ -1,9 +1,12 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
import logging as log
|
import logging as log
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class TemplateParamDecl(Patch):
|
class TemplateParamDecl(Patch):
|
@ -1,8 +1,11 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.HelperMethods import get_text
|
from autosync.cpptranslator.patches.Helper import get_text
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
from CppTranslator.TemplateCollector import TemplateCollector
|
from autosync.cpptranslator.TemplateCollector import TemplateCollector
|
||||||
|
|
||||||
|
|
||||||
class TemplateRefs(Patch):
|
class TemplateRefs(Patch):
|
@ -1,5 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
from CppTranslator.Patches.Patch import Patch
|
|
||||||
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class UseMarkup(Patch):
|
class UseMarkup(Patch):
|
@ -1,6 +1,9 @@
|
|||||||
|
# Copyright © 2022 Rot127 <unisono@quyllur.org>
|
||||||
|
# SPDX-License-Identifier: BSD-3
|
||||||
|
|
||||||
from tree_sitter import Node
|
from tree_sitter import Node
|
||||||
|
|
||||||
from CppTranslator.Patches.Patch import Patch
|
from autosync.cpptranslator.patches.Patch import Patch
|
||||||
|
|
||||||
|
|
||||||
class UsingDeclaration(Patch):
|
class UsingDeclaration(Patch):
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user