diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..d9de4ec --- /dev/null +++ b/.flake8 @@ -0,0 +1,5 @@ +[flake8] +per-file-ignores = + __init__.py:F401, F403 + __main__.py:F401, F403 +max-line-length = 127 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..4d905b8 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +version: 2 + +updates: + - directory: / + package-ecosystem: pip + schedule: + interval: daily + - directory: / + package-ecosystem: maven + schedule: + interval: daily + - directory: / + package-ecosystem: github-actions + schedule: + interval: weekly diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ad638bf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,177 @@ +name: CI/CD + +on: + push: + branches: + - "*" + - "**" + tags: + - "*" + pull_request: + +env: + project-name: 2PPy + +defaults: + run: + shell: bash + +jobs: + build: + name: build & test + strategy: + matrix: + os: [ubuntu, windows, macos] + python-version: ['3.9', '3.10', '3.11'] + include: + - package: false + - os: ubuntu + python-version: '3.9' + package: true # only build package artifacts once + fail-fast: false + runs-on: ${{ matrix.os }}-latest + outputs: + artifact-name: ${{ steps.artifact.outputs.artifact-name }} + version: ${{ steps.artifact.outputs.version }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: pip + - name: Set up Maven with Java 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' + architecture: 'x64' + cache: maven + - name: Install build tool + run: | + python -m pip install --upgrade pip + - name: Install CI dependencies + run: | + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Build + run: | + python -m build --sdist --wheel + - name: Install + run: | + pip install dist/*.whl + - name: Test + run: | + coverage run -m pytest -p no:faulthandler + - name: Coverage + run: | + coverage report -i -m + - name: Prepare artifacts + id: artifact + if: ${{ matrix.package }} + run: | + echo 'artifact-name=${{ env.project-name }}-${{ matrix.python-version }}-${{ matrix.os }}' >> "$GITHUB_OUTPUT" + VERSION=$(python -m setuptools_git_versioning) + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + - name: Upload artifacts + if: ${{ matrix.package }} + uses: actions/upload-artifact@v3 + with: + name: ${{ steps.artifact.outputs.artifact-name }} + path: | + dist/*.whl + dist/*.tar.gz + LICENSE + - name: Upload test install script to artifact + if: ${{ matrix.package }} + uses: actions/upload-artifact@v3 + with: + name: test-install-script + path: test/post_install_test.py + + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with Flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + python -m flake8 . --count --statistics + + install: + strategy: + matrix: + os: [ubuntu, windows, macos] + python-version: ['3.9', '3.10', '3.11'] + install: ['wheel', 'sdist'] + fail-fast: false + runs-on: ${{ matrix.os }}-latest + needs: [build] + steps: + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Download Artifacts + uses: actions/download-artifact@v3 + with: + name: ${{ needs.build.outputs.artifact-name }} + - name: Install from wheel + if: ${{ matrix.install == 'wheel' }} + run: | + pip install dist/*.whl + - name: Install from sdist + if: ${{ matrix.install == 'sdist' }} + run: | + pip install dist/*.tar.gz + - name: Pull test file from artifacts + uses: actions/download-artifact@v3 + with: + name: test-install-script + - name: Test installation + run: | + python post_install_test.py + + release: + runs-on: ubuntu-latest + needs: [build, lint, install] + concurrency: + group: release + if: startsWith(github.ref, 'refs/tags/') && github.event_name == 'push' + steps: + - name: Download Artifacts + uses: actions/download-artifact@v3 + with: + name: ${{ needs.build.outputs.artifact-name }} + - name: GitHub Release + uses: softprops/action-gh-release@v1 + with: + name: ${{ needs.build.outputs.version }} + fail_on_unmatched_files: true + files: | + dist/*.whl + dist/*.tar.gz + LICENSE + + publish: + runs-on: ubuntu-latest + needs: [build, release] + concurrency: + group: publish + environment: test-pypi + permissions: + id-token: write + steps: + - name: Download Artifacts + uses: actions/download-artifact@v3 + with: + name: ${{ needs.build.outputs.artifact-name }} + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index ad7c410..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: deploy -on: - push: -# tags: -# - '[0-9]+.[0-9]+.[0-9]+' - branches: - - develop - - master -env: - project-name: 2PPy - workflow: deploy -jobs: - deploy-on-pypi: - runs-on: ubuntu-latest - steps: - - name: Show Env - run: | - python --version - pip --version - java --version - javac --version - - - name: Checkout code - uses: actions/checkout@v2 - with: - fetch-depth: 0 # all history - - - name: Get All Tags - run: git fetch --tags -f - - - name: Restore Python dependencies - run: pip install -r requirements.txt - - - name: Restore JVM dependencies - run: ./download-jars.sh - - - name: Test - run: python -m unittest - - - name: Change default logging level - run: sed -i -e 's/DEBUG/WARN/g' tuprolog/__init__.py - - - name: Pack - run: python -m build - - - name: Archive Dist Artifacts - if: failure() || success() - uses: actions/upload-artifact@v2 - with: - name: dist - path: './dist' - - - name: Upload - run: python -m twine upload dist/* - env: - TWINE_USERNAME: ${{ secrets.PYPI_USERANAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} diff --git a/.github/workflows/quick-check.yml b/.github/workflows/quick-check.yml deleted file mode 100644 index b538daf..0000000 --- a/.github/workflows/quick-check.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: quick-check -on: - push: - branches: - - master - - develop - - 'feature/**' -env: - # jdk-version: openjdk@~1.15.0 - project-name: 2PPy - workflow: quick-check - # gradle-options: "--no-daemon --console=plain --stacktrace" -jobs: - run-unit-tests: - runs-on: ubuntu-latest - steps: - - name: Show Env - run: | - python --version - pip --version - java --version - javac --version - - - name: Checkout code - uses: actions/checkout@v2 - with: - fetch-depth: 0 # all history - - # - name: Get All Tags - # run: git fetch --tags -f - - - name: Restore Python dependencies - run: pip install -r requirements.txt - - - name: Restore JVM dependencies - run: ./download-jars.sh - - - name: Test - run: python -m unittest diff --git a/.gitignore b/.gitignore index a5aa068..a45180d 100644 --- a/.gitignore +++ b/.gitignore @@ -6,9 +6,9 @@ VERSION venv/ .idea/ .vscode/ - *~ *.jar +tuprolog/libs/*/ ### Python ### # Byte-compiled / optimized / DLL files diff --git a/.python-version b/.python-version index 1635d0f..371cfe3 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.9.6 +3.11.1 diff --git a/MANIFEST.in b/MANIFEST.in index 29ed537..918337f 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,4 @@ -include VERSION +include pom.xml include tuprolog/libs/*.jar exclude test/* -exclude main.py \ No newline at end of file +exclude main.py diff --git a/README.md b/README.md index 8d5b57a..95a640f 100644 --- a/README.md +++ b/README.md @@ -2,40 +2,38 @@ Experimental porting of [2P-Kt](https://github.com/tuProlog/2p-kt) on Python, via [JPype](https://jpype.readthedocs.io). -> This is a __work in progress__. 2PPy is not ready for general availability, yet. +> This is a __work in progress__. ## Introduction Object-oriented and modular ecosystem for symbolic AI and logic programming, currently featuring: -* a module for logic terms and clauses representation, namely `tuprolog.core`, +* [a command-line interface, in the form of a REPL](#use-2ppy-as-an-interactive-repl) -* a module for logic unification, namely `tuprolog.unify`, +* a module for logic terms and clauses representation, namely `tuprolog.core` -* a module for in-memory indexing and storing logic theories, as well as other sorts of collections of logic clauses, namely `tuprolog.theory`, +* a module for logic unification, namely `tuprolog.unify` -* a module providing generic API for resolution of logic queries, namely `tuprolog.solve`, currently implementing a Prolog solver +* a module for in-memory indexing and storing logic theories, as well as other sorts of collections of logic clauses, namely `tuprolog.theory` -* two parsing modules: one aimed at parsing terms, namely `tuprolog.core.parsing`, and the other aimed at parsing theories, namely `tuprolog.theory.parsing`, +* a module providing generic API for resolution of logic queries, namely `tuprolog.solve` + * a module that implements deterministic logic programming and solving, namely `tuprolog.solve.prolog` + * a module that implements probabilistic logic programming and solving, namely `tuprolog.solve.problog` -* two serialisation-related modules: one aimed at (de)serialising terms and clauses, namely `tuprolog.core.serialize`, and the -other aimed at (de)serialising terms theories, namely `tuprolog.theory.serialize`, +* two parsing modules: one aimed at parsing terms, namely `tuprolog.core.parsing`, and the other aimed at parsing theories, namely `tuprolog.theory.parsing` -* a module for using Prolog via a command-line interface, namely `tuprolog.repl`. +## How to use 2ppy -## How to do stuff +### Installing 2ppy -### Prerequisites +1. Install Python 3 (look into the [`pyproject.toml`](pyproject.toml) to know the exact versions supported) -1. Install Python 3 (look into the `.python-version` to know the exact version) - * I suggest using [Pyenv](https://github.com/pyenv/pyenv) to easily handle multiple Python versions on the same machine - * Ensure PIP works fine + * If your system has 64-bit processor, install the Python 3 64-bit distribution, and viceversa + * Ensure `pip` works fine + * It's suggested to use a [virtual environment](https://docs.python.org/3/library/venv.html) to install the dependencies locally + * It's suggested to use [Pyenv](https://github.com/pyenv/pyenv) to easily handle multiple Python versions on the same machine -2. Install Java (JDK preferred), and **ensure the `JAVA_HOME` variable is correctly set** - -3. Ensure Java and Python are both either 64bit or 32bit - -4. If you have installed some prior development version of 2PPy (e.g. `tuppy` or `tuprolog`), uninstall them via +1. If you have installed some prior development version of 2PPy (e.g. `tuppy` and/or `tuprolog`), uninstall them via ```bash pip uninstall tuppy tuprolog ``` @@ -44,58 +42,70 @@ other aimed at (de)serialising terms theories, namely `tuprolog.theory.serializ ```bash python3 -m pip uninstall tuppy tuprolog ``` - -### How to develop 2PPy - -5. Restore Python dependencies via PIP, by running: +1. Install 2PPy from Pypi by running: ```bash - pip install -r requirements.txt + pip install tuprolog ``` On __Mac OS__ this may not work as expected. Consider running the following command instead: ```bash - python3 -m pip -r requirements.txt + python3 -m pip install tuprolog ``` - -6. Restore JVM dependencies via `download-jars.sh`, by running: +1. *Note for the expert users:* 2ppy downloads its own [Java Virtual Machine](https://en.wikipedia.org/wiki/Java_virtual_machine) in order to call Java bytecode from python. If you install the package with sdist, it's downloaded during install. If you use the binary wheels packaging, it's downloaded on first import of the `tuprolog` package. + +### Use 2ppy as a Python library + +1. Import `tuprolog.*` modules in your Python scripts +1. Use the Pythonic API to write, parse or solve your logic programs. You can find some examples in the [api tests folder](test/api). +1. *Known issues*: + Some methods called on `tuprolog` types are forwarded to the underlying Java objects. This means that the return type of such methods is not always the expected one. For example, the `tuprolog.theory.Theory` class has a `getClauses` method that returns an anonymous object tha *should* implement `java.util.Iterable`. However, iterating such object from Python will result in an error. + In order to avoid this, wrap these anonymous non-iterable objects with `protect_iterable(object: Iterable) -> Iterable` from `tuprolog.jvmutils` before iterating them. This will return an iterable object that can be safely iterated from Python. + +### Use 2PPy as an interactive REPL + +1. Python shell mode: run `python -m tuprolog` +1. Logic solver [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop): + 1. run `python -m tuprolog.repl.prolog` for Prolog + 1. run `python -m tuprolog.repl.problog` for ProbLog + +## How to contribute to 2PPy + +1. Install dependencies + 1. Restore Python dev dependencies via `pip`, by running: + ```bash + pip install -r requirements.txt + ``` + On __Mac OS__ this may not work as expected. + Consider running the following command instead: + ```bash + python3 -m pip install -r requirements.txt + ``` + 1. Install [maven](https://maven.apache.org/install.html) and make sure that the `mvn` command is available by adding Maven to your `PATH`. Maven is used to download java dependencies from the [Maven Central Repository for tuProlog](https://mvnrepository.com/artifact/it.unibo.tuprolog). +1. Write the code inside `tuprolog` and the unit tests inside `test` +1. Execute tests with `python -m pytest -p no:faulthandler` +1. Build the package with `python -m build` +1. Install the recently built package locally using wheels with `pip install dist/2ppy-$(python -m setuptools_git_versioning)-*.whl --force-reinstall` +1. Optionally, print the package version, computed from git tags with `python -m setuptools_git_versioning` + +### Adopted Git flow + +The Git Flow for 2ppy consists of the following: + +- The ongoing development happens on the `develop` branch +- The `master` branch is used to display the latest released code +- Independent features are developed on their own branches, and merged into `develop` when ready +- In order to make a new release, the code should be merged on master and a new [git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging#_annotated_tags) should be created on the release commit, following the [Semantic Versioning](https://semver.org/) semantic. + As an example, the following commands can be used to make a new release: ```bash - ./download-jars.sh + git checkout master + git merge develop + git tag -a 0.1.0 -m "First release" + git push origin master --follow-tags ``` - Notice that this command requires `curl` and `wget` to be installed on your system (`wget` may be lacking on __Mac OS__ and Windows) - -### How to use 2PPy as a library -5. Install 2PPy from Pypi by running: - ```bash - pip install 2ppy - ``` - On __Mac OS__ this may not work as expected. - Consider running the following command instead: - ```bash - python3 -m pip install 2ppy - ``` - -6. Import `tuprolog.*` modules in your Python scripts - -7. Profit - -### How to use 2PPy as an executable - -5. Install 2PPy from Pypi by running: - ```bash - pip install 2ppy - ``` - On __Mac OS__ this may not work as expected. - Consider running the following command instead: - ```bash - python3 -m pip install 2ppy - ``` - -6. Run `tuprolog` module via - ```bash - python -m tuprolog - ``` +#### CI/CD -For the moment, running 2PPy means starting an interactive Python shell with pre-loaded `tuprolog.*` modules. +The Continuous Integration pipeline will run unit tests against some combinations of operating systems, supported java versions for the JVM and supported python versions. +It will also check the Python style with [flake8](https://flake8.pycqa.org/en/latest/). -Eventually `python -m tuprolog` will launch a command-line logic solver. +The Continuous Delivery pipeline will create a new [Github Release](https://github.com/tuProlog/2ppy/releases) and will deploy the package on [PyPI](https://pypi.org/project/2ppy/). diff --git a/download-jars.sh b/download-jars.sh deleted file mode 100755 index 93da6b7..0000000 --- a/download-jars.sh +++ /dev/null @@ -1,11 +0,0 @@ -get_latest_release() { - curl --silent "https://api.github.com/repos/$1/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/' -} - -TUPROLOG_GITHUB='tuProlog/2p-kt' -TUPROLOG_VERSION=`get_latest_release $TUPROLOG_GITHUB` -TUPROLOG_JAR_URL="https://github.com/$TUPROLOG_GITHUB/releases/download/$TUPROLOG_VERSION/2p-repl-$TUPROLOG_VERSION-redist.jar" - -rm -rf tuprolog/libs/*.jar - -wget -P tuprolog/libs/ $TUPROLOG_JAR_URL || (echo "Failed to download $TUPROLOG_JAR_URL"; echo "Ensure command wget is installed (brew install wget on Mac OS)") diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b53f181 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + com.mycompany.app + my-app + 1 + + org.jetbrains.kotlin + kotlin-bom + 1.9.10 + + + + it.unibo.tuprolog + repl-jvm + 0.31.16 + + + it.unibo.tuprolog + solve-problog-jvm + 0.31.16 + + + diff --git a/pyproject.toml b/pyproject.toml index 07de284..043f7da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,41 @@ [build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" \ No newline at end of file +requires = ["setuptools>=61", "wheel", "setuptools-git-versioning<2"] +build-backend = "setuptools.build_meta" + +[tool.setuptools-git-versioning] +enabled = true + +[project] +dynamic = ["version"] +name = "2ppy" +authors = [ + { name="Giovanni Ciatto", email="giovanni.ciatto@unibo.it" }, + { name="Luca Deluigi", email="luca.deluigi5@unibo.it" }, +] +description = "Python-based implementation of tuProlog -- the open ecosystem for symbolic AI --, based on 2P-Kt" +readme = "README.md" +requires-python = ">=3.9, <3.12" +classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Topic :: Software Development :: Interpreters", + "Topic :: Software Development :: Libraries", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Prolog", +] +license = {file = "LICENSE"} +keywords = ["prolog", "symbolic ai", "ecosystem", "tuprolog", "2p", "python"] +dependencies = [ + "JPype1==1.4.1", + "jdk4py==17.0.7.0" +] + +[project.urls] +"Homepage" = "https://github.com/tuProlog/2ppy" +"Bug" = "https://github.com/tuProlog/2ppy/issues" diff --git a/requirements.txt b/requirements.txt index f559e34..0b62b7b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,6 @@ -JPype1==1.3.0 -build>=0.6.0 -twine>=3.4.2 +# CI & Test dependencies +flake8==6.1.0 +build==1.0.3 +pytest==7.4.2 +coverage==7.3.2 +setuptools-git-versioning==1.13.5 diff --git a/setup.py b/setup.py index e34e8d3..ba62d15 100644 --- a/setup.py +++ b/setup.py @@ -1,86 +1,58 @@ - -from setuptools import setup, find_packages -import pathlib +import platform import subprocess +from pathlib import Path +from setuptools import setup +from setuptools.command.build_py import build_py + + +PACKAGE_NAME = 'tuprolog' +JAR_FOLDER = Path(PACKAGE_NAME, 'libs') +MAVEN_EXECUTABLE = ['mvn', '--batch-mode'] -# current directory -here = pathlib.Path(__file__).parent.resolve() -version_file = here / 'VERSION' +def is_windows(): + return platform.system() == 'Windows' -print(f"Executing setup.py from {here}") -# Get the long description from the README file -long_description = (here / 'README.md').read_text(encoding='utf-8') +def run_maven(*args, cwd=None) -> (str, str): + proc = subprocess.Popen( + MAVEN_EXECUTABLE + list(args), + shell=is_windows(), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + cwd=cwd) + stdout, stderr = proc.communicate() + if proc.returncode != 0: + raise RuntimeError(f'Error while running mvn:\n{stdout}\n{stderr}') + return stdout, stderr -def format_git_describe_version(version): - if '-' in version: - splitted = version.split('-') - tag = splitted[0] - index = f"dev{splitted[1]}" #{hex(int(splitted[1]))[2:]}" - # commit = splitted[2] - # return f"{tag}.{index}+{commit}" - return f"{tag}.{index}" - else: - return version -def get_version_from_git(): - try: - process = subprocess.run(["git", "describe"], cwd=str(here), check=True, capture_output=True) - version = process.stdout.decode('utf-8').strip() - version = format_git_describe_version(version) - with version_file.open('w') as f: - f.write(version) - return version - except subprocess.CalledProcessError: - # with version_file.open('r') as f: - return version_file.read_text().strip() +def download_jars(): + stdout, _ = run_maven('-v') + if 'Apache Maven' not in stdout: + raise RuntimeError(f'Could not find Apache Maven in {stdout}') + run_maven( + 'dependency:copy-dependencies', + f'-DoutputDirectory={JAR_FOLDER}', + cwd=Path(__file__).parent + ) + # run_maven( + # 'dependency:copy-dependencies', + # f'-DoutputDirectory={JAR_FOLDER}', + # '-Dclassifier=javadoc', + # cwd=Path(__file__).parent + # ) -# version = os.popen('git describe').read().strip() -version = get_version_from_git() -print(f"Detected version {version} from git describe") +class BuildPyCommand(build_py): + def run(self): + download_jars() + super().run() -# Arguments marked as "Required" below must be included for upload to PyPI. -# Fields marked as "Optional" may be commented out. setup( - name='2ppy', # Required - version=version, - description='Python-based implementation of tuProlog -- the open ecosystem for symbolic AI --, based on 2P-Kt', - license='Apache 2.0 License', - long_description=long_description, - long_description_content_type='text/markdown', - url='https://github.com/tuProlog/2ppy', - author='Giovanni Ciatto', - author_email='giovanni.ciatto@unibo.it', - classifiers=[ - 'Development Status :: 3 - Alpha', - 'Intended Audience :: Developers', - 'Topic :: Software Development :: Interpreters', - 'Topic :: Software Development :: Libraries', - 'Topic :: Scientific/Engineering :: Artificial Intelligence', - 'License :: OSI Approved :: Apache Software License', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Prolog' - ], - keywords='prolog, symbolic ai, ecosystem, tuprolog, 2p, python', # Optional - # package_dir={'': 'src'}, # Optional - packages=find_packages(), # Required - include_package_data=True, - python_requires='>=3.6, <4', - install_requires=['JPype1==1.3.0'], # Optional - zip_safe = False, - platforms = "Independant", - project_urls={ # Optional - 'Bug Reports': 'https://github.com/tuProlog/2ppy/issues', - # 'Funding': 'https://donate.pypi.org', - # 'Say Thanks!': 'http://saythanks.io/to/example', - 'Source': 'https://github.com/tuProlog/2ppy', - }, + cmdclass={ + 'build_py': BuildPyCommand, + } ) diff --git a/test/core/test_formatters.py b/test/core/test_formatters.py index c9a03ff..4e585ec 100644 --- a/test/core/test_formatters.py +++ b/test/core/test_formatters.py @@ -1,18 +1,11 @@ import unittest -from tuprolog.core import * -from tuprolog.core.formatters import AbstractTermFormatter +from tuprolog.core import Atom, Integer, Var +from tuprolog.core.impl import DefaultTermFormatter class TestFormatters(unittest.TestCase): def test_term_formatter(self): - class MyFormatter(AbstractTermFormatter): - def defaultValue(self, term): - return str(term) - formatter = MyFormatter() + formatter = DefaultTermFormatter() for term in [Atom.of('a'), Integer.of(1), Var.of("X")]: self.assertEqual(formatter.format(term), str(term)) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/core/test_kt_math.py b/test/core/test_kt_math.py new file mode 100644 index 0000000..694251d --- /dev/null +++ b/test/core/test_kt_math.py @@ -0,0 +1,183 @@ +import unittest +from decimal import Decimal +from tuprolog.math import big_integer, python_integer, BigInteger, big_decimal, python_decimal +from tuprolog.math import BIG_INTEGER_ZERO, BIG_INTEGER_TEN, BIG_INTEGER_ONE, BIG_INTEGER_NEGATIVE_ONE, BIG_INTEGER_TWO +from tuprolog.math import BIG_DECIMAL_ZERO, BIG_DECIMAL_ONE, BIG_DECIMAL_ONE_HALF, BIG_DECIMAL_ONE_TENTH +from tuprolog.math import BIG_DECIMAL_E, BIG_DECIMAL_PI + + +class TestKtMath(unittest.TestCase): + + def assertSameStringRepresentation(self, expected, actual): + self.assertEqual(str(expected), str(actual)) + + +class TestBigInteger(TestKtMath): + + def setUp(self): + self.large_int = 1 << 64 + + def test_python_to_java(self): + self.assertSameStringRepresentation(0, big_integer("0")) + self.assertSameStringRepresentation(0, big_integer(0)) + self.assertSameStringRepresentation(1, big_integer("1")) + self.assertSameStringRepresentation(1, big_integer(1)) + self.assertSameStringRepresentation(self.large_int, big_integer(self.large_int)) + self.assertSameStringRepresentation(-1, big_integer("-1")) + self.assertSameStringRepresentation(-1, big_integer(-1)) + self.assertSameStringRepresentation(-self.large_int, big_integer(-self.large_int)) + self.assertSameStringRepresentation(0x16, big_integer("16", 16)) + self.assertSameStringRepresentation(-0x16, big_integer("-16", 16)) + + def test_java_to_python(self): + self.assertEqual(0, python_integer(big_integer("0"))) + self.assertEqual(0, python_integer(big_integer(0))) + self.assertEqual(1, python_integer(big_integer("1"))) + self.assertEqual(1, python_integer(big_integer(1))) + self.assertEqual(self.large_int, python_integer(big_integer(self.large_int))) + self.assertEqual(-1, python_integer(big_integer("-1"))) + self.assertEqual(-1, python_integer(big_integer(-1))) + self.assertEqual(-self.large_int, python_integer(big_integer(-self.large_int))) + self.assertEqual(0x16, python_integer(big_integer("16", 16))) + self.assertEqual(-0x16, python_integer(big_integer("-16", 16))) + + def test_constants(self): + self.assertEqual(big_integer(0), BIG_INTEGER_ZERO) + self.assertEqual(big_integer(10), BIG_INTEGER_TEN) + self.assertEqual(big_integer(1), BIG_INTEGER_ONE) + self.assertEqual(big_integer(-1), BIG_INTEGER_NEGATIVE_ONE) + self.assertEqual(big_integer(2), BIG_INTEGER_TWO) + + def test_integers(self): + for i in range(-512, 513): + self.assertEqual(BigInteger.of(i), big_integer(i)) + for t in [8, 16, 32, 64, 128]: + for i in [1 << t - 1, 1 << t]: + self.assertEqual(BigInteger.of(str(i)), big_integer(i)) + self.assertEqual(BigInteger.of(str(-i)), big_integer(-i)) + + +class TestBigDecimal(TestKtMath): + + def setUp(self): + self.e = '2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852' + \ + '5166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880' + \ + '753195251019011573834187930702154089149934884167509244761460668082264' + + self.pi = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253' + \ + '421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446' + \ + '22948954930381964428810975665933446128475648233786783165271201909145648' + + self.one_tenth = "0.01000000000000000020816681711721685132943093776702880859375" + + def test_python_to_java_zero(self): + self.assertSameStringRepresentation(0, big_decimal("0")) + self.assertSameStringRepresentation(0, big_decimal("0.0")) + self.assertSameStringRepresentation(0, big_decimal("0.00")) + self.assertSameStringRepresentation(0, big_decimal(0)) + self.assertSameStringRepresentation(0, big_decimal(0.0)) + self.assertSameStringRepresentation(0, big_decimal(0.00)) + self.assertSameStringRepresentation(0, big_decimal(Decimal(0))) + self.assertSameStringRepresentation(0, big_decimal(Decimal(0.0))) + self.assertSameStringRepresentation(0, big_decimal(Decimal(0.00))) + + def test_python_to_java_one(self): + self.assertSameStringRepresentation(1, big_decimal("1")) + self.assertSameStringRepresentation(1, big_decimal("1.0")) + self.assertSameStringRepresentation(1, big_decimal("1.00")) + self.assertSameStringRepresentation(1, big_decimal(1)) + self.assertSameStringRepresentation(1, big_decimal(1.0)) + self.assertSameStringRepresentation(1, big_decimal(1.00)) + self.assertSameStringRepresentation(1, big_decimal(Decimal(1))) + self.assertSameStringRepresentation(1, big_decimal(Decimal(1.0))) + self.assertSameStringRepresentation(1, big_decimal(Decimal(1.00))) + + def test_python_to_java_minus_one(self): + self.assertSameStringRepresentation(-1, big_decimal("-1")) + self.assertSameStringRepresentation(-1, big_decimal("-1.0")) + self.assertSameStringRepresentation(-1, big_decimal("-1.00")) + self.assertSameStringRepresentation(-1, big_decimal(-1)) + self.assertSameStringRepresentation(-1, big_decimal(-1.0)) + self.assertSameStringRepresentation(-1, big_decimal(-1.00)) + self.assertSameStringRepresentation(-1, big_decimal(Decimal(-1))) + self.assertSameStringRepresentation(-1, big_decimal(Decimal(-1.0))) + self.assertSameStringRepresentation(-1, big_decimal(Decimal(-1.00))) + + def test_python_to_java_one_half(self): + self.assertSameStringRepresentation(0.5, big_decimal("0.5")) + self.assertSameStringRepresentation(0.5, big_decimal("0.50")) + self.assertSameStringRepresentation(0.5, big_decimal("0.500")) + self.assertSameStringRepresentation(0.5, big_decimal(0.5)) + self.assertSameStringRepresentation(0.5, big_decimal(0.50)) + self.assertSameStringRepresentation(0.5, big_decimal(0.500)) + self.assertSameStringRepresentation(0.5, big_decimal(Decimal(0.5))) + self.assertSameStringRepresentation(0.5, big_decimal(Decimal(0.50))) + self.assertSameStringRepresentation(0.5, big_decimal(Decimal(0.500))) + + def test_python_to_java_one_cent(self): + self.assertSameStringRepresentation(0.01, big_decimal("0.01")) + self.assertSameStringRepresentation(0.01, big_decimal("0.010")) + self.assertSameStringRepresentation(0.01, big_decimal("0.0100")) + self.assertSameStringRepresentation(self.one_tenth, big_decimal(Decimal(0.01))) + self.assertSameStringRepresentation(self.one_tenth, big_decimal(Decimal(0.010))) + self.assertSameStringRepresentation(self.one_tenth, big_decimal(Decimal(0.0100))) + + def test_java_to_python_zero(self): + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal("0"))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal("0.0"))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal("0.00"))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal(0))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal(0.0))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal(0.00))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal(Decimal(0)))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal(Decimal(0.0)))) + self.assertSameStringRepresentation(Decimal(0), python_decimal(big_decimal(Decimal(0.00)))) + + def test_java_to_python_one(self): + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal("1"))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal("1.0"))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal("1.00"))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal(1))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal(1.0))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal(1.00))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal(Decimal(1)))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal(Decimal(1.0)))) + self.assertSameStringRepresentation(Decimal(1), python_decimal(big_decimal(Decimal(1.00)))) + + def test_java_to_python_minus_one(self): + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal("-1"))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal("-1.0"))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal("-1.00"))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal(-1))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal(-1.0))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal(-1.00))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal(Decimal(-1)))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal(Decimal(-1.0)))) + self.assertSameStringRepresentation(Decimal(-1), python_decimal(big_decimal(Decimal(-1.00)))) + + def test_java_to_python_one_half(self): + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal("0.5"))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal("0.50"))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal("0.500"))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal(0.5))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal(0.50))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal(0.500))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal(Decimal(0.5)))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal(Decimal(0.50)))) + self.assertSameStringRepresentation(Decimal(0.5), python_decimal(big_decimal(Decimal(0.500)))) + + def test_java_to_python_one_cent(self): + self.assertSameStringRepresentation(Decimal("0.01"), python_decimal(big_decimal("0.01"))) + self.assertSameStringRepresentation(Decimal("0.01"), python_decimal(big_decimal("0.010"))) + self.assertSameStringRepresentation(Decimal("0.01"), python_decimal(big_decimal("0.0100"))) + self.assertSameStringRepresentation(Decimal(self.one_tenth), python_decimal(big_decimal(Decimal(0.01)))) + self.assertSameStringRepresentation(Decimal(self.one_tenth), python_decimal(big_decimal(Decimal(0.010)))) + self.assertSameStringRepresentation(Decimal(self.one_tenth), python_decimal(big_decimal(Decimal(0.0100)))) + + def test_constants(self): + self.assertEqual(big_decimal(0), BIG_DECIMAL_ZERO) + self.assertEqual(big_decimal(1), BIG_DECIMAL_ONE) + self.assertEqual(big_decimal(0.5), BIG_DECIMAL_ONE_HALF) + self.assertEqual(big_decimal("0.1"), BIG_DECIMAL_ONE_TENTH) + self.assertEqual(big_decimal(self.e), BIG_DECIMAL_E) + self.assertEqual(big_decimal(self.pi), BIG_DECIMAL_PI) diff --git a/test/core/operators/test_operators.py b/test/core/test_operators.py similarity index 94% rename from test/core/operators/test_operators.py rename to test/core/test_operators.py index 40ba9f5..9b5e870 100644 --- a/test/core/operators/test_operators.py +++ b/test/core/test_operators.py @@ -1,13 +1,12 @@ +import unittest import random import string -import unittest - -from tuprolog.core import * -from tuprolog.core.operators import DEFAULT_OPERATORS, EMPTY_OPERATORS, STANDARD_OPERATORS, XF, XFY, YF, YFX, FX, FY, \ - XFX, operator, operator_set, OperatorSet, specifier - -# noinspection PyUnresolvedReferences -from java.lang import IllegalArgumentException +from tuprolog.core import integer, atom, struct +from tuprolog.core.operators import operator, specifier, operator_set +from tuprolog.core.operators import XF, YF, FX, FY, XFY, YFX, XFX, OperatorSet +from tuprolog.core.operators import EMPTY_OPERATORS, DEFAULT_OPERATORS, STANDARD_OPERATORS +import jpype.imports # noqa: F401 +from java.lang import IllegalArgumentException # type: ignore class AbstractTestOperatorStuff(unittest.TestCase): @@ -142,7 +141,3 @@ def test_constant_operators_set(self): # Assert standard operators are in set of builtin operators for op in STANDARD_OPERATORS: self.assertTrue(op in self.all_builtin_operators) - - -if __name__ == '__main__': - unittest.main() diff --git a/test/core/test_parsing.py b/test/core/test_parsing.py new file mode 100644 index 0000000..777ab4d --- /dev/null +++ b/test/core/test_parsing.py @@ -0,0 +1 @@ +# TODO: write tests diff --git a/test/core/test_scope.py b/test/core/test_scope.py new file mode 100644 index 0000000..c96db19 --- /dev/null +++ b/test/core/test_scope.py @@ -0,0 +1,31 @@ +import unittest +from tuprolog.core import scope, var, Scope, variables, struct, FAIL + + +class TestScope(unittest.TestCase): + + def test_empty_scope_creation(self): + empty_scope = scope() + self.assertIsNotNone(empty_scope) + self.assertIsInstance(empty_scope, Scope) + self.assertEqual(0, len(empty_scope.variables)) + + def test_scope_creation(self): + full_scope = scope('A', var('B')) + self.assertIsNotNone(full_scope) + self.assertIsInstance(full_scope, Scope) + self.assertEqual(2, len(full_scope.variables)) + for v in full_scope.variables: + self.assertIn(v, {'A', 'B'}) + + def test_variables_reuse(self): + A, B = variables('A', 'B') + s = scope(A, B) + self.assertEqual(A, s['A']) + self.assertEqual(B, s['B']) + fAB = s.struct('f', s.var('A'), s.var('B')) + self.assertEqual(struct('f', A, B), fAB) + + def test_attributes(self): + s = scope() + self.assertEqual(s.fail, FAIL) diff --git a/test/core/test_substitution.py b/test/core/test_substitution.py new file mode 100644 index 0000000..126746f --- /dev/null +++ b/test/core/test_substitution.py @@ -0,0 +1,22 @@ +import unittest +from tuprolog.core import substitution, struct, atom, scope + + +class TestSubstitution(unittest.TestCase): + + def test_substitution_creation(self): + sub = substitution({}) + self.assertEqual(0, len(sub)) + self.assertEqual(True, sub.isSuccess()) + self.assertEqual(True, sub.is_success) + + def test_substitution_application(self): + sc = scope("X", "Y") + term = struct("father", sc["X"], sc["Y"]) + sub1 = substitution({sc["X"]: atom("abraham")}) + sub2 = substitution({sc["Y"]: atom("isaac")}) + + sub = sub1 + sub2 + + result = sub.apply_to(term) + self.assertEqual("father(abraham, isaac)", result.to_string()) diff --git a/test/core/test_terms.py b/test/core/test_terms.py index f0e1bc1..c8e8b99 100644 --- a/test/core/test_terms.py +++ b/test/core/test_terms.py @@ -1,6 +1,6 @@ import unittest -from tuprolog import * -from tuprolog.core import * +from tuprolog.core import atom, integer, real, var, TRUE, FALSE, FAIL, struct + class TestTermCreation(unittest.TestCase): @@ -9,31 +9,32 @@ def setUp(self): self.integer = integer(1) self.real = real(1.2) self.var = var("X") - self.true = truth(True) - self.false = truth(False) + self.true = TRUE + self.false = FALSE self.fail = FAIL self.struct = struct('f', self.atom, self.integer, self.real) self.struct2 = struct('f', [self.atom, self.integer, self.real]) - def test_simple_terms_creation(self): - self.assertEqual(self.atom.getValue(), 'a') - self.assertEqual(self.integer.getValue().toInt(), 1) - self.assertEqual(self.real.getValue().toDouble(), 1.2) - self.assertEqual(self.var.getName(), 'X') - self.assertEqual(self.true.getValue(), 'true') - self.assertEqual(self.false.getValue(), 'false') - self.assertEqual(self.fail.getValue(), 'fail') + self.assertEqual(self.atom.value, 'a') + self.assertEqual(self.integer.value.to_int(), 1) + self.assertEqual(self.real.value.to_double(), 1.2) + self.assertEqual(self.var.name, 'X') + self.assertEqual(self.true.value, 'true') + self.assertEqual(self.false.value, 'false') + self.assertEqual(self.fail.value, 'fail') + self.assertEqual(True, self.false.isTruth()) + self.assertEqual(True, self.true.isTruth()) + self.assertEqual(list(self.var.variables)[0], self.var) + self.assertEqual(True, self.var.structurally_equals(var('Y'))) + self.assertEqual(True, self.false.is_truth) + self.assertEqual(True, self.true.is_truth) def test_struct_creation(self): - self.assertEqual(self.struct.getFunctor(), 'f') - self.assertEqual(self.struct.getArity(), 3) + self.assertEqual(self.struct.functor, 'f') + self.assertEqual(self.struct.arity, 3) self.assertEqual(self.struct.getArgAt(0), self.atom) self.assertEqual(self.struct.getArgAt(1), self.integer) self.assertEqual(self.struct.getArgAt(2), self.real) - self.assertEqual(self.struct, self.struct2) - - -if __name__ == '__main__': - unittest.main() + self.assertEqual(self.struct, self.struct2) diff --git a/test/core/test_try_except.py b/test/core/test_try_except.py new file mode 100644 index 0000000..76b41cb --- /dev/null +++ b/test/core/test_try_except.py @@ -0,0 +1,30 @@ +import unittest +from tuprolog.core import Substitution, Atom +from tuprolog.core.exception import TuPrologException, SubstitutionException, SubstitutionApplicationException + + +class TestExceptions(unittest.TestCase): + + def test_TuprologException(self): + try: + raise TuPrologException("test") + except TuPrologException as e: + self.assertEqual("test", e.message) + + def test_SubstitutionException(self): + sub = Substitution.empty() + try: + raise SubstitutionException(sub, "test") + except SubstitutionException as e: + self.assertEqual("test", e.message) + self.assertEqual(sub, e.substitution) + + def test_SubstitutionApplicationException(self): + term = Atom.of("test") + sub = Substitution.empty() + try: + raise SubstitutionApplicationException(term, sub, "test") + except SubstitutionApplicationException as e: + self.assertEqual("test", e.message) + self.assertEqual(sub, e.substitution) + self.assertEqual(term, e.term) diff --git a/test/core/test_visitors.py b/test/core/test_visitors.py index 4fad903..851585a 100644 --- a/test/core/test_visitors.py +++ b/test/core/test_visitors.py @@ -1,6 +1,6 @@ import unittest -from tuprolog.core import * -from tuprolog.core.visitors import AbstractTermVisitor +from tuprolog.core import Atom, Integer, Var +from tuprolog.core import AbstractTermVisitor class TestVisitors(unittest.TestCase): @@ -10,10 +10,5 @@ class MyVisitor(AbstractTermVisitor): def defaultValue(self, term): return 'a' visitor = MyVisitor() - someTerm = Atom.of('b') for term in [Atom.of('a'), Integer.of(1), Var.of("X")]: self.assertEqual(term.accept(visitor), 'a') - - -if __name__ == '__main__': - unittest.main() \ No newline at end of file diff --git a/main.py b/test/post_install_test.py similarity index 84% rename from main.py rename to test/post_install_test.py index 238b1ac..8235b27 100644 --- a/main.py +++ b/test/post_install_test.py @@ -1,6 +1,5 @@ -from tuprolog.core import * -from tuprolog.core.parsing import * -from tuprolog.core.visitors import AbstractTermVisitor +from tuprolog.core import TermFormatter, Struct, Integer, Real, Term, Numeric, numeric, var, struct, real +from tuprolog.core import AbstractTermVisitor formatter = TermFormatter.prettyExpressions() @@ -41,10 +40,6 @@ def absolute(term: Term): return term -def is_sum(term: Struct): - return term.getArity() == 2 and term.getFunctor() == '+' - - def foldr(accumulator, iterable, default=None): items = list(iterable) if len(items) == 0: @@ -79,7 +74,7 @@ def visitStruct(self, term): features = map(var, ["A", 'B', 'C', 'D', 'E', 'F']) -weights = map(real, [2.5, -3.4, -0.09, 0.2, 0.0, -2.0]) +weights = map(real, ['2.5', '-3.4', '-0.09', '0.2', '0.0', '-2.0']) x = zip(features, weights) @@ -88,5 +83,5 @@ def visitStruct(self, term): x = foldr(lambda a, b: struct('+', a, b), x) x = struct('is', var('Y'), x) -print(formatter.format(x)) -print(formatter.format(x.accept(Simplifier()))) \ No newline at end of file +assert formatter.format(x) == 'Y is 2.5 * A + -3.4 * B + -0.09 * C + 0.2 * D + -2.0 * F' +assert formatter.format(x.accept(Simplifier())) == 'Y is 2.5 * A - 3.4 * B - 0.09 * C + 0.2 * D - 2.0 * F' diff --git a/test/core/operators/__init__.py b/test/solve/__init__.py similarity index 100% rename from test/core/operators/__init__.py rename to test/solve/__init__.py diff --git a/test/solve/problog/__init__.py b/test/solve/problog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/solve/problog/test_problog_parsing.py b/test/solve/problog/test_problog_parsing.py new file mode 100644 index 0000000..2d6600c --- /dev/null +++ b/test/solve/problog/test_problog_parsing.py @@ -0,0 +1,54 @@ +import unittest +from tuprolog.core import struct, var +from tuprolog.theory.parsing import parse_theory +from tuprolog.solve.plp import solve_options, probability +from tuprolog.solve.problog import problog_solver +from tuprolog.solve.problog import PROBLOG_OPERATORS + + +class TestProblogWithParsingAndResolution(unittest.TestCase): + + def setUp(self) -> None: + self.theory_text = """ + 0.6::edge(1,2). + 0.1::edge(1,3). + 0.4::edge(2,5). + 0.3::edge(2,6). + 0.3::edge(3,4). + 0.8::edge(4,5). + 0.2::edge(5,6). + + path(X,Y) :- edge(X,Y). + path(X,Y) :- edge(X,Z),Y \\== Z,path(Z,Y). + """ + self.prints = [] + + def print(self, message): + self.prints.append(message) + + def test_problog(self): + probabilistic_theory = parse_theory(self.theory_text, PROBLOG_OPERATORS) + solver = problog_solver(static_kb=probabilistic_theory) + query = struct('path', var('From'), var('To')) + for solution in solver.solve(query, solve_options(lazy=True, probabilistic=True)): + if solution.is_yes: + self.print(f"yes: {solution.solved_query} with probability {probability(solution)}") + + self.assertEqual( + self.prints, + [ + 'yes: path(1, 2) with probability 0.6', + 'yes: path(1, 3) with probability 0.1', + 'yes: path(2, 5) with probability 0.4', + 'yes: path(2, 6) with probability 0.356', + 'yes: path(3, 4) with probability 0.3', + 'yes: path(4, 5) with probability 0.8', + 'yes: path(5, 6) with probability 0.2', + 'yes: path(1, 5) with probability 0.25824', + 'yes: path(1, 6) with probability 0.2167296', + 'yes: path(1, 4) with probability 0.03', + 'yes: path(3, 5) with probability 0.24', + 'yes: path(3, 6) with probability 0.04800000000000001', + 'yes: path(4, 6) with probability 0.16000000000000003' + ] + ) diff --git a/test/solve/prolog/__init__.py b/test/solve/prolog/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/solve/prolog/test_prolog.py b/test/solve/prolog/test_prolog.py new file mode 100644 index 0000000..ee6f2d6 --- /dev/null +++ b/test/solve/prolog/test_prolog.py @@ -0,0 +1,30 @@ +import unittest +from tuprolog.core import rule, struct, var, fact, atom +from tuprolog.theory import theory +from tuprolog.solve.prolog import prolog_solver + + +class TestPrologWithResolution(unittest.TestCase): + def test_abraham_family_tree(self): + my_program = theory([ + rule( + struct("ancestor", var("X"), var("Y")), # :- + struct("parent", var("X"), var("Y")), + ), + rule( + struct("ancestor", var("X"), var("Y")), # :- + struct("parent", var("X"), var("Z")), + struct("ancestor", var("Z"), var("Y")), + ), + fact(struct("parent", atom("abraham"), atom("isaac"))), + fact(struct("parent", atom("isaac"), atom("jacob"))), + fact(struct("parent", atom("jacob"), atom("joseph"))), + ]) + solver = prolog_solver(static_kb=my_program) + who = var("Who") + query = struct("ancestor", atom("abraham"), who) + result = list[str]() + for solution in solver.solve(query): + if solution.is_yes: + result.append(str(solution.substitution[who])) + self.assertSequenceEqual(result, ["isaac", "jacob", "joseph"]) diff --git a/test/solve/prolog/test_prolog_parsing.py b/test/solve/prolog/test_prolog_parsing.py new file mode 100644 index 0000000..6665a1c --- /dev/null +++ b/test/solve/prolog/test_prolog_parsing.py @@ -0,0 +1,65 @@ +import unittest +from tuprolog.core import struct, atom, integer +from tuprolog.theory.parsing import parse_theory +from tuprolog.solve.prolog import prolog_solver +from tuprolog.solve.flags import DEFAULT_FLAG_STORE, TrackVariables +from tuprolog.solve.channel import output_channel + + +class TestPrologWithParsingAndResolution(unittest.TestCase): + def setUp(self) -> None: + self.theory_text = """ + % Towers of Hanoi + move(1,X,Y,_) :- + write('Move top disk from '), + write(X), + write(' to '), + write(Y), + nl. + move(N,X,Y,Z) :- + N>1, + M is N-1, + move(M,X,Z,Y), + move(1,X,Y,_), + move(M,Z,Y,X). + """ + self.prints: list[str] = [] + self.maxDiff = None + + def print(self, message): + self.prints.append(message) + + def print_output(self, message): + message = str(message) + if len(self.prints) == 0: + self.prints.append(message) + elif self.prints[-1].endswith('\n'): + self.prints.append(message) + else: + self.prints[-1] += message + + def test_prolog(self): + logic_theory = parse_theory(self.theory_text) + flags = DEFAULT_FLAG_STORE.set(TrackVariables, TrackVariables.ON) + solver = prolog_solver( + static_kb=logic_theory, + flags=flags, + std_out=output_channel(self.print_output)) + query = struct("move", integer(3), atom("left"), atom("right"), atom("center")) + for solution in solver.solve(query): + if solution.is_yes: + self.print(f"yes: {solution.solved_query}") + + self.assertEqual( + self.prints, + [ + 'Move top disk from left to right\n', + 'Move top disk from left to center\n', + 'Move top disk from right to center\n', + 'Move top disk from left to right\n', + 'Move top disk from center to left\n', + 'Move top disk from center to right\n', + 'Move top disk from left to right\n', + 'yes: move(3, left, right, center)' + ] + ) diff --git a/test/solve/prolog/test_thermostat_agent.py b/test/solve/prolog/test_thermostat_agent.py new file mode 100644 index 0000000..6d14097 --- /dev/null +++ b/test/solve/prolog/test_thermostat_agent.py @@ -0,0 +1,105 @@ +import unittest +from typing import Iterable +from pathlib import Path +from tuprolog.core import atom, integer +from tuprolog.unify import mgu +from tuprolog.theory.parsing import parse_theory +from tuprolog.solve import signature +from tuprolog.solve.library import library, Library +from tuprolog.solve.primitive import primitive, SolveRequest, SolveResponse, ensuring_argument_is_variable, \ + ensuring_all_arguments_are_instantiated, ensuring_argument_is_atom +from tuprolog.solve.flags import DEFAULT_FLAG_STORE, TrackVariables +from tuprolog.solve.channel import output_channel +from tuprolog.solve.prolog import prolog_solver + + +class ThermostatAgent: + def __init__(self, name: str, cold_threshold: int, hot_threshold: int, initial_temperature: int): + self.name = name + self.cold_threshold = cold_threshold + self.hot_threshold = hot_threshold + self.initial_temperature = initial_temperature + self._temperature = initial_temperature + + @property + def temperature(self) -> int: + return self._temperature + + def get_temp(self, request: SolveRequest) -> Iterable[SolveResponse]: + ensuring_argument_is_variable(request, 0) + sub = mgu(request.arguments[0], integer(self.temperature)) + yield request.reply_with(sub) + + def push(self, request: SolveRequest) -> Iterable[SolveResponse]: + ensuring_all_arguments_are_instantiated(request) + ensuring_argument_is_atom(request, 0) + arg = request.arguments[0].cast_to_atom().value + if arg == "hot": + self._temperature += 1 + elif arg == "cold": + self._temperature -= 1 + else: + yield request.reply_fail() + yield request.reply_success() + + @property + def library(self) -> Library: + get_temp = primitive(self.get_temp) + push = primitive(self.push) + return library( + alias="libs.agency.thermostat", + primitives={ + signature("get_temp", arity=1): get_temp, + signature("push", arity=1): push + } + ) + + def program(self) -> str: + with open(Path(__file__).parent / "thermostat.pl", "r") as f: + return f.read() \ + .replace("__COLD_THRESHOLD__", str(self.cold_threshold)) \ + .replace("__HOT_THRESHOLD__", str(self.hot_threshold)) + + +class ThermostatAgentTest(unittest.TestCase): + def setUp(self) -> None: + self.thermostat_agent = ThermostatAgent("thermostat", 20, 24, 15) + self.prints: list[str] = [] + + def print_output(self, message): + message = str(message) + if len(self.prints) == 0: + self.prints.append(message) + elif self.prints[-1].endswith('\n'): + self.prints.append(message) + else: + self.prints[-1] += message + + def test_program(self): + theory = parse_theory(self.thermostat_agent.program()) + solver = prolog_solver( + libraries=self.thermostat_agent.library, + flags=DEFAULT_FLAG_STORE.set(TrackVariables, TrackVariables.ON), + static_kb=theory, + std_out=output_channel(self.print_output) + ) + solution = solver.solve_once(atom("start")) + self.assertTrue(solution.is_yes) + self.assertSequenceEqual( + self.prints, + [ + "Temperature is 15.\n", + "Pushing hot air.\n", + "Temperature is 16.\n", + "Pushing hot air.\n", + "Temperature is 17.\n", + "Pushing hot air.\n", + "Temperature is 18.\n", + "Pushing hot air.\n", + "Temperature is 19.\n", + "Pushing hot air.\n", + "Temperature is 20.\n", + "Pushing hot air.\n", + "Temperature is 21.\n", + "I'm done.\n"] + ) diff --git a/test/solve/prolog/thermostat.pl b/test/solve/prolog/thermostat.pl new file mode 100644 index 0000000..8b954ed --- /dev/null +++ b/test/solve/prolog/thermostat.pl @@ -0,0 +1,32 @@ +:- dynamic(done/1). + +warm_range(__COLD_THRESHOLD__, __HOT_THRESHOLD__). +done(no). + +start :- + between(1, 20, _), + sleep(100 /* ms */), % just to slow down the execution + warm_range(Min, Max), + keep_temperature(Min, Max), + done(yes). + +keep_temperature(Min, Max) :- + check_temperature(T), + handle_temperature(T, Min, Max). + +check_temperature(T) :- + get_temp(T), + write("Temperature is "), write(T), write('.'), nl. + +handle_temperature(T, Min, _) :- T =< Min, !, + push(hot), + write("Pushing hot air."), nl. + +handle_temperature(T, _, Max) :- T >= Max, !, + push(cold), + write("Pushing cold air."), nl. + +handle_temperature(_, _, _) :- + retract(done(_)), !, + assert(done(yes)), + write("I'm done."), nl. diff --git a/test/theory/test_theory.py b/test/theory/test_theory.py new file mode 100644 index 0000000..2134e7e --- /dev/null +++ b/test/theory/test_theory.py @@ -0,0 +1,52 @@ +import unittest +from tuprolog.core import clause, var, struct, atom +from tuprolog.theory import theory + + +class TestTheory(unittest.TestCase): + def test_empty_theory(self): + t = theory() + self.assertIsNotNone(t) + self.assertEqual(0, len(t)) + self.assertTrue(t.is_empty) + + def test_retract(self): + A = var('A') + a = atom('a') + + def f(arg): + return struct('f', arg) + + def g(arg): + return struct('g', arg) + + t = theory([ + c1 := clause(f(A), g(A)), + clause(g(a)), + ]) + self.assertEqual(2, len(t)) + result = t.retract(c1) + self.assertEqual(1, len(result.theory)) + + def test_unificator(self): + A = var('A') + a = atom('a') + + def f(arg): + return struct('f', arg) + + def g(arg): + return struct('g', arg) + + t = theory([ + clause(g(a)), + ]) + results = list(t[f(a)]) + self.assertEqual(0, len(results)) + + t = theory([ + clause(f(A), g(A)), + clause(g(a)), + ]) + results = list(t[f(a)]) + self.assertEqual(1, len(results)) diff --git a/test/unify/__init__.py b/test/unify/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/unify/test_unify.py b/test/unify/test_unify.py new file mode 100644 index 0000000..414346b --- /dev/null +++ b/test/unify/test_unify.py @@ -0,0 +1,33 @@ +import unittest +from tuprolog.jvmutils import Pair +from tuprolog.core import scope +from tuprolog.unify import DEFAULT_UNIFICATOR + + +class TestSubstitutionMerge(unittest.TestCase): + def test_merge_with(self): + s = scope("X", "Y", "Z") + base = s.unifier_of( + ("X", s["Y"]), + ("Y", s["Z"]), + ) + a = s.atom_of("a") + + for v_name, v in s.variables.items(): + assignment = s.unifier_of(Pair @ (v_name, a)) + self.assertEqual( + s.unifier_of( + ("X", a), + ("Y", a), + ("Z", a), + ), + DEFAULT_UNIFICATOR.merge(base, assignment), + ) + self.assertEqual( + s.unifier_of( + ("X", a), + ("Y", a), + ("Z", a), + ), + DEFAULT_UNIFICATOR.merge(assignment, base), + ) diff --git a/tuprolog/__init__.py b/tuprolog/__init__.py index c8de217..b2b52e7 100644 --- a/tuprolog/__init__.py +++ b/tuprolog/__init__.py @@ -1,20 +1,19 @@ +import os import logging - -# noinspection PyUnresolvedReferences import jpype -import jpype.imports - -from .libs import CLASSPATH +from .libs import CLASSPATH, find_jvm -logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger('tuprolog') jars = [str(j.resolve()) for j in CLASSPATH.glob('*.jar')] -jpype.startJVM(classpath=jars) +if not jpype.isJVMStarted(): + jpype.startJVM(classpath=jars, jvmpath=str(find_jvm())) + +import jpype.imports # noqa: F401, E402 +from it.unibo import tuprolog as _tuprolog # type: ignore # noqa: E402 -# noinspection PyUnresolvedReferences -from it.unibo.tuprolog import Info +Info = _tuprolog.Info JVM_VERSION = '.'.join(map(str, jpype.getJVMVersion())) diff --git a/tuprolog/__main__.py b/tuprolog/__main__.py index 263451a..c6cb5c9 100644 --- a/tuprolog/__main__.py +++ b/tuprolog/__main__.py @@ -1,12 +1,11 @@ from tuprolog import Info from tuprolog.core import * -from tuprolog.core.comparators import * from tuprolog.core.exception import * -from tuprolog.core.formatters import * +from tuprolog.core.impl import * from tuprolog.core.operators import * -from tuprolog.core.visitors import * from tuprolog.core.parsing import * from tuprolog.unify import * +from tuprolog.unify.exception import * from tuprolog.theory import * from tuprolog.theory.parsing import * from tuprolog.solve import * @@ -17,7 +16,7 @@ from tuprolog.solve.flags import * from tuprolog.solve.function import * from tuprolog.solve.primitive import * -from tuprolog.solve.sideffcts import * +from tuprolog.solve.sideffects import * from tuprolog.solve.library import * from tuprolog.solve.library.exception import * from tuprolog.solve.data import * @@ -25,11 +24,13 @@ from tuprolog.solve.stdlib.primitive import * from tuprolog.solve.stdlib.rule import * from tuprolog.solve.stdlib.function import * -from tuprolog.solve.classic import * +from tuprolog.solve.stdlib.magic import * from tuprolog.solve.prolog import * +from tuprolog.solve.plp import * +from tuprolog.solve.problog import * import code code.interact(local=locals()) -input() \ No newline at end of file +input() diff --git a/tuprolog/core/__init__.py b/tuprolog/core/__init__.py index e107356..ff10c46 100644 --- a/tuprolog/core/__init__.py +++ b/tuprolog/core/__init__.py @@ -1,203 +1,3 @@ -from tuprolog import logger -import jpype -import jpype.imports -from ._ktadapt import * -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.core as _core -from tuprolog.pyutils import iterable_or_varargs -from tuprolog.jvmutils import jiterable, jmap -from typing import Iterable, Union, Dict -from ._ktmath import * - -Atom = _core.Atom - -Block = _core.Block - -Clause = _core.Clause - -Cons = _core.Cons - -Constant = _core.Constant - -Directive = _core.Directive - -Empty = _core.Empty - -EmptyBlock = _core.EmptyBlock - -EmptyList = _core.EmptyList - -Fact = _core.Fact - -Formatter = _core.Formatter - -Indicator = _core.Indicator - -Integer = _core.Integer - -List = _core.List - -Numeric = _core.Numeric - -Real = _core.Real - -Recursive = _core.Recursive - -Rule = _core.Rule - -Scope = _core.Scope - -Struct = _core.Struct - -Substitution = _core.Substitution - -Term = _core.Term - -TermComparator = _core.TermComparator - -TermConvertible = _core.TermConvertible - -TermFormatter = _core.TermFormatter - -Terms = _core.Terms - -TermVisitor = _core.TermVisitor - -Truth = _core.Truth - -Tuple = _core.Tuple - -Var = _core.Var - - -@jpype.JImplements(TermConvertible) -class AbstractTermConvertible(object): - @jpype.JOverride - def toTerm(self): - raise NotImplementedError() - - -def atom(string: str) -> Atom: - return Atom.of(string) - - -def block(*terms: Union[Term, Iterable[Term]]) -> Block: - return iterable_or_varargs(terms, lambda ts: Block.of(jiterable(ts))) - - -def clause(head: Term=None, *body: Union[Term, Iterable[Term]]): - return iterable_or_varargs(body, lambda bs: Clause.of(head, jiterable(bs))) - - -def empty_logic_list() -> EmptyList: - return EmptyList.getInstance() - - -def cons(head: Term, tail: Term=None) -> Cons: - if tail is None: - return Cons.singleton(head) - else: - return Cons.of(head, tail) - - -def directive(*goals: Union[Term, Iterable[Term]]) -> Directive: - return iterable_or_varargs(goals, lambda gs: Directive.of(jiterable(gs))) - - -def empty_block() -> Block: - return EmptyBlock.getInstance() - - -def fact(struct: Union[Term, Iterable[Term]]) -> Fact: - return Fact.of(struct) - - -def indicator(name: Union[str, Term], arity: Union[int, Term]) -> Indicator: - return Indicator.of(name, arity) - - -def numeric(value: Union[int, BigInteger, BigDecimal, str, float]) -> Numeric: - if isinstance(value, str): - return Numeric.of(jpype.JString @ value) - if isinstance(value, BigInteger): - return Integer.of(BigInteger @ value) - if isinstance(value, BigDecimal): - return Real.of(BigDecimal @ value) - if isinstance(value, int): - return Integer.of(jpype.JLong @ value) - if isinstance(value, float): - return Real.of(jpype.JDouble @ value) - return Numeric.of(value) - - -def integer(value: Union[int, BigInteger, str]) -> Integer: - if isinstance(value, str): - return Integer.of(jpype.JString @ value) - if isinstance(value, BigInteger): - return Integer.of(BigInteger @ value) - if isinstance(value, int): - return Integer.of(jpype.JLong @ value) - return Integer.of(value) - - -def real(value: Union[float, BigDecimal, str]) -> Real: - if isinstance(value, str): - return Real.of(jpype.JString @ value) - if isinstance(value, BigDecimal): - return Real.of(BigDecimal @ value) - if isinstance(value, float): - return Real.of(jpype.JDouble @ value) - return Real.of(value) - - -def rule(head: Struct, *body: Union[Term, Iterable[Term]]) -> Rule: - return iterable_or_varargs(body, lambda bs: Rule.of(head, jiterable(bs))) - - -def struct(functor: str, *args: Union[Term, Iterable[Term]]) -> Struct: - return iterable_or_varargs(args, lambda xs: Struct.of(functor, jiterable(xs))) - - -def truth(boolean: bool) -> Truth: - return Truth.of(boolean) - - -TRUE = Truth.TRUE - - -FALSE = Truth.FALSE - - -FAIL = Truth.FAIL - - -def logic_list(*items: Union[Term, Iterable[Term]]) -> Tuple: - return iterable_or_varargs(items, lambda xs: List.of(jiterable(xs))) - - -def logic_tuple(first: Term, second: Term, *others: Union[Term, Iterable[Term]]) -> Tuple: - return iterable_or_varargs(others, lambda os: Tuple.of(jiterable([first, second] + list(os)))) - - -def var(name: str) -> Var: - return Var.of(name) - - -def unifier(assignments: Dict[Var, Term]={}) -> Substitution.Unifier: - return Substitution.unifier(jmap(assignments)) - - -def substitution(assignments: Dict[Var, Term]={}) -> Substitution: - return Substitution.of(jmap(assignments)) - - -def failed() -> Substitution.Fail: - return Substitution.failed() - - -EMPTY_UNIFIER: Substitution.Unifier = substitution() - -FAILED_SUBSTITUTION: Substitution.Fail = failed() - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.core.*") +import tuprolog.core._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/core/_adapters.py b/tuprolog/core/_adapters.py new file mode 100644 index 0000000..e4e377a --- /dev/null +++ b/tuprolog/core/_adapters.py @@ -0,0 +1,205 @@ +from typing import Sized, Callable +from jpype import JOverride, JImplementationFor +from tuprolog import logger +from tuprolog.jvmutils import jiterable, kfunction +from tuprolog.pyutils import iterable_or_varargs +from tuprolog.math import big_integer, BigInteger, python_integer, python_decimal + + +@JImplementationFor("it.unibo.tuprolog.core.Term") +class _KtTerm: + def __jclass_init__(cls): + pass + + def __getitem__(self, item, *items): + return self.get(item, *items) + + @JOverride() + def equals(self, other, use_var_complete_name: bool = True): + return self.equals_(other, use_var_complete_name) + + def fresh_copy(self, scope=None): + if scope is None: + return self.freshCopy() + else: + return self.freshCopy(scope) + + +@JImplementationFor("it.unibo.tuprolog.core.Struct") +class _KtStruct: + def __jclass_init__(cls): + pass + + def insert_at(self, index, argument): + return self.addFirst(index, argument) + + def set_args(self, *args): + return iterable_or_varargs(args, lambda xs: self.setArgs(jiterable(args))) + + +@JImplementationFor("it.unibo.tuprolog.core.Numeric") +class _KtNumeric: + def __jclass_init__(cls): + pass + + @property + def int_value(self): + return python_integer(self.getIntValue()) + + @property + def decimal_value(self): + return python_decimal(self.getDecimalValue()) + + def to_int(self): + return self.int_value + + def to_float(self): + return float(self.decimal_value) + + +@JImplementationFor("it.unibo.tuprolog.core.Integer") +class _KtInteger: + def __jclass_init__(cls): + pass + + @property + def value(self): + return self.int_value + + +@JImplementationFor("it.unibo.tuprolog.core.Real") +class _KtReal: + def __jclass_init__(cls): + pass + + @property + def value(self): + return self.decimal_value + + +@JImplementationFor("it.unibo.tuprolog.core.Recursive") +class _KtRecursive: + def __jclass_init__(cls): + Sized.register(cls) + + @property + def lazily_unfolded(self): + return self.getUnfoldedSequence() + + @property + def unfolded(self): + return self.getUnfoldedList() + + @property + def __len__(self): + return self.getSize() + + def to_iterable(self): + return self.toSequence() + + +@JImplementationFor("it.unibo.tuprolog.core.Clause") +class _KtClause: + def __jclass_init__(cls): + pass + + def set_head_args(self, *args): + return iterable_or_varargs(args, lambda xs: self.setHeadArgs(jiterable(args))) + + def insert_head_arg(self, index, argument): + return self.setHeadArg(index, argument) + + def set_body_items(self, *args): + return iterable_or_varargs(args, lambda xs: self.setBodyItems(jiterable(args))) + + +@JImplementationFor("it.unibo.tuprolog.core.Substitution") +class _KtSubstitution: + def __jclass_init__(cls): + pass + + def __add__(self, other): + return self.plus(other) + + def __sub__(self, other): + return self.minus(other) + + @JOverride + def filter(self, filter): + if isinstance(filter, Callable): + return self.filter_(kfunction(1)(filter)) + else: + return self.filter_(filter) + + +@JImplementationFor("it.unibo.tuprolog.core.Scope") +class _KtScope: + def __jclass_init__(cls): + pass + + def __contains__(self, item): + return self.contains(item) + + def __getitem__(self, item): + return self.get(item) + + def atom(self, string): + return self.atomOf(string) + + def block(self, *terms): + return iterable_or_varargs(terms, lambda ts: self.blockOf(jiterable(ts))) + + def clause(self, head=None, *body): + return iterable_or_varargs(body, lambda bs: self.clauseOf(head, jiterable(bs))) + + def cons(self, head, tail=None): + if tail is None: + return self.listOf(head) + else: + return self.consOf(head, tail) + + def directive(self, *goals): + return iterable_or_varargs(goals, lambda gs: self.directiveOf(jiterable(gs))) + + def fact(self, head): + return self.factOf(head) + + def indicator(self, name, arity): + return self.indicatorOf(name, arity) + + def integer(self, value): + return self.intOf(big_integer(value)) + + def real(self, value): + return self.intOf(big_integer(value)) + + def numeric(self, value): + if isinstance(value, str): + return self.numOf(value) + if isinstance(value, int) or isinstance(value, BigInteger): + return self.intOf(value) + return self.realOf(value) + + def rule(self, head, *body): + return iterable_or_varargs(body, lambda bs: self.ruleOf(head, jiterable(bs))) + + def struct(self, functor, *args): + return iterable_or_varargs(args, lambda xs: self.structOf(functor, jiterable(xs))) + + def truth(self, value): + return self.truthOf(value) + + def var(self, name): + return self.varOf(name) + + def list(self, *items): + return iterable_or_varargs(items, lambda xs: self.listOf(jiterable(xs))) + + def list_from(self, items, last=None): + return self.listFrom(jiterable(items), last) + + def tuple(self, first, second, *others): + return iterable_or_varargs(others, lambda os: self.tupleOf(jiterable([first, second] + list(os)))) + + +logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.core.*") diff --git a/tuprolog/core/_api.py b/tuprolog/core/_api.py new file mode 100644 index 0000000..6b16f32 --- /dev/null +++ b/tuprolog/core/_api.py @@ -0,0 +1,124 @@ +from typing import Iterable, Dict, Tuple as PyTuple, Union +from decimal import Decimal +from jpype import JString, JArray +from tuprolog.pyutils import iterable_or_varargs +from tuprolog.jvmutils import jiterable, jmap +from tuprolog.math import big_integer, big_decimal, BigInteger, BigDecimal +from ._definitions import Atom, Block, Clause, Cons, Directive, EmptyBlock +from ._definitions import EmptyList, Fact, Indicator, Integer, List, Numeric +from ._definitions import Real, Rule, Scope, Struct, Substitution, Term, Tuple, Truth, Var + + +def atom(string: str) -> Atom: + return Atom.of(string) + + +def block(*terms: Union[Term, Iterable[Term]]) -> Block: + return iterable_or_varargs(terms, lambda ts: Block.of(jiterable(ts))) + + +def clause(head: Term = None, *body: Union[Term, Iterable[Term]]): + return iterable_or_varargs(body, lambda bs: Clause.of(head, jiterable(bs))) + + +def empty_logic_list() -> EmptyList: + return EmptyList.getInstance() + + +def cons(head: Term, tail: Term = None) -> Cons: + if tail is None: + return Cons.singleton(head) + else: + return Cons.of(head, tail) + + +def directive(*goals: Union[Term, Iterable[Term]]) -> Directive: + return iterable_or_varargs(goals, lambda gs: Directive.of(jiterable(gs))) + + +def empty_block() -> Block: + return EmptyBlock.getInstance() + + +def fact(struct: Union[Term, Iterable[Term]]) -> Fact: + return Fact.of(struct) + + +def indicator(name: Union[str, Term], arity: Union[int, Term]) -> Indicator: + return Indicator.of(name, arity) + + +def integer(value: Union[int, BigInteger, str]) -> Integer: + return Integer.of(big_integer(value)) + + +def real(value: Union[float, BigDecimal, str, Decimal]) -> Real: + if isinstance(value, BigDecimal): + return Real.of(value) + return Real.of(big_decimal(value)) + + +def numeric(value: Union[int, BigInteger, BigDecimal, str, float, Decimal]) -> Numeric: + if isinstance(value, str): + return Numeric.of(JString @ value) + if isinstance(value, int) or isinstance(value, BigInteger): + return integer(value) + return real(value) + + +def rule(head: Struct, *body: Union[Term, Iterable[Term]]) -> Rule: + return iterable_or_varargs(body, lambda bs: Rule.of(head, jiterable(bs))) + + +def struct(functor: str, *args: Union[Term, Iterable[Term]]) -> Struct: + return iterable_or_varargs(args, lambda xs: Struct.of(functor, jiterable(xs))) + + +def truth(boolean: bool) -> Truth: + return Truth.of(boolean) + + +def logic_list(*items: Union[Term, Iterable[Term]]) -> List: + return iterable_or_varargs(items, lambda xs: List.of(jiterable(xs))) + + +def logic_list_from(items: Iterable[Term], last: Term = None) -> List: + return List.from_(jiterable(items), last) + + +def logic_tuple(first: Term, second: Term, *others: Union[Term, Iterable[Term]]) -> Tuple: + return iterable_or_varargs(others, lambda os: Tuple.of(jiterable([first, second] + list(os)))) + + +def var(name: str) -> Var: + return Var.of(name) + + +def unifier(assignments: Dict[Var, Term] = {}) -> Substitution.Unifier: + return Substitution.unifier(jmap(assignments)) + + +def substitution(assignments: Dict[Var, Term] = {}) -> Substitution: + return Substitution.of(jmap(assignments)) + + +def failed() -> Substitution.Fail: + return Substitution.failed() + + +EMPTY_UNIFIER: Substitution.Unifier = substitution() + + +FAILED_SUBSTITUTION: Substitution.Fail = failed() + + +def scope(*variables: Union[Var, str]) -> Scope: + if len(variables) == 0: + return Scope.empty() + vars = [var(v) if isinstance(v, str) else v for v in variables] + return Scope.of(vars[0], JArray(Var) @ vars[1:]) + + +def variables(*names: str) -> PyTuple[Var]: + assert len(names) > 0 + return tuple((var(n) for n in names)) diff --git a/tuprolog/core/_definitions.py b/tuprolog/core/_definitions.py new file mode 100644 index 0000000..4b589f8 --- /dev/null +++ b/tuprolog/core/_definitions.py @@ -0,0 +1,226 @@ +from jpype import JImplements, JOverride +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.core as _core # type: ignore + + +Applicable = _core.Applicable + + +Atom = _core.Atom + + +Block = _core.Block + + +Clause = _core.Clause + + +Cons = _core.Cons + + +Constant = _core.Constant + + +Directive = _core.Directive + + +Empty = _core.Empty + + +EmptyBlock = _core.EmptyBlock + + +EmptyList = _core.EmptyList + + +Fact = _core.Fact + + +Formatter = _core.Formatter + + +Indicator = _core.Indicator + + +Integer = _core.Integer + + +List = _core.List + + +Numeric = _core.Numeric + + +Real = _core.Real + + +Recursive = _core.Recursive + + +Rule = _core.Rule + + +Scope = _core.Scope + + +Struct = _core.Struct + + +Substitution = _core.Substitution + + +Term = _core.Term + + +TermComparator = _core.TermComparator + + +TermConvertible = _core.TermConvertible + + +TermFormatter = _core.TermFormatter + + +Terms = _core.Terms + + +TermVisitor = _core.TermVisitor + + +Truth = _core.Truth + + +Tuple = _core.Tuple + + +Var = _core.Var + + +Variabled = _core.Variabled + + +TRUE = Truth.TRUE + + +FALSE = Truth.FALSE + + +FAIL = Truth.FAIL + + +@JImplements(TermComparator) +class AbstractTermComparator(object): + @JOverride + def equals(self, other): + return self is other + + @JOverride + def compare(self, first, second): + raise NotImplementedError() + + +@JImplements(TermConvertible) +class AbstractTermConvertible(object): + @JOverride + def toTerm(self): + raise NotImplementedError() + + +@JImplements(TermVisitor) +class AbstractTermVisitor(object): + + @JOverride + def defaultValue(self, term): + raise NotImplementedError() + + @JOverride + def visitTerm(self, term): + return TermVisitor.visitTerm(self, term) + + @JOverride + def visitVar(self, term): + return TermVisitor.visitVar(self, term) + + @JOverride + def visitConstant(self, term): + return TermVisitor.visitConstant(self, term) + + @JOverride + def visitStruct(self, term): + return TermVisitor.visitStruct(self, term) + + @JOverride + def visitCollection(self, term): + return TermVisitor.visitCollection(self, term) + + @JOverride + def visitAtom(self, term): + return TermVisitor.visitAtom(self, term) + + @JOverride + def visitTruth(self, term): + return TermVisitor.visitTruth(self, term) + + @JOverride + def visitNumeric(self, term): + return TermVisitor.visitNumeric(self, term) + + @JOverride + def visitInteger(self, term): + return TermVisitor.visitInteger(self, term) + + @JOverride + def visitReal(self, term): + return TermVisitor.visitReal(self, term) + + @JOverride + def visitBlock(self, term): + return TermVisitor.visitBlock(self, term) + + @JOverride + def visitEmpty(self, term): + return TermVisitor.visitEmpty(self, term) + + @JOverride + def visitEmptyBlock(self, term): + return TermVisitor.visitEmptyBlock(self, term) + + @JOverride + def visitList(self, term): + return TermVisitor.visitList(self, term) + + @JOverride + def visitCons(self, term): + return TermVisitor.visitCons(self, term) + + @JOverride + def visitEmptyList(self, term): + return TermVisitor.visitEmptyList(self, term) + + @JOverride + def visitTuple(self, term): + return TermVisitor.visitTuple(self, term) + + @JOverride + def visitIndicator(self, term): + return TermVisitor.visitIndicator(self, term) + + @JOverride + def visitClause(self, term): + return TermVisitor.visitClause(self, term) + + @JOverride + def visitRule(self, term): + return TermVisitor.visitRule(self, term) + + @JOverride + def visitFact(self, term): + return TermVisitor.visitFact(self, term) + + @JOverride + def visitDirective(self, term): + return TermVisitor.visitDirective(self, term) + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.core.*") diff --git a/tuprolog/core/_ktadapt.py b/tuprolog/core/_ktadapt.py deleted file mode 100644 index f728a04..0000000 --- a/tuprolog/core/_ktadapt.py +++ /dev/null @@ -1,73 +0,0 @@ -from tuprolog import logger - -import jpype - - -@jpype.JImplementationFor("it.unibo.tuprolog.core.Term") -class _KtTerm: - def __jclass_init__(self): - pass - - def __getitem__(self, item, *items): - return self.get(item, *items) - - @property - def variables(self): - return self.getVariables() - - -@jpype.JImplementationFor("it.unibo.tuprolog.core.operators.Operator") -class _KtOperator: - def __jclass_init__(self): - pass - - @property - def functor(self): - return self.getFunctor() - - @property - def specifier(self): - return self.getSpecifier() - - @property - def priority(self): - return self.getPriority() - - -@jpype.JImplementationFor("it.unibo.tuprolog.core.Struct") -class _KtStruct: - def __jclass_init__(self): - pass - - @property - def functor(self): - return self.getFunctor() - - @property - def args(self): - return self.getArgs() - - @property - def arity(self): - return self.getArity() - - -@jpype.JImplementationFor("it.unibo.tuprolog.core.Clause") -class _KtClause: - def __jclass_init__(self): - pass - - @property - def head(self): - return self.getHead() - - @property - def body(self): - return self.getBody() - - @property - def is_well_formed(self): - return self.isWellFormed() - - -logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.core.*") diff --git a/tuprolog/core/_ktmath.py b/tuprolog/core/_ktmath.py deleted file mode 100644 index 6482181..0000000 --- a/tuprolog/core/_ktmath.py +++ /dev/null @@ -1,21 +0,0 @@ -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import org.gciatto.kt.math as _ktmath - - -BigInteger = _ktmath.BigInteger - -BigDecimal = _ktmath.BigDecimal - -MathContext = _ktmath.MathContext - -RoundingMode = _ktmath.RoundingMode - - -def big_integer(value) -> BigInteger: - return BigInteger.Companion.of(value) - - -def big_decimal(value) -> BigDecimal: - return BigDecimal.Companion.of(value) diff --git a/tuprolog/core/comparators.py b/tuprolog/core/comparators.py deleted file mode 100644 index 152e9f7..0000000 --- a/tuprolog/core/comparators.py +++ /dev/null @@ -1,19 +0,0 @@ -from tuprolog import logger - -import jpype - -from tuprolog.core import TermComparator - - -@jpype.JImplements(TermComparator) -class AbstractTermComparator(object): - @jpype.JOverride - def equals(self, other): - return self is other - - @jpype.JOverride - def compare(self, first, second): - raise NotImplementedError() - - -logger.debug("Loaded compatibility layer for JVM subtypes of " + str(TermComparator.class_.getName())) diff --git a/tuprolog/core/exception.py b/tuprolog/core/exception.py index cba30b7..fd4ae2a 100644 --- a/tuprolog/core/exception.py +++ b/tuprolog/core/exception.py @@ -1,16 +1,12 @@ from tuprolog import logger - -# noinspection PyUnresolvedReferences -import jpype.imports - -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.core.exception as _exceptions +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.core.exception as _exceptions # type: ignore TuPrologException = _exceptions.TuPrologException -SubstitutionException = _exceptions.TuPrologException +SubstitutionException = _exceptions.SubstitutionException -SubstitutionApplicationException = _exceptions.TuPrologException +SubstitutionApplicationException = _exceptions.SubstitutionApplicationException logger.debug("Loaded JVM classes from it.unibo.tuprolog.core.exception.*") diff --git a/tuprolog/core/formatters.py b/tuprolog/core/formatters.py deleted file mode 100644 index 730cad0..0000000 --- a/tuprolog/core/formatters.py +++ /dev/null @@ -1,115 +0,0 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype -import jpype.imports -from tuprolog.core import Formatter, TermFormatter -from tuprolog.core.visitors import AbstractTermVisitor - - -@jpype.JImplements(Formatter) -class AbstractFormatter(object): - @jpype.JOverride - def format(self, term): - raise NotImplementedError() - - -@jpype.JImplements(TermFormatter) -class AbstractTermFormatter(AbstractFormatter, AbstractTermVisitor): - @jpype.JOverride - def format(self, term): - return term.accept(self) - - @jpype.JOverride - def defaultValue(self, term): - return super(AbstractTermVisitor).defaultValue(self, term) - - @jpype.JOverride - def visitTerm(self, term): - return super(AbstractTermVisitor, self).visitTerm(term) - - @jpype.JOverride - def visitVar(self, term): - return super(AbstractTermVisitor, self).visitVar(term) - - @jpype.JOverride - def visitConstant(self, term): - return super(AbstractTermVisitor, self).visitConstant(term) - - @jpype.JOverride - def visitStruct(self, term): - return super(AbstractTermVisitor, self).visitStruct(term) - - @jpype.JOverride - def visitCollection(self, term): - return super(AbstractTermVisitor, self).visitCollection(term) - - @jpype.JOverride - def visitAtom(self, term): - return super(AbstractTermVisitor, self).visitAtom(term) - - @jpype.JOverride - def visitTruth(self, term): - return super(AbstractTermVisitor, self).visitTruth(term) - - @jpype.JOverride - def visitNumeric(self, term): - return super(AbstractTermVisitor, self).visitNumeric(term) - - @jpype.JOverride - def visitInteger(self, term): - return super(AbstractTermVisitor, self).visitInteger(term) - - @jpype.JOverride - def visitReal(self, term): - return super(AbstractTermVisitor, self).visitReal(term) - - @jpype.JOverride - def visitBlock(self, term): - return super(AbstractTermVisitor, self).visitBlock(term) - - @jpype.JOverride - def visitEmpty(self, term): - return super(AbstractTermVisitor, self).visitEmpty(term) - - @jpype.JOverride - def visitEmptyBlock(self, term): - return super(AbstractTermVisitor, self).visitEmptyBlock(term) - - @jpype.JOverride - def visitList(self, term): - return super(AbstractTermVisitor, self).visitList(term) - - @jpype.JOverride - def visitCons(self, term): - return super(AbstractTermVisitor, self).visitCons(term) - - @jpype.JOverride - def visitEmptyList(self, term): - return super(AbstractTermVisitor, self).visitEmptyList(term) - - @jpype.JOverride - def visitTuple(self, term): - return super(AbstractTermVisitor, self).visitTuple(term) - - @jpype.JOverride - def visitIndicator(self, term): - return super(AbstractTermVisitor, self).visitIndicator(term) - - @jpype.JOverride - def visitClause(self, term): - return super(AbstractTermVisitor, self).visitClause(term) - - @jpype.JOverride - def visitRule(self, term): - return super(AbstractTermVisitor, self).visitRule(term) - - @jpype.JOverride - def visitFact(self, term): - return super(AbstractTermVisitor, self).visitFact(term) - - @jpype.JOverride - def visitDirective(self, term): - return super(AbstractTermVisitor, self).visitDirective(term) - - -logger.debug("Loaded compatibility layer for JVM subtypes of " + str(TermFormatter.class_.getName())) diff --git a/tuprolog/core/impl.py b/tuprolog/core/impl.py new file mode 100644 index 0000000..fb5819b --- /dev/null +++ b/tuprolog/core/impl.py @@ -0,0 +1,8 @@ +from tuprolog import logger +from tuprolog.core import TermFormatter +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.core.impl as _impl # type: ignore + +DefaultTermFormatter = _impl.SimpleTermFormatter + +logger.debug("Loaded compatibility layer for JVM subtypes of " + str(TermFormatter.class_.getName())) diff --git a/tuprolog/core/operators.py b/tuprolog/core/operators.py deleted file mode 100644 index 604b012..0000000 --- a/tuprolog/core/operators.py +++ /dev/null @@ -1,74 +0,0 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.core.operators as _operators -from tuprolog.jvmutils import jiterable -from tuprolog.pyutils import iterable_or_varargs -from tuprolog.core import Atom, Integer, Struct, Term -from functools import singledispatch - - -Operator = _operators.Operator - -OperatorSet = _operators.OperatorSet - -Specifier = _operators.Specifier - - -@singledispatch -def operator(functor: str, specifier: Specifier, priority: int) -> Operator: - return Operator(functor, specifier, priority) - - -@operator.register -def _(priority: Integer, specifier: Atom, functor: Atom) -> Operator: - return Operator.fromTerms(priority, specifier, functor) - - -@operator.register -def _(term: Struct) -> Operator: - return Operator.fromTerm(term) - - -def operator_set(*operators) -> OperatorSet: - return iterable_or_varargs(operators, lambda os: OperatorSet(jiterable(os))) - - -@singledispatch -def specifier(name: str) -> Specifier: - return Specifier.valueOf(name.upper()) - - -@specifier.register -def _(term: Term) -> Specifier: - return Specifier.fromTerm(term) - - -EMPTY_OPERATORS: OperatorSet = OperatorSet.EMPTY - -DEFAULT_OPERATORS: OperatorSet = OperatorSet.DEFAULT - -STANDARD_OPERATORS: OperatorSet = OperatorSet.STANDARD - -XF: Specifier = Specifier.XF - -YF: Specifier = Specifier.YF - -FX: Specifier = Specifier.FX - -FY: Specifier = Specifier.FY - -XFX: Specifier = Specifier.XFX - -XFY: Specifier = Specifier.XFY - -YFX: Specifier = Specifier.YFX - -OperatorSet.__add__ = lambda this, other: this.plus(other) -OperatorSet.__sub__ = lambda this, other: this.minus(other) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.core.operators.*") diff --git a/tuprolog/core/operators/__init__.py b/tuprolog/core/operators/__init__.py new file mode 100644 index 0000000..501ec39 --- /dev/null +++ b/tuprolog/core/operators/__init__.py @@ -0,0 +1,3 @@ +import tuprolog.core.operators._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/core/operators/_adapters.py b/tuprolog/core/operators/_adapters.py new file mode 100644 index 0000000..8412c9a --- /dev/null +++ b/tuprolog/core/operators/_adapters.py @@ -0,0 +1,17 @@ +from tuprolog import logger +from jpype import JImplementationFor + + +@JImplementationFor("it.unibo.tuprolog.core.operators.OperatorSet") +class _KtOperatorSet: + def __jclass_init__(cls): + pass + + def __add__(self, other): + return self.plus(other) + + def __sub__(self, other): + return self.minus(other) + + +logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.core.operators.*") diff --git a/tuprolog/core/operators/_api.py b/tuprolog/core/operators/_api.py new file mode 100644 index 0000000..48b87dc --- /dev/null +++ b/tuprolog/core/operators/_api.py @@ -0,0 +1,34 @@ +from functools import singledispatch +from tuprolog.jvmutils import jiterable +from tuprolog.pyutils import iterable_or_varargs +from tuprolog.core import Atom, Integer, Struct, Term +from ._definitions import Operator, OperatorSet, Specifier + + +@singledispatch +def operator(functor: str, specifier: Specifier, priority: int) -> Operator: + return Operator(functor, specifier, priority) + + +@operator.register +def _(priority: Integer, specifier: Atom, functor: Atom) -> Operator: + return Operator.fromTerms(priority, specifier, functor) + + +@operator.register +def _(term: Struct) -> Operator: + return Operator.fromTerm(term) + + +def operator_set(*operators) -> OperatorSet: + return iterable_or_varargs(operators, lambda os: OperatorSet(jiterable(os))) + + +@singledispatch +def specifier(name: str) -> Specifier: + return Specifier.valueOf(name.upper()) + + +@specifier.register +def _(term: Term) -> Specifier: + return Specifier.fromTerm(term) diff --git a/tuprolog/core/operators/_definitions.py b/tuprolog/core/operators/_definitions.py new file mode 100644 index 0000000..c168015 --- /dev/null +++ b/tuprolog/core/operators/_definitions.py @@ -0,0 +1,45 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.core.operators as _operators # type: ignore + + +Operator = _operators.Operator + + +OperatorSet = _operators.OperatorSet + + +Specifier = _operators.Specifier + + +EMPTY_OPERATORS: OperatorSet = OperatorSet.EMPTY + + +DEFAULT_OPERATORS: OperatorSet = OperatorSet.DEFAULT + + +STANDARD_OPERATORS: OperatorSet = OperatorSet.STANDARD + + +XF: Specifier = Specifier.XF + + +YF: Specifier = Specifier.YF + + +FX: Specifier = Specifier.FX + + +FY: Specifier = Specifier.FY + + +XFX: Specifier = Specifier.XFX + + +XFY: Specifier = Specifier.XFY + + +YFX: Specifier = Specifier.YFX + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.core.operators.*") diff --git a/tuprolog/core/parsing.py b/tuprolog/core/parsing.py deleted file mode 100644 index 3ebf426..0000000 --- a/tuprolog/core/parsing.py +++ /dev/null @@ -1,133 +0,0 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.core.parsing as _parsing -from tuprolog.core import Term, Struct, Constant, Var, Atom, Numeric, Integer, Real, Clause -from tuprolog.jvmutils import InputStream - -TermParser = _parsing.TermParser - -TermReader = _parsing.TermReader - -ParseException = _parsing.ParseException - -InvalidTermTypeException = _parsing.InvalidTermTypeException - -# noinspection PyUnresolvedReferences -from tuprolog.core.operators import Operator, OperatorSet, DEFAULT_OPERATORS, EMPTY_OPERATORS - -from typing import Union, Iterable - - -def term_parser(with_default_operators: bool=True, operators: OperatorSet=None) -> TermParser: - if operators is None: - if with_default_operators: - return TermParser.getWithDefaultOperators() - else: - return TermParser.getWithNoOperator() - else: - if with_default_operators: - return TermParser.withOperators(DEFAULT_OPERATORS.plus(operators)) - else: - return TermParser.withOperators(operators) - - -def term_reader(with_default_operators: bool=True, operators: OperatorSet=None) -> TermParser: - if operators is None: - if with_default_operators: - return TermReader.getWithDefaultOperators() - else: - return TermReader.getWithNoOperator() - else: - if with_default_operators: - return TermReader.withOperators(DEFAULT_OPERATORS.plus(operators)) - else: - return TermReader.withOperators(operators) - - -DEFAULT_TERM_PARSER = term_parser() - -DEFAULT_TERM_READER = term_reader() - - -def parse_term(string: str, operators: OperatorSet=None) -> Term: - if operators is None: - return DEFAULT_TERM_PARSER.parseTerm(string) - else: - return DEFAULT_TERM_PARSER.parseTerm(string, operators) - - -def parse_struct(string: str, operators: OperatorSet=None) -> Struct: - if operators is None: - return DEFAULT_TERM_PARSER.parseStruct(string) - else: - return DEFAULT_TERM_PARSER.parseStruct(string, operators) - - -def parse_constant(string: str, operators: OperatorSet=None) -> Constant: - if operators is None: - return DEFAULT_TERM_PARSER.parseConstant(string) - else: - return DEFAULT_TERM_PARSER.parseConstant(string, operators) - - -def parse_var(string: str, operators: OperatorSet=None) -> Var: - if operators is None: - return DEFAULT_TERM_PARSER.parseVar(string) - else: - return DEFAULT_TERM_PARSER.parseVar(string, operators) - - -def parse_atom(string: str, operators: OperatorSet=None) -> Atom: - if operators is None: - return DEFAULT_TERM_PARSER.parseAtom(string) - else: - return DEFAULT_TERM_PARSER.parseAtom(string, operators) - - -def parse_numeric(string: str, operators: OperatorSet=None) -> Numeric: - if operators is None: - return DEFAULT_TERM_PARSER.parseNumeric(string) - else: - return DEFAULT_TERM_PARSER.parseNumeric(string, operators) - - -def parse_integer(string: str, operators: OperatorSet=None) -> Integer: - if operators is None: - return DEFAULT_TERM_PARSER.parseInteger(string) - else: - return DEFAULT_TERM_PARSER.parseInteger(string, operators) - - -def parse_real(string: str, operators: OperatorSet=None) -> Real: - if operators is None: - return DEFAULT_TERM_PARSER.parseReal(string) - else: - return DEFAULT_TERM_PARSER.parseReal(string, operators) - - -def parse_clause(string: str, operators: OperatorSet=None) -> Clause: - if operators is None: - return DEFAULT_TERM_PARSER.parseClause(string) - else: - return DEFAULT_TERM_PARSER.parseClause(string, operators) - - -def read_term(input: Union[InputStream, str], operators: OperatorSet=None) -> Term: - input = ensure_input_steam(input) - if operators is None: - return DEFAULT_TERM_READER.readTerm(input) - else: - return DEFAULT_TERM_READER.readTerm(input, operators) - - -def read_terms(input: Union[InputStream, str], operators: OperatorSet=None) -> Iterable[Term]: - input = ensure_input_steam(input) - if operators is None: - return DEFAULT_TERM_READER.readTerms(input) - else: - return DEFAULT_TERM_READER.readTerms(input, operators) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.core.parsing.*") diff --git a/tuprolog/core/parsing/__init__.py b/tuprolog/core/parsing/__init__.py new file mode 100644 index 0000000..f014f62 --- /dev/null +++ b/tuprolog/core/parsing/__init__.py @@ -0,0 +1,3 @@ +import tuprolog.core.parsing._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/core/parsing/_adapters.py b/tuprolog/core/parsing/_adapters.py new file mode 100644 index 0000000..2bd7d93 --- /dev/null +++ b/tuprolog/core/parsing/_adapters.py @@ -0,0 +1,81 @@ +from tuprolog import logger +from jpype import JImplementationFor +from tuprolog.jvmioutils import ensure_input_steam + + +@JImplementationFor("it.unibo.tuprolog.core.parsing.TermParser") +class _KtTermParser: + def __jclass_init__(cls): + pass + + @property + def default_operator_set(self): + return self.getDefaultOperatorSet() + + def _parse(self, method, input, operators): + if operators is None: + return method(input) + else: + return method(input, operators) + + def parse(self, input, operators=None): + return self.parse_term(input, operators) + + def parse_term(self, input, operators=None): + return self._parse(self.parseTerm, input, operators) + + def parse_struct(self, input, operators=None): + return self._parse(self.parseStruct, input, operators) + + def parse_constant(self, input, operators=None): + return self._parse(self.parseConstant, input, operators) + + def parse_var(self, input, operators=None): + return self._parse(self.parseVar, input, operators) + + def parse_atom(self, input, operators=None): + return self._parse(self.parseAtom, input, operators) + + def parse_numeric(self, input, operators=None): + return self._parse(self.parseNumeric, input, operators) + + def parse_integer(self, input, operators=None): + return self._parse(self.parseInteger, input, operators) + + def parse_real(self, input, operators=None): + return self._parse(self.parseReal, input, operators) + + def parse_clause(self, input, operators=None): + return self._parse(self.parseClause, input, operators) + + +@JImplementationFor("it.unibo.tuprolog.core.parsing.TermReader") +class _KtTermReader: + def __jclass_init__(cls): + pass + + @property + def default_operator_set(self): + return self.getDefaultOperatorSet() + + def _read(self, method, input, operators): + input_stream = ensure_input_steam(input) + if operators is None: + return method(input_stream) + else: + return method(input_stream, operators) + + def read(self, input, operators=None): + return self.read_term(input, operators) + + def read_term(self, input, operators=None): + return self._read(self.readTerm, input, operators) + + def read_all(self, input, operators=None): + return self.read_terms(input, operators) + + def read_terms(self, input, operators=None): + return self._read(self.readTerms, input, operators) + + +logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.core.parsing.*") diff --git a/tuprolog/core/parsing/_api.py b/tuprolog/core/parsing/_api.py new file mode 100644 index 0000000..a727e31 --- /dev/null +++ b/tuprolog/core/parsing/_api.py @@ -0,0 +1,70 @@ +from typing import Union, Iterable +from tuprolog.jvmioutils import InputStream +from tuprolog.core import Term, Struct, Constant, Var, Atom, Numeric, Integer, Real, Clause +from tuprolog.core.operators import OperatorSet, DEFAULT_OPERATORS +from ._definitions import TermParser, TermReader, DEFAULT_TERM_PARSER, DEFAULT_TERM_READER + + +def parser_factory(source, with_default_operators: bool = True, operators: OperatorSet = None): + if operators is None: + if with_default_operators: + return source.withDefaultOperators() + else: + return source.withNoOperator() + else: + if with_default_operators: + return source.withOperators(DEFAULT_OPERATORS.plus(operators)) + else: + return source.withOperators(operators) + + +def term_parser(with_default_operators: bool = True, operators: OperatorSet = None) -> TermParser: + return parser_factory(TermParser, with_default_operators, operators) + + +def term_reader(with_default_operators: bool = True, operators: OperatorSet = None) -> TermParser: + return parser_factory(TermReader, with_default_operators, operators) + + +def parse_term(string: str, operators: OperatorSet = None) -> Term: + return DEFAULT_TERM_PARSER.parse_term(string, operators) + + +def parse_struct(string: str, operators: OperatorSet = None) -> Struct: + return DEFAULT_TERM_PARSER.parse_struct(string, operators) + + +def parse_constant(string: str, operators: OperatorSet = None) -> Constant: + return DEFAULT_TERM_PARSER.parse_constant(string, operators) + + +def parse_var(string: str, operators: OperatorSet = None) -> Var: + return DEFAULT_TERM_PARSER.parse_var(string, operators) + + +def parse_atom(string: str, operators: OperatorSet = None) -> Atom: + return DEFAULT_TERM_PARSER.parse_atom(string, operators) + + +def parse_numeric(string: str, operators: OperatorSet = None) -> Numeric: + return DEFAULT_TERM_PARSER.parse_numeric(string, operators) + + +def parse_integer(string: str, operators: OperatorSet = None) -> Integer: + return DEFAULT_TERM_PARSER.parse_integer(string, operators) + + +def parse_real(string: str, operators: OperatorSet = None) -> Real: + return DEFAULT_TERM_PARSER.parse_real(string, operators) + + +def parse_clause(string: str, operators: OperatorSet = None) -> Clause: + return DEFAULT_TERM_PARSER.parse_clause(string, operators) + + +def read_term(input: Union[InputStream, str], operators: OperatorSet = None) -> Term: + return DEFAULT_TERM_READER.read_term(input, operators) + + +def read_terms(input: Union[InputStream, str], operators: OperatorSet = None) -> Iterable[Term]: + return DEFAULT_TERM_READER.read_terms(input, operators) diff --git a/tuprolog/core/parsing/_definitions.py b/tuprolog/core/parsing/_definitions.py new file mode 100644 index 0000000..e1a795f --- /dev/null +++ b/tuprolog/core/parsing/_definitions.py @@ -0,0 +1,23 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.core.parsing as _parsing # type: ignore + +TermParser = _parsing.TermParser + + +TermReader = _parsing.TermReader + + +ParseException = _parsing.ParseException + + +InvalidTermTypeException = _parsing.InvalidTermTypeException + + +DEFAULT_TERM_PARSER = TermParser.withDefaultOperators() + + +DEFAULT_TERM_READER = TermReader.withDefaultOperators() + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.core.parsing.*") diff --git a/tuprolog/core/visitors.py b/tuprolog/core/visitors.py deleted file mode 100644 index ca0f246..0000000 --- a/tuprolog/core/visitors.py +++ /dev/null @@ -1,102 +0,0 @@ -from tuprolog import logger -import jpype -from tuprolog.core import TermVisitor - - -@jpype.JImplements(TermVisitor) -class AbstractTermVisitor(object): - - @jpype.JOverride - def defaultValue(self, term): - raise NotImplementedError() - - @jpype.JOverride - def visitTerm(self, term): - return TermVisitor.DefaultImpls.visitTerm(self, term) - - @jpype.JOverride - def visitVar(self, term): - return TermVisitor.DefaultImpls.visitVar(self, term) - - @jpype.JOverride - def visitConstant(self, term): - return TermVisitor.DefaultImpls.visitConstant(self, term) - - @jpype.JOverride - def visitStruct(self, term): - return TermVisitor.DefaultImpls.visitStruct(self, term) - - @jpype.JOverride - def visitCollection(self, term): - return TermVisitor.DefaultImpls.visitCollection(self, term) - - @jpype.JOverride - def visitAtom(self, term): - return TermVisitor.DefaultImpls.visitAtom(self, term) - - @jpype.JOverride - def visitTruth(self, term): - return TermVisitor.DefaultImpls.visitTruth(self, term) - - @jpype.JOverride - def visitNumeric(self, term): - return TermVisitor.DefaultImpls.visitNumeric(self, term) - - @jpype.JOverride - def visitInteger(self, term): - return TermVisitor.DefaultImpls.visitInteger(self, term) - - @jpype.JOverride - def visitReal(self, term): - return TermVisitor.DefaultImpls.visitReal(self, term) - - @jpype.JOverride - def visitBlock(self, term): - return TermVisitor.DefaultImpls.visitBlock(self, term) - - @jpype.JOverride - def visitEmpty(self, term): - return TermVisitor.DefaultImpls.visitEmpty(self, term) - - @jpype.JOverride - def visitEmptyBlock(self, term): - return TermVisitor.DefaultImpls.visitEmptyBlock(self, term) - - @jpype.JOverride - def visitList(self, term): - return TermVisitor.DefaultImpls.visitList(self, term) - - @jpype.JOverride - def visitCons(self, term): - return TermVisitor.DefaultImpls.visitCons(self, term) - - @jpype.JOverride - def visitEmptyList(self, term): - return TermVisitor.DefaultImpls.visitEmptyList(self, term) - - @jpype.JOverride - def visitTuple(self, term): - return TermVisitor.DefaultImpls.visitTuple(self, term) - - @jpype.JOverride - def visitIndicator(self, term): - return TermVisitor.DefaultImpls.visitIndicator(self, term) - - @jpype.JOverride - def visitClause(self, term): - return TermVisitor.DefaultImpls.visitClause(self, term) - - @jpype.JOverride - def visitRule(self, term): - return TermVisitor.DefaultImpls.visitRule(self, term) - - @jpype.JOverride - def visitFact(self, term): - return TermVisitor.DefaultImpls.visitFact(self, term) - - @jpype.JOverride - def visitDirective(self, term): - return TermVisitor.DefaultImpls.visitDirective(self, term) - - -logger.debug("Loaded compatibility layer for JVM subtypes of " + str(TermVisitor.class_.getName())) diff --git a/tuprolog/jvmioutils.py b/tuprolog/jvmioutils.py index 221d512..4fe499b 100644 --- a/tuprolog/jvmioutils.py +++ b/tuprolog/jvmioutils.py @@ -1,14 +1,10 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import java.io as _jio -# noinspection PyUnresolvedReferences -import java.nio.file as _jnio_file -from io import IOBase, SEEK_SET from typing import Union +from io import IOBase, SEEK_SET +from tuprolog import logger +from jpype import JImplementationFor, JOverride +import jpype.imports # noqa: F401 +import java.io as _jio # type: ignore +import java.nio.file as _jnio_file # type: ignore InputStream = _jio.InputStream @@ -24,12 +20,12 @@ Paths = _jnio_file.Paths -@jpype.JImplementationFor("java.io.InputStream") +@JImplementationFor("java.io.InputStream") class _JvmInputStream: def __jclass_init__(cls): IOBase.register(cls) - @jpype.JOverride + @JOverride def close(self): self._closed = True self.close_() @@ -53,10 +49,10 @@ def isatty(self): def readable(self): return True - def seekable(self): + def seekable(self): return False - def writable(self): + def writable(self): return False def _buffer(self): diff --git a/tuprolog/jvmutils.py b/tuprolog/jvmutils.py index 2de2aa0..a88b7b1 100644 --- a/tuprolog/jvmutils.py +++ b/tuprolog/jvmutils.py @@ -1,26 +1,13 @@ +from typing import Iterable as PyIterable, Iterator as PyIterator, Mapping, MutableMapping, Callable, Any +from jpype import JImplements, JOverride, JConversion, JImplementationFor, JArray from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyProtectedMember -from _jpype import _JObject as JObjectClass -# noinspection PyUnresolvedReferences -import java.util as _jutils -# noinspection PyUnresolvedReferences -import java.lang as _jlang -# noinspection PyUnresolvedReferences -import kotlin as _kotlin -# noinspection PyUnresolvedReferences -import kotlin.sequences as _ksequences -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.utils as _tuprolog_utils - -from typing import Iterable as PyIterable -from typing import Iterator as PyIterator -from typing import Mapping, MutableMapping, Callable, Any - -from .jvmioutils import * +import jpype.imports # noqa: F401 +from _jpype import _JObject as JObjectClass, _JMethod as JMethodClass # type: ignore +import java.util as _jutils # type: ignore +import java.lang as _jlang # type: ignore +import kotlin as _kotlin # type: ignore +import kotlin.sequences as _ksequences # type: ignore +import it.unibo.tuprolog.utils as _tuprolog_utils # type: ignore Arrays = _jutils.Arrays @@ -50,14 +37,18 @@ PyUtils = _tuprolog_utils.PyUtils -@jpype.JImplements("java.util.Iterator", deferred=True) +def protect_iterable(iterable: Iterable) -> Iterable: + return PyUtils.iterable(iterable) + + +@JImplements("java.util.Iterator", deferred=True) class _IteratorAdapter(object): def __init__(self, iterator): assert isinstance(iterator, PyIterator) self._iterator = iterator self._queue = None - @jpype.JOverride + @JOverride def hasNext(self): if self._queue is None: try: @@ -74,7 +65,7 @@ def hasNext(self): except StopIteration: return False - @jpype.JOverride + @JOverride def next(self): if self.hasNext(): return self._queue.pop(0) @@ -82,13 +73,13 @@ def next(self): raise NoSuchElementException() -@jpype.JImplements("java.lang.Iterable", deferred=True) +@JImplements("java.lang.Iterable", deferred=True) class _IterableAdapter(object): def __init__(self, iterable): assert isinstance(iterable, PyIterable) self._iterable = iterable - @jpype.JOverride + @JOverride def iterator(self): return _IteratorAdapter(iter(self._iterable)) @@ -102,7 +93,7 @@ def kpair(items: PyIterable) -> Pair: return Pair(first, second) -@jpype.JConversion("kotlin.Pair", instanceof=PyIterable, excludes=str) +@JConversion("kotlin.Pair", instanceof=PyIterable, excludes=str) def _kt_pair_covert(jcls, obj): return kpair(obj) @@ -117,7 +108,7 @@ def ktriple(items: PyIterable) -> Triple: return Triple(first, second, third) -@jpype.JConversion("kotlin.Triple", instanceof=PyIterable, excludes=str) +@JConversion("kotlin.Triple", instanceof=PyIterable, excludes=str) def _kt_triple_covert(jcls, obj): return ktriple(obj) @@ -137,13 +128,13 @@ def jiterable(iterable: PyIterable) -> Iterable: return _IterableAdapter(iterable) -@jpype.JConversion("java.lang.Iterable", instanceof=PyIterable, excludes=str) +@JConversion("java.lang.Iterable", instanceof=PyIterable, excludes=str) def _java_iterable_convert(jcls, obj): return jiterable(obj) def jarray(type, rank: int = 1): - return jpype.JArray(type, rank) + return JArray(type, rank) def jiterator(iterator: PyIterator) -> Iterator: @@ -153,7 +144,7 @@ def jiterator(iterator: PyIterator) -> Iterator: def jmap(dictionary: Mapping) -> Map: assert isinstance(dictionary, Mapping) - return Map@dictionary + return Map @ dictionary def _java_obj_repr(java_object: Object) -> str: @@ -164,25 +155,25 @@ def _java_obj_repr(java_object: Object) -> str: JObjectClass.__repr__ = _java_obj_repr -@jpype.JImplementationFor("kotlin.sequences.Sequence") +@JImplementationFor("kotlin.sequences.Sequence") class _KtSequence: def __jclass_init__(self): PyIterable.register(self) def __iter__(self): - return PyUtils.iterable(self).iterator() + return protect_iterable(self).iterator() def ksequence(iterable: PyIterable) -> Sequence: - return SequencesKt.asSequence(jiterable(iterable)) + return SequencesKt.asSequence(jiterable(iterable).iterator()) -@jpype.JConversion("kotlin.sequences.Sequence", instanceof=PyIterable, excludes=str) +@JConversion("kotlin.sequences.Sequence", instanceof=PyIterable, excludes=str) def _kt_sequence_convert(jcls, obj): return ksequence(obj) -@jpype.JImplementationFor("java.util.stream.Stream") +@JImplementationFor("java.util.stream.Stream") class _JvmStream: def __jclass_init__(self): PyIterable.register(self) @@ -191,7 +182,7 @@ def __iter__(self): return self.iterator() -@jpype.JImplementationFor("java.lang.Comparable") +@JImplementationFor("java.lang.Comparable") class _JvmComparable: def __jclass_init__(self): pass @@ -209,6 +200,72 @@ def __ge__(self, other): return self.compareTo(other) >= 0 +def to_snake_case(camel_str: str) -> str: + return "".join( + "_" + x.lower() if x.isupper() and camel_str[i + 1:i + 2].islower() else x + for i, x in enumerate(camel_str) + ).lstrip("_") + + +@JImplementationFor("java.lang.Object") +class _KtObjectWithSmartPythonicAccessors: + """ + This class provides every Java imported type with Pythonic versions of its methods and properties, + unless pythonic versions would conflict with existing members. + """ + def __jclass_init__(self): + members = dir(self) + members_set = set(members) + for name in members: + member = getattr(self, name, None) + if member is None: + continue + elif name.startswith("_") or '$' in name or name == 'getClass': + continue + elif isinstance(member, JMethodClass): + if len(name) > 3: + snake_case = to_snake_case(name) + method_has_0_args = member.__annotations__.keys() == {"return"} + add_property = None + add_method = (snake_case, member) + # Shorten method name and promote to property if it's a getter + if method_has_0_args and snake_case.startswith("get_"): + property_name = snake_case[4:] + if member._isBeanAccessor(): + getter = member + # Attempt to find paired bean setter + setter_name = "set" + name.removeprefix("get") + setter = getattr(self, setter_name, None) + if setter is not None and isinstance(setter, JMethodClass) and setter._isBeanMutator(): + add_property = (property_name, property(fget=getter, fset=setter)) + else: + add_property = (property_name, property(fget=getter)) + else: + add_property = (property_name, property(fget=member)) + # Promote method to property if it's a boolean getter + elif method_has_0_args and snake_case.startswith("is_"): + add_property = (snake_case, property(fget=member)) + # Do not add method with the same name + add_method = None + # Add method and property + for to_add in (add_property, add_method): + if to_add is not None: + # Avoid conflicts with existing members + if to_add[0] not in members_set or not hasattr(self, to_add[0]): + self._customize(*to_add) + members_set.add(to_add[0]) + + +@JImplementationFor("java.lang.Throwable") +class _JvmThrowable: + def __jclass_init__(self): + pass + + @property + def message(self): + return self.getMessage() + + class _KtFunction(Callable): def __init__(self, arity: int, function: Callable): self._function = function @@ -227,12 +284,12 @@ def __call__(self, *args): def kfunction(arity: int): if arity not in _kt_function_classes: - @jpype.JImplements("kotlin.jvm.functions.Function" + str(arity), deferred=True) + @JImplements("kotlin.jvm.functions.Function" + str(arity), deferred=True) class _KtFunctionN(_KtFunction): def __init__(self, f): super().__init__(arity, f) - @jpype.JOverride + @JOverride def invoke(self, *args): return super().invoke(*args) diff --git a/tuprolog/libs/__init__.py b/tuprolog/libs/__init__.py index fcae02a..224546d 100644 --- a/tuprolog/libs/__init__.py +++ b/tuprolog/libs/__init__.py @@ -1,3 +1 @@ -from pathlib import Path - -CLASSPATH = Path(__file__).parents[0] +from .java import JAVA_HOME, CLASSPATH, find_jvm diff --git a/tuprolog/libs/java.py b/tuprolog/libs/java.py new file mode 100644 index 0000000..f8bb945 --- /dev/null +++ b/tuprolog/libs/java.py @@ -0,0 +1,31 @@ +import sys +from pathlib import Path +from jdk4py import JAVA_HOME + + +CLASSPATH = Path(__file__).parent + + +def __jvm_lib_file_names(): + if sys.platform == "win32": + return {"jvm.dll"} + elif sys.platform == "darwin": + return {"libjli.dylib"} + else: + return {"libjvm.so"} + + +def __jvmlib(): + for name in __jvm_lib_file_names(): + for path in JAVA_HOME.glob(f"**/{name}"): + path.resolve() + if path.exists: + return path + return None + + +def find_jvm() -> Path: + jvm = __jvmlib() + if jvm is None: + raise FileNotFoundError("Could not find jvm executable.") + return jvm diff --git a/tuprolog/math/__init__.py b/tuprolog/math/__init__.py new file mode 100644 index 0000000..3272497 --- /dev/null +++ b/tuprolog/math/__init__.py @@ -0,0 +1,2 @@ +from ._definitions import * +from ._api import * diff --git a/tuprolog/math/_api.py b/tuprolog/math/_api.py new file mode 100644 index 0000000..a66b4f8 --- /dev/null +++ b/tuprolog/math/_api.py @@ -0,0 +1,72 @@ +from typing import Union +import decimal +from tuprolog.pyutils import and_then +from ._definitions import BigInteger, BigDecimal, MathContext, RoundingMode +from jpype import JDouble, JString + + +def big_integer(value: Union[str, int], radix: int = None) -> BigInteger: + if radix is not None: + assert isinstance(value, str) + return BigInteger.of(value, radix) + if isinstance(value, str): + return BigInteger.of(JString @ value) + assert isinstance(value, int) + return BigInteger.of(str(value)) + + +def python_integer(value: BigInteger) -> int: + return int.from_bytes(value.toByteArray(), byteorder='big', signed=True) + + +_python_rounding_modes = {decimal.ROUND_DOWN, decimal.ROUND_HALF_UP, decimal.ROUND_HALF_EVEN, decimal.ROUND_CEILING, + decimal.ROUND_FLOOR, decimal.ROUND_UP, decimal.ROUND_HALF_DOWN, decimal.ROUND_05UP} + + +def jvm_rounding_mode(mode): + if mode == decimal.ROUND_DOWN: + return RoundingMode.DOWN + elif mode == decimal.ROUND_UP: + return RoundingMode.UP + elif mode == decimal.ROUND_FLOOR: + return RoundingMode.FLOOR + elif mode == decimal.ROUND_CEILING: + return RoundingMode.CEILING + elif mode == decimal.ROUND_HALF_UP: + return RoundingMode.HALF_UP + elif mode == decimal.ROUND_HALF_EVEN: + return RoundingMode.HALF_EVEN + elif mode == decimal.ROUND_HALF_DOWN: + return RoundingMode.HALF_DOWN + elif mode == decimal.ROUND_05UP: + raise ValueError(f"Rounding mode {decimal.ROUND_05UP} has no Java correspondence") + else: + raise ValueError(f"Not a rounding mode {mode}") + + +@and_then(lambda bd: bd.stripTrailingZeros()) +def big_decimal(value: Union[str, int, float, decimal.Decimal], precision=0, + rounding=RoundingMode.HALF_UP) -> BigDecimal: + if precision is None: + precision = decimal.getcontext().prec + assert isinstance(precision, int) + if rounding is None: + rounding = jvm_rounding_mode(decimal.getcontext().rounding) + elif rounding in _python_rounding_modes: + rounding = jvm_rounding_mode(rounding) + assert isinstance(rounding, RoundingMode) + context = MathContext(precision, rounding) + if isinstance(value, str): + return BigDecimal.of(value, context) + if isinstance(value, decimal.Decimal): + return BigDecimal.of(JString @ str(value), context) + if isinstance(value, BigInteger): + return BigDecimal.of(value, context) + if isinstance(value, int): + return BigDecimal.of(big_integer(value), context) + assert isinstance(value, float) + return BigDecimal.of(JDouble @ value, context) + + +def python_decimal(value: BigDecimal) -> decimal.Decimal: + return decimal.Decimal(str(value)) diff --git a/tuprolog/math/_definitions.py b/tuprolog/math/_definitions.py new file mode 100644 index 0000000..35d9e63 --- /dev/null +++ b/tuprolog/math/_definitions.py @@ -0,0 +1,60 @@ +import jpype.imports # noqa: F401 +import org.gciatto.kt.math as _ktmath # type: ignore +import java.lang as _java_lang # type: ignore + + +BigInteger = _ktmath.BigInteger + + +BigDecimal = _ktmath.BigDecimal + + +MathContext = _ktmath.MathContext + + +RoundingMode = _ktmath.RoundingMode + + +_MAX_LONG = _java_lang.Long.MAX_VALUE + + +_MIN_LONG = _java_lang.Long.MIN_VALUE + + +BIG_INTEGER_MAX_LONG = BigInteger.of(_MAX_LONG) + + +BIG_INTEGER_MIN_LONG = BigInteger.of(_MIN_LONG) + + +BIG_INTEGER_ZERO = BigInteger.ZERO + + +BIG_INTEGER_TEN = BigInteger.TEN + + +BIG_INTEGER_ONE = BigInteger.ONE + + +BIG_INTEGER_NEGATIVE_ONE = BigInteger.NEGATIVE_ONE + + +BIG_INTEGER_TWO = BigInteger.TWO + + +BIG_DECIMAL_ZERO = BigDecimal.ZERO + + +BIG_DECIMAL_ONE = BigDecimal.ONE + + +BIG_DECIMAL_ONE_HALF = BigDecimal.ONE_HALF + + +BIG_DECIMAL_ONE_TENTH = BigDecimal.ONE_TENTH + + +BIG_DECIMAL_E = BigDecimal.E + + +BIG_DECIMAL_PI = BigDecimal.PI diff --git a/tuprolog/pyutils.py b/tuprolog/pyutils.py index 4640456..034c1a2 100644 --- a/tuprolog/pyutils.py +++ b/tuprolog/pyutils.py @@ -30,3 +30,22 @@ def dict_or_keyword_args( for k in kwargs: all_data[k] = kwargs[k] return dispatch(all_data) + + +def and_then(continuation): + def call_and_then_continue(function): + def wrapper(*args, **kwargs): + result = function(*args, **kwargs) + return continuation(result) + return wrapper + return call_and_then_continue + + +def apply_to_result(consumer): + def call_and_then_apply(function): + def wrapper(*args, **kwargs): + result = function(*args, **kwargs) + consumer(result) + return result + return wrapper + return call_and_then_apply diff --git a/tuprolog/repl/__init__.py b/tuprolog/repl/__init__.py new file mode 100644 index 0000000..47c7575 --- /dev/null +++ b/tuprolog/repl/__init__.py @@ -0,0 +1 @@ +from ._definitions import * diff --git a/tuprolog/repl/_definitions.py b/tuprolog/repl/_definitions.py new file mode 100644 index 0000000..f12ff5f --- /dev/null +++ b/tuprolog/repl/_definitions.py @@ -0,0 +1,92 @@ +from cmd import Cmd +from typing import IO +from tuprolog.core.parsing import TermParser, ParseException +from tuprolog.theory.parsing import ClausesParser +from tuprolog.solve import solution_formatter, TermFormatter +from tuprolog.solve import Solver + + +class PrologREPL(Cmd): + use_rawinput = False + + def __init__(self, + solver: Solver, + name: str, + completekey: str = "tab", + stdin: IO[str] | None = None, + stdout: IO[str] | None = None): + super().__init__(completekey, stdin, stdout) + self.intro = f""" +Welcome to the {name.title()} REPL. + Usage + Assert a clause by typing it in. + Query the theory by typing ?- followed by a query. + Clauses and queries must end with a period, otherwise they will be + considered incomplete and you will be prompted for more input. + Type ":help" for more information, including the list of available + commands that can be used by prefixing a colon ":". + Type ":exit" to exit. +""" + self.solver = solver + self.name = name + self.clauses_parser = ClausesParser.withOperators(self.solver.operators) + self.query_parser = TermParser.withOperators(self.solver.operators) + self.solution_formatter = solution_formatter(TermFormatter.prettyExpressions(self.solver.operators)) + self.multi_line_command = "" + + @property + def prompt(self) -> str: + return "...>" if self.multi_line_command else f"{self.name}>" + + def emptyline(self) -> bool: + if self.multi_line_command: + return False + return super().emptyline() + + def precmd(self, line: str) -> str: + if line.startswith(":"): + return line + if line.endswith("."): + command = self.multi_line_command + line + self.multi_line_command = "" + return command + self.multi_line_command += line + "\n" + return "" + + def do_exit(self, arg: str) -> bool: + """Exit the REPL.""" + return True + + def parseline(self, line: str) -> tuple[str | None, str | None, str]: + line = line.strip() + if line.startswith(":"): + return super().parseline(line[1:]) + if line.startswith("?-"): + return "query", line[2:].strip(), line + return "assert", line, line + + def do_query(self, arg: str) -> bool: + """Query the theory.""" + try: + query = self.query_parser.parse_struct(arg) + solutions = self.solver.solve(query) + for solution in solutions: + formatted = str(self.solution_formatter.format(solution)) + self.stdout.write(formatted) + self.stdout.write("\n") + except ParseException as e: + self.on_parsing_error(e) + return False + + def do_assert(self, arg: str) -> bool: + """Asserts a clause, appending to the theory.""" + try: + clauses = self.clauses_parser.parseClauses(arg) + for clause in clauses: + self.solver.assertZ(clause) + except ParseException as e: + self.on_parsing_error(e) + return False + + def on_parsing_error(self, err: ParseException) -> None: + self.stdout.write(f"Error: {err.message}\n".replace("''", "end of input")) diff --git a/tuprolog/repl/problog.py b/tuprolog/repl/problog.py new file mode 100644 index 0000000..ca41e03 --- /dev/null +++ b/tuprolog/repl/problog.py @@ -0,0 +1,6 @@ +from tuprolog.repl import PrologREPL +from tuprolog.solve.problog import problog_solver + + +if __name__ == '__main__': + PrologREPL(solver=problog_solver(mutable=True), name="problog").cmdloop() diff --git a/tuprolog/repl/prolog.py b/tuprolog/repl/prolog.py new file mode 100644 index 0000000..b6d81ed --- /dev/null +++ b/tuprolog/repl/prolog.py @@ -0,0 +1,6 @@ +from tuprolog.repl import PrologREPL +from tuprolog.solve.prolog import prolog_solver + + +if __name__ == '__main__': + PrologREPL(solver=prolog_solver(mutable=True), name="prolog").cmdloop() diff --git a/tuprolog/solve/__init__.py b/tuprolog/solve/__init__.py index c915e33..ddab90b 100644 --- a/tuprolog/solve/__init__.py +++ b/tuprolog/solve/__init__.py @@ -1,115 +1,3 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports - -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve as _solve -from tuprolog.core import Indicator, Struct, Term, Substitution, EMPTY_UNIFIER, TermFormatter -from tuprolog.solve.exception import ResolutionException -from tuprolog.jvmutils import jlist, jmap, JavaSystem - -from functools import singledispatch - -from typing import Iterable, Mapping, Any - - -ExecutionContext = _solve.ExecutionContext - -ExecutionContextAware = _solve.ExecutionContextAware - -MutableSolver = _solve.MutableSolver - -Signature = _solve.Signature - -Solution = _solve.Solution - -SolutionFormatter = _solve.SolutionFormatter - -SolveOptions = _solve.SolveOptions - -Solver = _solve.Solver - -SolverFactory = _solve.SolverFactory - -Time = _solve.Time - - -@singledispatch -def signature(name: str, arity: int, vararg: bool = False) -> Signature: - return Signature(name, arity, vararg) - - -@signature.register -def _signature_from_indicator(indicator: Indicator) -> Signature: - return Signature.fromIndicator(indicator) - - -@signature.register -def _signature_from_term(term: Term) -> Signature: - return Signature.fromSignatureTerm(term) - - -@singledispatch -def yes_solution( - signature: Signature, - arguments: Iterable[Term], - substitution: Substitution.Unifier = EMPTY_UNIFIER -) -> Solution.Yes: - return Solution.yes(signature, jlist(arguments), substitution) - - -@yes_solution.register -def _yes_solution_from_query(query: Struct, substitution: Substitution.Unifier = EMPTY_UNIFIER) -> Solution.Yes: - return Solution.yes(query, substitution) - - -@singledispatch -def no_solution(signature: Signature, arguments: Iterable[Term]) -> Solution.No: - return Solution.no(signature, jlist(arguments)) - - -@no_solution.register -def _no_solution_from_query(query: Struct) -> Solution.No: - return Solution.no(query) - - -@singledispatch -def halt_solution(signature: Signature, arguments: Iterable[Term], exception: ResolutionException) -> Solution.Halt: - return Solution.halt(signature, jlist(arguments), exception) - - -@halt_solution.register -def _halt_solution_from_query(query: Struct, exception: ResolutionException) -> Solution.No: - return Solution.halt(query, exception) - - -def current_time_instant() -> int: - return JavaSystem.currentTimeMillis() - - -def solution_formatter(term_formatter: TermFormatter = TermFormatter.prettyExpressions()) -> SolutionFormatter: - return SolutionFormatter.of(term_formatter) - - -MAX_TIMEOUT: int = SolveOptions.MAX_TIMEOUT - -ALL_SOLUTIONS: int = SolveOptions.ALL_SOLUTIONS - - -def solve_options( - lazy: bool = True, - timeout: int = MAX_TIMEOUT, - limit: int = ALL_SOLUTIONS, - custom: Mapping[str, Any] = dict(), - **kwargs: Any -) -> SolveOptions: - opts = dict(kwargs) - for key in custom: - opts[key] = custom[key] - temp = SolveOptions.of(lazy, timeout, limit) - if len(opts) > 0: - return temp.setOptions(jmap(opts)) - return temp - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.*") +import tuprolog.theory._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/_adapters.py b/tuprolog/solve/_adapters.py new file mode 100644 index 0000000..afcf48d --- /dev/null +++ b/tuprolog/solve/_adapters.py @@ -0,0 +1,123 @@ +from itertools import chain +from jpype import JImplementationFor, JOverride +from tuprolog import logger +from tuprolog.pyutils import iterable_or_varargs + + +@JImplementationFor("it.unibo.tuprolog.solve.SolveOptions") +class _KtSolveOptions: + + _static_keys = {'lazy', 'is_lazy', 'eager', 'is_eager', 'timeout', 'limit'} + + @property + def is_lazy(self): + return self.isLazy() + + @property + def is_eager(self): + return self.isEager() + + @property + def timeout(self): + return self.getTimeout() + + @property + def limit(self): + return self.getLimit() + + @property + def options(self): + return self.getOptions() + + def __len__(self): + return 4 + len(self.options) + + def __iter__(self): + return chain(_KtSolveOptions._static_keys, self.options) + + def __contains__(self, item): + return item in _KtSolveOptions._static_keys + + def __getitem__(self, item, default=None): + if item in {'lazy', 'is_lazy'}: + return self.is_lazy + elif item in {'eager', 'is_eager'}: + return self.is_eager + elif item == 'timeout': + return self.timeout + elif item == 'limit': + return self.limit + elif item in self.options: + return self.options[item] + elif default is not None: + return default + return KeyError(f"No such option: {item}") + + +@JImplementationFor("it.unibo.tuprolog.solve.Solver") +class _KtSolver: + def __jclass_init__(self): + pass + + @JOverride + def solve(self, goal, options=None): + if options is None: + return self.solve_(goal) + elif options.is_eager: + return self.solveList(goal, options) + else: + return self.solve_(goal, options) + + @JOverride + def solve_once(self, goal, options=None): + if options is None: + return self.solveOnce(goal) + else: + return self.solveOnce(goal, options) + + +@JImplementationFor("it.unibo.tuprolog.solve.MutableSolver") +class _KtMutableSolver: + def __jclass_init__(self): + pass + + def load_static_clauses(self, *clauses): + return iterable_or_varargs(clauses, lambda cs: self.loadStaticClauses(cs)) + + def load_dynamic_clauses(self, *clauses): + return iterable_or_varargs(clauses, lambda cs: self.loadDynamicClauses(cs)) + + @property + def standard_output(self): + return self.getStandardOutput() + + @property + def standard_input(self): + return self.getStandardInput() + + @property + def standard_error(self): + return self.getStandardError() + + @property + def warnings(self): + return self.getWarnings() + + @standard_input.setter + def standard_input(self, channel): + return self.setStandardInput(channel) + + @standard_output.setter + def standard_output(self, channel): + return self.setStandardOutput(channel) + + @standard_error.setter + def standard_error(self, channel): + return self.setStandardError(channel) + + @warnings.setter + def warnings(self, channel): + return self.setWarnings(channel) + + +logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.solve.*") diff --git a/tuprolog/solve/_api.py b/tuprolog/solve/_api.py new file mode 100644 index 0000000..46fa75c --- /dev/null +++ b/tuprolog/solve/_api.py @@ -0,0 +1,79 @@ +from typing import Iterable, Mapping, Any +from functools import singledispatch +from tuprolog.jvmutils import jlist, jmap, JavaSystem +from tuprolog.core import Indicator, Struct, Term, Substitution, EMPTY_UNIFIER, TermFormatter +from .exception import ResolutionException +from ._definitions import Signature, Solution, SolveOptions, SolutionFormatter, MAX_TIMEOUT, ALL_SOLUTIONS + + +@singledispatch +def signature(name: str, arity: int, vararg: bool = False) -> Signature: + return Signature(name, arity, vararg) + + +@signature.register +def _signature_from_indicator(indicator: Indicator) -> Signature: + return Signature.fromIndicator(indicator) + + +@signature.register +def _signature_from_term(term: Term) -> Signature: + return Signature.fromSignatureTerm(term) + + +@singledispatch +def yes_solution( + signature: Signature, + arguments: Iterable[Term], + substitution: Substitution.Unifier = EMPTY_UNIFIER +) -> Solution.Yes: + return Solution.yes(signature, jlist(arguments), substitution) + + +@yes_solution.register +def _yes_solution_from_query(query: Struct, substitution: Substitution.Unifier = EMPTY_UNIFIER) -> Solution.Yes: + return Solution.yes(query, substitution) + + +@singledispatch +def no_solution(signature: Signature, arguments: Iterable[Term]) -> Solution.No: + return Solution.no(signature, jlist(arguments)) + + +@no_solution.register +def _no_solution_from_query(query: Struct) -> Solution.No: + return Solution.no(query) + + +@singledispatch +def halt_solution(signature: Signature, arguments: Iterable[Term], exception: ResolutionException) -> Solution.Halt: + return Solution.halt(signature, jlist(arguments), exception) + + +@halt_solution.register +def _halt_solution_from_query(query: Struct, exception: ResolutionException) -> Solution.No: + return Solution.halt(query, exception) + + +def current_time_instant() -> int: + return JavaSystem.currentTimeMillis() + + +def solution_formatter(term_formatter: TermFormatter = TermFormatter.prettyExpressions()) -> SolutionFormatter: + return SolutionFormatter.of(term_formatter) + + +def solve_options( + lazy: bool = True, + timeout: int = MAX_TIMEOUT, + limit: int = ALL_SOLUTIONS, + custom: Mapping[str, Any] = dict(), + **kwargs: Any +) -> SolveOptions: + opts = dict(kwargs) + for key in custom: + opts[key] = custom[key] + temp = SolveOptions.of(lazy, timeout, limit) + if len(opts) > 0: + return temp.setOptions(jmap(opts)) + return temp diff --git a/tuprolog/solve/_definitions.py b/tuprolog/solve/_definitions.py new file mode 100644 index 0000000..ecff6f3 --- /dev/null +++ b/tuprolog/solve/_definitions.py @@ -0,0 +1,48 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve as _solve # type: ignore + + +Durable = _solve.Durable + + +ExecutionContext = _solve.ExecutionContext + + +ExecutionContextAware = _solve.ExecutionContextAware + + +MutableSolver = _solve.MutableSolver + + +Signature = _solve.Signature + + +Solution = _solve.Solution + + +SolutionFormatter = _solve.SolutionFormatter + + +SolveOptions = _solve.SolveOptions + + +Solver = _solve.Solver + + +SolverBuilder = _solve.SolverBuilder + + +SolverFactory = _solve.SolverFactory + + +Time = _solve.Time + + +MAX_TIMEOUT: int = SolveOptions.MAX_TIMEOUT + + +ALL_SOLUTIONS: int = SolveOptions.ALL_SOLUTIONS + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.*") diff --git a/tuprolog/solve/_ktadapt.py b/tuprolog/solve/_ktadapt.py deleted file mode 100644 index b123ce1..0000000 --- a/tuprolog/solve/_ktadapt.py +++ /dev/null @@ -1,13 +0,0 @@ -from tuprolog import logger - -# noinspection PyUnresolvedReferences -import jpype - - -@jpype.JImplementationFor("it.unibo.tuprolog.solve.SolverFactory") -class _KtSolverFactory: - def __jclass_init__(self): - pass - - -logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.solve.*") diff --git a/tuprolog/solve/channel/__init__.py b/tuprolog/solve/channel/__init__.py index ce67d3f..3272497 100644 --- a/tuprolog/solve/channel/__init__.py +++ b/tuprolog/solve/channel/__init__.py @@ -1,100 +1,2 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.channel as _channel -# noinspection PyUnresolvedReferences -import kotlin.jvm.functions as _kfunctions -from tuprolog.jvmutils import jmap, kfunction -from typing import Callable, Mapping -from functools import singledispatch - -Channel = _channel.Channel - -ChannelStore = _channel.ChannelStore - -InputChannel = _channel.InputChannel - -InputStore = _channel.InputStore - -OutputChannel = _channel.OutputChannel - -OutputStore = _channel.OutputStore - -Listener = _kfunctions.Function1 - - -def std_in() -> InputChannel: - return InputChannel.stdIn() - - -@singledispatch -def input_channel(generator: Callable, availability_checker: Callable = None) -> InputChannel: - if availability_checker is None: - return InputChannel.of(kfunction(0)(generator)) - else: - return InputChannel.of(kfunction(0)(generator), kfunction(0)(availability_checker)) - - -@input_channel.register -def input_channel_from_string(string: str) -> InputChannel: - return InputChannel.of(string) - - -def input_store(stdin: InputChannel = None, channels: Mapping[str, InputChannel] = None) -> InputStore: - if stdin is None and channels is None: - return InputStore.fromStandard() - elif channels is None: - return InputStore.fromStandard(stdin) - else: - cs = {InputStore.STDIN: stdin or std_in()} - for k, v in channels: - cs[k] = v - return InputStore.of(jmap(cs)) - - -def std_out() -> OutputChannel: - return OutputChannel.stdOut() - - -def std_err() -> OutputChannel: - return OutputChannel.stdErr() - - -def warn() -> OutputChannel: - return OutputChannel.warn() - - -def output_channel(consumer: Callable) -> OutputChannel: - return OutputChannel.of(kfunction(1)(consumer)) - - -def output_store( - stdout: OutputChannel = None, - stderr: OutputChannel = None, - warnings: OutputChannel = None, - channels: Mapping[str, OutputChannel] = None -) -> OutputStore: - if all((channel is None for channel in (stdout, stderr, warnings))): - return OutputStore.fromStandard() - elif channels is None: - return OutputStore.fromStandard( - stdout or std_out(), - stderr or std_err(), - warnings or warn() - ) - else: - cs = { - OutputStore.STDOUT: stdout or std_out(), - OutputStore.STDERR: stderr or std_err() - } - for k, v in channels: - cs[k] = v - return OutputStore.of(jmap(cs), warnings or warn()) - - -def listener(consumer: Callable) -> Listener: - return kfunction(1)(consumer) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.channel.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/channel/_api.py b/tuprolog/solve/channel/_api.py new file mode 100644 index 0000000..6a85ce2 --- /dev/null +++ b/tuprolog/solve/channel/_api.py @@ -0,0 +1,77 @@ +from typing import Callable, Mapping +from functools import singledispatch +from tuprolog.jvmutils import jmap, kfunction +from ._definitions import InputChannel, InputStore, OutputChannel, OutputStore, Listener + + +def std_in() -> InputChannel: + return InputChannel.stdIn() + + +@singledispatch +def input_channel(generator: Callable, availability_checker: Callable = None) -> InputChannel: + if availability_checker is None: + return InputChannel.of(kfunction(0)(generator)) + else: + return InputChannel.of(kfunction(0)(generator), kfunction(0)(availability_checker)) + + +@input_channel.register +def input_channel_from_string(string: str) -> InputChannel: + return InputChannel.of(string) + + +def input_store(stdin: InputChannel = None, channels: Mapping[str, InputChannel] = None) -> InputStore: + if stdin is None and channels is None: + return InputStore.fromStandard() + elif channels is None: + return InputStore.fromStandard(stdin) + else: + cs = {InputStore.STDIN: stdin or std_in()} + for k, v in channels: + cs[k] = v + return InputStore.of(jmap(cs)) + + +def std_out() -> OutputChannel: + return OutputChannel.stdOut() + + +def std_err() -> OutputChannel: + return OutputChannel.stdErr() + + +def warn() -> OutputChannel: + return OutputChannel.warn() + + +def output_channel(consumer: Callable) -> OutputChannel: + return OutputChannel.of(kfunction(1)(consumer)) + + +def output_store( + stdout: OutputChannel = None, + stderr: OutputChannel = None, + warnings: OutputChannel = None, + channels: Mapping[str, OutputChannel] = None +) -> OutputStore: + if all((channel is None for channel in (stdout, stderr, warnings))): + return OutputStore.fromStandard() + elif channels is None: + return OutputStore.fromStandard( + stdout or std_out(), + stderr or std_err(), + warnings or warn() + ) + else: + cs = { + OutputStore.STDOUT: stdout or std_out(), + OutputStore.STDERR: stderr or std_err() + } + for k, v in channels: + cs[k] = v + return OutputStore.of(jmap(cs), warnings or warn()) + + +def listener(consumer: Callable) -> Listener: + return kfunction(1)(consumer) diff --git a/tuprolog/solve/channel/_definitions.py b/tuprolog/solve/channel/_definitions.py new file mode 100644 index 0000000..d260b51 --- /dev/null +++ b/tuprolog/solve/channel/_definitions.py @@ -0,0 +1,28 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.channel as _channel # type: ignore +import kotlin.jvm.functions as _kfunctions # type: ignore + + +Channel = _channel.Channel + + +ChannelStore = _channel.ChannelStore + + +InputChannel = _channel.InputChannel + + +InputStore = _channel.InputStore + + +OutputChannel = _channel.OutputChannel + + +OutputStore = _channel.OutputStore + + +Listener = _kfunctions.Function1 + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.channel.*") diff --git a/tuprolog/solve/classic/__init__.py b/tuprolog/solve/classic/__init__.py deleted file mode 100644 index c2de785..0000000 --- a/tuprolog/solve/classic/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -from tuprolog.solve.flags import DEFAULT_FLAG_STORE, FlagStore -from tuprolog.solve.library import libraries, Libraries -from tuprolog.solve.channel import InputChannel, OutputChannel, std_out, std_in, std_err, warn -from tuprolog.theory import theory, mutable_theory, Theory -from tuprolog.solve import Solver, SolverFactory - - -_CLASSIC_SOLVER_FACTORY = Solver.getClassic() - - -def classic_solver( - libraries: Libraries = libraries(), - flags: FlagStore = DEFAULT_FLAG_STORE, - static_kb: Theory = theory(), - dynamic_kb: Theory = mutable_theory(), - std_in: InputChannel = std_in(), - std_out: OutputChannel = std_out(), - std_err: OutputChannel = std_err(), - warning: OutputChannel = warn(), - mutable: bool = True -) -> Solver: - if mutable: - return _CLASSIC_SOLVER_FACTORY.mutableSolverWithDefaultBuiltins( - libraries, flags, static_kb, dynamic_kb, std_in, std_out, std_err, warning - ) - else: - return _CLASSIC_SOLVER_FACTORY.solverWithDefaultBuiltins( - libraries, flags, static_kb, dynamic_kb, std_in, std_out, std_err, warning - ) - - -def classic_solver_factory() -> SolverFactory: - return _CLASSIC_SOLVER_FACTORY diff --git a/tuprolog/solve/data/__init__.py b/tuprolog/solve/data/__init__.py index 28ed54a..3272497 100644 --- a/tuprolog/solve/data/__init__.py +++ b/tuprolog/solve/data/__init__.py @@ -1,35 +1,2 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.data as _data -from tuprolog.jvmutils import Map -from tuprolog.pyutils import dict_or_keyword_args -from tuprolog.jvmutils import jmap -from typing import Mapping, Any - - -CustomDataStore = _data.CustomDataStore - -CustomData = Map - - -def custom_data(data: Mapping[str, Any] = {}, **kwargs) -> CustomData: - return dict_or_keyword_args(data, kwargs, lambda ds: jmap(ds)) - - -EMPTY_DATA: CustomData = custom_data() - - -def custom_data_store( - persistent: CustomData = EMPTY_DATA, - durable: CustomData = EMPTY_DATA, - ephemeral: CustomData = EMPTY_DATA -) -> CustomDataStore: - return CustomDataStore.empty().copy(persistent, durable, ephemeral) - - -EMPTY_DATA_STORE: CustomDataStore = CustomDataStore.empty() - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.data.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/data/_api.py b/tuprolog/solve/data/_api.py new file mode 100644 index 0000000..dd1fc17 --- /dev/null +++ b/tuprolog/solve/data/_api.py @@ -0,0 +1,16 @@ +from typing import Mapping, Any +from tuprolog.pyutils import dict_or_keyword_args +from tuprolog.jvmutils import jmap +from ._definitions import CustomData, CustomDataStore, EMPTY_DATA + + +def custom_data(data: Mapping[str, Any] = {}, **kwargs) -> CustomData: + return dict_or_keyword_args(data, kwargs, lambda ds: jmap(ds)) + + +def custom_data_store( + persistent: CustomData = EMPTY_DATA, + durable: CustomData = EMPTY_DATA, + ephemeral: CustomData = EMPTY_DATA +) -> CustomDataStore: + return CustomDataStore.empty().copy(persistent, durable, ephemeral) diff --git a/tuprolog/solve/data/_definitions.py b/tuprolog/solve/data/_definitions.py new file mode 100644 index 0000000..49894c1 --- /dev/null +++ b/tuprolog/solve/data/_definitions.py @@ -0,0 +1,19 @@ +from tuprolog import logger +from tuprolog.jvmutils import Map +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.data as _data # type: ignore + + +CustomDataStore = _data.CustomDataStore + + +CustomData = Map + + +EMPTY_DATA: CustomData = Map @ {} + + +EMPTY_DATA_STORE: CustomDataStore = CustomDataStore.empty() + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.data.*") diff --git a/tuprolog/solve/exception/__init__.py b/tuprolog/solve/exception/__init__.py index 1e433c5..47c7575 100644 --- a/tuprolog/solve/exception/__init__.py +++ b/tuprolog/solve/exception/__init__.py @@ -1,18 +1 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception as _exceptions - -HaltException = _exceptions.HaltException - -LogicError = _exceptions.LogicError - -ResolutionException = _exceptions.ResolutionException - -TimeOutException = _exceptions.TimeOutException - -Warning = _exceptions.Warning - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.*") +from ._definitions import * diff --git a/tuprolog/solve/exception/_definitions.py b/tuprolog/solve/exception/_definitions.py new file mode 100644 index 0000000..995b9c7 --- /dev/null +++ b/tuprolog/solve/exception/_definitions.py @@ -0,0 +1,21 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception as _exceptions # type: ignore + + +HaltException = _exceptions.HaltException + + +LogicError = _exceptions.LogicError + + +ResolutionException = _exceptions.ResolutionException + + +TimeOutException = _exceptions.TimeOutException + + +Warning = _exceptions.Warning + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.*") diff --git a/tuprolog/solve/exception/error/domain/__init__.py b/tuprolog/solve/exception/error/domain/__init__.py index d0f75f4..3272497 100644 --- a/tuprolog/solve/exception/error/domain/__init__.py +++ b/tuprolog/solve/exception/error/domain/__init__.py @@ -1,137 +1,2 @@ -from typing import Iterable, Union -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors -from tuprolog.core import Term -from tuprolog.solve import ExecutionContext, Signature - -DomainError = errors.DomainError - -Domain = DomainError.Expected - -DOMAIN_wATOM_PROPERTY = Domain.ATOM_PROPERTY - -DOMAIN_BUFFERING_MODE = Domain.BUFFERING_MODE - -DOMAIN_CHARACTER_CODE_LIST = Domain.CHARACTER_CODE_LIST - -DOMAIN_CLOSE_OPTION = Domain.CLOSE_OPTION - -DOMAIN_DATE_TIME = Domain.DATE_TIME - -DOMAIN_EOF_ACTION = Domain.EOF_ACTION - -DOMAIN_FLAG_VALUE = Domain.FLAG_VALUE - -DOMAIN_FORMAT_CONTROL_SEQUENCE = Domain.FORMAT_CONTROL_SEQUENCE - -DOMAIN_IO_MODE = Domain.IO_MODE - -DOMAIN_WELL_FORMED_LIST = Domain.WELL_FORMED_LIST - -DOMAIN_NON_EMPTY_LIST = Domain.NON_EMPTY_LIST - -DOMAIN_NOT_LESS_THAN_ZERO = Domain.NOT_LESS_THAN_ZERO - -DOMAIN_OPERATOR_PRIORITY = Domain.OPERATOR_PRIORITY - -DOMAIN_OPERATOR_SPECIFIER = Domain.OPERATOR_SPECIFIER - -DOMAIN_ORDER = Domain.ORDER - -DOMAIN_OS_FILE_PERMISSION = Domain.OS_FILE_PERMISSION - -DOMAIN_OS_FILE_PROPERTY = Domain.OS_FILE_PROPERTY - -DOMAIN_OS_PATH = Domain.OS_PATH - -DOMAIN_PREDICATE_PROPERTY = Domain.PREDICATE_PROPERTY - -DOMAIN_FLAG = Domain.FLAG - -DOMAIN_READ_OPTION = Domain.READ_OPTION - -DOMAIN_SELECTABLE_ITEM = Domain.SELECTABLE_ITEM - -DOMAIN_SOCKET_ADDRESS = Domain.SOCKET_ADDRESS - -DOMAIN_SOCKET_DOMAIN = Domain.SOCKET_DOMAIN - -DOMAIN_SOURCE_SINK = Domain.SOURCE_SINK - -DOMAIN_STREAM = Domain.STREAM - -DOMAIN_STREAM_OPTION = Domain.STREAM_OPTION - -DOMAIN_STREAM_OR_ALIAS = Domain.STREAM_OR_ALIAS - -DOMAIN_STREAM_POSITION = Domain.STREAM_POSITION - -DOMAIN_STREAM_PROPERTY = Domain.STREAM_PROPERTY - -DOMAIN_STREAM_SEEK_METHOD = Domain.STREAM_SEEK_METHOD - -DOMAIN_STREAM_TYPE = Domain.STREAM_TYPE - -DOMAIN_TERM_STREAM_OR_ALIAS = Domain.TERM_STREAM_OR_ALIAS - -DOMAIN_VAR_BINDING_OPTION = Domain.VAR_BINDING_OPTION - -DOMAIN_WRITE_OPTION = Domain.WRITE_OPTION - -DOMAIN_CLAUSE = Domain.CLAUSE - -DOMAIN_RULE = Domain.RULE - -DOMAIN_FACT = Domain.FACT - -DIRECTIVE = Domain.DIRECTIVE - - -def domain_error_for_flag_values( - context: ExecutionContext, - procedure: Signature, - flag_values: Iterable[Term], - actual: Term, - index: int = None -) -> DomainError: - return DomainError.forFlagValues(context, procedure, flag_values, actual, index) - - -def domain_error_for_argument( - context: ExecutionContext, - procedure: Signature, - expected: Domain, - actual: Term, - index: int = None -) -> DomainError: - return DomainError.forArgument(context, procedure, expected, actual, index) - - -def domain_error_for_term( - context: ExecutionContext, - expected: Domain, - actual_value: Term, -) -> DomainError: - return DomainError.forTerm(context, expected, actual_value) - - -def domain_error_for_goal( - context: ExecutionContext, - procedure: Signature, - expected: Domain, - actual: Term, -) -> DomainError: - return DomainError.forGoal(context, procedure, expected, actual) - - -def domain(name: Union[str, Term]) -> Domain: - if isinstance(name, str): - return Domain.of(name) - else: - return Domain.fromTerm(name) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.DomainError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/domain/_api.py b/tuprolog/solve/exception/error/domain/_api.py new file mode 100644 index 0000000..ce87447 --- /dev/null +++ b/tuprolog/solve/exception/error/domain/_api.py @@ -0,0 +1,48 @@ +from typing import Iterable, Union +from tuprolog.core import Term +from tuprolog.solve import ExecutionContext, Signature +from ._definitions import DomainError, Domain + + +def domain_error_for_flag_values( + context: ExecutionContext, + procedure: Signature, + flag_values: Iterable[Term], + actual: Term, + index: int = None +) -> DomainError: + return DomainError.forFlagValues(context, procedure, flag_values, actual, index) + + +def domain_error_for_argument( + context: ExecutionContext, + procedure: Signature, + expected: Domain, + actual: Term, + index: int = None +) -> DomainError: + return DomainError.forArgument(context, procedure, expected, actual, index) + + +def domain_error_for_term( + context: ExecutionContext, + expected: Domain, + actual_value: Term, +) -> DomainError: + return DomainError.forTerm(context, expected, actual_value) + + +def domain_error_for_goal( + context: ExecutionContext, + procedure: Signature, + expected: Domain, + actual: Term, +) -> DomainError: + return DomainError.forGoal(context, procedure, expected, actual) + + +def domain(name: Union[str, Term]) -> Domain: + if isinstance(name, str): + return Domain.of(name) + else: + return Domain.fromTerm(name) diff --git a/tuprolog/solve/exception/error/domain/_definitions.py b/tuprolog/solve/exception/error/domain/_definitions.py new file mode 100644 index 0000000..31aeb20 --- /dev/null +++ b/tuprolog/solve/exception/error/domain/_definitions.py @@ -0,0 +1,129 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as errors # type: ignore + + +DomainError = errors.DomainError + + +Domain = DomainError.Expected + + +DOMAIN_wATOM_PROPERTY = Domain.ATOM_PROPERTY + + +DOMAIN_BUFFERING_MODE = Domain.BUFFERING_MODE + + +DOMAIN_CHARACTER_CODE_LIST = Domain.CHARACTER_CODE_LIST + + +DOMAIN_CLOSE_OPTION = Domain.CLOSE_OPTION + + +DOMAIN_DATE_TIME = Domain.DATE_TIME + + +DOMAIN_EOF_ACTION = Domain.EOF_ACTION + + +DOMAIN_FLAG_VALUE = Domain.FLAG_VALUE + + +DOMAIN_FORMAT_CONTROL_SEQUENCE = Domain.FORMAT_CONTROL_SEQUENCE + + +DOMAIN_IO_MODE = Domain.IO_MODE + + +DOMAIN_WELL_FORMED_LIST = Domain.WELL_FORMED_LIST + + +DOMAIN_NON_EMPTY_LIST = Domain.NON_EMPTY_LIST + + +DOMAIN_NOT_LESS_THAN_ZERO = Domain.NOT_LESS_THAN_ZERO + + +DOMAIN_OPERATOR_PRIORITY = Domain.OPERATOR_PRIORITY + + +DOMAIN_OPERATOR_SPECIFIER = Domain.OPERATOR_SPECIFIER + + +DOMAIN_ORDER = Domain.ORDER + + +DOMAIN_OS_FILE_PERMISSION = Domain.OS_FILE_PERMISSION + + +DOMAIN_OS_FILE_PROPERTY = Domain.OS_FILE_PROPERTY + + +DOMAIN_OS_PATH = Domain.OS_PATH + + +DOMAIN_PREDICATE_PROPERTY = Domain.PREDICATE_PROPERTY + + +DOMAIN_FLAG = Domain.FLAG + + +DOMAIN_READ_OPTION = Domain.READ_OPTION + + +DOMAIN_SELECTABLE_ITEM = Domain.SELECTABLE_ITEM + + +DOMAIN_SOCKET_ADDRESS = Domain.SOCKET_ADDRESS + + +DOMAIN_SOCKET_DOMAIN = Domain.SOCKET_DOMAIN + + +DOMAIN_SOURCE_SINK = Domain.SOURCE_SINK + + +DOMAIN_STREAM = Domain.STREAM + + +DOMAIN_STREAM_OPTION = Domain.STREAM_OPTION + + +DOMAIN_STREAM_OR_ALIAS = Domain.STREAM_OR_ALIAS + + +DOMAIN_STREAM_POSITION = Domain.STREAM_POSITION + + +DOMAIN_STREAM_PROPERTY = Domain.STREAM_PROPERTY + + +DOMAIN_STREAM_SEEK_METHOD = Domain.STREAM_SEEK_METHOD + + +DOMAIN_STREAM_TYPE = Domain.STREAM_TYPE + + +DOMAIN_TERM_STREAM_OR_ALIAS = Domain.TERM_STREAM_OR_ALIAS + + +DOMAIN_VAR_BINDING_OPTION = Domain.VAR_BINDING_OPTION + + +DOMAIN_WRITE_OPTION = Domain.WRITE_OPTION + + +DOMAIN_CLAUSE = Domain.CLAUSE + + +DOMAIN_RULE = Domain.RULE + + +DOMAIN_FACT = Domain.FACT + + +DIRECTIVE = Domain.DIRECTIVE + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.DomainError.*") diff --git a/tuprolog/solve/exception/error/evaluation/__init__.py b/tuprolog/solve/exception/error/evaluation/__init__.py index b0e8494..3272497 100644 --- a/tuprolog/solve/exception/error/evaluation/__init__.py +++ b/tuprolog/solve/exception/error/evaluation/__init__.py @@ -1,40 +1,2 @@ -from typing import Union -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors -from tuprolog.core import Term, atom -from tuprolog.solve import ExecutionContext - -EvaluationError = errors.EvaluationError - -ErrorType = EvaluationError.Type - -ERROR_INT_OVERFLOW = ErrorType.INT_OVERFLOW - -ERROR_FLOAT_OVERFLOW = ErrorType.FLOAT_OVERFLOW - -ERROR_UNDERFLOW = ErrorType.UNDERFLOW - -ERROR_ZERO_DIVISOR = ErrorType.ZERO_DIVISOR - -ERROR_UNDEFINED = ErrorType.UNDEFINED - - -def evaluation_error( - context: ExecutionContext, - type: ErrorType, - message: str -) -> EvaluationError: - return EvaluationError(message, None, context, type, atom(message)) - - -def error_type(name: Union[str, Term]) -> ErrorType: - if isinstance(name, str): - return ErrorType.valueOf(name) - else: - return ErrorType.fromTerm(name) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.EvaluationError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/evaluation/_api.py b/tuprolog/solve/exception/error/evaluation/_api.py new file mode 100644 index 0000000..06463ee --- /dev/null +++ b/tuprolog/solve/exception/error/evaluation/_api.py @@ -0,0 +1,19 @@ +from typing import Union +from tuprolog.core import Term, atom +from tuprolog.solve import ExecutionContext +from ._definitions import EvaluationError, ErrorType + + +def evaluation_error( + context: ExecutionContext, + type: ErrorType, + message: str +) -> EvaluationError: + return EvaluationError(message, None, context, type, atom(message)) + + +def error_type(name: Union[str, Term]) -> ErrorType: + if isinstance(name, str): + return ErrorType.valueOf(name) + else: + return ErrorType.fromTerm(name) diff --git a/tuprolog/solve/exception/error/evaluation/_definitions.py b/tuprolog/solve/exception/error/evaluation/_definitions.py new file mode 100644 index 0000000..3715b89 --- /dev/null +++ b/tuprolog/solve/exception/error/evaluation/_definitions.py @@ -0,0 +1,27 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as errors # type: ignore + + +EvaluationError = errors.EvaluationError + + +ErrorType = EvaluationError.Type + + +ERROR_INT_OVERFLOW = ErrorType.INT_OVERFLOW + + +ERROR_FLOAT_OVERFLOW = ErrorType.FLOAT_OVERFLOW + + +ERROR_UNDERFLOW = ErrorType.UNDERFLOW + + +ERROR_ZERO_DIVISOR = ErrorType.ZERO_DIVISOR + + +ERROR_UNDEFINED = ErrorType.UNDEFINED + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.EvaluationError.*") diff --git a/tuprolog/solve/exception/error/existence/__init__.py b/tuprolog/solve/exception/error/existence/__init__.py index bec8185..3272497 100644 --- a/tuprolog/solve/exception/error/existence/__init__.py +++ b/tuprolog/solve/exception/error/existence/__init__.py @@ -1,75 +1,2 @@ -from typing import Union -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors -from tuprolog.core import Term, Atom -from tuprolog.solve import ExecutionContext, Signature - -ExistenceError = errors.ExistenceError - -ObjectType = ExistenceError.ObjectType - -OBJECT_PROCEDURE = ObjectType.PROCEDURE - -OBJECT_SOURCE_SINK = ObjectType.SOURCE_SINK - -OBJECT_RESOURCE = ObjectType.RESOURCE - -OBJECT_STREAM = ObjectType.STREAM - -OBJECT_OOP_ALIAS = ObjectType.OOP_ALIAS - -OBJECT_OOP_METHOD = ObjectType.OOP_METHOD - -OBJECT_OOP_CONSTRUCTOR = ObjectType.OOP_CONSTRUCTOR - -OBJECT_OOP_PROPERTY = ObjectType.OOP_PROPERTY - - -def existence_error( - context: ExecutionContext, - type: ObjectType, - culprit: Term, - message: str -) -> ExistenceError: - return ExistenceError.of(context, type, culprit, message) - - -def existence_error_for_source_sink( - context: ExecutionContext, - alias: Union[Atom, str] -) -> ExistenceError: - return ExistenceError.forSourceSink(context, alias) - - -def existence_error_for_procedure( - context: ExecutionContext, - procedure: Signature -) -> ExistenceError: - return ExistenceError.forProcedure(context, procedure) - - -def existence_error_for_stream( - context: ExecutionContext, - stream: Term -) -> ExistenceError: - return ExistenceError.forStream(context, stream) - - -def existence_error_for_resource( - context: ExecutionContext, - name: str -) -> ExistenceError: - return ExistenceError.forResource(context, name) - - -def object_type(name: Union[str, Term]) -> ObjectType: - if isinstance(name, str): - return ObjectType.of(name) - else: - return ObjectType.fromTerm(name) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.ExistenceError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/existence/_api.py b/tuprolog/solve/exception/error/existence/_api.py new file mode 100644 index 0000000..adcfd9e --- /dev/null +++ b/tuprolog/solve/exception/error/existence/_api.py @@ -0,0 +1,48 @@ +from typing import Union +from tuprolog.core import Term, Atom +from tuprolog.solve import ExecutionContext, Signature +from ._definitions import ExistenceError, ObjectType + + +def existence_error( + context: ExecutionContext, + type: ObjectType, + culprit: Term, + message: str +) -> ExistenceError: + return ExistenceError.of(context, type, culprit, message) + + +def existence_error_for_source_sink( + context: ExecutionContext, + alias: Union[Atom, str] +) -> ExistenceError: + return ExistenceError.forSourceSink(context, alias) + + +def existence_error_for_procedure( + context: ExecutionContext, + procedure: Signature +) -> ExistenceError: + return ExistenceError.forProcedure(context, procedure) + + +def existence_error_for_stream( + context: ExecutionContext, + stream: Term +) -> ExistenceError: + return ExistenceError.forStream(context, stream) + + +def existence_error_for_resource( + context: ExecutionContext, + name: str +) -> ExistenceError: + return ExistenceError.forResource(context, name) + + +def object_type(name: Union[str, Term]) -> ObjectType: + if isinstance(name, str): + return ObjectType.of(name) + else: + return ObjectType.fromTerm(name) diff --git a/tuprolog/solve/exception/error/existence/_definitions.py b/tuprolog/solve/exception/error/existence/_definitions.py new file mode 100644 index 0000000..13cccf0 --- /dev/null +++ b/tuprolog/solve/exception/error/existence/_definitions.py @@ -0,0 +1,36 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as errors # type: ignore + + +ExistenceError = errors.ExistenceError + + +ObjectType = ExistenceError.ObjectType + + +OBJECT_PROCEDURE = ObjectType.PROCEDURE + + +OBJECT_SOURCE_SINK = ObjectType.SOURCE_SINK + + +OBJECT_RESOURCE = ObjectType.RESOURCE + + +OBJECT_STREAM = ObjectType.STREAM + + +OBJECT_OOP_ALIAS = ObjectType.OOP_ALIAS + + +OBJECT_OOP_METHOD = ObjectType.OOP_METHOD + + +OBJECT_OOP_CONSTRUCTOR = ObjectType.OOP_CONSTRUCTOR + + +OBJECT_OOP_PROPERTY = ObjectType.OOP_PROPERTY + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.ExistenceError.*") diff --git a/tuprolog/solve/exception/error/instantiation/__init__.py b/tuprolog/solve/exception/error/instantiation/__init__.py index 2eb929d..3272497 100644 --- a/tuprolog/solve/exception/error/instantiation/__init__.py +++ b/tuprolog/solve/exception/error/instantiation/__init__.py @@ -1,30 +1,2 @@ -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog import logger -from tuprolog.core import Var -from tuprolog.solve import ExecutionContext, Signature -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors - - -InstantiationError = errors.InstantiationError - - -def instantiation_error_for_argument( - context: ExecutionContext, - procedure: Signature, - variable: Var, - index: int = None -) -> InstantiationError: - return InstantiationError.forArgument(context, procedure, variable, index) - - -def instantiation_error_for_goal( - context: ExecutionContext, - procedure: Signature, - variable: Var -) -> InstantiationError: - return InstantiationError.forGoal(context, procedure, variable) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.InstantiationError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/instantiation/_api.py b/tuprolog/solve/exception/error/instantiation/_api.py new file mode 100644 index 0000000..51e5817 --- /dev/null +++ b/tuprolog/solve/exception/error/instantiation/_api.py @@ -0,0 +1,20 @@ +from tuprolog.core import Var +from tuprolog.solve import ExecutionContext, Signature +from ._definitions import InstantiationError + + +def instantiation_error_for_argument( + context: ExecutionContext, + procedure: Signature, + variable: Var, + index: int = None +) -> InstantiationError: + return InstantiationError.forArgument(context, procedure, variable, index) + + +def instantiation_error_for_goal( + context: ExecutionContext, + procedure: Signature, + variable: Var +) -> InstantiationError: + return InstantiationError.forGoal(context, procedure, variable) diff --git a/tuprolog/solve/exception/error/instantiation/_definitions.py b/tuprolog/solve/exception/error/instantiation/_definitions.py new file mode 100644 index 0000000..0899c55 --- /dev/null +++ b/tuprolog/solve/exception/error/instantiation/_definitions.py @@ -0,0 +1,9 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as _errors # type: ignore + + +InstantiationError = _errors.InstantiationError + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.InstantiationError.*") diff --git a/tuprolog/solve/exception/error/message/__init__.py b/tuprolog/solve/exception/error/message/__init__.py index 45dd98e..3272497 100644 --- a/tuprolog/solve/exception/error/message/__init__.py +++ b/tuprolog/solve/exception/error/message/__init__.py @@ -1,17 +1,2 @@ -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog import logger -from tuprolog.core import Term -from tuprolog.solve import ExecutionContext -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors - - -MessageError = errors.MessageError - - -def message_error(content: Term, context: ExecutionContext, cause=None) -> MessageError: - return MessageError.of(content, context, cause) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.MessageError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/message/_api.py b/tuprolog/solve/exception/error/message/_api.py new file mode 100644 index 0000000..778f800 --- /dev/null +++ b/tuprolog/solve/exception/error/message/_api.py @@ -0,0 +1,7 @@ +from tuprolog.core import Term +from tuprolog.solve import ExecutionContext +from ._definitions import MessageError + + +def message_error(content: Term, context: ExecutionContext, cause=None) -> MessageError: + return MessageError.of(content, context, cause) diff --git a/tuprolog/solve/exception/error/message/_definitions.py b/tuprolog/solve/exception/error/message/_definitions.py new file mode 100644 index 0000000..5f42580 --- /dev/null +++ b/tuprolog/solve/exception/error/message/_definitions.py @@ -0,0 +1,9 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as _errors # type: ignore + + +MessageError = _errors.MessageError + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.MessageError.*") diff --git a/tuprolog/solve/exception/error/permission/__init__.py b/tuprolog/solve/exception/error/permission/__init__.py index 51669ee..3272497 100644 --- a/tuprolog/solve/exception/error/permission/__init__.py +++ b/tuprolog/solve/exception/error/permission/__init__.py @@ -1,82 +1,2 @@ -from typing import Union -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog import logger -from tuprolog.core import Term -from tuprolog.solve import ExecutionContext, Signature -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors - - -PermissionError = errors.PermissionError - -Operation = PermissionError.Operation - -Permission = PermissionError.Permission - -OPERATION_ACCESS = Operation.ACCESS - -OPERATION_ADD_ALIAS = Operation.ADD_ALIAS - -OPERATION_CLOSE = Operation.CLOSE - -OPERATION_CREATE = Operation.CREATE - -OPERATION_INPUT = Operation.INPUT - -OPERATION_INVOKE = Operation.INVOKE - -OPERATION_MODIFY = Operation.MODIFY - -OPERATION_OPEN = Operation.OPEN - -OPERATION_OUTPUT = Operation.OUTPUT - -OPERATION_REPOSITION = Operation.REPOSITION - -PERMISSION_BINARY_STREAM = Permission.BINARY_STREAM - -PERMISSION_FLAG = Permission.FLAG - -PERMISSION_OPERATOR = Permission.OPERATOR - -PERMISSION_PAST_END_OF_STREAM = Permission.PAST_END_OF_STREAM - -PERMISSION_PRIVATE_PROCEDURE = Permission.PRIVATE_PROCEDURE - -PERMISSION_SOURCE_SINK = Permission.SOURCE_SINK - -PERMISSION_STATIC_PROCEDURE = Permission.STATIC_PROCEDURE - -PERMISSION_OOP_METHOD = Permission.OOP_METHOD - -PERMISSION_STREAM = Permission.STREAM - -PERMISSION_TEXT_STREAM = Permission.TEXT_STREAM - - -def permission_error( - context: ExecutionContext, - procedure: Signature, - operation: Operation, - permission: Permission, - culprit: Term -) -> PermissionError: - return PermissionError.of(context, procedure, operation, permission, culprit) - - -def operation(name: Union[str, Term]) -> Operation: - if isinstance(name, str): - return Operation.of(name) - else: - return Operation.fromTerm(name) - - -def permission(name: Union[str, Term]) -> Permission: - if isinstance(name, str): - return Permission.of(name) - else: - return Permission.fromTerm(name) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.PermissionError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/permission/_api.py b/tuprolog/solve/exception/error/permission/_api.py new file mode 100644 index 0000000..03b4819 --- /dev/null +++ b/tuprolog/solve/exception/error/permission/_api.py @@ -0,0 +1,28 @@ +from typing import Union +from tuprolog.core import Term +from tuprolog.solve import ExecutionContext, Signature +from ._definitions import PermissionError, Operation, Permission + + +def permission_error( + context: ExecutionContext, + procedure: Signature, + operation: Operation, + permission: Permission, + culprit: Term +) -> PermissionError: + return PermissionError.of(context, procedure, operation, permission, culprit) + + +def operation(name: Union[str, Term]) -> Operation: + if isinstance(name, str): + return Operation.of(name) + else: + return Operation.fromTerm(name) + + +def permission(name: Union[str, Term]) -> Permission: + if isinstance(name, str): + return Permission.of(name) + else: + return Permission.fromTerm(name) diff --git a/tuprolog/solve/exception/error/permission/_definitions.py b/tuprolog/solve/exception/error/permission/_definitions.py new file mode 100644 index 0000000..5295c49 --- /dev/null +++ b/tuprolog/solve/exception/error/permission/_definitions.py @@ -0,0 +1,75 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as _errors # type: ignore + + +PermissionError = _errors.PermissionError + + +Operation = PermissionError.Operation + + +Permission = PermissionError.Permission + + +OPERATION_ACCESS = Operation.ACCESS + + +OPERATION_ADD_ALIAS = Operation.ADD_ALIAS + + +OPERATION_CLOSE = Operation.CLOSE + + +OPERATION_CREATE = Operation.CREATE + + +OPERATION_INPUT = Operation.INPUT + + +OPERATION_INVOKE = Operation.INVOKE + + +OPERATION_MODIFY = Operation.MODIFY + + +OPERATION_OPEN = Operation.OPEN + + +OPERATION_OUTPUT = Operation.OUTPUT + + +OPERATION_REPOSITION = Operation.REPOSITION + + +PERMISSION_BINARY_STREAM = Permission.BINARY_STREAM + + +PERMISSION_FLAG = Permission.FLAG + + +PERMISSION_OPERATOR = Permission.OPERATOR + + +PERMISSION_PAST_END_OF_STREAM = Permission.PAST_END_OF_STREAM + + +PERMISSION_PRIVATE_PROCEDURE = Permission.PRIVATE_PROCEDURE + + +PERMISSION_SOURCE_SINK = Permission.SOURCE_SINK + + +PERMISSION_STATIC_PROCEDURE = Permission.STATIC_PROCEDURE + + +PERMISSION_OOP_METHOD = Permission.OOP_METHOD + + +PERMISSION_STREAM = Permission.STREAM + + +PERMISSION_TEXT_STREAM = Permission.TEXT_STREAM + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.PermissionError.*") diff --git a/tuprolog/solve/exception/error/representation/__init__.py b/tuprolog/solve/exception/error/representation/__init__.py index d9b0e68..3272497 100644 --- a/tuprolog/solve/exception/error/representation/__init__.py +++ b/tuprolog/solve/exception/error/representation/__init__.py @@ -1,49 +1,2 @@ -from typing import Union -# noinspection PyUnresolvedReferences -import jpype.imports - -from tuprolog import logger -from tuprolog.core import Term -from tuprolog.solve import ExecutionContext, Signature - -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors - -RepresentationError = errors.RepresentationError - -Limit = RepresentationError.Limit - -LIMIT_CHARACTER = Limit.CHARACTER - -LIMIT_CHARACTER_CODE = Limit.CHARACTER_CODE - -LIMIT_IN_CHARACTER_CODE = Limit.IN_CHARACTER_CODE - -LIMIT_MAX_ARITY = Limit.MAX_ARITY - -LIMIT_MAX_INTEGER = Limit.MAX_INTEGER - -LIMIT_MIN_INTEGER = Limit.MIN_INTEGER - -LIMIT_OOP_OBJECT = Limit.OOP_OBJECT - -LIMIT_TOO_MANY_VARIABLES = Limit.TOO_MANY_VARIABLES - - -def representation_error( - context: ExecutionContext, - procedure: Signature, - limit: Limit, - cause=None -) -> RepresentationError: - return RepresentationError.of(context, procedure, limit, cause) - - -def limit(name: Union[str, Term]) -> Limit: - if isinstance(name, str): - return Limit.of(name) - else: - return Limit.fromTerm(name) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.RepresentationError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/representation/_api.py b/tuprolog/solve/exception/error/representation/_api.py new file mode 100644 index 0000000..f97754a --- /dev/null +++ b/tuprolog/solve/exception/error/representation/_api.py @@ -0,0 +1,20 @@ +from typing import Union +from tuprolog.core import Term +from tuprolog.solve import ExecutionContext, Signature +from ._definitions import RepresentationError, Limit + + +def representation_error( + context: ExecutionContext, + procedure: Signature, + limit: Limit, + cause=None +) -> RepresentationError: + return RepresentationError.of(context, procedure, limit, cause) + + +def limit(name: Union[str, Term]) -> Limit: + if isinstance(name, str): + return Limit.of(name) + else: + return Limit.fromTerm(name) diff --git a/tuprolog/solve/exception/error/representation/_definitions.py b/tuprolog/solve/exception/error/representation/_definitions.py new file mode 100644 index 0000000..9fd90eb --- /dev/null +++ b/tuprolog/solve/exception/error/representation/_definitions.py @@ -0,0 +1,36 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as _errors # type: ignore + + +RepresentationError = _errors.RepresentationError + + +Limit = RepresentationError.Limit + + +LIMIT_CHARACTER = Limit.CHARACTER + + +LIMIT_CHARACTER_CODE = Limit.CHARACTER_CODE + + +LIMIT_IN_CHARACTER_CODE = Limit.IN_CHARACTER_CODE + + +LIMIT_MAX_ARITY = Limit.MAX_ARITY + + +LIMIT_MAX_INTEGER = Limit.MAX_INTEGER + + +LIMIT_MIN_INTEGER = Limit.MIN_INTEGER + + +LIMIT_OOP_OBJECT = Limit.OOP_OBJECT + + +LIMIT_TOO_MANY_VARIABLES = Limit.TOO_MANY_VARIABLES + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.RepresentationError.*") diff --git a/tuprolog/solve/exception/error/syntax/__init__.py b/tuprolog/solve/exception/error/syntax/__init__.py index 5c2acfd..3272497 100644 --- a/tuprolog/solve/exception/error/syntax/__init__.py +++ b/tuprolog/solve/exception/error/syntax/__init__.py @@ -1,44 +1,2 @@ -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog import logger -from tuprolog.solve import ExecutionContext -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors - - -SyntaxError = errors.SyntaxError - - -def syntax_error( - context: ExecutionContext, - message: str -) -> SyntaxError: - return SyntaxError.of(context, message) - - -def syntax_error_while_parsing_term( - context: ExecutionContext, - input: str, - row: int, - column: int, - message: str -) -> SyntaxError: - return SyntaxError.whileParsingTerm(context, input, row, column, message) - - -def syntax_error_while_parsing_clauses( - context: ExecutionContext, - input: str, - index: int, - row: int, - column: int, - message: str -) -> SyntaxError: - return SyntaxError.whileParsingClauses(context, input, index, row, column, message) - - -def error_detector(text: str, line: int, column: int, message: str = None) -> str: - return SyntaxError.errorDetector(text, line, column, message) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.SyntaxError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/syntax/_api.py b/tuprolog/solve/exception/error/syntax/_api.py new file mode 100644 index 0000000..00b463e --- /dev/null +++ b/tuprolog/solve/exception/error/syntax/_api.py @@ -0,0 +1,34 @@ +from tuprolog.solve import ExecutionContext +from ._definitions import SyntaxError + + +def syntax_error( + context: ExecutionContext, + message: str +) -> SyntaxError: + return SyntaxError.of(context, message) + + +def syntax_error_while_parsing_term( + context: ExecutionContext, + input: str, + row: int, + column: int, + message: str +) -> SyntaxError: + return SyntaxError.whileParsingTerm(context, input, row, column, message) + + +def syntax_error_while_parsing_clauses( + context: ExecutionContext, + input: str, + index: int, + row: int, + column: int, + message: str +) -> SyntaxError: + return SyntaxError.whileParsingClauses(context, input, index, row, column, message) + + +def error_detector(text: str, line: int, column: int, message: str = None) -> str: + return SyntaxError.errorDetector(text, line, column, message) diff --git a/tuprolog/solve/exception/error/syntax/_definitions.py b/tuprolog/solve/exception/error/syntax/_definitions.py new file mode 100644 index 0000000..1da6a1a --- /dev/null +++ b/tuprolog/solve/exception/error/syntax/_definitions.py @@ -0,0 +1,9 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as _errors # type: ignore + + +SyntaxError = _errors.SyntaxError + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.SyntaxError.*") diff --git a/tuprolog/solve/exception/error/system/__init__.py b/tuprolog/solve/exception/error/system/__init__.py index 82c610e..3272497 100644 --- a/tuprolog/solve/exception/error/system/__init__.py +++ b/tuprolog/solve/exception/error/system/__init__.py @@ -1,19 +1,2 @@ -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog import logger -from tuprolog.solve import ExecutionContext -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors -from tuprolog.solve.exception import LogicError - - -SystemError = errors.SyntaxError - - -def syntax_error(context: ExecutionContext, message: str, exception) -> SystemError: - if isinstance(exception, LogicError): - return SystemError.forUncaughtError(context, message, exception) - return SystemError.forUncaughtException(context, message, exception) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.SystemError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/system/_api.py b/tuprolog/solve/exception/error/system/_api.py new file mode 100644 index 0000000..44fc0ba --- /dev/null +++ b/tuprolog/solve/exception/error/system/_api.py @@ -0,0 +1,9 @@ +from tuprolog.solve import ExecutionContext +from tuprolog.solve.exception import LogicError +from ._definitions import SystemError + + +def syntax_error(context: ExecutionContext, message: str, exception) -> SystemError: + if isinstance(exception, LogicError): + return SystemError.forUncaughtError(context, message, exception) + return SystemError.forUncaughtException(context, message, exception) diff --git a/tuprolog/solve/exception/error/system/_definitions.py b/tuprolog/solve/exception/error/system/_definitions.py new file mode 100644 index 0000000..cba43ab --- /dev/null +++ b/tuprolog/solve/exception/error/system/_definitions.py @@ -0,0 +1,9 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as _errors # type: ignore + + +SystemError = _errors.SyntaxError + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.SystemError.*") diff --git a/tuprolog/solve/exception/error/type/__init__.py b/tuprolog/solve/exception/error/type/__init__.py index e8e66f8..3272497 100644 --- a/tuprolog/solve/exception/error/type/__init__.py +++ b/tuprolog/solve/exception/error/type/__init__.py @@ -1,111 +1,2 @@ -from typing import Union -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog import logger -from tuprolog.core import Term -from tuprolog.solve import ExecutionContext, Signature -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.error as errors - - -TypeError = errors.TypeError - -Type = TypeError.Expected - -TYPE_ATOM = Type.ATOM - -TYPE_ATOMIC = Type.ATOMIC - -TYPE_BOOLEAN = Type.BOOLEAN - -TYPE_BYTE = Type.BYTE - -TYPE_CALLABLE = Type.CALLABLE - -TYPE_CHARACTER = Type.CHARACTER - -TYPE_COMPOUND = Type.COMPOUND - -TYPE_DEALIASING_EXPRESSION = Type.DEALIASING_EXPRESSION - -TYPE_EVALUABLE = Type.EVALUABLE - -TYPE_FLOAT = Type.FLOAT - -TYPE_INTEGER = Type.INTEGER - -TYPE_IN_CHARACTER = Type.IN_CHARACTER - -TYPE_LIST = Type.LIST - -TYPE_NUMBER = Type.NUMBER - -TYPE_OBJECT_REFERENCE = Type.OBJECT_REFERENCE - -TYPE_PAIR = Type.PAIR - -TYPE_PREDICATE_INDICATOR = Type.PREDICATE_INDICATOR - -TYPE_REFERENCE = Type.REFERENCE - -TYPE_TYPE_REFERENCE = Type.TYPE_REFERENCE - -TYPE_URL = Type.URL - -TYPE_VARIABLE = Type.VARIABLE - -def type_error_for_flag_values( - context: ExecutionContext, - procedure: Signature, - expected: Type, - actual: Term, - message: str -) -> TypeError: - return TypeError.of(context, procedure, expected, actual, message) - - -def type_error_for_argument_list( - context: ExecutionContext, - procedure: Signature, - expected: Type, - actual: Term, - index: int = None -) -> TypeError: - return TypeError.forArgumentList(context, procedure, expected, actual, index) - - -def type_error_for_argument( - context: ExecutionContext, - procedure: Signature, - expected: Type, - actual: Term, - index: int = None -) -> TypeError: - return TypeError.forArgument(context, procedure, expected, actual, index) - - -def type_error_for_term( - context: ExecutionContext, - expected: Type, - actual_value: Term, -) -> TypeError: - return TypeError.forTerm(context, expected, actual_value) - - -def type_error_for_goal( - context: ExecutionContext, - procedure: Signature, - expected: Type, - actual: Term, -) -> TypeError: - return TypeError.forGoal(context, procedure, expected, actual) - - -def type(name: Union[str, Term]) -> Type: - if isinstance(name, str): - return TypeError.valueOf(name) - else: - return TypeError.fromTerm(name) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.TypeError.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/error/type/_api.py b/tuprolog/solve/exception/error/type/_api.py new file mode 100644 index 0000000..41f4831 --- /dev/null +++ b/tuprolog/solve/exception/error/type/_api.py @@ -0,0 +1,58 @@ +from typing import Union +from tuprolog.core import Term +from tuprolog.solve import ExecutionContext, Signature +from ._definitions import TypeError, Type + + +def type_error_for_flag_values( + context: ExecutionContext, + procedure: Signature, + expected: Type, + actual: Term, + message: str +) -> TypeError: + return TypeError.of(context, procedure, expected, actual, message) + + +def type_error_for_argument_list( + context: ExecutionContext, + procedure: Signature, + expected: Type, + actual: Term, + index: int = None +) -> TypeError: + return TypeError.forArgumentList(context, procedure, expected, actual, index) + + +def type_error_for_argument( + context: ExecutionContext, + procedure: Signature, + expected: Type, + actual: Term, + index: int = None +) -> TypeError: + return TypeError.forArgument(context, procedure, expected, actual, index) + + +def type_error_for_term( + context: ExecutionContext, + expected: Type, + actual_value: Term, +) -> TypeError: + return TypeError.forTerm(context, expected, actual_value) + + +def type_error_for_goal( + context: ExecutionContext, + procedure: Signature, + expected: Type, + actual: Term, +) -> TypeError: + return TypeError.forGoal(context, procedure, expected, actual) + + +def type(name: Union[str, Term]) -> Type: + if isinstance(name, str): + return TypeError.valueOf(name) + else: + return TypeError.fromTerm(name) diff --git a/tuprolog/solve/exception/error/type/_definitions.py b/tuprolog/solve/exception/error/type/_definitions.py new file mode 100644 index 0000000..68676f0 --- /dev/null +++ b/tuprolog/solve/exception/error/type/_definitions.py @@ -0,0 +1,75 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.error as _errors # type: ignore + + +TypeError = _errors.TypeError + + +Type = TypeError.Expected + + +TYPE_ATOM = Type.ATOM + + +TYPE_ATOMIC = Type.ATOMIC + + +TYPE_BOOLEAN = Type.BOOLEAN + + +TYPE_BYTE = Type.BYTE + + +TYPE_CALLABLE = Type.CALLABLE + + +TYPE_CHARACTER = Type.CHARACTER + + +TYPE_COMPOUND = Type.COMPOUND + + +TYPE_DEALIASING_EXPRESSION = Type.DEALIASING_EXPRESSION + + +TYPE_EVALUABLE = Type.EVALUABLE + + +TYPE_FLOAT = Type.FLOAT + + +TYPE_INTEGER = Type.INTEGER + + +TYPE_IN_CHARACTER = Type.IN_CHARACTER + + +TYPE_LIST = Type.LIST + + +TYPE_NUMBER = Type.NUMBER + + +TYPE_OBJECT_REFERENCE = Type.OBJECT_REFERENCE + + +TYPE_PAIR = Type.PAIR + + +TYPE_PREDICATE_INDICATOR = Type.PREDICATE_INDICATOR + + +TYPE_REFERENCE = Type.REFERENCE + + +TYPE_TYPE_REFERENCE = Type.TYPE_REFERENCE + + +TYPE_URL = Type.URL + + +TYPE_VARIABLE = Type.VARIABLE + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.error.TypeError.*") diff --git a/tuprolog/solve/exception/warning/__init__.py b/tuprolog/solve/exception/warning/__init__.py index fe5539d..3272497 100644 --- a/tuprolog/solve/exception/warning/__init__.py +++ b/tuprolog/solve/exception/warning/__init__.py @@ -1,30 +1,2 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.exception.warning as warnings -from tuprolog.core import Struct -from tuprolog.solve import ExecutionContext, ResolutionException, Signature - -InitializationIssue = warnings.InitializationIssue - -MissingPredicate = warnings.MissingPredicate - - -def initialization_issue( - goal: Struct, - context: ExecutionContext, - cause: ResolutionException = None -) -> InitializationIssue: - return InitializationIssue(goal, cause, context) - - -def missing_predicate( - signature: Signature, - context: ExecutionContext, - cause=None -) -> MissingPredicate: - return MissingPredicate(cause, context, signature) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.warning.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/exception/warning/_api.py b/tuprolog/solve/exception/warning/_api.py new file mode 100644 index 0000000..f3cd7ec --- /dev/null +++ b/tuprolog/solve/exception/warning/_api.py @@ -0,0 +1,19 @@ +from tuprolog.core import Struct +from tuprolog.solve import ExecutionContext, ResolutionException, Signature +from ._definitions import InitializationIssue, MissingPredicate + + +def initialization_issue( + goal: Struct, + context: ExecutionContext, + cause: ResolutionException = None +) -> InitializationIssue: + return InitializationIssue(goal, cause, context) + + +def missing_predicate( + signature: Signature, + context: ExecutionContext, + cause=None +) -> MissingPredicate: + return MissingPredicate(cause, context, signature) diff --git a/tuprolog/solve/exception/warning/_definitions.py b/tuprolog/solve/exception/warning/_definitions.py new file mode 100644 index 0000000..3d58fd8 --- /dev/null +++ b/tuprolog/solve/exception/warning/_definitions.py @@ -0,0 +1,12 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.exception.warning as _warnings # type: ignore + + +InitializationIssue = _warnings.InitializationIssue + + +MissingPredicate = _warnings.MissingPredicate + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.exception.warning.*") diff --git a/tuprolog/solve/flags/__init__.py b/tuprolog/solve/flags/__init__.py index 85e2bd9..8467ebd 100644 --- a/tuprolog/solve/flags/__init__.py +++ b/tuprolog/solve/flags/__init__.py @@ -1,76 +1,3 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.flags as _flags -from tuprolog.core import Term -from tuprolog.jvmutils import kpair, jmap, jarray, Pair -from typing import Iterable, Union, Mapping - - -DoubleQuotes = _flags.DoubleQuotes - -FlagStore = _flags.FlagStore - -LastCallOptimization = _flags.LastCallOptimization - -MaxArity = _flags.MaxArity - -NotableFlag = _flags.NotableFlag - -Unknown = _flags.Unknown - -Flag = Pair - -EMPTY_FLAG_STORE: FlagStore = FlagStore.EMPTY - -DEFAULT_FLAG_STORE: FlagStore = FlagStore.DEFAULT - -DoubleQuotes: NotableFlag = DoubleQuotes.INSTANCE - -LastCallOptimization: NotableFlag = LastCallOptimization.INSTANCE - -MaxArity: NotableFlag = MaxArity.INSTANCE - -Unknown: NotableFlag = Unknown.INSTANCE - - -def flag(first: Union[str, NotableFlag, Iterable], value: Term = None) -> Flag: - if isinstance(first, NotableFlag): - if value is None: - return first.toPair() - else: - return first.to(value) - elif isinstance(first, str): - if value is None: - raise ValueError("Argument value is None") - return Flag(first, value) - elif isinstance(first, Iterable) and value is None: - return kpair(first) - else: - raise ValueError("Argument first is not iterable nor str") - - -def flag_store(*flags: Union[NotableFlag, Flag, Iterable, FlagStore], **kwargs: Mapping[str, Term]): - normal_flags = [] - notable_flags = [] - other_stores = [] - for f in flags: - if isinstance(f, NotableFlag): - notable_flags.append(f) - elif isinstance(f, Flag): - normal_flags.append(f) - elif isinstance(f, FlagStore): - other_stores.append(f) - else: - normal_flags.append(flag(f)) - store1 = FlagStore.of(jarray(NotableFlag)@notable_flags) - store2 = FlagStore.of(jarray(Flag)@normal_flags) - store3 = FlagStore.of(jmap(kwargs)) - store = store1.plus(store2).plus(store3) - for s in other_stores: - store = store.plus(s) - return store - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.flags.*") +import tuprolog.solve.flags._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/flags/_adapters.py b/tuprolog/solve/flags/_adapters.py new file mode 100644 index 0000000..84cc63c --- /dev/null +++ b/tuprolog/solve/flags/_adapters.py @@ -0,0 +1,26 @@ +from jpype import JImplementationFor +from tuprolog import logger +from ._definitions import NotableFlag + + +@JImplementationFor("it.unibo.tuprolog.solve.flags.FlagStore") +class _KtFlagStore: + def __jclass_init__(cls): + pass + + def __len__(self): + return self.getSize() + + def __getitem__(self, notableFlag): + return self.get(notableFlag) + + def __add__(self, other): + return self.plus(other) + + def __sub__(self, other): + if isinstance(other, NotableFlag): + return self.minus(other.name) + return self.minus(other) + + +logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.solve.flags.*") diff --git a/tuprolog/solve/flags/_api.py b/tuprolog/solve/flags/_api.py new file mode 100644 index 0000000..3e3fdc7 --- /dev/null +++ b/tuprolog/solve/flags/_api.py @@ -0,0 +1,42 @@ +from typing import Iterable, Union, Mapping +from tuprolog.core import Term +from tuprolog.jvmutils import kpair, jmap, jarray +from ._definitions import FlagStore, NotableFlag, Flag + + +def flag(first: Union[str, NotableFlag, Iterable], value: Term = None) -> Flag: + if isinstance(first, NotableFlag): + if value is None: + return first.toPair() + else: + return first.to(value) + elif isinstance(first, str): + if value is None: + raise ValueError("Argument value is None") + return Flag(first, value) + elif isinstance(first, Iterable) and value is None: + return kpair(first) + else: + raise ValueError("Argument first is not iterable nor str") + + +def flag_store(*flags: Union[NotableFlag, Flag, Iterable, FlagStore], **kwargs: Mapping[str, Term]): + normal_flags = [] + notable_flags = [] + other_stores = [] + for f in flags: + if isinstance(f, NotableFlag): + notable_flags.append(f) + elif isinstance(f, Flag): + normal_flags.append(f) + elif isinstance(f, FlagStore): + other_stores.append(f) + else: + normal_flags.append(flag(f)) + store1 = FlagStore.of(jarray(NotableFlag)@notable_flags) + store2 = FlagStore.of(jarray(Flag)@normal_flags) + store3 = FlagStore.of(jmap(kwargs)) + store = store1.plus(store2).plus(store3) + for s in other_stores: + store = store.plus(s) + return store diff --git a/tuprolog/solve/flags/_definitions.py b/tuprolog/solve/flags/_definitions.py new file mode 100644 index 0000000..95f4869 --- /dev/null +++ b/tuprolog/solve/flags/_definitions.py @@ -0,0 +1,52 @@ +from tuprolog import logger +from tuprolog.jvmutils import Pair +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.flags as _flags # type: ignore + + +DoubleQuotes = _flags.DoubleQuotes + + +FlagStore = _flags.FlagStore + + +LastCallOptimization = _flags.LastCallOptimization + + +MaxArity = _flags.MaxArity + + +NotableFlag = _flags.NotableFlag + + +TrackVariables = _flags.TrackVariables + + +Unknown = _flags.Unknown + + +Flag = Pair + + +EMPTY_FLAG_STORE: FlagStore = FlagStore.EMPTY + + +DEFAULT_FLAG_STORE: FlagStore = FlagStore.DEFAULT + + +DoubleQuotes: NotableFlag = DoubleQuotes.INSTANCE + + +LastCallOptimization: NotableFlag = LastCallOptimization.INSTANCE + + +MaxArity: NotableFlag = MaxArity.INSTANCE + + +TrackVariables: NotableFlag = TrackVariables.INSTANCE + + +Unknown: NotableFlag = Unknown.INSTANCE + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.flags.*") diff --git a/tuprolog/solve/function/__init__.py b/tuprolog/solve/function/__init__.py index 75eb034..3272497 100644 --- a/tuprolog/solve/function/__init__.py +++ b/tuprolog/solve/function/__init__.py @@ -1,60 +1,2 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog.core import Term -from tuprolog.solve import ExecutionContext, Signature, current_time_instant, MAX_TIMEOUT -from tuprolog.solve.primitive import SolveRequest -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.function as _function -from typing import List, Callable - - -LogicFunction = _function.LogicFunction - -Compute = _function.Compute - -ArithmeticUtilsKt = _function.ArithmeticUtilsKt - -ComputeRequest = Compute.Request - -ComputeResponse = Compute.Request - - -@jpype.JImplements(LogicFunction) -class AbstractLogicFunction(object): - @jpype.JOverride - def compute(self, request: ComputeRequest) -> ComputeResponse: - raise NotImplementedError() - - -def logic_function(callable: Callable[[ComputeRequest], ComputeResponse]) -> LogicFunction: - class CallableToLogicFunctionAdapter(AbstractLogicFunction): - def compute(self, request: ComputeRequest) -> ComputeResponse: - return callable(request) - - return CallableToLogicFunctionAdapter() - - -def compute_request( - signature: Signature, - arguments: List[Term], - context: ExecutionContext, - issuing_instant: int = current_time_instant, - max_duration: int = MAX_TIMEOUT -) -> ComputeRequest: - return ComputeRequest(signature, arguments, context, issuing_instant, max_duration) - - -def compute_response(result: Term) -> ComputeResponse: - return ComputeResponse(result) - - -def eval_as_expression(term: Term, request: SolveRequest, index: int = None) -> Term: - return ArithmeticUtilsKt.evalAsExpression(term, request, index) - - -def eval_as_arithmetic_expression(term: Term, request: SolveRequest, index: int = None) -> Term: - return ArithmeticUtilsKt.evalAsArithmeticExpression(term, request, index) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.function.*") +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/function/_api.py b/tuprolog/solve/function/_api.py new file mode 100644 index 0000000..52fd721 --- /dev/null +++ b/tuprolog/solve/function/_api.py @@ -0,0 +1,35 @@ +from typing import List, Callable +from tuprolog.core import Term +from tuprolog.solve import ExecutionContext, Signature, current_time_instant, MAX_TIMEOUT +from tuprolog.solve.primitive import SolveRequest +from ._definitions import LogicFunction, ArithmeticUtilsKt, ComputeRequest, ComputeResponse, AbstractLogicFunction + + +def logic_function(callable: Callable[[ComputeRequest], ComputeResponse]) -> LogicFunction: + class CallableToLogicFunctionAdapter(AbstractLogicFunction): + def compute(self, request: ComputeRequest) -> ComputeResponse: + return callable(request) + + return CallableToLogicFunctionAdapter() + + +def compute_request( + signature: Signature, + arguments: List[Term], + context: ExecutionContext, + issuing_instant: int = current_time_instant, + max_duration: int = MAX_TIMEOUT +) -> ComputeRequest: + return ComputeRequest(signature, arguments, context, issuing_instant, max_duration) + + +def compute_response(result: Term) -> ComputeResponse: + return ComputeResponse(result) + + +def eval_as_expression(term: Term, request: SolveRequest, index: int = None) -> Term: + return ArithmeticUtilsKt.evalAsExpression(term, request, index) + + +def eval_as_arithmetic_expression(term: Term, request: SolveRequest, index: int = None) -> Term: + return ArithmeticUtilsKt.evalAsArithmeticExpression(term, request, index) diff --git a/tuprolog/solve/function/_definitions.py b/tuprolog/solve/function/_definitions.py new file mode 100644 index 0000000..e5921d1 --- /dev/null +++ b/tuprolog/solve/function/_definitions.py @@ -0,0 +1,29 @@ +from jpype import JImplements, JOverride +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.function as _function # type: ignore + + +LogicFunction = _function.LogicFunction + + +Compute = _function.Compute + + +ArithmeticUtilsKt = _function.ArithmeticUtilsKt + + +ComputeRequest = Compute.Request + + +ComputeResponse = Compute.Request + + +@JImplements(LogicFunction) +class AbstractLogicFunction(object): + @JOverride + def compute(self, request: ComputeRequest) -> ComputeResponse: + raise NotImplementedError() + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.function.*") diff --git a/tuprolog/solve/library/__init__.py b/tuprolog/solve/library/__init__.py index 9829fe3..5cc9400 100644 --- a/tuprolog/solve/library/__init__.py +++ b/tuprolog/solve/library/__init__.py @@ -1,63 +1,3 @@ -from functools import reduce -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog.core.operators import OperatorSet, operator_set -from tuprolog.theory import Theory, theory -from tuprolog.solve import Signature -from tuprolog.solve.primitive import Primitive -from tuprolog.solve.function import LogicFunction -from tuprolog.jvmutils import jiterable -from typing import Union, Mapping, Iterable -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.library as _library - - -Library = _library.Library - -Libraries = _library.Libraries - -LibraryGroup = _library.LibraryGroup - -AliasedLibrary = _library.AliasedLibrary - - -def library( - alias: str = None, - primitives: Mapping[Signature, Primitive] = dict(), - theory: Theory = theory(), - operators: OperatorSet = operator_set(), - functions: Mapping[Signature, LogicFunction] = dict(), -) -> Union[Library, AliasedLibrary]: - if alias is None: - return Library.unaliased(primitives, theory, operators, functions) - else: - return Library.aliased(alias, primitives, theory, operators, functions) - - -def aliased(alias: str, library: Library) -> AliasedLibrary: - return Library.of(alias, library) - - -def libraries( - *libs: Union[Libraries, AliasedLibrary, Iterable[Union[Libraries, AliasedLibrary]]], - **kwargs: Library -) -> Libraries: - all_libraries = [] - aliased_libs = [] - queue = list(libs) - while len(queue) > 0: - current = queue.pop() - if isinstance(current, Libraries): - all_libraries.append(current) - elif isinstance(current, AliasedLibrary): - aliased_libs.append(current) - else: - queue.extend(current) - for alias in kwargs: - aliased_libs.append(aliased(alias, kwargs[alias])) - first = Libraries.of(jiterable(aliased_libs)) - return reduce(lambda a, b: a.plus(b), all_libraries, first) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.library.*") \ No newline at end of file +import tuprolog.solve.library._adapters as _ +from ._definititions import * +from ._api import * diff --git a/tuprolog/solve/library/_adapters.py b/tuprolog/solve/library/_adapters.py new file mode 100644 index 0000000..16bee21 --- /dev/null +++ b/tuprolog/solve/library/_adapters.py @@ -0,0 +1,20 @@ +from jpype import JImplementationFor +from ._definititions import Runtime + + +@JImplementationFor("it.unibo.tuprolog.solve.library.Library") +class _KtLibrary: + def __jclass_init__(self): + pass + + def to_runtime(self): + return Runtime.of(self) + + +@JImplementationFor("it.unibo.tuprolog.solve.library.Runtime") +class _KtRuntime: + def __jclass_init__(self): + pass + + def __add__(self, other): + return self.plus(other) diff --git a/tuprolog/solve/library/_api.py b/tuprolog/solve/library/_api.py new file mode 100644 index 0000000..fd94003 --- /dev/null +++ b/tuprolog/solve/library/_api.py @@ -0,0 +1,45 @@ +from typing import Union, Mapping, Iterable +from functools import reduce +from tuprolog.core.operators import OperatorSet, operator_set +from tuprolog.theory import Clause +from tuprolog.solve import Signature +from tuprolog.solve.primitive import Primitive +from tuprolog.solve.function import LogicFunction +from ._definititions import Library, Pluggable + + +def library( + alias: str = None, + primitives: Mapping[Signature, Primitive] = dict(), + clauses: Iterable[Clause] = [], + operators: OperatorSet = operator_set(), + functions: Mapping[Signature, LogicFunction] = dict(), +) -> Union[Library, Pluggable]: + if alias is None: + return Library.of(primitives, clauses, operators, functions) + else: + return Library.of(alias, primitives, clauses, operators, functions) + + +def aliased(alias: str, library: Library) -> Library: + return Library.of(alias, library) + + +def libraries( + *libs: Union[Library, Iterable[Library]], + **kwargs: Library +) -> Library: + all_libraries = [] + queue = list(libs) + while len(queue) > 0: + current = queue.pop() + if isinstance(current, Library): + all_libraries.append(current) + elif isinstance(current, Iterable): + queue.extend(current) + else: + raise TypeError(f'Expected Library or Iterable[Library], got {type(current)}') + for alias, library in kwargs.items(): + if isinstance(library, Library): + all_libraries.append(aliased(alias, kwargs[alias])) + return reduce(lambda a, b: a.plus(b), all_libraries, Library.of({}, [], operator_set(), {})) diff --git a/tuprolog/solve/library/_definititions.py b/tuprolog/solve/library/_definititions.py new file mode 100644 index 0000000..24e6a3e --- /dev/null +++ b/tuprolog/solve/library/_definititions.py @@ -0,0 +1,15 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.library as _library # type: ignore + + +Library = _library.Library + + +Pluggable = _library.Pluggable + + +Runtime = _library.Runtime + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.library.*") diff --git a/tuprolog/solve/library/exception/__init__.py b/tuprolog/solve/library/exception.py similarity index 65% rename from tuprolog/solve/library/exception/__init__.py rename to tuprolog/solve/library/exception.py index 1827e16..c202226 100644 --- a/tuprolog/solve/library/exception/__init__.py +++ b/tuprolog/solve/library/exception.py @@ -1,14 +1,14 @@ from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.library.exception as _exception +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.library.exception as _exception # type: ignore AlreadyLoadedLibraryException = _exception.AlreadyLoadedLibraryException + LibraryException = _exception.LibraryException + NoSuchALibraryException = _exception.NoSuchALibraryException diff --git a/tuprolog/solve/plp/__init__.py b/tuprolog/solve/plp/__init__.py new file mode 100644 index 0000000..3272497 --- /dev/null +++ b/tuprolog/solve/plp/__init__.py @@ -0,0 +1,2 @@ +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/plp/_api.py b/tuprolog/solve/plp/_api.py new file mode 100644 index 0000000..6f24267 --- /dev/null +++ b/tuprolog/solve/plp/_api.py @@ -0,0 +1,41 @@ +from typing import TypeVar, Mapping, Any +from tuprolog.utils import Taggable +from tuprolog.solve import SolveOptions, solve_options as _solve_options, MAX_TIMEOUT, ALL_SOLUTIONS +from ._definitions import ProbExtensions + + +def probability(taggable: Taggable) -> float: + return ProbExtensions.getProbability(taggable) + + +T = TypeVar("T", bound=Taggable, covariant=True) + + +def set_probability(taggable: T) -> T: + return ProbExtensions.setProbability(taggable) + + +def is_probabilistic(solve_opts: SolveOptions) -> bool: + return ProbExtensions.isProbabilistic(solve_opts) + + +def set_probabilistic(solve_opts: SolveOptions, value: bool) -> SolveOptions: + return ProbExtensions.setProbabilistic(solve_opts, value) + + +def probabilistic(solve_opts: SolveOptions) -> SolveOptions: + return ProbExtensions.probabilistic(solve_opts) + + +def solve_options( + lazy: bool = True, + timeout: int = MAX_TIMEOUT, + limit: int = ALL_SOLUTIONS, + probabilistic: bool = False, + custom: Mapping[str, Any] = dict(), + **kwargs: Any +) -> SolveOptions: + non_probabilistic = _solve_options(lazy, timeout, limit, custom, **kwargs) + if probabilistic: + return set_probabilistic(non_probabilistic, True) + return non_probabilistic diff --git a/tuprolog/solve/plp/_definitions.py b/tuprolog/solve/plp/_definitions.py new file mode 100644 index 0000000..de4ea70 --- /dev/null +++ b/tuprolog/solve/plp/_definitions.py @@ -0,0 +1,9 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve as _solve # type: ignore + + +ProbExtensions = _solve.ProbExtensions + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.plp.*") diff --git a/tuprolog/solve/primitive/__init__.py b/tuprolog/solve/primitive/__init__.py index d61b4ce..e41f046 100644 --- a/tuprolog/solve/primitive/__init__.py +++ b/tuprolog/solve/primitive/__init__.py @@ -1,162 +1,3 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -from tuprolog.core import Term, Clause, Integer -from tuprolog.solve import ExecutionContext, Signature, Solution, current_time_instant, MAX_TIMEOUT -# from tuprolog.solve.sideffcts import SideEffect -from tuprolog.pyutils import iterable_or_varargs -from tuprolog.jvmutils import jlist -from typing import List, Iterable, Callable -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.primitive as _primitive - - -Primitive = _primitive.Primitive - -Solve = _primitive.Solve - -PrimitiveWrapper = _primitive.PrimitiveWrapper - -SolveRequest = Solve.Request - -SolveResponse = Solve.Request - - -@jpype.JImplements(Primitive) -class AbstractPrimitive(object): - @jpype.JOverride - def solve(self, request: SolveRequest) -> Iterable[SolveResponse]: - raise NotImplementedError() - - -def primitive(callable: Callable[[SolveResponse], Iterable[SolveResponse]]) -> Primitive: - class CallableToPrimitiveAdapter(AbstractPrimitive): - def solve(self, request: SolveRequest) -> Iterable[SolveResponse]: - return callable(request) - - return CallableToPrimitiveAdapter() - - -def solve_request( - signature: Signature, - arguments: List[Term], - context: ExecutionContext, - issuing_instant: int = current_time_instant(), - max_duration: int = MAX_TIMEOUT -) -> SolveRequest: - return SolveRequest(signature, arguments, context, issuing_instant, max_duration) - - -def solve_response(solution: Solution, *side_effects) -> SolveResponse: - return iterable_or_varargs(side_effects, lambda ses: SolveResponse(solution, None, jlist(ses))) - - -def check_term_is_recursively_callable(request: SolveRequest, term: Term): - return PrimitiveWrapper.checkTermIsRecursivelyCallable(request, term) - - -def ensuring_all_arguments_are_instantiated(request: SolveRequest) -> SolveRequest: - return PrimitiveWrapper.ensuringAllArgumentsAreInstantiated(request) - - -def ensuring_procedure_has_permission(request: SolveRequest, signature: Signature, operation) -> SolveRequest: - return PrimitiveWrapper.ensuringProcedureHasPermission(request, signature, operation) - - -def ensuring_clause_procedure_has_permission(request: SolveRequest, clause: Clause, operation) -> SolveRequest: - return PrimitiveWrapper.ensuringClauseProcedureHasPermission(request, clause, operation) - - -def ensuring_argument_is_well_formed_indicator(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsWellFormedIndicator(request, index) - - -def not_implemented(request: SolveRequest, message: str) -> SolveResponse: - return PrimitiveWrapper.notImplemented(request, message) - - -def not_supported(request: SolveRequest, message: str) -> SolveResponse: - return PrimitiveWrapper.notSupported(request, message) - - -def ensuring_argument_is_well_formed_clause(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsWellFormedClause(request, index) - - -def ensuring_argument_is_instantiated(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsInstantiated(request, index) - - -def ensuring_argument_is_numeric(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsNumeric(request, index) - - -def ensuring_argument_is_struct(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsStruct(request, index) - - -def ensuring_argument_is_callable(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsCallable(request, index) - - -def ensuring_argument_is_variable(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsVariable(request, index) - - -def ensuring_argument_is_compound(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsCompound(request, index) - - -def ensuring_argument_is_atom(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsCompound(request, index) - - -def ensuring_argument_is_constant(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsConstant(request, index) - - -def ensuring_argument_is_ground(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsGround(request, index) - - -def ensuring_argument_is_char(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsChar(request, index) - - -def ensuring_argument_is_specifier(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsSpecifier(request, index) - - -def ensuring_argument_is_integer(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsInteger(request, index) - - -def ensuring_argument_is_list(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsList(request, index) - - -def ensuring_argument_is_arity(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsArity(request, index) - - -def ensuring_argument_is_non_negative_integer(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsNonNegativeInteger(request, index) - - -def is_character_code(integer: Integer) -> bool: - return PrimitiveWrapper.isCharacterCode(integer) - - -def ensuring_term_is_char_code(request: SolveRequest, term: Term) -> SolveRequest: - return PrimitiveWrapper.ensuringTermIsCharCode(request, term) - - -def ensuring_term_is_well_formed_list(request: SolveRequest, term: Term) -> SolveRequest: - return PrimitiveWrapper.ensuringTermIsWellFormedList(request, term) - - -def ensuring_argument_is_char_code(request: SolveRequest, index: int) -> SolveRequest: - return PrimitiveWrapper.ensuringArgumentIsCharCode(request, index) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.primitive.*") +import tuprolog.solve.primitive._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/primitive/_adapters.py b/tuprolog/solve/primitive/_adapters.py new file mode 100644 index 0000000..df00ec4 --- /dev/null +++ b/tuprolog/solve/primitive/_adapters.py @@ -0,0 +1,14 @@ +from jpype import JImplementationFor +from tuprolog.core import Substitution + + +@JImplementationFor("it.unibo.tuprolog.solve.primitive.Solve.Request") +class _KtSolveRequest: + def __jclass_init__(self): + pass + + def reply_with(self, substitution): + return self.replyWith(substitution, None) + + def reply_success(self): + return self.replySuccess(Substitution.empty(), None) diff --git a/tuprolog/solve/primitive/_api.py b/tuprolog/solve/primitive/_api.py new file mode 100644 index 0000000..142916a --- /dev/null +++ b/tuprolog/solve/primitive/_api.py @@ -0,0 +1,136 @@ +from typing import List, Iterable, Callable +from tuprolog.pyutils import iterable_or_varargs +from tuprolog.jvmutils import jlist +from tuprolog.core import Term, Clause, Integer +from tuprolog.solve import ExecutionContext, Signature, Solution, current_time_instant, MAX_TIMEOUT +from ._definitions import Primitive, PrimitiveWrapper, SolveRequest, SolveResponse, AbstractPrimitive + + +def primitive(callable: Callable[[SolveResponse], Iterable[SolveResponse]]) -> Primitive: + class CallableToPrimitiveAdapter(AbstractPrimitive): + def solve(self, request: SolveRequest) -> Iterable[SolveResponse]: + return callable(request) + + return CallableToPrimitiveAdapter() + + +def solve_request( + signature: Signature, + arguments: List[Term], + context: ExecutionContext, + issuing_instant: int = current_time_instant(), + max_duration: int = MAX_TIMEOUT +) -> SolveRequest: + return SolveRequest(signature, arguments, context, issuing_instant, max_duration) + + +def solve_response(solution: Solution, *side_effects) -> SolveResponse: + return iterable_or_varargs(side_effects, lambda ses: SolveResponse(solution, None, jlist(ses))) + + +def check_term_is_recursively_callable(request: SolveRequest, term: Term): + return PrimitiveWrapper.checkTermIsRecursivelyCallable(request, term) + + +def ensuring_all_arguments_are_instantiated(request: SolveRequest) -> SolveRequest: + return PrimitiveWrapper.ensuringAllArgumentsAreInstantiated(request) + + +def ensuring_procedure_has_permission(request: SolveRequest, signature: Signature, operation) -> SolveRequest: + return PrimitiveWrapper.ensuringProcedureHasPermission(request, signature, operation) + + +def ensuring_clause_procedure_has_permission(request: SolveRequest, clause: Clause, operation) -> SolveRequest: + return PrimitiveWrapper.ensuringClauseProcedureHasPermission(request, clause, operation) + + +def ensuring_argument_is_well_formed_indicator(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsWellFormedIndicator(request, index) + + +def not_implemented(request: SolveRequest, message: str) -> SolveResponse: + return PrimitiveWrapper.notImplemented(request, message) + + +def not_supported(request: SolveRequest, message: str) -> SolveResponse: + return PrimitiveWrapper.notSupported(request, message) + + +def ensuring_argument_is_well_formed_clause(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsWellFormedClause(request, index) + + +def ensuring_argument_is_instantiated(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsInstantiated(request, index) + + +def ensuring_argument_is_numeric(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsNumeric(request, index) + + +def ensuring_argument_is_struct(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsStruct(request, index) + + +def ensuring_argument_is_callable(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsCallable(request, index) + + +def ensuring_argument_is_variable(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsVariable(request, index) + + +def ensuring_argument_is_compound(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsCompound(request, index) + + +def ensuring_argument_is_atom(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsAtom(request, index) + + +def ensuring_argument_is_constant(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsConstant(request, index) + + +def ensuring_argument_is_ground(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsGround(request, index) + + +def ensuring_argument_is_char(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsChar(request, index) + + +def ensuring_argument_is_specifier(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsSpecifier(request, index) + + +def ensuring_argument_is_integer(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsInteger(request, index) + + +def ensuring_argument_is_list(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsList(request, index) + + +def ensuring_argument_is_arity(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsArity(request, index) + + +def ensuring_argument_is_non_negative_integer(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsNonNegativeInteger(request, index) + + +def is_character_code(integer: Integer) -> bool: + return PrimitiveWrapper.isCharacterCode(integer) + + +def ensuring_term_is_char_code(request: SolveRequest, term: Term) -> SolveRequest: + return PrimitiveWrapper.ensuringTermIsCharCode(request, term) + + +def ensuring_term_is_well_formed_list(request: SolveRequest, term: Term) -> SolveRequest: + return PrimitiveWrapper.ensuringTermIsWellFormedList(request, term) + + +def ensuring_argument_is_char_code(request: SolveRequest, index: int) -> SolveRequest: + return PrimitiveWrapper.ensuringArgumentIsCharCode(request, index) diff --git a/tuprolog/solve/primitive/_definitions.py b/tuprolog/solve/primitive/_definitions.py new file mode 100644 index 0000000..02c5b0b --- /dev/null +++ b/tuprolog/solve/primitive/_definitions.py @@ -0,0 +1,30 @@ +from typing import Iterable +from jpype import JImplements, JOverride +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.primitive as _primitive # type: ignore + + +Primitive = _primitive.Primitive + + +Solve = _primitive.Solve + + +PrimitiveWrapper = _primitive.PrimitiveWrapper + + +SolveRequest = Solve.Request + + +SolveResponse = Solve.Response + + +@JImplements(Primitive) +class AbstractPrimitive(object): + @JOverride + def solve(self, request: SolveRequest) -> Iterable[SolveResponse]: + raise NotImplementedError() + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.primitive.*") diff --git a/tuprolog/solve/problog/__init__.py b/tuprolog/solve/problog/__init__.py new file mode 100644 index 0000000..3272497 --- /dev/null +++ b/tuprolog/solve/problog/__init__.py @@ -0,0 +1,2 @@ +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/problog/_api.py b/tuprolog/solve/problog/_api.py new file mode 100644 index 0000000..13ad3d4 --- /dev/null +++ b/tuprolog/solve/problog/_api.py @@ -0,0 +1,28 @@ +from tuprolog.solve import Solver +from tuprolog.solve.flags import DEFAULT_FLAG_STORE, FlagStore +from tuprolog.solve.library import libraries, Library, Runtime +from tuprolog.solve.channel import InputChannel, OutputChannel, std_out, std_in, std_err, warn +from tuprolog.theory import theory, mutable_theory, Theory, Unificator +from ._definitions import PROBLOG_SOLVER_FACTORY + + +def problog_solver( + unificator: Unificator = Unificator.getDefault(), + libraries: Library = libraries(), + flags: FlagStore = DEFAULT_FLAG_STORE, + static_kb: Theory = theory(), + dynamic_kb: Theory = mutable_theory(), + std_in: InputChannel = std_in(), + std_out: OutputChannel = std_out(), + std_err: OutputChannel = std_err(), + warning: OutputChannel = warn(), + mutable: bool = True +) -> Solver: + if mutable: + return PROBLOG_SOLVER_FACTORY.mutableSolverWithDefaultBuiltins( + unificator, Runtime.of(libraries), flags, static_kb, dynamic_kb, std_in, std_out, std_err, warning + ) + else: + return PROBLOG_SOLVER_FACTORY.solverWithDefaultBuiltins( + unificator, Runtime.of(libraries), flags, static_kb, dynamic_kb, std_in, std_out, std_err, warning + ) diff --git a/tuprolog/solve/problog/_definitions.py b/tuprolog/solve/problog/_definitions.py new file mode 100644 index 0000000..580fa36 --- /dev/null +++ b/tuprolog/solve/problog/_definitions.py @@ -0,0 +1,22 @@ +from tuprolog import logger +from tuprolog.solve import Solver, SolverFactory +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.problog as _problog # type: ignore + + +PROBLOG_SOLVER_FACTORY: SolverFactory = Solver.problog() + + +Operators = _problog.Operators + + +ANNOTATION_OPERATOR = Operators.ANNOTATION_OPERATOR + + +PROBLOG_SPECIFIC_OPERATORS = Operators.PROBLOG_SPECIFIC_OPERATORS + + +PROBLOG_OPERATORS = Operators.PROBLOG_OPERATORS + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.problog.*") diff --git a/tuprolog/solve/prolog/__init__.py b/tuprolog/solve/prolog/__init__.py index 7e47822..8151d30 100644 --- a/tuprolog/solve/prolog/__init__.py +++ b/tuprolog/solve/prolog/__init__.py @@ -1,5 +1,2 @@ -from tuprolog.solve.classic import classic_solver, classic_solver_factory - -prolog_solver = classic_solver - -prolog_solver_factory = classic_solver_factory +from ._definitions import PROLOG_SOLVER_FACTORY +from ._api import prolog_solver diff --git a/tuprolog/solve/prolog/_api.py b/tuprolog/solve/prolog/_api.py new file mode 100644 index 0000000..6ead96c --- /dev/null +++ b/tuprolog/solve/prolog/_api.py @@ -0,0 +1,28 @@ +from tuprolog.solve import Solver +from tuprolog.solve.flags import DEFAULT_FLAG_STORE, FlagStore +from tuprolog.solve.library import libraries, Library, Runtime +from tuprolog.solve.channel import InputChannel, OutputChannel, std_out, std_in, std_err, warn +from tuprolog.theory import theory, mutable_theory, Theory, Unificator +from ._definitions import PROLOG_SOLVER_FACTORY + + +def prolog_solver( + unificator: Unificator = Unificator.getDefault(), + libraries: Library = libraries(), + flags: FlagStore = DEFAULT_FLAG_STORE, + static_kb: Theory = theory(), + dynamic_kb: Theory = mutable_theory(), + std_in: InputChannel = std_in(), + std_out: OutputChannel = std_out(), + std_err: OutputChannel = std_err(), + warning: OutputChannel = warn(), + mutable: bool = True +) -> Solver: + if mutable: + return PROLOG_SOLVER_FACTORY.mutableSolverWithDefaultBuiltins( + unificator, Runtime.of(libraries), flags, static_kb, dynamic_kb, std_in, std_out, std_err, warning + ) + else: + return PROLOG_SOLVER_FACTORY.solverWithDefaultBuiltins( + unificator, Runtime.of(libraries), flags, static_kb, dynamic_kb, std_in, std_out, std_err, warning + ) diff --git a/tuprolog/solve/prolog/_definitions.py b/tuprolog/solve/prolog/_definitions.py new file mode 100644 index 0000000..b3fe98c --- /dev/null +++ b/tuprolog/solve/prolog/_definitions.py @@ -0,0 +1,8 @@ +from tuprolog import logger +from tuprolog.solve import Solver, SolverFactory + + +PROLOG_SOLVER_FACTORY: SolverFactory = Solver.prolog() + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.prolog.*") diff --git a/tuprolog/solve/sideffcts/__init__.py b/tuprolog/solve/sideffcts/__init__.py deleted file mode 100644 index 5fa38f3..0000000 --- a/tuprolog/solve/sideffcts/__init__.py +++ /dev/null @@ -1,185 +0,0 @@ -from functools import reduce - -from tuprolog import logger - -# noinspection PyUnresolvedReferences -import jpype -# noinspection PyUnresolvedReferences -import jpype.imports - -# noinspection PyUnresolvedReferences -from it.unibo.tuprolog.solve.sideffects import SideEffect -# noinspection PyUnresolvedReferences -from it.unibo.tuprolog.solve.sideffects import SideEffectFactory -# noinspection PyUnresolvedReferences -from it.unibo.tuprolog.solve.sideffects import SideEffectsBuilder - -# noinspection PyUnresolvedReferences -from tuprolog.core import Clause, Term -# noinspection PyUnresolvedReferences -from tuprolog.core.operators import Operator, OperatorSet -# noinspection PyUnresolvedReferences -from tuprolog.solve.library import Library, AliasedLibrary, Libraries, libraries as new_libraries -# noinspection PyUnresolvedReferences -from tuprolog.solve.channel import InputChannel, OutputChannel -from tuprolog.pyutils import iterable_or_varargs, dict_or_keyword_args -from tuprolog.jvmutils import jlist, jmap - -from typing import Mapping, Union, Iterable, Any - - -def _forward_iterable_or_varargs(callable, args, *callable_args): - return iterable_or_varargs(args, lambda xs: callable(jlist(xs), *callable_args)) - - -def _forward_dict_or_keywords(callable, dict, kwargs, *callable_args): - return dict_or_keyword_args(dict, kwargs, lambda ds: callable(jmap(ds), *callable_args)) - - -def reset_static_kb(*clauses: Union[Clause, Iterable[Clause]]) -> SideEffect.ResetStaticKb: - return _forward_iterable_or_varargs(SideEffect.ResetStaticKb, clauses) - - -def add_static_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> SideEffect.AddStaticClauses: - return _forward_iterable_or_varargs(SideEffect.AddStaticClauses, clauses) - - -def remove_static_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> SideEffect.RemoveStaticClauses: - return _forward_iterable_or_varargs(SideEffect.RemoveStaticClauses, clauses) - - -def reset_dynamic_kb(*clauses: Union[Clause, Iterable[Clause]]) -> SideEffect.ResetDynamicKb: - return _forward_iterable_or_varargs(SideEffect.ResetDynamicKb, clauses) - - -def add_dynamic_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> SideEffect.AddDynamicClauses: - return _forward_iterable_or_varargs(SideEffect.AddDynamicClauses, clauses) - - -def remove_dynamic_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> SideEffect.RemoveDynamicClauses: - return _forward_iterable_or_varargs(SideEffect.RemoveDynamicClauses, clauses) - - -def set_flags(flags: Mapping[str, Term] = {}, **kwargs: Term) -> SideEffect.SetFlags: - return _forward_dict_or_keywords(SideEffect.SetFlags, flags, kwargs) - - -def reset_flags(flags: Mapping[str, Term] = {}, **kwargs: Term) -> SideEffect.ResetFlags: - return _forward_dict_or_keywords(SideEffect.ResetFlags, flags, kwargs) - - -def clear_flags(*flag_names: str) -> SideEffect.ClearFlags: - return _forward_iterable_or_varargs(SideEffect.ClearFlags, flag_names) - - -def load_library(alias: str, library: Library) -> SideEffect.LoadLibrary: - return SideEffect.LoadLibrary(alias, library) - - -def unload_libraries(*aliases: str) -> SideEffect.UnloadLibraries: - return _forward_iterable_or_varargs(SideEffect.UnloadLibraries, aliases) - - -def update_library(alias: str, library: Library) -> SideEffect.UpdateLibrary: - return SideEffect.UpdateLibrary(alias, library) - - -def add_libraries(*libraries: Union[Libraries, AliasedLibrary]) -> SideEffect.AddLibraries: - return SideEffect.AddLibraries(new_libraries(libraries)) - - -def reset_libraries(*libraries: Union[Libraries, AliasedLibrary]) -> SideEffect.ResetLibraries: - return SideEffect.ResetLibraries(new_libraries(libraries)) - - -def set_operators(*operators: Union[Operator, Iterable[Operator]]) -> SideEffect.SetOperators: - return _forward_iterable_or_varargs(SideEffect.SetOperators, operators) - - -def reset_operators(*operators: Union[Operator, Iterable[Operator]]) -> SideEffect.ResetOperators: - return _forward_iterable_or_varargs(SideEffect.ResetOperators, operators) - - -def remove_operators(*operators: Union[Operator, Iterable[Operator]]) -> SideEffect.RemoveOperators: - return _forward_iterable_or_varargs(SideEffect.RemoveOperators, operators) - - -def open_input_channels( - channels: Mapping[str, InputChannel] = {}, - **kwargs: InputChannel -) -> SideEffect.OpenInputChannels: - return _forward_dict_or_keywords(SideEffect.OpenInputChannels, channels, kwargs) - - -def reset_input_channels( - channels: Mapping[str, InputChannel] = {}, - **kwargs: InputChannel -) -> SideEffect.ResetInputChannels: - return _forward_dict_or_keywords(SideEffect.ResetInputChannels, channels, kwargs) - - -def close_input_channels(*names: Union[str, Iterable[str]]) -> SideEffect.CloseInputChannels: - return _forward_iterable_or_varargs(SideEffect.CloseInputChannels, names) - - -def open_output_channels( - channels: Mapping[str, OutputChannel] = {}, - **kwargs: OutputChannel -) -> SideEffect.OpenOutputChannels: - return _forward_dict_or_keywords(SideEffect.OpenOutputChannels, channels, kwargs) - - -def reset_output_channels( - channels: Mapping[str, OutputChannel] = {}, - **kwargs: OutputChannel -) -> SideEffect.ResetOutputChannels: - return _forward_dict_or_keywords(SideEffect.ResetOutputChannels, channels, kwargs) - - -def close_output_channels(*names: Union[str, Iterable[str]]) -> SideEffect.CloseOutputChannels: - return _forward_iterable_or_varargs(SideEffect.CloseOutputChannels, names) - - -def set_persistent_data( - data: Mapping[str, Any] = {}, - **kwargs: Any -) -> SideEffect.SetPersistentData: - return _forward_dict_or_keywords(SideEffect.SetPersistentData, data, kwargs, False) - - -def reset_persistent_data( - data: Mapping[str, Any] = {}, - **kwargs: Any -) -> SideEffect.SetPersistentData: - return _forward_dict_or_keywords(SideEffect.SetPersistentData, data, kwargs, True) - - -def set_durable_data( - data: Mapping[str, Any] = {}, - **kwargs: Any -) -> SideEffect.SetDurableData: - return _forward_dict_or_keywords(SideEffect.SetDurableData, data, kwargs, False) - - -def reset_durable_data( - data: Mapping[str, Any] = {}, - **kwargs: Any -) -> SideEffect.SetDurableData: - return _forward_dict_or_keywords(SideEffect.SetDurableData, data, kwargs, True) - - -def set_ephemeral_data( - data: Mapping[str, Any] = {}, - **kwargs: Any -) -> SideEffect.SetEphemeralData: - return _forward_dict_or_keywords(SideEffect.SetEphemeralData, data, kwargs, False) - - -def reset_ephemeral_data( - data: Mapping[str, Any] = {}, - **kwargs: Any -) -> SideEffect.SetEphemeralData: - return _forward_dict_or_keywords(SideEffect.SetEphemeralData, data, kwargs, True) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.sideffects.*") diff --git a/tuprolog/solve/sideffects/__init__.py b/tuprolog/solve/sideffects/__init__.py new file mode 100644 index 0000000..3272497 --- /dev/null +++ b/tuprolog/solve/sideffects/__init__.py @@ -0,0 +1,2 @@ +from ._definitions import * +from ._api import * diff --git a/tuprolog/solve/sideffects/_api.py b/tuprolog/solve/sideffects/_api.py new file mode 100644 index 0000000..60ac411 --- /dev/null +++ b/tuprolog/solve/sideffects/_api.py @@ -0,0 +1,166 @@ +from typing import Mapping, Union, Iterable, Any +from tuprolog.core import Clause, Term +from tuprolog.pyutils import iterable_or_varargs, dict_or_keyword_args +from tuprolog.jvmutils import jlist, jmap +from tuprolog.core.operators import Operator +from tuprolog.solve.library import Library, libraries as new_libraries +from tuprolog.solve.channel import InputChannel, OutputChannel +from ._definitions import ResetStaticKb, AddStaticClauses, RemoveStaticClauses, ResetDynamicKb, AddDynamicClauses, \ + RemoveDynamicClauses, SetFlags, ResetFlags, ClearFlags, LoadLibrary, UnloadLibraries, UpdateLibrary, AddLibraries, \ + ResetRuntime, SetOperators, ResetOperators, RemoveOperators, OpenInputChannels, ResetInputChannels, \ + CloseInputChannels, OpenOutputChannels, ResetOutputChannels, CloseOutputChannels, SetPersistentData, SetDurableData, \ + SetEphemeralData + + +def _forward_iterable_or_varargs(callable, args, *callable_args): + return iterable_or_varargs(args, lambda xs: callable(jlist(xs), *callable_args)) + + +def _forward_dict_or_keywords(callable, dict, kwargs, *callable_args): + return dict_or_keyword_args(dict, kwargs, lambda ds: callable(jmap(ds), *callable_args)) + + +def reset_static_kb(*clauses: Union[Clause, Iterable[Clause]]) -> ResetStaticKb: + return _forward_iterable_or_varargs(ResetStaticKb, clauses) + + +def add_static_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> AddStaticClauses: + return _forward_iterable_or_varargs(AddStaticClauses, clauses) + + +def remove_static_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> RemoveStaticClauses: + return _forward_iterable_or_varargs(RemoveStaticClauses, clauses) + + +def reset_dynamic_kb(*clauses: Union[Clause, Iterable[Clause]]) -> ResetDynamicKb: + return _forward_iterable_or_varargs(ResetDynamicKb, clauses) + + +def add_dynamic_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> AddDynamicClauses: + return _forward_iterable_or_varargs(AddDynamicClauses, clauses) + + +def remove_dynamic_clauses(*clauses: Union[Clause, Iterable[Clause]]) -> RemoveDynamicClauses: + return _forward_iterable_or_varargs(RemoveDynamicClauses, clauses) + + +def set_flags(flags: Mapping[str, Term] = {}, **kwargs: Term) -> SetFlags: + return _forward_dict_or_keywords(SetFlags, flags, kwargs) + + +def reset_flags(flags: Mapping[str, Term] = {}, **kwargs: Term) -> ResetFlags: + return _forward_dict_or_keywords(ResetFlags, flags, kwargs) + + +def clear_flags(*flag_names: str) -> ClearFlags: + return _forward_iterable_or_varargs(ClearFlags, flag_names) + + +def load_library(alias: str, library: Library) -> LoadLibrary: + return LoadLibrary(alias, library) + + +def unload_libraries(*aliases: str) -> UnloadLibraries: + return _forward_iterable_or_varargs(UnloadLibraries, aliases) + + +def update_library(alias: str, library: Library) -> UpdateLibrary: + return UpdateLibrary(alias, library) + + +def add_libraries(*libraries: Library) -> AddLibraries: + return AddLibraries(new_libraries(libraries)) + + +def reset_libraries(*libraries: Library) -> ResetRuntime: + return ResetRuntime(new_libraries(libraries)) + + +def set_operators(*operators: Union[Operator, Iterable[Operator]]) -> SetOperators: + return _forward_iterable_or_varargs(SetOperators, operators) + + +def reset_operators(*operators: Union[Operator, Iterable[Operator]]) -> ResetOperators: + return _forward_iterable_or_varargs(ResetOperators, operators) + + +def remove_operators(*operators: Union[Operator, Iterable[Operator]]) -> RemoveOperators: + return _forward_iterable_or_varargs(RemoveOperators, operators) + + +def open_input_channels( + channels: Mapping[str, InputChannel] = {}, + **kwargs: InputChannel +) -> OpenInputChannels: + return _forward_dict_or_keywords(OpenInputChannels, channels, kwargs) + + +def reset_input_channels( + channels: Mapping[str, InputChannel] = {}, + **kwargs: InputChannel +) -> ResetInputChannels: + return _forward_dict_or_keywords(ResetInputChannels, channels, kwargs) + + +def close_input_channels(*names: Union[str, Iterable[str]]) -> CloseInputChannels: + return _forward_iterable_or_varargs(CloseInputChannels, names) + + +def open_output_channels( + channels: Mapping[str, OutputChannel] = {}, + **kwargs: OutputChannel +) -> OpenOutputChannels: + return _forward_dict_or_keywords(OpenOutputChannels, channels, kwargs) + + +def reset_output_channels( + channels: Mapping[str, OutputChannel] = {}, + **kwargs: OutputChannel +) -> ResetOutputChannels: + return _forward_dict_or_keywords(ResetOutputChannels, channels, kwargs) + + +def close_output_channels(*names: Union[str, Iterable[str]]) -> CloseOutputChannels: + return _forward_iterable_or_varargs(CloseOutputChannels, names) + + +def set_persistent_data( + data: Mapping[str, Any] = {}, + **kwargs: Any +) -> SetPersistentData: + return _forward_dict_or_keywords(SetPersistentData, data, kwargs, False) + + +def reset_persistent_data( + data: Mapping[str, Any] = {}, + **kwargs: Any +) -> SetPersistentData: + return _forward_dict_or_keywords(SetPersistentData, data, kwargs, True) + + +def set_durable_data( + data: Mapping[str, Any] = {}, + **kwargs: Any +) -> SetDurableData: + return _forward_dict_or_keywords(SetDurableData, data, kwargs, False) + + +def reset_durable_data( + data: Mapping[str, Any] = {}, + **kwargs: Any +) -> SetDurableData: + return _forward_dict_or_keywords(SetDurableData, data, kwargs, True) + + +def set_ephemeral_data( + data: Mapping[str, Any] = {}, + **kwargs: Any +) -> SetEphemeralData: + return _forward_dict_or_keywords(SetEphemeralData, data, kwargs, False) + + +def reset_ephemeral_data( + data: Mapping[str, Any] = {}, + **kwargs: Any +) -> SetEphemeralData: + return _forward_dict_or_keywords(SetEphemeralData, data, kwargs, True) diff --git a/tuprolog/solve/sideffects/_definitions.py b/tuprolog/solve/sideffects/_definitions.py new file mode 100644 index 0000000..cfde09c --- /dev/null +++ b/tuprolog/solve/sideffects/_definitions.py @@ -0,0 +1,99 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.sideffects as _sideffects # type: ignore + + +SideEffect = _sideffects.SideEffect + + +ResetStaticKb = SideEffect.ResetStaticKb + + +AddStaticClauses = SideEffect.AddStaticClauses + + +RemoveStaticClauses = SideEffect.RemoveStaticClauses + + +ResetDynamicKb = SideEffect.ResetDynamicKb + + +AddDynamicClauses = SideEffect.AddDynamicClauses + + +RemoveDynamicClauses = SideEffect.RemoveDynamicClauses + + +SetFlags = SideEffect.SetFlags + + +ResetFlags = SideEffect.ResetFlags + + +ClearFlags = SideEffect.ClearFlags + + +LoadLibrary = SideEffect.LoadLibrary + + +UnloadLibraries = SideEffect.UnloadLibraries + + +UpdateLibrary = SideEffect.UpdateLibrary + + +AddLibraries = SideEffect.AddLibraries + + +ResetRuntime = SideEffect.ResetRuntime + + +SetOperators = SideEffect.SetOperators + + +ResetOperators = SideEffect.ResetOperators + + +RemoveOperators = SideEffect.RemoveOperators + + +OpenInputChannels = SideEffect.OpenInputChannels + + +ResetInputChannels = SideEffect.ResetInputChannels + + +CloseInputChannels = SideEffect.CloseInputChannels + + +OpenOutputChannels = SideEffect.OpenOutputChannels + + +ResetOutputChannels = SideEffect.ResetOutputChannels + + +CloseOutputChannels = SideEffect.CloseOutputChannels + + +SetPersistentData = SideEffect.SetPersistentData + + +SetDurableData = SideEffect.SetDurableData + + +SetEphemeralData = SideEffect.SetEphemeralData + + +SideEffectFactory = _sideffects.SideEffectFactory + + +DEFAULT_SIDE_EFFECT_FACTORY = SideEffectFactory.getDefault() + + +SideEffectManager = _sideffects.SideEffectManager + + +SideEffectsBuilder = _sideffects.SideEffectsBuilder + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.sideffects.*") diff --git a/tuprolog/solve/stdlib/__init__.py b/tuprolog/solve/stdlib/__init__.py index 1d7a1d6..47c7575 100644 --- a/tuprolog/solve/stdlib/__init__.py +++ b/tuprolog/solve/stdlib/__init__.py @@ -1,17 +1 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.stdlib as _stdlib - - -CommonBuiltins = _stdlib.CommonBuiltins - -CommonFunctions = _stdlib.CommonFunctions - -CommonPrimitives = _stdlib.CommonPrimitives - -CommonRules = _stdlib.CommonRules - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.stdlib.*") +from ._definitions import * diff --git a/tuprolog/solve/stdlib/_definitions.py b/tuprolog/solve/stdlib/_definitions.py new file mode 100644 index 0000000..0ec64a0 --- /dev/null +++ b/tuprolog/solve/stdlib/_definitions.py @@ -0,0 +1,18 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.stdlib as _stdlib # type: ignore + + +CommonBuiltins: _stdlib.CommonBuiltins = _stdlib.CommonBuiltins.INSTANCE + + +CommonFunctions: _stdlib.CommonFunctions = _stdlib.CommonFunctions.INSTANCE + + +CommonPrimitives: _stdlib.CommonPrimitives = _stdlib.CommonPrimitives.INSTANCE + + +CommonRules: _stdlib.CommonRules = _stdlib.CommonRules.INSTANCE + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.stdlib.*") diff --git a/tuprolog/solve/stdlib/function/__init__.py b/tuprolog/solve/stdlib/function.py similarity index 90% rename from tuprolog/solve/stdlib/function/__init__.py rename to tuprolog/solve/stdlib/function.py index f544358..968506b 100644 --- a/tuprolog/solve/stdlib/function/__init__.py +++ b/tuprolog/solve/stdlib/function.py @@ -1,66 +1,92 @@ from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.stdlib.function as _function +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.stdlib.function as _function # type: ignore AbsoluteValue = _function.AbsoluteValue.INSTANCE + Addition = _function.Addition.INSTANCE + ArcTangent = _function.ArcTangent.INSTANCE + BitwiseAnd = _function.BitwiseAnd.INSTANCE + BitwiseComplement = _function.BitwiseComplement.INSTANCE + BitwiseLeftShift = _function.BitwiseLeftShift.INSTANCE + BitwiseOr = _function.BitwiseOr.INSTANCE + BitwiseRightShift = _function.BitwiseRightShift.INSTANCE + Ceiling = _function.Ceiling.INSTANCE + Cosine = _function.Cosine.INSTANCE + Exponential = _function.Exponential.INSTANCE + Exponentiation = _function.Exponentiation.INSTANCE + FloatFractionalPart = _function.FloatFractionalPart.INSTANCE + FloatIntegerPart = _function.FloatIntegerPart.INSTANCE + FloatingPointDivision = _function.FloatingPointDivision.INSTANCE + Floor = _function.Floor.INSTANCE + IntegerDivision = _function.IntegerDivision.INSTANCE + Modulo = _function.Modulo.INSTANCE + Multiplication = _function.Multiplication.INSTANCE + NaturalLogarithm = _function.NaturalLogarithm.INSTANCE + Remainder = _function.Remainder.INSTANCE + Round = _function.Round.INSTANCE + Sign = _function.Sign.INSTANCE + SignReversal = _function.SignReversal.INSTANCE + Sine = _function.Sine.INSTANCE + SquareRoot = _function.SquareRoot.INSTANCE + Subtraction = _function.Subtraction.INSTANCE + ToFloat = _function.ToFloat.INSTANCE + Truncate = _function.Truncate.INSTANCE diff --git a/tuprolog/solve/stdlib/magic.py b/tuprolog/solve/stdlib/magic.py new file mode 100644 index 0000000..d012dae --- /dev/null +++ b/tuprolog/solve/stdlib/magic.py @@ -0,0 +1,9 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.stdlib.magic as _magic # type: ignore + + +MagicCut: _magic.MagicCut = _magic.MagicCut.INSTANCE + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.stdlib.magic.*") diff --git a/tuprolog/solve/stdlib/primitive.py b/tuprolog/solve/stdlib/primitive.py new file mode 100644 index 0000000..b6e9dd4 --- /dev/null +++ b/tuprolog/solve/stdlib/primitive.py @@ -0,0 +1,213 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.stdlib.primitive as _primitive # type: ignore + + +Abolish: _primitive.Abolish = _primitive.Abolish.INSTANCE + + +Arg: _primitive.Arg = _primitive.Arg.INSTANCE + + +ArithmeticEqual: _primitive.ArithmeticEqual = _primitive.ArithmeticEqual.INSTANCE + + +ArithmeticGreaterThan: _primitive.ArithmeticGreaterThan = _primitive.ArithmeticGreaterThan.INSTANCE + + +ArithmeticGreaterThanOrEqualTo: _primitive.ArithmeticGreaterThanOrEqualTo = _primitive.ArithmeticGreaterThanOrEqualTo.INSTANCE + + +ArithmeticLowerThan: _primitive.ArithmeticLowerThan = _primitive.ArithmeticLowerThan.INSTANCE + + +ArithmeticLowerThanOrEqualTo: _primitive.ArithmeticLowerThanOrEqualTo = _primitive.ArithmeticLowerThanOrEqualTo.INSTANCE + + +ArithmeticNotEqual: _primitive.ArithmeticNotEqual = _primitive.ArithmeticNotEqual.INSTANCE + + +Assert: _primitive.Assert = _primitive.Assert.INSTANCE + + +AssertA: _primitive.AssertA = _primitive.AssertA.INSTANCE + + +AssertZ: _primitive.AssertZ = _primitive.AssertZ.INSTANCE + + +Atom: _primitive.Atom = _primitive.Atom.INSTANCE + + +AtomChars: _primitive.AtomChars = _primitive.AtomChars.INSTANCE + + +AtomCodes: _primitive.AtomCodes = _primitive.AtomCodes.INSTANCE + + +AtomConcat: _primitive.AtomConcat = _primitive.AtomConcat.INSTANCE + + +AtomLength: _primitive.AtomLength = _primitive.AtomLength.INSTANCE + + +Atomic: _primitive.Atomic = _primitive.Atomic.INSTANCE + + +BagOf: _primitive.BagOf = _primitive.BagOf.INSTANCE + + +Between: _primitive.Between = _primitive.Between.INSTANCE + + +Callable: _primitive.Callable = _primitive.Callable.INSTANCE + + +CharCode: _primitive.CharCode = _primitive.CharCode.INSTANCE + + +Clause: _primitive.Clause = _primitive.Clause.INSTANCE + + +Compound: _primitive.Compound = _primitive.Compound.INSTANCE + + +CopyTerm: _primitive.CopyTerm = _primitive.CopyTerm.INSTANCE + + +CurrentFlag: _primitive.CurrentFlag = _primitive.CurrentFlag.INSTANCE + + +CurrentOp: _primitive.CurrentOp = _primitive.CurrentOp.INSTANCE + + +EnsureExecutable: _primitive.EnsureExecutable = _primitive.EnsureExecutable.INSTANCE + + +FindAll: _primitive.FindAll = _primitive.FindAll.INSTANCE + + +Float: _primitive.Float = _primitive.Float.INSTANCE + + +Functor: _primitive.Functor = _primitive.Functor.INSTANCE + + +GetDurable: _primitive.GetDurable = _primitive.GetDurable.INSTANCE + + +GetEphemeral: _primitive.GetEphemeral = _primitive.GetEphemeral.INSTANCE + + +GetPersistent: _primitive.GetPersistent = _primitive.GetPersistent.INSTANCE + + +Ground: _primitive.Ground = _primitive.Ground.INSTANCE + + +Halt: _primitive.Halt = _primitive.Halt.INSTANCE + + +Halt1: _primitive.Halt1 = _primitive.Halt1.INSTANCE + + +Integer: _primitive.Integer = _primitive.Integer.INSTANCE + + +Is: _primitive.Is = _primitive.Is.INSTANCE + + +Natural: _primitive.Natural = _primitive.Natural.INSTANCE + + +NewLine: _primitive.NewLine = _primitive.NewLine.INSTANCE + + +NonVar: _primitive.NonVar = _primitive.NonVar.INSTANCE + + +NotUnifiableWith: _primitive.NotUnifiableWith = _primitive.NotUnifiableWith.INSTANCE + + +Number: _primitive.Number = _primitive.Number.INSTANCE + + +NumberChars: _primitive.NumberChars = _primitive.NumberChars.INSTANCE + + +NumberCodes: _primitive.NumberCodes = _primitive.NumberCodes.INSTANCE + + +Op: _primitive.Op = _primitive.Op.INSTANCE + + +Repeat: _primitive.Repeat = _primitive.Repeat.INSTANCE + + +Retract: _primitive.Retract = _primitive.Retract.INSTANCE + + +RetractAll: _primitive.RetractAll = _primitive.RetractAll.INSTANCE + + +Reverse: _primitive.Reverse = _primitive.Reverse.INSTANCE + + +SetDurable: _primitive.SetDurable = _primitive.SetDurable.INSTANCE + + +SetEphemeral: _primitive.SetEphemeral = _primitive.SetEphemeral.INSTANCE + + +SetFlag: _primitive.SetFlag = _primitive.SetFlag.INSTANCE + + +SetOf: _primitive.SetOf = _primitive.SetOf.INSTANCE + + +SetPersistent: _primitive.SetPersistent = _primitive.SetPersistent.INSTANCE + + +Sleep: _primitive.Sleep = _primitive.Sleep.INSTANCE + + +SubAtom: _primitive.SubAtom = _primitive.SubAtom.INSTANCE + + +TermGreaterThan: _primitive.TermGreaterThan = _primitive.TermGreaterThan.INSTANCE + + +TermGreaterThanOrEqualTo: _primitive.TermGreaterThanOrEqualTo = _primitive.TermGreaterThanOrEqualTo.INSTANCE + + +TermIdentical: _primitive.TermIdentical = _primitive.TermIdentical.INSTANCE + + +TermLowerThan: _primitive.TermLowerThan = _primitive.TermLowerThan.INSTANCE + + +TermLowerThanOrEqualTo: _primitive.TermLowerThanOrEqualTo = _primitive.TermLowerThanOrEqualTo.INSTANCE + + +TermNotIdentical: _primitive.TermNotIdentical = _primitive.TermNotIdentical.INSTANCE + + +TermNotSame: _primitive.TermNotSame = _primitive.TermNotSame.INSTANCE + + +TermSame: _primitive.TermSame = _primitive.TermSame.INSTANCE + + +UnifiesWith: _primitive.UnifiesWith = _primitive.UnifiesWith.INSTANCE + + +Univ: _primitive.Univ = _primitive.Univ.INSTANCE + + +Var: _primitive.Var = _primitive.Var.INSTANCE + + +Write: _primitive.Write = _primitive.Write.INSTANCE + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.stdlib.primitive.*") diff --git a/tuprolog/solve/stdlib/primitive/__init__.py b/tuprolog/solve/stdlib/primitive/__init__.py deleted file mode 100644 index 0220484..0000000 --- a/tuprolog/solve/stdlib/primitive/__init__.py +++ /dev/null @@ -1,147 +0,0 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.stdlib.primitive as _primitive - - -Abolish = _primitive.Abolish.INSTANCE - -Arg = _primitive.Arg.INSTANCE - -ArithmeticEqual = _primitive.ArithmeticEqual.INSTANCE - -ArithmeticGreaterThan = _primitive.ArithmeticGreaterThan.INSTANCE - -ArithmeticGreaterThanOrEqualTo = _primitive.ArithmeticGreaterThanOrEqualTo.INSTANCE - -ArithmeticLowerThan = _primitive.ArithmeticLowerThan.INSTANCE - -ArithmeticLowerThanOrEqualTo = _primitive.ArithmeticLowerThanOrEqualTo.INSTANCE - -ArithmeticNotEqual = _primitive.ArithmeticNotEqual.INSTANCE - -Assert = _primitive.Assert.INSTANCE - -AssertA = _primitive.AssertA.INSTANCE - -AssertZ = _primitive.AssertZ.INSTANCE - -Atom = _primitive.Atom.INSTANCE - -AtomChars = _primitive.AtomChars.INSTANCE - -AtomCodes = _primitive.AtomCodes.INSTANCE - -AtomConcat = _primitive.AtomConcat.INSTANCE - -AtomLength = _primitive.AtomLength.INSTANCE - -Atomic = _primitive.Atomic.INSTANCE - -BagOf = _primitive.BagOf.INSTANCE - -Between = _primitive.Between.INSTANCE - -Callable = _primitive.Callable.INSTANCE - -CharCode = _primitive.CharCode.INSTANCE - -Clause = _primitive.Clause.INSTANCE - -Compound = _primitive.Compound.INSTANCE - -CopyTerm = _primitive.CopyTerm.INSTANCE - -CurrentFlag = _primitive.CurrentFlag.INSTANCE - -CurrentOp = _primitive.CurrentOp.INSTANCE - -EnsureExecutable = _primitive.EnsureExecutable.INSTANCE - -FindAll = _primitive.FindAll.INSTANCE - -Float = _primitive.Float.INSTANCE - -Functor = _primitive.Functor.INSTANCE - -GetDurable = _primitive.GetDurable.INSTANCE - -GetEphemeral = _primitive.GetEphemeral.INSTANCE - -GetPersistent = _primitive.GetPersistent.INSTANCE - -Ground = _primitive.Ground.INSTANCE - -Halt = _primitive.Halt.INSTANCE - -Halt1 = _primitive.Halt1.INSTANCE - -Integer = _primitive.Integer.INSTANCE - -Is = _primitive.Is.INSTANCE - -Natural = _primitive.Natural.INSTANCE - -NewLine = _primitive.NewLine.INSTANCE - -NonVar = _primitive.NonVar.INSTANCE - -NotUnifiableWith = _primitive.NotUnifiableWith.INSTANCE - -Number = _primitive.Number.INSTANCE - -NumberChars = _primitive.NumberChars.INSTANCE - -NumberCodes = _primitive.NumberCodes.INSTANCE - -Op = _primitive.Op.INSTANCE - -Repeat = _primitive.Repeat.INSTANCE - -Retract = _primitive.Retract.INSTANCE - -RetractAll = _primitive.RetractAll.INSTANCE - -Reverse = _primitive.Reverse.INSTANCE - -SetDurable = _primitive.SetDurable.INSTANCE - -SetEphemeral = _primitive.SetEphemeral.INSTANCE - -SetFlag = _primitive.SetFlag.INSTANCE - -SetOf = _primitive.SetOf.INSTANCE - -SetPersistent = _primitive.SetPersistent.INSTANCE - -Sleep = _primitive.Sleep.INSTANCE - -SubAtom = _primitive.SubAtom.INSTANCE - -TermGreaterThan = _primitive.TermGreaterThan.INSTANCE - -TermGreaterThanOrEqualTo = _primitive.TermGreaterThanOrEqualTo.INSTANCE - -TermIdentical = _primitive.TermIdentical.INSTANCE - -TermLowerThan = _primitive.TermLowerThan.INSTANCE - -TermLowerThanOrEqualTo = _primitive.TermLowerThanOrEqualTo.INSTANCE - -TermNotIdentical = _primitive.TermNotIdentical.INSTANCE - -TermNotSame = _primitive.TermNotSame.INSTANCE - -TermSame = _primitive.TermSame.INSTANCE - -UnifiesWith = _primitive.UnifiesWith.INSTANCE - -Univ = _primitive.Univ.INSTANCE - -Var = _primitive.Var.INSTANCE - -Write = _primitive.Write.INSTANCE - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.stdlib.primitive.*") diff --git a/tuprolog/solve/stdlib/rule.py b/tuprolog/solve/stdlib/rule.py new file mode 100644 index 0000000..88b5b9a --- /dev/null +++ b/tuprolog/solve/stdlib/rule.py @@ -0,0 +1,73 @@ +from tuprolog import logger +from tuprolog.solve import signature +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.solve.stdlib.rule as _rule # type: ignore + + +_Append = _rule.Append + + +class Append: + FUNCTOR = _Append.FUNCTOR + + ARITY = _Append.ARITY + + SIGNATURE = signature(FUNCTOR, ARITY) + + Base = _Append.Base.INSTANCE + + Recursive = _Append.Recursive.INSTANCE + + +Arrow: _rule.Arrow = _rule.Arrow.INSTANCE + + +CurrentPrologFlag: _rule.CurrentPrologFlag = _rule.CurrentPrologFlag.INSTANCE + + +_Member = _rule.Member + + +class Member: + FUNCTOR = _Member.FUNCTOR + + ARITY = _Member.ARITY + + SIGNATURE = signature(FUNCTOR, ARITY) + + Base = _Member.Base.INSTANCE + + Recursive = _Member.Recursive.INSTANCE + + +Not: _rule.Not = _rule.Not.INSTANCE + + +Once: _rule.Once = _rule.Once.INSTANCE + + +_Semicolon = _rule.Semicolon + + +class Semicolon: + FUNCTOR = _Semicolon.FUNCTOR + + ARITY = _Semicolon.ARITY + + SIGNATURE = signature(FUNCTOR, ARITY) + + class If: + Then = _Semicolon.If.Then.INSTANCE + + Else = _Semicolon.If.Else.INSTANCE + + class Or: + Left = _Semicolon.Or.Left.INSTANCE + + Right = _Semicolon.Or.Right.INSTANCE + + +SetPrologFlag: _rule.SetPrologFlag = _rule.SetPrologFlag.INSTANCE + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.stdlib.rule.*") diff --git a/tuprolog/solve/stdlib/rule/__init__.py b/tuprolog/solve/stdlib/rule/__init__.py deleted file mode 100644 index 29a4020..0000000 --- a/tuprolog/solve/stdlib/rule/__init__.py +++ /dev/null @@ -1,78 +0,0 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.solve.stdlib.rule as _rule -from tuprolog.solve import signature - - -KtAppend = _rule.Append - -Arrow = _rule.Arrow - -CurrentPrologFlag = _rule.CurrentPrologFlag - -KtMember = _rule.Member - -Not = _rule.Not - -Once = _rule.Once - -KtSemicolon = _rule.Semicolon - -SetPrologFlag = _rule.SetPrologFlag - - -class Append: - FUNCTOR = KtAppend.FUNCTOR - - ARITY = KtAppend.ARITY - - SIGNATURE = signature(FUNCTOR, ARITY) - - Base = KtAppend.Base.INSTANCE - - Recursive = KtAppend.Recursive.INSTANCE - - -Arrow = Arrow.INSTANCE - -CurrentPrologFlag = CurrentPrologFlag.INSTANCE - - -class Member: - FUNCTOR = KtMember.FUNCTOR - - ARITY = KtMember.ARITY - - SIGNATURE = signature(FUNCTOR, ARITY) - - Base = KtMember.Base.INSTANCE - - Recursive = KtMember.Recursive.INSTANCE - - -Not = Not.INSTANCE - -Once = Once.INSTANCE - - -class Semicolon: - FUNCTOR = KtSemicolon.FUNCTOR - - ARITY = KtSemicolon.ARITY - - SIGNATURE = signature(FUNCTOR, ARITY) - - class If: - Then = KtSemicolon.If.Then.INSTANCE - - Else = KtSemicolon.If.Else.INSTANCE - - class Or: - Left = KtSemicolon.Or.Left.INSTANCE - - Right = KtSemicolon.Or.Right.INSTANCE - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.solve.stdlib.rule.*") diff --git a/tuprolog/theory/__init__.py b/tuprolog/theory/__init__.py index 19e1ac0..ddab90b 100644 --- a/tuprolog/theory/__init__.py +++ b/tuprolog/theory/__init__.py @@ -1,26 +1,3 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.theory as _theory -from typing import Iterable, Union -from tuprolog.core import Clause -from tuprolog.pyutils import iterable_or_varargs -from tuprolog.jvmutils import jiterable - -Theory = _theory.Theory - -MutableTheory = _theory.MutableTheory - -RetractResult = _theory.RetractResult - - -def theory(*clauses: Union[Clause, Iterable[Clause]]) -> Theory: - return iterable_or_varargs(clauses, lambda ts: Theory.of(jiterable(ts))) - - -def mutable_theory(*clauses: Union[Clause, Iterable[Clause]]) -> MutableTheory: - return iterable_or_varargs(clauses, lambda ts: MutableTheory.of(jiterable(ts))) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.theory.*") +import tuprolog.theory._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/theory/_adapters.py b/tuprolog/theory/_adapters.py new file mode 100644 index 0000000..2a8bfb0 --- /dev/null +++ b/tuprolog/theory/_adapters.py @@ -0,0 +1,68 @@ +from typing import Sized +from jpype import JImplementationFor, JOverride +from tuprolog import logger +from tuprolog.core import indicator as new_indicator +from tuprolog.jvmutils import jiterable +from tuprolog.pyutils import iterable_or_varargs + + +@JImplementationFor("it.unibo.tuprolog.theory.Theory") +class _KtTheory: + def __jclass_init__(cls): + Sized.register(cls) + + def __len__(self): + return self.getSize() + + def __add__(self, other): + return self.plus(other) + + def __contains__(self, item): + return self.contains(item) + + def __getitem__(self, item): + return self.get(item) + + def _assert(self, method, clause, *clauses): + if len(clauses) == 0: + return method(clause) + return iterable_or_varargs((clause,) + clauses, lambda cs: method(jiterable(cs))) + + def assert_a(self, clause, *clauses): + self._assert(self.assertA, clause, *clauses) + + def assert_z(self, clause, *clauses): + self._assert(self.assertZ, clause, *clauses) + + @JOverride + def retract(self, clause, *clauses): + if len(clauses) == 0: + return self.retract_(clause) + return iterable_or_varargs((clause,) + clauses, lambda cs: self.retract_(jiterable(cs))) + + def retract_all(self, clause): + return self.retractAll(clause) + + @JOverride + def abolish(self, name, arity=None, indicator=None): + if name is not None: + if arity is not None: + return self.abolish_(new_indicator(name, arity)) + else: + return self.abolish_(name) + elif indicator is not None: + return self.abolish_(indicator) + raise ValueError("You should provide at least either a name-arity couple or an indicator") + + @JOverride + def equals(self, other, use_var_complete_name=True): + return self.equals_(other, use_var_complete_name) + + def __eq__(self, other): + return self.equals(other, use_var_complete_name=True) + + def to_string(self, as_prolog_text=False): + return self.toString(as_prolog_text) + + +logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.theory.*") diff --git a/tuprolog/theory/_api.py b/tuprolog/theory/_api.py new file mode 100644 index 0000000..f75c61f --- /dev/null +++ b/tuprolog/theory/_api.py @@ -0,0 +1,14 @@ +from typing import Iterable, Union +from tuprolog.core import Clause +from tuprolog.unify import Unificator +from tuprolog.jvmutils import jiterable +from tuprolog.pyutils import iterable_or_varargs +from ._definitions import Theory, MutableTheory + + +def theory(*clauses: Union[Clause, Iterable[Clause]]) -> Theory: + return iterable_or_varargs(clauses, lambda ts: Theory.of(jiterable(ts))) + + +def mutable_theory(*clauses: Union[Clause, Iterable[Clause]]) -> MutableTheory: + return iterable_or_varargs(clauses, lambda ts: MutableTheory.of(Unificator.getDefault(), jiterable(ts))) diff --git a/tuprolog/theory/_definitions.py b/tuprolog/theory/_definitions.py new file mode 100644 index 0000000..398d7fc --- /dev/null +++ b/tuprolog/theory/_definitions.py @@ -0,0 +1,11 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.theory as _theory # type: ignore + +Theory = _theory.Theory + +MutableTheory = _theory.MutableTheory + +RetractResult = _theory.RetractResult + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.theory.*") diff --git a/tuprolog/theory/parsing.py b/tuprolog/theory/parsing.py deleted file mode 100644 index 5c2cb1d..0000000 --- a/tuprolog/theory/parsing.py +++ /dev/null @@ -1,93 +0,0 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.theory.parsing as _parsing -from tuprolog.core import Clause -from tuprolog.theory import Theory -from tuprolog.jvmutils import InputStream, ensure_input_steam -from tuprolog.core.operators import OperatorSet, DEFAULT_OPERATORS -from typing import Union, Iterable - - -ClausesParser = _parsing.ClausesParser - -ClausesReader = _parsing.ClausesReader - - -def clauses_parser(with_default_operators: bool = True, operators: OperatorSet = None) -> ClausesParser: - if operators is None: - if with_default_operators: - return ClausesParser.getWithDefaultOperators() - else: - return ClausesParser.getWithNoOperator() - else: - if with_default_operators: - return ClausesParser.withOperators(DEFAULT_OPERATORS.plus(operators)) - else: - return ClausesParser.withOperators(operators) - - -def clauses_reader(with_default_operators: bool = True, operators: OperatorSet = None) -> ClausesReader: - if operators is None: - if with_default_operators: - return ClausesReader.getWithDefaultOperators() - else: - return ClausesReader.getWithNoOperator() - else: - if with_default_operators: - return ClausesReader.withOperators(DEFAULT_OPERATORS.plus(operators)) - else: - return ClausesReader.withOperators(operators) - - -DEFAULT_CLAUSES_PARSER = clauses_parser() - -DEFAULT_CLAUSES_READER = clauses_reader() - - -def parse_theory(string: str, operators: OperatorSet = None) -> Theory: - if operators is None: - return DEFAULT_CLAUSES_PARSER.parseTheory(string) - else: - return DEFAULT_CLAUSES_PARSER.parseTheory(string, operators) - - -def parse_clauses(string: str, operators: OperatorSet = None, lazy: bool = True) -> Iterable[Clause]: - if lazy: - if operators is None: - return DEFAULT_CLAUSES_PARSER.parseClausesLazily(string) - else: - return DEFAULT_CLAUSES_PARSER.parseClausesLazily(string, operators) - else: - if operators is None: - return DEFAULT_CLAUSES_PARSER.parseClauses(string) - else: - return DEFAULT_CLAUSES_PARSER.parseClauses(string, operators) - - -def read_theory(input: Union[InputStream, str], operators: OperatorSet = None) -> Theory: - input = ensure_input_steam(input) - if operators is None: - return DEFAULT_CLAUSES_READER.readTheory(input) - else: - return DEFAULT_CLAUSES_READER.readTheory(input, operators) - - -def read_clauses(input: Union[InputStream, str], operators: OperatorSet = None, lazy: bool = True) -> Iterable[Clause]: - input = ensure_input_steam(input) - if lazy: - if operators is None: - return DEFAULT_CLAUSES_READER.readClausesLazily(input) - else: - return DEFAULT_CLAUSES_READER.readClausesLazily(input, operators) - else: - if operators is None: - return DEFAULT_CLAUSES_READER.readClauses(input) - else: - return DEFAULT_CLAUSES_READER.readClauses(input, operators) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.theory.parsing.*") diff --git a/tuprolog/theory/parsing/__init__.py b/tuprolog/theory/parsing/__init__.py new file mode 100644 index 0000000..be8a174 --- /dev/null +++ b/tuprolog/theory/parsing/__init__.py @@ -0,0 +1,3 @@ +import tuprolog.theory.parsing._adapters as _ +from ._definitions import * +from ._api import * diff --git a/tuprolog/theory/parsing/_adapters.py b/tuprolog/theory/parsing/_adapters.py new file mode 100644 index 0000000..bd0bffb --- /dev/null +++ b/tuprolog/theory/parsing/_adapters.py @@ -0,0 +1,57 @@ +from jpype import JImplementationFor +from tuprolog import logger +from tuprolog.jvmioutils import ensure_input_steam + + +@JImplementationFor("it.unibo.tuprolog.theory.parsing.ClausesParser") +class _KtClausesParser: + def __jclass_init__(cls): + pass + + @property + def default_operator_set(self): + return self.getDefaultOperatorSet() + + def _parse(self, method, input, operators): + if operators is None: + return method(input) + else: + return method(input, operators) + + def parse_theory(self, input, operators): + return self._parse(self.parseTheory, input, operators) + + def parse_clauses_lazily(self, input, operators): + return self._parse(self.parseClausesLazily, input, operators) + + def parse_clauses(self, input, operators): + return list(self.parse_clauses_lazily(input, operators)) + + +@JImplementationFor("it.unibo.tuprolog.theory.parsing.ClausesReader") +class _KtClausesReader: + def __jclass_init__(cls): + pass + + @property + def default_operator_set(self): + return self.getDefaultOperatorSet() + + def _read(self, method, input, operators): + input_stream = ensure_input_steam(input) + if operators is None: + return method(input_stream) + else: + return method(input_stream, operators) + + def read_theory(self, input, operators): + return self._read(self.readTheory, input, operators) + + def read_clauses_lazily(self, input, operators): + return self._read(self.readClausesLazily, input, operators) + + def read_clauses(self, input, operators): + return list(self.read_clauses_lazily(input, operators)) + + +logger.debug("Configure Kotlin adapters for types in it.unibo.tuprolog.theory.parsing.*") diff --git a/tuprolog/theory/parsing/_api.py b/tuprolog/theory/parsing/_api.py new file mode 100644 index 0000000..2c71a37 --- /dev/null +++ b/tuprolog/theory/parsing/_api.py @@ -0,0 +1,37 @@ +from typing import Union, Iterable +from tuprolog.core import Clause +from tuprolog.core.parsing import parser_factory +from tuprolog.theory import Theory +from tuprolog.jvmioutils import InputStream +from tuprolog.core.operators import OperatorSet +from ._definitions import ClausesParser, ClausesReader, DEFAULT_CLAUSES_PARSER, DEFAULT_CLAUSES_READER + + +def clauses_parser(with_default_operators: bool = True, operators: OperatorSet = None) -> ClausesParser: + return parser_factory(ClausesParser, with_default_operators, operators) + + +def clauses_reader(with_default_operators: bool = True, operators: OperatorSet = None) -> ClausesReader: + return parser_factory(ClausesReader, with_default_operators, operators) + + +def parse_theory(string: str, operators: OperatorSet = None) -> Theory: + return DEFAULT_CLAUSES_PARSER.parse_theory(string, operators) + + +def parse_clauses(string: str, operators: OperatorSet = None, lazy: bool = True) -> Iterable[Clause]: + if lazy: + return DEFAULT_CLAUSES_PARSER.parse_clauses_lazily(string, operators) + else: + return DEFAULT_CLAUSES_PARSER.parse_clauses(string, operators) + + +def read_theory(input: Union[InputStream, str], operators: OperatorSet = None) -> Theory: + return DEFAULT_CLAUSES_READER.read_theory(input, operators) + + +def read_clauses(input: Union[InputStream, str], operators: OperatorSet = None, lazy: bool = True) -> Iterable[Clause]: + if lazy: + return DEFAULT_CLAUSES_READER.read_clauses_lazily(input, operators) + else: + return DEFAULT_CLAUSES_READER.read_clauses(input, operators) diff --git a/tuprolog/theory/parsing/_definitions.py b/tuprolog/theory/parsing/_definitions.py new file mode 100644 index 0000000..8daeedd --- /dev/null +++ b/tuprolog/theory/parsing/_definitions.py @@ -0,0 +1,18 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.theory.parsing as _parsing # type: ignore + + +ClausesParser = _parsing.ClausesParser + + +ClausesReader = _parsing.ClausesReader + + +DEFAULT_CLAUSES_PARSER = ClausesParser.withDefaultOperators() + + +DEFAULT_CLAUSES_READER = ClausesReader.withDefaultOperators() + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.theory.parsing.*") diff --git a/tuprolog/unify/__init__.py b/tuprolog/unify/__init__.py new file mode 100644 index 0000000..3272497 --- /dev/null +++ b/tuprolog/unify/__init__.py @@ -0,0 +1,2 @@ +from ._definitions import * +from ._api import * diff --git a/tuprolog/unify.py b/tuprolog/unify/_api.py similarity index 77% rename from tuprolog/unify.py rename to tuprolog/unify/_api.py index c50e649..6492dc9 100644 --- a/tuprolog/unify.py +++ b/tuprolog/unify/_api.py @@ -1,12 +1,5 @@ -from tuprolog import logger -# noinspection PyUnresolvedReferences -import jpype.imports -# noinspection PyUnresolvedReferences -import it.unibo.tuprolog.unify as _unify from tuprolog.core import Term, Substitution - - -Unificator = _unify.Unificator +from ._definitions import Unificator, DEFAULT_UNIFICATOR def strict_unificator(context: Substitution = None) -> Unificator: @@ -31,9 +24,6 @@ def unificator(context: Substitution = None) -> Unificator: return cached_unificator(strict_unificator(context)) -DEFAULT_UNIFICATOR = Unificator.getDefault() - - def mgu(x: Term, y: Term, occur_check: bool = True) -> Substitution: return DEFAULT_UNIFICATOR.mgu(x, y, occur_check) @@ -44,6 +34,3 @@ def unify(x: Term, y: Term, occur_check: bool = True) -> Term: def match(x: Term, y: Term, occur_check: bool = True) -> bool: return DEFAULT_UNIFICATOR.match(x, y, occur_check) - - -logger.debug("Loaded JVM classes from it.unibo.tuprolog.unify.*") diff --git a/tuprolog/unify/_definitions.py b/tuprolog/unify/_definitions.py new file mode 100644 index 0000000..c14b073 --- /dev/null +++ b/tuprolog/unify/_definitions.py @@ -0,0 +1,12 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.unify as _unify # type: ignore + + +Unificator = _unify.Unificator + + +DEFAULT_UNIFICATOR = Unificator.getDefault() + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.unify.*") diff --git a/tuprolog/unify/exception.py b/tuprolog/unify/exception.py new file mode 100644 index 0000000..afb2463 --- /dev/null +++ b/tuprolog/unify/exception.py @@ -0,0 +1,11 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.unify.exception as _exceptions # type: ignore + + +NoUnifyException = _exceptions.NoUnifyException + +OccurCheckException = _exceptions.OccurCheckException + + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.unify.exception.*") diff --git a/tuprolog/utils/__init__.py b/tuprolog/utils/__init__.py new file mode 100644 index 0000000..2126cab --- /dev/null +++ b/tuprolog/utils/__init__.py @@ -0,0 +1 @@ +from ._definitions import Castable, Taggable diff --git a/tuprolog/utils/_definitions.py b/tuprolog/utils/_definitions.py new file mode 100644 index 0000000..c269d84 --- /dev/null +++ b/tuprolog/utils/_definitions.py @@ -0,0 +1,9 @@ +from tuprolog import logger +import jpype.imports # noqa: F401 +import it.unibo.tuprolog.utils as _utils # type: ignore + +Castable = _utils.Castable + +Taggable = _utils.Taggable + +logger.debug("Loaded JVM classes from it.unibo.tuprolog.utils.*")