diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..ac7c0848 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,15 @@ +# These are supported funding model platforms + +github: [xpenatan] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +thanks_dev: # Replace with a single thanks.dev username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/workflows/build_and_upload.yml b/.github/workflows/build_and_upload.yml index ef89fb82..941feea4 100644 --- a/.github/workflows/build_and_upload.yml +++ b/.github/workflows/build_and_upload.yml @@ -16,7 +16,7 @@ env: jobs: build_windows: name: Build Windows - runs-on: ubuntu-latest + runs-on: windows-latest steps: - name: Cancel Previous Runs @@ -27,18 +27,25 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: 11 + java-version: 17 - name: Set up MinGW - run: | - sudo apt install -y --force-yes mingw-w64 lib32z1 + uses: msys2/setup-msys2@v2 - - name: Change wrapper permissions - run: chmod +x ./gradlew + - name: Set up Developer Command Prompt + uses: TheMrMilchmann/setup-msvc-dev@v3 + with: + arch: x64 + + - name: Append the directory of 'vcvarsall.bat' to PATH environment variable + uses: myci-actions/export-env-var-powershell@1 + with: + name: PATH + value: $env:PATH;C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build - name: Build project run: ./gradlew build_project_windows64 @@ -62,11 +69,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: 11 + java-version: 17 - name: Set up MinGW run: | @@ -97,11 +104,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: 11 + java-version: 17 - name: Change wrapper permissions run: chmod +x ./gradlew @@ -129,11 +136,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: 11 + java-version: 17 - name: Set up MinGW run: | @@ -141,6 +148,8 @@ jobs: - name: Install emscripten uses: mymindstorm/setup-emsdk@v14 + with: + version: 4.0.4 - name: Change wrapper permissions run: chmod +x ./gradlew @@ -167,11 +176,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: 11 + java-version: 17 - name: Set up MinGW run: | @@ -183,6 +192,8 @@ jobs: with: ndk-version: r25c add-to-path: false + env: + ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} - name: Change wrapper permissions run: chmod +x ./gradlew @@ -211,11 +222,19 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up JDK 11 + - name: Get version + uses: madhead/read-java-properties@latest + id: version + with: + file: "./gradle.properties" + property: version + default: 0.0.1 + + - name: Set up JDK 17 uses: actions/setup-java@v4 with: distribution: "zulu" - java-version: 11 + java-version: 17 - name: Set up MinGW run: | @@ -259,6 +278,7 @@ jobs: - name: Upload to repository uses: nick-fields/retry@v3 + if: ${{ inputs.shouldUpload }} with: max_attempts: 3 timeout_minutes: 10 @@ -268,4 +288,23 @@ jobs: USER: ${{ secrets.USER }} PASSWORD: ${{ secrets.PASSWORD }} SIGNING_KEY: ${{ secrets.PGP_SECRET }} - SIGNING_PASSWORD: ${{ secrets.PGP_PASSPHRASE }} \ No newline at end of file + SIGNING_PASSWORD: ${{ secrets.PGP_PASSPHRASE }} + + - name: Create Git tag + uses: actions/github-script@v7 + if: ${{ inputs.isRelease }} + with: + script: | + const versionOutputs = ${{ toJSON(steps.version.outputs) }}; + + var version = versionOutputs.value; + + console.log("Version: " + version); + + var ref = "refs/tags/" + version + github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: ref, + sha: context.sha + }); \ No newline at end of file diff --git a/.github/workflows/dispatch_build.yml b/.github/workflows/dispatch_build.yml index c3e4fc9b..755483f5 100644 --- a/.github/workflows/dispatch_build.yml +++ b/.github/workflows/dispatch_build.yml @@ -6,10 +6,13 @@ on: isRelease: required: true type: boolean + shouldUpload: + required: true + type: boolean jobs: build-and-upload: uses: ./.github/workflows/build_and_upload.yml with: isRelease: ${{ inputs.isRelease }} - shouldUpload: true - secrets: inherit \ No newline at end of file + shouldUpload: ${{ inputs.shouldUpload }} + secrets: inherit diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml deleted file mode 100644 index a6ae966f..00000000 --- a/.github/workflows/tag.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Create Tag - -on: - push: - branches: - - 'release' - -jobs: - add-tag: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - uses: madhead/read-java-properties@latest - id: version - with: - file: "./gradle.properties" - property: version - default: 0.0.1 - - - name: Create Git tag - uses: actions/github-script@v7 - with: - script: | - const versionOutputs = ${{ toJSON(steps.version.outputs) }}; - - var version = versionOutputs.value; - - console.log("Version: " + version); - - var ref = "refs/tags/" + version - github.rest.git.createRef({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: ref, - sha: context.sha - }); \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0e47b640..c97ec5d4 100644 --- a/.gitignore +++ b/.gitignore @@ -27,12 +27,12 @@ local.properties out/ *.ini .temp/ +*.log **/webapp/** **/lib/core/src/** **/lib/desktop/src/main/** -**/lib-ext/ext-core/src/** -**/lib-ext/ext-desktop/src/main/** -**/lib/lib-teavm/src/main/java/emu/** +**/lib/lib-teavm/src/main/java/** **/lib/lib-core/src/main/java/** **/app/android/libs/ +.codiumai \ No newline at end of file diff --git a/.run/build_project_all.run.xml b/.run/build_project_all.run.xml new file mode 100644 index 00000000..4571da5f --- /dev/null +++ b/.run/build_project_all.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/build_project_teavm.run.xml b/.run/build_project_teavm.run.xml new file mode 100644 index 00000000..1f39452e --- /dev/null +++ b/.run/build_project_teavm.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/build_project_windows64.run.xml b/.run/build_project_windows64.run.xml new file mode 100644 index 00000000..85d58926 --- /dev/null +++ b/.run/build_project_windows64.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/clean.run.xml b/.run/clean.run.xml new file mode 100644 index 00000000..2dc3805a --- /dev/null +++ b/.run/clean.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/generate_project.run.xml b/.run/generate_project.run.xml new file mode 100644 index 00000000..ce859dd2 --- /dev/null +++ b/.run/generate_project.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/run-app-desktop.run.xml b/.run/run-app-desktop.run.xml new file mode 100644 index 00000000..30f4afc5 --- /dev/null +++ b/.run/run-app-desktop.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/run-app-teavm.run.xml b/.run/run-app-teavm.run.xml new file mode 100644 index 00000000..1aa747b8 --- /dev/null +++ b/.run/run-app-teavm.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/README.md b/README.md index b54925ee..352ca127 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,45 @@ +# jParser + ![Build](https://github.com/xpenatan/jParser/actions/workflows/release.yml/badge.svg) ![Build](https://github.com/xpenatan/jParser/actions/workflows/snapshot.yml/badge.svg) +[![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/releases/com.github.xpenatan.jParser/jParser-core?nexusVersion=2&server=https%3A%2F%2Foss.sonatype.org&label=release)](https://repo.maven.apache.org/maven2/com/github/xpenatan/jParser/) +[![Static Badge](https://img.shields.io/badge/snapshot---SNAPSHOT-red)](https://oss.sonatype.org/content/repositories/snapshots/com/github/xpenatan/jParser/) -[![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/r/com.github.xpenatan.jParser/jParser-core?nexusVersion=2&server=https%3A%2F%2Foss.sonatype.org&label=release)](https://repo.maven.apache.org/maven2/com/github/xpenatan/jParser/) -[![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/com.github.xpenatan.jParser/jParser-core?server=https%3A%2F%2Foss.sonatype.org&label=snapshot)](https://oss.sonatype.org/content/repositories/snapshots/com/github/xpenatan/jParser/) +jParser is a compact Java library designed to facilitate the integration of C/C++ code with desktop, mobile, and web platforms, enabling inline writing within Java source code. +Inspired by [gdx-jnigen](https://github.com/libgdx/gdx-jnigen), jParser allows you to embed native code within a code block. This block is then translated into the appropriate target-specific code. You can define multiple code block targets within the same Java source file, and for each target, jParser generates a corresponding Java source file. -## jParser -jParser is a small Java library that helps bind C/C++ code to desktop, mobile, and the web, allowing it to be written inline with Java source code. +For web applications, jParser requires Emscripten to produce JS/WASM files and utilizes [TeaVM](https://github.com/konsoletyper/teavm). The classes generated in the TeaVM module use `JSBody` annotation solution to interact with JavaScript. -It was inspired by [gdx-jnigen](https://github.com/libgdx/gdx-jnigen) that you add a native code into a code block. This code block will be translated to the specific code target. You can add multiple code block targets in the same java source. For each code target, it will generate a new java source code. +Currently, jParser supports only `JNI` and `TEAVM` code targets. -For the web, it needs emscripten to generate a js/wasm file and teaVM for the binding part. +### How it Works +jParser consists of two main components: -jParser only supports ```JNI``` and ```TEAVM``` code targets. +1. **Code Generation**: It reads the Java source code containing the jParser solution and generates new Java source code for each target platform. The `base` module is used for this purpose. For desktop and mobile platforms, the generated JNI code is located in the `core` module, while the web-specific code is placed in the `teavm` module. -### How it works -jParser has two part. -* Read the java source code containing the jParser solution and generate a new java source code for each target. We use base module for this. For desktop/mobile the generated JNI code will be at ```core module``` and the web code will be inside ```teavm module```. -* Compile C/C++ for each platform (Windows/Linux/MacOS/Android/iOS/Web). +2. **C/C++ Compilation**: It compiles the C/C++ code for various platforms, including Windows, Linux, macOS, Android, iOS, and the Web. ## WebIDL -To improve even more the long hours of porting each method manually, jParser also has Emscripten WebIDL support. You create a webidl file, and it will generate binding code for JNI and teaVM. -It's not 100%, but it will reduce the amount of work binding big libraries. You can check the example:lib module or gdx-imgui for a complete example. +To further streamline the lengthy process of manually porting each method, jParser includes support for Emscripten WebIDL. By creating a WebIDL file, you can automatically generate binding code for both JNI and TeaVM. While this feature may not cover every scenario, it significantly reduces the effort required to bind large libraries. For a comprehensive example, refer to the `example:lib` module or `gdx-imgui`. + +The generated methods will match those defined in the WebIDL file. If the C++ code is case-sensitive, as seen in ImGui, the corresponding Java methods will also maintain case sensitivity. Additionally, C/C++ attributes are converted into methods prefixed with `set_` or `get_`. + +## WebIDL Classes +IDL classes, such as `IDLInt` or `IDLIntArray`, provide a method for passing primitive pointers to C++ code, compatible with Emscripten, desktop, and mobile platforms. Use these classes when you need to pass a pointer array or a primitive that the C++ code will modify. -Libraries usisng jParser:
-- [gdx-imgui](https://github.com/xpenatan/gdx-imgui) -- [gdx-lua](https://github.com/xpenatan/gdx-lua) -- [gdx-bullet](https://github.com/xpenatan/gdx-bullet) -- [gdx-physx](https://github.com/xpenatan/gdx-physx) -- [gdx-box2d](https://github.com/xpenatan/gdx-box2d) +Libraries using jParser:
+- [gdx-imgui](https://github.com/xpenatan/gdx-imgui)¹ +- [gdx-jolt](https://github.com/xpenatan/gdx-jolt)¹ +- [gdx-lua](https://github.com/xpenatan/gdx-lua)¹ +- [gdx-box2d](https://github.com/xpenatan/gdx-box2d)² +- [gdx-bullet](https://github.com/xpenatan/gdx-bullet)² +- [gdx-physx](https://github.com/xpenatan/gdx-physx)² + +¹: The focus is on maintaining this project.
+²: This project is currently inactive and may only be used to test the generator. ## Requirements: -#### [mingw64](https://github.com/niXman/mingw-builds-binaries/releases) -#### [emscripten](https://emscripten.org/) +#### [Mingw64](https://github.com/niXman/mingw-builds-binaries/releases) or [Visual Studio C++](https://visualstudio.microsoft.com/vs/community/) +#### [Emscripten](https://emscripten.org/) + diff --git a/build.gradle.kts b/build.gradle.kts index 91a9f1f6..07b54e2f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ buildscript { google() } - val kotlinVersion = "1.8.10" + val kotlinVersion = "2.1.10" dependencies { classpath("com.android.tools.build:gradle:7.3.1") @@ -39,7 +39,10 @@ allprojects() { } } -configure(allprojects - project(":example:app:android") - project(":example:lib:lib-android")) { +configure(allprojects + - project(":example:app:android") + - project(":example:lib:lib-android") +) { apply { plugin("java") } diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index d52ed76d..852aa44c 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -8,8 +8,8 @@ object LibExt { const val jUnitVersion = "4.13.2" const val groupId = "com.github.xpenatan.jParser" const val exampleUseRepoLibs = false - const val gdxVersion = "1.12.1" - const val teaVMVersion = "0.10.0" + const val gdxVersion = "1.13.1" + const val teaVMVersion = "0.11.0" const val gdxTeaVMVersion = "-SNAPSHOT" } diff --git a/example/app/android/build.gradle.kts b/example/app/android/build.gradle.kts index a6e85c47..0f2401d9 100644 --- a/example/app/android/build.gradle.kts +++ b/example/app/android/build.gradle.kts @@ -7,12 +7,11 @@ group = "jparser.app.android" android { namespace = "com.example.myapplication" - compileSdk = 33 + compileSdk = 34 defaultConfig { applicationId = "com.example.myapplication" minSdk = 24 - targetSdk = 33 versionCode = 1 versionName = "1.0" } diff --git a/example/app/core/src/main/java/com/github/xpenatan/jparser/example/app/AppTest.java b/example/app/core/src/main/java/com/github/xpenatan/jparser/example/app/AppTest.java index 9ccea2ac..3a135fd0 100644 --- a/example/app/core/src/main/java/com/github/xpenatan/jparser/example/app/AppTest.java +++ b/example/app/core/src/main/java/com/github/xpenatan/jparser/example/app/AppTest.java @@ -1,21 +1,12 @@ package com.github.xpenatan.jparser.example.app; import com.badlogic.gdx.ApplicationAdapter; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.utils.ScreenUtils; -import com.github.xpenatan.jparser.example.lib.EnumClassWithinClass; -import com.github.xpenatan.jparser.example.lib.EnumInNamespace; -import com.github.xpenatan.jparser.example.lib.EnumLib; -import com.github.xpenatan.jparser.example.lib.EnumTwoLib; -import com.github.xpenatan.jparser.example.lib.EnumWithinClass; -import com.github.xpenatan.jparser.example.lib.ExampleLibLoader; -import com.github.xpenatan.jparser.example.lib.NormalClass; -import com.github.xpenatan.jparser.example.lib.OperatorClass; -import com.github.xpenatan.jparser.example.lib.ReturnClass; -import com.github.xpenatan.jparser.example.lib.idl.helper.IDLFloat; -import com.github.xpenatan.jparser.example.lib.idl.helper.IDLFloatArray; -import com.github.xpenatan.jparser.example.lib.idl.helper.IDLString; +import com.github.xpenatan.jparser.example.testlib.TestLibLoader; public class AppTest extends ApplicationAdapter { private boolean init = false; @@ -23,141 +14,32 @@ public class AppTest extends ApplicationAdapter { private SpriteBatch batch; private BitmapFont font; - private int a1 = 1; - private int b1 = 1; - private int ret1; + boolean testPass = false; + + Color color = Color.GRAY; @Override public void create() { - ExampleLibLoader.init(new Runnable() { - @Override - public void run() { - initLib(); - } - }); + TestLibLoader.init((isSuccess, e) -> init = isSuccess); batch = new SpriteBatch(); font = new BitmapFont(); } - private void initLib() { - if(init) { - return; - } - init = true; - - NormalClass normalClass = new NormalClass(); - - IDLString string = new IDLString(); - - string.append("MY TEXT"); - string.append(" HELLO"); - - String text = string.c_str(); - - System.out.println("String: " + text); - - normalClass.setString(string); - - IDLString retString = normalClass.getString(); - System.out.println("retString: " + retString.c_str()); - IDLString retStringValue = normalClass.getStringValue(); - System.out.println("retStringValue: " + retStringValue.c_str()); - - int version = normalClass.getVersion(); - System.out.println("Version " + version); - - ret1 = normalClass.addIntValue(a1, b1); - System.out.println("addIntValue " + a1 + " + " + b1 + " = " + ret1); - - IDLFloatArray array = new IDLFloatArray(1); - array.setValue(0, 10); - float value = array.getValue(0); - System.out.println("VALUE: " + value); - - System.out.println("ENUM FIRST: " + EnumLib.FIRST); - System.out.println("ENUM SECOND: " + EnumLib.SECOND); - System.out.println("ENUMPARAM FIRST: " + normalClass.enumParam(EnumLib.FIRST)); - System.out.println("ENUMPARAM SECOND: " + normalClass.enumParam(EnumLib.SECOND)); - normalClass.enumVoidParam(EnumLib.FIRST); - System.out.println("ENUM Return FIRST: " + normalClass.enumReturn(1)); - System.out.println("ENUM Return SECOND: " + normalClass.enumReturn(2)); - System.out.println("ENUM Return DEFAULT: " + normalClass.enumReturn(99)); - System.out.println("EnumWithinClass e_val: " + EnumWithinClass.e_val); - System.out.println("EnumClassWithinClass testEnum: " + EnumClassWithinClass.testEnum); - System.out.println("EnumInNamespace e_namespace_val: " + EnumInNamespace.e_namespace_val); - - ReturnClass returnValueObject = normalClass.getReturnValueObject(); - System.out.println("returnValueObject: " + returnValueObject.value()); - - normalClass.printText(10, "printText HELLO"); - IDLFloat floatArray = IDLFloat.TMP_1; - long pointer = floatArray.getPointer(); - System.out.println("pointer: " + pointer); - normalClass.setArray(floatArray); - System.out.println("setArray: " + floatArray.getValue()); - System.out.println("EnumTwoLib THIRD: " + EnumTwoLib.EnumTwoLib_THIRD); - System.out.println("EnumTwoLib FOURTH: " + EnumTwoLib.EnumTwoLib_FOURTH); - System.out.println("NormalClass.subIntValue: " + NormalClass.subIntValue(2, 1)); - - OperatorClass operatorClass1 = new OperatorClass(); - operatorClass1.value(41); - OperatorClass operatorClass2 = new OperatorClass(); - operatorClass2.value(3); - operatorClass1.copy(operatorClass2); - - System.out.println("operatorClass1 copy: " + operatorClass1.value()); - - testPrimitive(); - -// CustomLib.print(); - } - - private void testPrimitive() { - System.out.println("########## TESTING ATTRIBUTES ##########"); - - NormalClass.hiddenInt_static(22); - int hiddenIntStatic = NormalClass.hiddenInt_static(); - System.out.println("hiddenIntStatic: " + hiddenIntStatic); - - ReturnClass nullPointerReturnClassStatic = NormalClass.nullPointerReturnClass_static(); - System.out.println("nullPointerReturnClassStatic: " + nullPointerReturnClassStatic); - -// ReturnClass pointerReturnClassStatic = NormalClass.get_pointerReturnClass_static(); -// pointerReturnClassStatic.set_value(51); -// System.out.println("pointerReturnClassStatic: " + pointerReturnClassStatic.get_value()); - - ReturnClass valueReturnClassStatic = NormalClass.valueReturnClass_static(); - System.out.println("valueReturnClassStatic: " + valueReturnClassStatic.value()); - - NormalClass normalClass = new NormalClass(); - - normalClass.hiddenInt(4); - int hiddenInt = normalClass.hiddenInt(); - System.out.println("hiddenInt: " + hiddenInt); - - ReturnClass pointerReturnClass = normalClass.pointerReturnClass(); - pointerReturnClass.value(11); - System.out.println("pointerReturnClass: " + pointerReturnClass.value()); - - ReturnClass valueReturnClass = normalClass.valueReturnClass(); - valueReturnClass.value(12); - System.out.println("valueReturnClass: " + valueReturnClass.value()); - - ReturnClass nullPointerReturnClass = normalClass.nullPointerReturnClass(); - System.out.println("nullPointerReturnClass: " + nullPointerReturnClass); - } @Override public void render() { - ScreenUtils.clear(0.4f, 0.4f, 0.4f, 1); + ScreenUtils.clear(color); - if(!init) { + if(init) { + init = false; + testPass = TestLib.test(); + color = testPass ? Color.LIME : Color.RED; return; } batch.begin(); - font.draw(batch, "addIntValue " + a1 + " + " + b1 + " = " + ret1, 100, 100); + font.draw(batch, "Test Pass " + testPass, 100, Gdx.graphics.getHeight()/2f); batch.end(); } } \ No newline at end of file diff --git a/example/app/core/src/main/java/com/github/xpenatan/jparser/example/app/TestLib.java b/example/app/core/src/main/java/com/github/xpenatan/jparser/example/app/TestLib.java new file mode 100644 index 00000000..e6e20b75 --- /dev/null +++ b/example/app/core/src/main/java/com/github/xpenatan/jparser/example/app/TestLib.java @@ -0,0 +1,689 @@ +package com.github.xpenatan.jparser.example.app; + +import com.github.xpenatan.jparser.example.testlib.CallbackClass; +import com.github.xpenatan.jparser.example.testlib.CallbackClassManual; +import com.github.xpenatan.jparser.example.testlib.DefaultCallbackClass; +import com.github.xpenatan.jparser.example.testlib.TestCallbackClass; +import com.github.xpenatan.jparser.example.testlib.TestConstructorClass; +import com.github.xpenatan.jparser.example.testlib.TestMethodClass; +import com.github.xpenatan.jparser.example.testlib.TestObjectClass; +import com.github.xpenatan.jparser.example.testlib.TestObjectClassArray; +import com.github.xpenatan.jparser.example.testlib.core.enums.TestEnumWithinClass; +import com.github.xpenatan.jparser.example.testlib.core.op.TestOperatorClass; +import com.github.xpenatan.jparser.example.testlib.core.sub.TestNamespaceClass; +import com.github.xpenatan.jparser.example.testlib.idl.helper.IDLString; + +public class TestLib { + + public static boolean test() { + int eVal = TestEnumWithinClass.e_val; + boolean constructorTest = testConstructorClass(); + boolean stringConstructorTest = testStringConstructorClass(); + boolean attributeTest = testAttributeClass(); + boolean staticAttributeTest = testStaticAttributeClass(); + boolean attributeArrayTest = testAttributeArrayClass(); + boolean methodTest = testMethodClass(); + boolean staticMethodTest = testStaticMethodClass(); + boolean callbackTest = testCallbackClass(); + boolean callbackTestManual = testCallbackClassManual(); + boolean namespaceTest = testNamespaceClass(); + boolean operatorTest = testOperatorClass(); + + System.out.println("constructorTest: " + constructorTest); + System.out.println("stringConstructorTest: " + stringConstructorTest); + System.out.println("attributeTest: " + attributeTest); + System.out.println("staticAttributeTest: " + staticAttributeTest); + System.out.println("attributeArrayTest: " + attributeArrayTest); + System.out.println("methodTest: " + methodTest); + System.out.println("staticMethodTest: " + staticMethodTest); + System.out.println("callbackTest: " + callbackTest); + System.out.println("namespaceTest: " + namespaceTest); + System.out.println("operatorTest: " + operatorTest); + + return constructorTest && stringConstructorTest && attributeTest && staticAttributeTest + && attributeArrayTest && methodTest && staticMethodTest && callbackTest + && callbackTestManual && namespaceTest && operatorTest; + } + + private static boolean testConstructorClass() { + { + int intValue01 = 40; + TestConstructorClass test = new TestConstructorClass(intValue01); + try { + if(!(test.get_intValue01() == intValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_intValue01() == intValue01"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + float floatValue01 = 4.654f; + int intValue01 = 29; + TestConstructorClass test = new TestConstructorClass(floatValue01, intValue01); + try { + if(!(test.get_floatValue01() == floatValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_floatValue01() == floatValue01"); + } + if(!(test.get_intValue01() == intValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_intValue01() == intValue01"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + int intValue01 = 40; + int intValue02 = 47; + float floatValue01 = 42.5f; + float floatValue02 = 72.9f; + TestConstructorClass test = new TestConstructorClass(intValue01, intValue02, floatValue01, floatValue02); + try { + if(!(test.get_intValue01() == intValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_intValue01() == intValue01"); + } + if(!(test.get_intValue02() == intValue02)) { + throw new RuntimeException("testConstructorClass Error: test.get_intValue02() == intValue02"); + } + if(!(test.get_floatValue01() == floatValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_floatValue01() == floatValue01"); + } + if(!(test.get_floatValue02() == floatValue02)) { + throw new RuntimeException("testConstructorClass Error: test.get_floatValue02() == floatValue02"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + int intValue01 = 40; + int intValue02 = 47; + float floatValue01 = 42.5f; + float floatValue02 = 72.9f; + boolean boolValue01 = true; + TestConstructorClass test = new TestConstructorClass(intValue01, intValue02, floatValue01, floatValue02, boolValue01); + try { + if(!(test.get_intValue01() == intValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_intValue01() == intValue01"); + } + if(!(test.get_intValue02() == intValue02)) { + throw new RuntimeException("testConstructorClass Error: test.get_intValue02() == intValue02"); + } + if(!(test.get_floatValue01() == floatValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_floatValue01() == floatValue01"); + } + if(!(test.get_floatValue02() == floatValue02)) { + throw new RuntimeException("testConstructorClass Error: test.get_floatValue02() == floatValue02"); + } + if(!(test.get_boolValue01() == boolValue01)) { + throw new RuntimeException("testConstructorClass Error: test.get_boolValue01() == boolValue01"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + return true; + } + + private static boolean testStringConstructorClass() { + + return true; + } + + private static boolean testAttributeClass() { + + + return true; + } + + private static boolean testStaticAttributeClass() { + + + return true; + } + + private static boolean testAttributeArrayClass() { + + + return true; + } + + private static boolean testMethodClass() { + { + TestMethodClass test = new TestMethodClass(); + test.setMethod01(10); + int intValue01 = test.getIntValue01(); + try { + if(!(intValue01 == 10)) { + test.dispose(); + throw new RuntimeException("intValue01 == 10"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestMethodClass test = new TestMethodClass(); + TestObjectClassArray array = new TestObjectClassArray(2); + TestObjectClass obj1 = new TestObjectClass(); + TestObjectClass obj2 = new TestObjectClass(); + obj1.set_floatValue01(20.5f); + obj1.set_intValue01(30); + obj2.set_floatValue01(40.5f); + obj2.set_intValue01(60); + array.setValue(0, obj1); + array.setValue(1, obj2); + try { + TestMethodClass.native_setMethod07(test.getNativeData().getCPointer(), array.getPointer()); + { + float intValue01 = obj1.get_intValue01(); + if(!(intValue01 == 20)) { + throw new RuntimeException("intValue01 == 20"); + } + float floatValue01 = obj1.get_floatValue01(); + if(!(floatValue01 == 10.4f)) { + throw new RuntimeException("floatValue01 == 10.4f"); + } + } + { + float intValue01 = obj2.get_intValue01(); + if(!(intValue01 == 40)) { + throw new RuntimeException("intValue01 == 40"); + } + float floatValue01 = obj2.get_floatValue01(); + if(!(floatValue01 == 30.8f)) { + throw new RuntimeException("floatValue01 == 30.8f"); + } + } + } catch(Throwable e) { + e.printStackTrace(); + obj1.dispose(); + obj2.dispose(); + array.dispose(); + test.dispose(); + return false; + } + obj1.dispose(); + obj2.dispose(); + array.dispose(); + test.dispose(); + } + { + TestMethodClass test = new TestMethodClass(); + try { + String strValue01 = "Hello"; + test.setMethod05(strValue01); + String stringValue = test.getStrValue01().data(); + if(!(strValue01.equals(stringValue))) { + throw new RuntimeException("strValue01.equals(stringValue)"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestMethodClass test = new TestMethodClass(); + try { + String strValue01 = "RefHello"; + test.setMethod05(strValue01); + IDLString refStrValue01 = test.getRefStrValue01(); + String stringValue = refStrValue01.data(); + if(!(strValue01.equals(stringValue))) { + throw new RuntimeException("strValue01.equals(stringValue)"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestMethodClass test = new TestMethodClass(); + try { + long longLongValue01 = 4; + test.setMethod08(longLongValue01); + long retLongLongValue01 = test.getLongLongValue01(); + if(!(longLongValue01 == retLongLongValue01)) { + throw new RuntimeException("longLongValue01 == retLongLongValue01"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + return true; + } + + private static boolean testStaticMethodClass() { + + + return true; + } + + private static boolean testCallbackClass() { + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onVoidCallback = { false }; + CallbackClass callback = new CallbackClass() { + @Override + public void onVoidCallback(TestObjectClass refData, TestObjectClass pointerData) { + internal_onVoidCallback[0] = true; + } + }; + test.callVoidCallback(callback); + if(!(internal_onVoidCallback[0] == true)) { + throw new RuntimeException("internal_onVoidCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onIntCallback = { false }; + CallbackClass callback = new CallbackClass() { + @Override + public int onIntCallback(int intValue01, int intValue02) { + internal_onIntCallback[0] = true; + return 0; + } + }; + test.callIntCallback(callback); + if(!(internal_onIntCallback[0] == true)) { + throw new RuntimeException("internal_onIntCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + test.set_intValue01(10); + test.set_intValue02(3); + CallbackClass callback = new DefaultCallbackClass(); + int value = test.callIntCallback(callback); + if(!(value == 7)) { + throw new RuntimeException("value == 7"); + } + callback.dispose(); + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onFloatCallback = { false }; + CallbackClass callback = new CallbackClass() { + @Override + public float onFloatCallback(float floatValue01, float floatValue02) { + internal_onFloatCallback[0] = true; + return 0; + } + }; + test.callFloatCallback(callback); + if(!(internal_onFloatCallback[0] == true)) { + throw new RuntimeException("internal_onFloatCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onBoolCallback = { false }; + CallbackClass callback = new CallbackClass() { + @Override + public boolean onBoolCallback(boolean boolValue01) { + internal_onBoolCallback[0] = true; + return false; + } + }; + test.callBoolCallback(callback); + if(!(internal_onBoolCallback[0] == true)) { + throw new RuntimeException("internal_onBoolCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + String text = "HELLO_WORLD"; + test.get_strValue01().append(text); + final String[] internal_onStringCallback = new String[1]; + CallbackClass callback = new CallbackClass() { + @Override + public void onStringCallback(String strValue01) { + internal_onStringCallback[0] = strValue01; + } + }; + test.callStringCallback(callback); + if(!(text.equals(internal_onStringCallback[0]) == true)) { + throw new RuntimeException("text.equals(internal_onStringCallback[0]) == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + int[] onUnsignedIntCallback = { 0 }; + CallbackClass callback = new CallbackClass() { + @Override + public int onUnsignedIntCallback(int unsignedInt) { + onUnsignedIntCallback[0] = unsignedInt; + return 2; + } + }; + int i = test.callUnsignedIntCallback(callback); + if(!(onUnsignedIntCallback[0] == 13 && i == 2)) { + throw new RuntimeException("onUnsignedIntCallback[0] == 13 && i == 2"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + short[] onUnsignedShortCallback = { 0 }; + CallbackClass callback = new CallbackClass() { + @Override + public short onUnsignedShortCallback(short unsignedShort) { + onUnsignedShortCallback[0] = unsignedShort; + return 3; + } + }; + short i = test.callUnsignedShortCallback(callback); + if(!(onUnsignedShortCallback[0] == 12 && i == 3)) { + throw new RuntimeException("onUnsignedShortCallback[0] == 12 && i == 3"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + return true; + } + + private static boolean testCallbackClassManual() { + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onVoidCallback = { false }; + CallbackClassManual callback = new CallbackClassManual() { + @Override + public void internal_onVoidCallback(long refData, long pointerData) { + internal_onVoidCallback[0] = true; + } + }; + test.callManualVoidCallback(callback); + if(!(internal_onVoidCallback[0] == true)) { + throw new RuntimeException("internal_onVoidCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onIntCallback = { false }; + CallbackClassManual callback = new CallbackClassManual() { + @Override + public int internal_onIntCallback(int intValue01, int intValue02) { + internal_onIntCallback[0] = true; + return 0; + } + }; + test.callManualIntCallback(callback); + if(!(internal_onIntCallback[0] == true)) { + throw new RuntimeException("internal_onIntCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onFloatCallback = { false }; + CallbackClassManual callback = new CallbackClassManual() { + @Override + public float internal_onFloatCallback(float floatValue01, float floatValue02) { + internal_onFloatCallback[0] = true; + return 0; + } + }; + test.callManualFloatCallback(callback); + if(!(internal_onFloatCallback[0] == true)) { + throw new RuntimeException("internal_onFloatCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + boolean[] internal_onBoolCallback = { false }; + CallbackClassManual callback = new CallbackClassManual() { + @Override + public boolean internal_onBoolCallback(boolean boolValue01) { + internal_onBoolCallback[0] = true; + return false; + } + }; + test.callManualBoolCallback(callback); + if(!(internal_onBoolCallback[0] == true)) { + throw new RuntimeException("internal_onBoolCallback[0] == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestCallbackClass test = new TestCallbackClass(); + try { + String text = "HELLO_WORLD"; + test.get_strValue01().append(text); + final String[] internal_onStringCallback = new String[1]; + CallbackClassManual callback = new CallbackClassManual() { + @Override + public void internal_onStringCallback(String strValue01) { + internal_onStringCallback[0] = strValue01; + } + }; + test.callManualStringCallback(callback); + if(!(text.equals(internal_onStringCallback[0]) == true)) { + throw new RuntimeException("text.equals(internal_onStringCallback[0]) == true"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + return true; + } + + private static boolean testNamespaceClass() { + { + TestNamespaceClass test = new TestNamespaceClass(); + try { + int value = 20; + test.setMethod01Value(value); + if(!(value == test.getMethod01Value())) { + throw new RuntimeException("value == test.getMethod01Value()"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + { + TestNamespaceClass test = new TestNamespaceClass(); + try { + int value = 40; + test.set_intValue01(value); + if(!(value == test.get_intValue01())) { + throw new RuntimeException("value == test.get_intValue01()"); + } + } catch(Throwable e) { + e.printStackTrace(); + test.dispose(); + return false; + } + test.dispose(); + } + return true; + } + + private static boolean testOperatorClass() { + try { + TestOperatorClass operatorClass = new TestOperatorClass(); + TestOperatorClass otherOPClass = new TestOperatorClass(); + otherOPClass.setValue(3); + + // Arithmetic Operators + { + operatorClass.setValue(10); + TestOperatorClass obj = operatorClass.addValue(otherOPClass); + float value = obj.getValue(); + if(!(value == 13 && (obj != operatorClass && obj != otherOPClass))) { + throw new RuntimeException("testOperatorClass '+' !(value == 13)"); + } + } + { + operatorClass.setValue(10); + TestOperatorClass obj = operatorClass.subValue(otherOPClass); + float value = obj.getValue(); + if(!(value == 7 && (obj != operatorClass && obj != otherOPClass))) { + throw new RuntimeException("testOperatorClass '-' !(value == 7)"); + } + } + { + operatorClass.setValue(10); + TestOperatorClass obj = operatorClass.mulValue(otherOPClass); + float value = obj.getValue(); + if(!(value == 30 && (obj != operatorClass && obj != otherOPClass))) { + throw new RuntimeException("testOperatorClass '*' !(value == 30)"); + } + } + { + operatorClass.setValue(30); + TestOperatorClass obj = operatorClass.divValue(otherOPClass); + float value = obj.getValue(); + if(!(value == 10 && (obj != operatorClass && obj != otherOPClass))) { + throw new RuntimeException("testOperatorClass '/' !(value == 10)"); + } + } + // Compound Assignment Operators + { + operatorClass.setValue(10); + TestOperatorClass obj = operatorClass.addRef(otherOPClass); + float value = obj.getValue(); + if(!(value == 13 && (obj == operatorClass))) { + throw new RuntimeException("testOperatorClass '+' !(value == 13)"); + } + } + { + operatorClass.setValue(10); + TestOperatorClass obj = operatorClass.subRef(otherOPClass); + float value = obj.getValue(); + if(!(value == 7 && (obj == operatorClass))) { + throw new RuntimeException("testOperatorClass '-' !(value == 7)"); + } + } + { + operatorClass.setValue(10); + TestOperatorClass obj = operatorClass.mulRef(otherOPClass); + float value = obj.getValue(); + if(!(value == 30 && (obj == operatorClass))) { + throw new RuntimeException("testOperatorClass '*' !(value == 30)"); + } + } + { + operatorClass.setValue(30); + TestOperatorClass obj = operatorClass.divRef(otherOPClass); + float value = obj.getValue(); + if(!(value == 10 && (obj == operatorClass))) { + throw new RuntimeException("testOperatorClass '/' !(value == 10)"); + } + } + operatorClass.dispose(); + otherOPClass.dispose(); + + return true; + } catch(Throwable e) { + e.printStackTrace(); + } + return false; + } +} \ No newline at end of file diff --git a/example/lib-ext/ext-base/build.gradle.kts b/example/lib-ext/ext-base/build.gradle.kts deleted file mode 100644 index 32e15f30..00000000 --- a/example/lib-ext/ext-base/build.gradle.kts +++ /dev/null @@ -1,3 +0,0 @@ -dependencies { - implementation(project(":example:lib:lib-core")) -} \ No newline at end of file diff --git a/example/lib-ext/ext-base/src/main/java/com.lib.ext/CustomLib.java b/example/lib-ext/ext-base/src/main/java/com.lib.ext/CustomLib.java deleted file mode 100644 index a5ae433e..00000000 --- a/example/lib-ext/ext-base/src/main/java/com.lib.ext/CustomLib.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.lib.ext; - -public class CustomLib { - /*[-JNI;-NATIVE] - #include "CustomLib.h" - */ -} \ No newline at end of file diff --git a/example/lib-ext/ext-build/build.gradle.kts b/example/lib-ext/ext-build/build.gradle.kts deleted file mode 100644 index 489a61a4..00000000 --- a/example/lib-ext/ext-build/build.gradle.kts +++ /dev/null @@ -1,12 +0,0 @@ -plugins { - id("java") -} - -dependencies { - implementation(project(":example:lib:lib-core")) - implementation(project(":jParser:core")) - implementation(project(":jParser:idl")) - implementation(project(":jParser:teavm")) - implementation(project(":jParser:cpp")) - implementation(project(":jParser:builder")) -} \ No newline at end of file diff --git a/example/lib-ext/ext-build/src/main/cpp/ExtLib.idl b/example/lib-ext/ext-build/src/main/cpp/ExtLib.idl deleted file mode 100644 index 1f5e2cc1..00000000 --- a/example/lib-ext/ext-build/src/main/cpp/ExtLib.idl +++ /dev/null @@ -1,3 +0,0 @@ -interface CustomLib { - static void print(); -}; \ No newline at end of file diff --git a/example/lib-ext/ext-build/src/main/cpp/cpp-source/custom/CustomLib.cpp b/example/lib-ext/ext-build/src/main/cpp/cpp-source/custom/CustomLib.cpp deleted file mode 100644 index 90238a3c..00000000 --- a/example/lib-ext/ext-build/src/main/cpp/cpp-source/custom/CustomLib.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "CustomLib.h" \ No newline at end of file diff --git a/example/lib-ext/ext-build/src/main/cpp/cpp-source/custom/CustomLib.h b/example/lib-ext/ext-build/src/main/cpp/cpp-source/custom/CustomLib.h deleted file mode 100644 index 139ef638..00000000 --- a/example/lib-ext/ext-build/src/main/cpp/cpp-source/custom/CustomLib.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include - -class CustomLib { - -private: - -public: - - static void print() { - std::cout << " PRINT " << std::endl; - } -}; \ No newline at end of file diff --git a/example/lib-ext/ext-build/src/main/java/BuildExtCode.java b/example/lib-ext/ext-build/src/main/java/BuildExtCode.java deleted file mode 100644 index 595cd54b..00000000 --- a/example/lib-ext/ext-build/src/main/java/BuildExtCode.java +++ /dev/null @@ -1,71 +0,0 @@ -import com.github.xpenatan.jparser.builder.BuildConfig; -import com.github.xpenatan.jparser.builder.BuildMultiTarget; -import com.github.xpenatan.jparser.builder.BuildTarget; -import com.github.xpenatan.jparser.builder.JBuilder; -import com.github.xpenatan.jparser.builder.targets.WindowsTarget; -import com.github.xpenatan.jparser.core.JParser; -import com.github.xpenatan.jparser.core.util.FileHelper; -import com.github.xpenatan.jparser.cpp.CppCodeParser; -import com.github.xpenatan.jparser.cpp.CppGenerator; -import com.github.xpenatan.jparser.cpp.NativeCPPGenerator; -import com.github.xpenatan.jparser.idl.IDLReader; -import java.io.File; -import java.io.IOException; -import java.nio.file.Path; -import java.util.ArrayList; - -public class BuildExtCode { - - public static void build() throws Exception { - String libName = "extlib"; - String basePackage = "com.lib.ext"; - - JParser.CREATE_IDL_HELPER = false; - - String libPath = new File("../../lib").getCanonicalPath().replace("\\", "/"); - String idlPath = new File("src/main/cpp/ExtLib.idl").getCanonicalPath(); - IDLReader idlReader = IDLReader.readIDL(idlPath); - String baseJavaDir = new File(".").getAbsolutePath() + "./ext-base/src/main/java"; - - String cppSourceDir = new File("./src/main/cpp/cpp-source//source/").getCanonicalPath(); - String libsDir = new File("./build/c++/libs/").getCanonicalPath(); - String libBuildPath = new File("./build/c++/").getCanonicalPath(); - String cppDestinationPath = libBuildPath + "/src"; - String libDestinationPath = cppDestinationPath + "/extlib"; - - FileHelper.copyDir(cppSourceDir, libDestinationPath); - - Path copyOut = new File(libDestinationPath).toPath(); - FileHelper.copyDir(new File("src/main/cpp/cpp-source/custom").toPath(), copyOut); - - CppGenerator cppGenerator = new NativeCPPGenerator(libDestinationPath); - CppCodeParser cppParser = new CppCodeParser(cppGenerator, idlReader, basePackage, cppSourceDir); - cppParser.generateClass = true; - JParser.generate(cppParser, baseJavaDir, "../ext-core/src/main/java"); - - BuildConfig buildConfig = new BuildConfig(cppDestinationPath, libBuildPath, libsDir, libName); - - ArrayList targets = new ArrayList<>(); - if(BuildTarget.isWindows() || BuildTarget.isUnix()) { -// targets.add(getWindowBuildTarget(libPath)); - } - - JBuilder.build(buildConfig, targets); - } - - private static BuildMultiTarget getWindowBuildTarget(String libPath) throws IOException { - BuildMultiTarget multiTarget = new BuildMultiTarget(); - - String libCppPath = libPath + "/generator/build/c++"; - - WindowsTarget windowsTarget = new WindowsTarget(); - windowsTarget.headerDirs.add("-I" + libCppPath + "/src/imgui"); - windowsTarget.isStatic = true; - windowsTarget.headerDirs.add("-Isrc/extlib/"); - windowsTarget.cppInclude.add("**/extlib/*.cpp"); - multiTarget.add(windowsTarget); - - return multiTarget; - } - -} \ No newline at end of file diff --git a/example/lib-ext/ext-core/build.gradle.kts b/example/lib-ext/ext-core/build.gradle.kts deleted file mode 100644 index 65c3f593..00000000 --- a/example/lib-ext/ext-core/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("java") -} - -dependencies { - implementation(project(":example:lib:lib-core")) -} - -tasks.named("clean") { - doFirst { - val srcPath = "$projectDir/src/main/" - project.delete(files(srcPath)) - } -} \ No newline at end of file diff --git a/example/lib-ext/ext-teavm/build.gradle.kts b/example/lib-ext/ext-teavm/build.gradle.kts deleted file mode 100644 index 0a542292..00000000 --- a/example/lib-ext/ext-teavm/build.gradle.kts +++ /dev/null @@ -1,17 +0,0 @@ -plugins { - id("java") -} - - -dependencies { - implementation(project(":example:lib:lib-core")) - implementation("org.teavm:teavm-jso:${LibExt.teaVMVersion}") - implementation("org.teavm:teavm-classlib:${LibExt.teaVMVersion}") -} - -tasks.named("clean") { - doFirst { - val srcPath = "$projectDir/src/main/java/gen" - project.delete(files(srcPath)) - } -} \ No newline at end of file diff --git a/example/lib-ext/ext-teavm/src/main/resources/META-INF/gdx-teavm.properties b/example/lib-ext/ext-teavm/src/main/resources/META-INF/gdx-teavm.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/example/lib-ext/ext-teavm/src/main/resources/META-INF/teavm.properties b/example/lib-ext/ext-teavm/src/main/resources/META-INF/teavm.properties deleted file mode 100644 index b5be5cb7..00000000 --- a/example/lib-ext/ext-teavm/src/main/resources/META-INF/teavm.properties +++ /dev/null @@ -1 +0,0 @@ -mapPackageHierarchy|gen.com=com \ No newline at end of file diff --git a/example/lib/lib-android/build.gradle.kts b/example/lib/lib-android/build.gradle.kts index d332eca6..377325f7 100644 --- a/example/lib/lib-android/build.gradle.kts +++ b/example/lib/lib-android/build.gradle.kts @@ -6,8 +6,8 @@ plugins { group = "jparser.lib.android" android { - namespace = "com.github.xpenatan.jparser.example.lib" - compileSdk = 33 + namespace = "com.github.xpenatan.jparser.example.testlib" + compileSdk = 34 defaultConfig { minSdk = 21 @@ -15,7 +15,7 @@ android { sourceSets { named("main") { - jniLibs.srcDirs("$projectDir/../generator/build/c++/libs/android") + jniLibs.srcDirs("$projectDir/../lib-build/build/c++/libs/android") } } compileOptions { diff --git a/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/lib/ExampleLibLoader.java b/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/lib/ExampleLibLoader.java deleted file mode 100644 index 99dc64a2..00000000 --- a/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/lib/ExampleLibLoader.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.github.xpenatan.jparser.example.lib; - -import com.github.xpenatan.jparser.loader.JParserLibraryLoader; - -public class ExampleLibLoader { - - /*[-JNI;-NATIVE] - #include "CustomCode.h" - */ - - /*[-TEAVM;-ADD] - @org.teavm.jso.JSFunctor - public interface OnInitFunction extends org.teavm.jso.JSObject { - void onInit(); - } - */ - - /*[-TEAVM;-REPLACE] - public static void init(Runnable onSuccess) { - JParserLibraryLoader libraryLoader = new JParserLibraryLoader(); - OnInitFunction onInitFunction = () -> onSuccess.run(); - setOnLoadInit(onInitFunction); - libraryLoader.load("exampleLib.wasm", isSuccess -> {}); - } - */ - - public static void init(Runnable onSuccess) { - JParserLibraryLoader libraryLoader = new JParserLibraryLoader(); - libraryLoader.load("exampleLib", isSuccess -> { - if(isSuccess) { - onSuccess.run(); - } - }); - } - - /*[-TEAVM;-REPLACE] - @org.teavm.jso.JSBody(params = { "onInitFunction" }, script = "window.exampleLibOnInit = onInitFunction;") - private static native void setOnLoadInit(OnInitFunction onInitFunction); - */ - /*[-JNI;-REMOVE] */ - public static native void setOnLoadInit(); -} \ No newline at end of file diff --git a/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/testlib/CallbackClassManual.java b/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/testlib/CallbackClassManual.java new file mode 100644 index 00000000..e2d61ac9 --- /dev/null +++ b/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/testlib/CallbackClassManual.java @@ -0,0 +1,164 @@ +package com.github.xpenatan.jparser.example.testlib; +import idl.IDLBase; + +/*[-IDL_SKIP]*/ +public class CallbackClassManual extends IDLBase { + + /*[-JNI;-NATIVE] + class CallbackClassManualImpl : public CallbackClassManual { + private: + JNIEnv* env; + jobject obj; + public: + inline static jclass jClassID = 0; + inline static jmethodID onVoidCallback_ID = 0; + inline static jmethodID onIntCallback_ID = 0; + inline static jmethodID onFloatCallback_ID = 0; + inline static jmethodID onBoolCallback_ID = 0; + inline static jmethodID onStringCallback_ID = 0; + + void setupCallback(JNIEnv* env, jobject obj) { + this->env = env; + this->obj = env->NewGlobalRef(obj); + + if(CallbackClassManualImpl::jClassID == 0) { + CallbackClassManualImpl::jClassID = (jclass)env->NewGlobalRef(env->GetObjectClass(obj)); + CallbackClassManualImpl::onVoidCallback_ID = env->GetMethodID(jClassID, "internal_onVoidCallback", "(JJ)V"); + CallbackClassManualImpl::onIntCallback_ID = env->GetMethodID(jClassID, "internal_onIntCallback", "(II)I"); + CallbackClassManualImpl::onFloatCallback_ID = env->GetMethodID(jClassID, "internal_onFloatCallback", "(FF)F"); + CallbackClassManualImpl::onBoolCallback_ID = env->GetMethodID(jClassID, "internal_onBoolCallback", "(Z)Z"); + CallbackClassManualImpl::onStringCallback_ID = env->GetMethodID(jClassID, "internal_onStringCallback", "(Ljava/lang/String;)V"); + } + } + virtual void onVoidCallback(TestObjectClass& refData, TestObjectClass* pointerData) const { + env->CallVoidMethod(obj, CallbackClassManualImpl::onVoidCallback_ID, (jlong)&refData, (jlong)pointerData); + } + virtual int onIntCallback(int intValue01, int intValue02) const { + return env->CallIntMethod(obj, CallbackClassManualImpl::onIntCallback_ID, intValue01, intValue02); + } + virtual float onFloatCallback(float floatValue01, float floatValue02) const { + return env->CallFloatMethod(obj, CallbackClassManualImpl::onFloatCallback_ID, floatValue01, floatValue02); + } + virtual bool onBoolCallback(bool boolValue01) const { + return env->CallBooleanMethod(obj, CallbackClassManualImpl::onBoolCallback_ID, boolValue01); + } + virtual void onStringCallback(const char* strValue01) const { + jstring jstrBuf = env->NewStringUTF(strValue01); + env->CallVoidMethod(obj, CallbackClassManualImpl::onStringCallback_ID, jstrBuf); + } + }; + */ + + /*[-TEAVM;-ADD] + @org.teavm.jso.JSFunctor + public interface onVoidCallback extends org.teavm.jso.JSObject { + void onVoidCallback(int refData, int pointerData); + } + */ + /*[-TEAVM;-ADD] + @org.teavm.jso.JSFunctor + public interface onIntCallback extends org.teavm.jso.JSObject { + int onIntCallback(int intValue01, int intValue02); + } + */ + /*[-TEAVM;-ADD] + @org.teavm.jso.JSFunctor + public interface onFloatCallback extends org.teavm.jso.JSObject { + float onFloatCallback(float floatValue01, float floatValue02); + } + */ + /*[-TEAVM;-ADD] + @org.teavm.jso.JSFunctor + public interface onBoolCallback extends org.teavm.jso.JSObject { + boolean onBoolCallback(boolean boolValue01); + } + */ + /*[-TEAVM;-ADD] + @org.teavm.jso.JSFunctor + public interface onStringCallback extends org.teavm.jso.JSObject { + void onStringCallback(int strValue01); + } + */ + + public CallbackClassManual() { + long addr = internal_native_create(); + nativeData.reset(addr, true); + setupCallbacks(); + } + + /*[-JNI;-NATIVE] + return (jlong)new CallbackClassManualImpl(); + */ + /*[-TEAVM;-NATIVE] + var CallbackClassManualImpl = new [MODULE].CallbackClassManualImpl(); + return [MODULE].getPointer(CallbackClassManualImpl); + */ + private static native long internal_native_create(); + + /*[-TEAVM;-REPLACE_BLOCK] + { + onVoidCallback onVoidCallback = new onVoidCallback() { + @Override + public void onVoidCallback(int refData, int pointerData) { + internal_onVoidCallback(refData, pointerData); + } + }; + onIntCallback onIntCallback = new onIntCallback() { + @Override + public int onIntCallback(int intValue01, int intValue02) { + return internal_onIntCallback(intValue01, intValue02); + } + }; + onFloatCallback onFloatCallback = new onFloatCallback() { + @Override + public float onFloatCallback(float floatValue01, float floatValue02) { + return internal_onFloatCallback(floatValue01, floatValue02); + } + }; + onBoolCallback onBoolCallback = new onBoolCallback() { + @Override + public boolean onBoolCallback(boolean boolValue01) { + return internal_onBoolCallback(boolValue01); + } + }; + onStringCallback onStringCallback = new onStringCallback() { + @Override + public void onStringCallback(int strValue01) { + internal_onStringCallback(IDLBase.getJSString(strValue01)); + } + }; + internal_native_setupCallbacks((int)getNativeData().getCPointer(), onVoidCallback, onIntCallback, onFloatCallback, onBoolCallback, onStringCallback); + } + */ + private void setupCallbacks() { + internal_native_setupCallbacks(getNativeData().getCPointer()); + } + + /*[-JNI;-NATIVE] + CallbackClassManualImpl* nativeObject = (CallbackClassManualImpl*)this_addr; + nativeObject->setupCallback(env, object); + */ + /*[-TEAVM;-REPLACE] + @org.teavm.jso.JSBody(params = { "this_addr", "onVoidCallback", "onIntCallback", "onFloatCallback", "onBoolCallback", "onStringCallback" }, script = "var CallbackClassManualImpl = [MODULE].wrapPointer(this_addr, [MODULE].CallbackClassManualImpl); CallbackClassManualImpl.onVoidCallback = onVoidCallback; CallbackClassManualImpl.onIntCallback = onIntCallback; CallbackClassManualImpl.onFloatCallback = onFloatCallback; CallbackClassManualImpl.onBoolCallback = onBoolCallback; CallbackClassManualImpl.onStringCallback = onStringCallback;") + private static native void internal_native_setupCallbacks(int this_addr, onVoidCallback onVoidCallback, onIntCallback onIntCallback, onFloatCallback onFloatCallback, onBoolCallback onBoolCallback, onStringCallback onStringCallback); + */ + private native void internal_native_setupCallbacks(long this_addr); + + public void internal_onVoidCallback(long refData, long pointerData) { + } + + public int internal_onIntCallback(int intValue01, int intValue02) { + return 0; + } + + public float internal_onFloatCallback(float floatValue01, float floatValue02) { + return 0; + } + + public boolean internal_onBoolCallback(boolean boolValue01) { + return false; + } + + public void internal_onStringCallback(String strValue01) { + } +} \ No newline at end of file diff --git a/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/testlib/TestLibLoader.java b/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/testlib/TestLibLoader.java new file mode 100644 index 00000000..b7e71b29 --- /dev/null +++ b/example/lib/lib-base/src/main/java/com/github/xpenatan/jparser/example/testlib/TestLibLoader.java @@ -0,0 +1,17 @@ +package com.github.xpenatan.jparser.example.testlib; + +import com.github.xpenatan.jparser.loader.JParserLibraryLoader; +import com.github.xpenatan.jparser.loader.JParserLibraryLoaderListener; + +public class TestLibLoader { + + public static final String LIB_NAME = "TestLib"; + + /*[-JNI;-NATIVE] + #include "CustomCode.h" + */ + + public static void init(JParserLibraryLoaderListener listener) { + JParserLibraryLoader.load(LIB_NAME, listener); + } +} \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/TestLib.idl b/example/lib/lib-build/src/main/cpp/TestLib.idl new file mode 100644 index 00000000..97f8cd01 --- /dev/null +++ b/example/lib/lib-build/src/main/cpp/TestLib.idl @@ -0,0 +1,251 @@ +// NOTE: +// * Emscripten webidl does not support [Value] object passed by parameter. Better to pass it as [Ref] +// * [BUG] Emscripten may give runtime errors if string is not at the same order in a overloading method or constructor parameter. +// See: TestStringConstructorClass. +// Error: VM41:980 Invalid UTF-8 leading byte 0x000000fe encountered when deserializing a UTF-8 string in wasm memory to a JS string! +// * Emscripten WebIDL does not support overloading method/constructor with different types at the same parameter size. +// Ex: void myMethod(float param1, boolean param2) and void myMethod(boolean param1, float param2) will not compile. +// It needs to be at the same order if both have the same parameter size. +// TestConstructorClass works because it have different parameter size. From the [BUG] above, don't use string or it will fail at runtime. +// * Arrays parameters for example "void method(int[] array)" is converted to IDLIntArray class object behind the scene because interacting with array is better using native code. +// For custom types is better to use 'using' alias. See TestObjectClassArray in CustomCode.h +// * Array get_ shape the same object for every index. Don't keep object reference. +// * Emscripten WebIDL callbacks don't work with overloaded methods so its better to use _[N] at the end of the method +// * Emscripten class methods don't work with overloaded methods with different parameter order so its better to use _[N] at the end of the method + +interface TestObjectClass { + void TestObjectClass(); + attribute long intValue01; + attribute float floatValue01; +}; + +interface TestObjectClassArray { + void TestObjectClassArray(long size); + void resize(long size); + void clear(); + TestObjectClass getValue(long index); + void setValue(long index, TestObjectClass value); + long getSize(); + any getPointer(); +}; + +interface TestConstructorClass { + readonly attribute long intValue01; + readonly attribute long intValue02; + readonly attribute float floatValue01; + readonly attribute float floatValue02; + readonly attribute boolean boolValue01; + + void TestConstructorClass(long intValue01); + void TestConstructorClass(float floatValue, long intValue01); + void TestConstructorClass(long intValue01, long intValue02, float floatValue01, float floatValue02, optional boolean boolValue01); + void TestConstructorClass(long intValue01, long[] intArray, float[] floatArray); +}; + +interface TestStringConstructorClass { + readonly attribute long intValue01; + [Value] readonly attribute IDLString strValue01; + + void TestStringConstructorClass([Const] DOMString strValue01); + void TestStringConstructorClass([Const] DOMString strValue01, long intValue01); + void TestStringConstructorClass([Const] DOMString strValue01, float floatValue01, long intValue01); +}; + +interface TestAttributeClass { + void TestAttributeClass(); + readonly attribute long readOnlyIntValue01; + attribute long intValue01; + attribute float floatValue01; + attribute double doubleValue01; + attribute boolean boolValue01; + [Value] attribute IDLString strValue01; + attribute any voidPointer01; + [Value] attribute TestObjectClass valueObject; + attribute TestObjectClass pointerObject; + attribute TestObjectClass nullPointerObject; +}; + +[NoDelete] +interface TestStaticAttributeClass { + static attribute long staticIntValue01; + static readonly attribute long staticConstIntValue01; + static attribute float staticFloatValue01; + static attribute double staticDoubleValue01; + static attribute boolean staticBoolValue01; +}; + +interface TestAttributeArrayClass { + void TestAttributeArrayClass(); + [BoundsChecked] attribute long[] intArray; + attribute float[] floatArray; + attribute byte[] byteArray; + attribute boolean[] boolArray; + [Value] attribute TestObjectClass[] valueObjectArray; + attribute TestObjectClass[] pointerObjectArray; +}; + +interface TestMethodClass { + void TestMethodClass(); + void TestMethodClass([Const] DOMString strValue01); + void setMethod01(long intValue01); + void setMethod02(float floatValue01, boolean boolValue01); + void setMethod03(long intValue01, long intValue02, float floatValue01, float floatValue02, optional boolean boolValue01); + void setMethod04(long intValue01, long[] intArray, float[] floatArray); + void setMethod05([Const] DOMString strValue01); + void setMethod06([Const] TestObjectClass pointerObject01, TestObjectClass pointerObject02, [Const, Ref] TestObjectClass refObject01, [Ref] TestObjectClass refObject02); + void setMethod07(TestObjectClass pointerObjectArray); + void setMethod08(long long longLongValue01); + + long getIntValue01(); + long getIntValue02(); + float getFloatValue01(); + float getFloatValue02(); + float getBoolValue01(); + [Const, Value] IDLStringView getStrValue01(); + [Const, Ref] IDLString getRefStrValue01(); + [Const] TestObjectClass getPointerObject01(); + TestObjectClass getPointerObject02(); + [Const, Ref] TestObjectClass getRefObject01(); + [Ref] TestObjectClass getRefObject02(); + [Value] TestObjectClass getValueObject(); + long long getLongLongValue01(); +}; + +[NoDelete] +interface TestStaticMethodClass { + static void setMethod01(long intValue01); + static void setMethod02(float floatValue01, boolean boolValue01); + static void setMethod03(long intValue01, long intValue02, float floatValue01, float floatValue02, optional boolean boolValue01); + static void setMethod04(long intValue01, long[] intArray, float[] floatArray); + static void setMethod05([Const] DOMString strValue01); + static void setMethod06([Const] TestObjectClass pointerObject01, TestObjectClass pointerObject02, [Const, Ref] TestObjectClass refObject01, [Ref] TestObjectClass refObject02); + + static long getIntValue01(); + static long getIntValue02(); + static float getFloatValue01(); + static float getFloatValue02(); + static float getBoolValue01(); + [Const, Value] static IDLStringView getStrValue01(); + [Const] static TestObjectClass getPointerObject01(); + static TestObjectClass getPointerObject02(); + [Const, Ref] static TestObjectClass getRefObject01(); + [Ref] static TestObjectClass getRefObject02(); + [Value] static TestObjectClass getValueObject(); +}; + +interface CallbackClass { + long addInt(long a, long b); +}; + +interface CallbackClassManual { + long addInt(long a, long b); +}; + +[JSImplementation="CallbackClass"] +interface CallbackClassImpl { + void CallbackClassImpl(); + + [Const] void onVoidCallback([Ref] TestObjectClass refData, TestObjectClass pointerData); + [Const] long onIntCallback(long intValue01, long intValue02); + [Const] float onFloatCallback(float floatValue01, float floatValue02); + [Const] boolean onBoolCallback(boolean boolValue01); + [Const] void onStringCallback([Const] DOMString strValue01); + unsigned long onUnsignedIntCallback(unsigned long unsignedInt); + [Const] unsigned short onUnsignedShortCallback(unsigned short unsignedShort); + [Const] void onAnyCallback_1(any anyPtr); + [Const] void onAnyCallback_2(any anyPtr, long value); + [Const] void onLongLongValue(unsigned long long longLongValue); +}; +CallbackClassImpl implements CallbackClass; + +[JSImplementation="CallbackClassManual"] +interface CallbackClassManualImpl { + void CallbackClassManualImpl(); + + [Const] void onVoidCallback([Ref] TestObjectClass refData, TestObjectClass pointerData); + [Const] long onIntCallback(long intValue01, long intValue02); + [Const] float onFloatCallback(float floatValue01, float floatValue02); + [Const] boolean onBoolCallback(boolean boolValue01); + [Const] void onStringCallback([Const] DOMString strValue01); +}; +CallbackClassManualImpl implements CallbackClassManual; + +interface DefaultCallbackClass : CallbackClass { + void DefaultCallbackClass(); +}; + +//[JSImplementation="DefaultCallbackClass"] +//interface DefaultCallbackClassImpl { +// void DefaultCallbackClassImpl(); +// +// [Const] long onIntCallback(long intValue01, long intValue02); +//}; +//DefaultCallbackClassImpl implements DefaultCallbackClass; + +interface TestCallbackClass { + void TestCallbackClass(); + + attribute long intValue01; + attribute long intValue02; + attribute float floatValue01; + attribute float floatValue02; + attribute boolean boolValue01; + [Value] attribute IDLString strValue01; + [Value] attribute TestObjectClass valueObject; + attribute TestObjectClass pointerObject; + + void callVoidCallback(CallbackClass callback); + long callIntCallback(CallbackClass callback); + float callFloatCallback(CallbackClass callback); + boolean callBoolCallback(CallbackClass callback); + void callStringCallback(CallbackClass callback); + unsigned long callUnsignedIntCallback(CallbackClass callback); + unsigned short callUnsignedShortCallback(CallbackClass callback); + + void callManualVoidCallback(CallbackClassManual callback); + long callManualIntCallback(CallbackClassManual callback); + float callManualFloatCallback(CallbackClassManual callback); + boolean callManualBoolCallback(CallbackClassManual callback); + void callManualStringCallback(CallbackClassManual callback); +}; + +[Prefix="TestNamespace::"] +interface TestNamespaceClass { //[-SUB_PACKAGE=core.sub] + attribute long intValue01; + void TestNamespaceClass(); + void setMethod01Value(long intValue01); + long getMethod01Value(); +}; + +interface TestOperatorClass { //[-SUB_PACKAGE=core.op] + void TestOperatorClass(); + void TestOperatorClass(float value); + [Operator="+", Value] TestOperatorClass addValue([Const, Ref] TestOperatorClass other); + [Operator="-", Value] TestOperatorClass subValue([Const, Ref] TestOperatorClass other); + [Operator="*", Value] TestOperatorClass mulValue([Const, Ref] TestOperatorClass other); + [Operator="/", Value] TestOperatorClass divValue([Const, Ref] TestOperatorClass other); + [Operator="+=", Ref] TestOperatorClass addRef([Const, Ref] TestOperatorClass other); + [Operator="-=", Ref] TestOperatorClass subRef([Const, Ref] TestOperatorClass other); + [Operator="*=", Ref] TestOperatorClass mulRef([Const, Ref] TestOperatorClass other); + [Operator="/=", Ref] TestOperatorClass divRef([Const, Ref] TestOperatorClass other); + float getValue(); + void setValue(float val); +}; + +enum TestEnumWithinClass { //[-SUB_PACKAGE=core.enums] + "TestEnumClass::e_val" +}; + +enum TestEnumClassWithinClass { + "TestEnumClassWithinClass::testEnum" +}; + +enum TestEnumInNamespace { + "TestEnumInNamespace::e_namespace_val" +}; + +enum TestEnumLib { + "TEST_DEFAULT", + "TEST_FIRST", + "TEST_SECOND" +}; \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/custom/CustomCode.h b/example/lib/lib-build/src/main/cpp/custom/CustomCode.h index 349b4026..c2ed825f 100644 --- a/example/lib/lib-build/src/main/cpp/custom/CustomCode.h +++ b/example/lib/lib-build/src/main/cpp/custom/CustomCode.h @@ -1,12 +1,8 @@ -#include "ReturnClass.h" -#include "ParentClass.h" -#include "OperatorClass.h" -#include "NormalClass.h" -#include "InterfaceClass.h" -#include "DefaultInterface.h" -#include "subpackage/ParamData.h" -#include "DefaultParamsClass.h" +#include "IDLHelper.h" +#include "TestLib.h" -typedef NormalClass::EnumWithinClass EnumWithinClass; -typedef NormalClass::EnumClassWithinClass EnumClassWithinClass; -typedef EnumNamespace::EnumInNamespace EnumInNamespace; \ No newline at end of file +using TestEnumWithinClass = TestEnumClass::TestEnumWithinClass; +using TestEnumClassWithinClass = TestEnumClass::TestEnumClassWithinClass; +using TestEnumInNamespace = TestEnumNamespace::TestEnumInNamespace; + +using TestObjectClassArray = IDLArray; \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/exampleLib.idl b/example/lib/lib-build/src/main/cpp/exampleLib.idl deleted file mode 100644 index bd40c5f0..00000000 --- a/example/lib/lib-build/src/main/cpp/exampleLib.idl +++ /dev/null @@ -1,130 +0,0 @@ -interface ParentClass { - float addFloatValue(float a, float b); - boolean invertBoolean(boolean value); -}; - -interface NormalClass { - attribute long hiddenInt; - [Value] attribute ReturnClass valueReturnClass; - attribute ReturnClass pointerReturnClass; - attribute ReturnClass nullPointerReturnClass; - - static attribute long hiddenInt_static; - [Value] static attribute ReturnClass valueReturnClass_static; - static attribute ReturnClass pointerReturnClass_static; - static attribute ReturnClass nullPointerReturnClass_static; - - void NormalClass(); - void NormalClass(long c, [Ref]ParamData refParamClass); - void NormalClass(EnumInNamespace nameSpaceEnum); - - long getVersion(); -// Emscripten don't allow param by value -// void NormalClass(ParamData pointerParamData, [Ref]ParamData refParamData, [Value]ParamData valueParamData); - -// void setString(DOMString text); -// static DOMString addString(DOMString text); -// [Value] static ReturnClass getStaticReturnValueClass(ParamData paramData); - [Value]ReturnClass getReturnValueClass(ParamData paramData); - - static long subIntValue(long a, long b, optional long subValue); - long addIntValue(long a, long b); - [Ref]ReturnClass getReturnRefClass(); - [Value]ReturnClass getReturnValueObject(); -// ReturnClass getReturnPointerClass(); -// ReturnClass getReturnNullPointerClass(); - void refParam([Ref]ParamData refParamOne, [Ref]ParamData refParamTwo, [Ref]ParamData refParamThree); -// void pointerParam(ParamData paramData); - - // Emscripten don't allow param by value -// void valueParam([Value]ParamData paramData); - -// void addIntArrayItems(long [] array); - - void callInterface([Ref]InterfaceClass obj); - - long enumParam(EnumLib value); - - void enumVoidParam(EnumLib value); - - EnumLib enumReturn(long value); - - boolean printText(long dummyParam, [Const]DOMString text); - - void setArray(float[] array); - - void setString([Ref] IDLString text); - [Ref] IDLString getString(); - [Value] IDLString getStringValue(); - - void setVoidParam(any param); - any getVoidParam(); -}; -NormalClass implements ParentClass; - -interface DefaultParamsClass { - void DefaultParamsClass(long a, long b, optional float c, optional float d); - - void defaultMethodParams(long a, long b, optional float c, optional float d); -}; - -[NoDelete] -interface ReturnClass { - void ReturnClass(); - - attribute float value; - - [Operator="=", Ref] ReturnClass copy([Ref]ReturnClass value); -}; - -interface OperatorClass { - void OperatorClass(); - - attribute float value; - - [Operator="=", Ref] OperatorClass copy([Ref]OperatorClass value); -}; - -interface ParamData { - void ParamData(); - attribute long intData; - attribute float floatData; -}; - -interface InterfaceClass { - void onParamCall([Ref]ParamData data); -}; - -[JSImplementation="InterfaceClass"] -interface InterfaceClassImpl { - void InterfaceClassImpl(); - [Const] void onParamCall([Ref]ParamData data); -}; - -interface DefaultInterface { - void DefaultInterface(); -}; -DefaultInterface implements InterfaceClass; - -enum EnumLib { - "FIRST", - "SECOND" -}; - -enum EnumTwoLib { - "EnumTwoLib_THIRD", - "EnumTwoLib_FOURTH" -}; - -enum EnumWithinClass { - "NormalClass::e_val" -}; - -enum EnumClassWithinClass { - "EnumClassWithinClass::testEnum" -}; - -enum EnumInNamespace { -// [-NAMESPACE] - "EnumNamespace::e_namespace_val" -}; \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/TestLib/src/TestLib.cpp b/example/lib/lib-build/src/main/cpp/source/TestLib/src/TestLib.cpp new file mode 100644 index 00000000..a9f6cae6 --- /dev/null +++ b/example/lib/lib-build/src/main/cpp/source/TestLib/src/TestLib.cpp @@ -0,0 +1 @@ +#include "TestLib.h" \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/TestLib/src/TestLib.h b/example/lib/lib-build/src/main/cpp/source/TestLib/src/TestLib.h new file mode 100644 index 00000000..137de348 --- /dev/null +++ b/example/lib/lib-build/src/main/cpp/source/TestLib/src/TestLib.h @@ -0,0 +1,495 @@ +#pragma once + +#include +#include +#include +#include + +using namespace std; + +class TestObjectClass { + private: + + public: + int intValue01; + float floatValue01; +}; + +class TestAttributeArrayClass { + private: + + public: + int intArray[3]; + float floatArray[3]; + char byteArray[3]; + bool boolArray[3]; + TestObjectClass valueObjectArray[3]; + TestObjectClass* pointerObjectArray[3]; +}; + +class TestAttributeClass { + private: + + public: + const int readOnlyIntValue01; + int intValue01; + float floatValue01; + double doubleValue01; + bool boolValue01; + string strValue01; + void* voidPointer01; + TestObjectClass valueObject; + TestObjectClass* pointerObject; + TestObjectClass* nullPointerObject; + + TestAttributeClass(): readOnlyIntValue01(7) { + pointerObject = new TestObjectClass(); + nullPointerObject = NULL; + }; + ~TestAttributeClass() { + delete pointerObject; + }; +}; + +class TestStaticAttributeClass { + private: + + public: + inline static int staticIntValue01; + inline static const int staticConstIntValue01 = 20; + inline static float staticFloatValue01; + inline static double staticDoubleValue01; + inline static bool staticBoolValue01; +}; + +class TestConstructorClass { + private: + + public: + int intValue01; + int intValue02; + float floatValue01; + float floatValue02; + bool boolValue01; + + TestConstructorClass(int intValue01) { + this->intValue01 = intValue01; + }; + TestConstructorClass(float floatValue01, int intValue01) { + this->floatValue01 = floatValue01; + this->intValue01 = intValue01; + }; + TestConstructorClass(int intValue01, int intValue02, float floatValue01, float floatValue02, bool boolValue01 = true) { + this->intValue01 = intValue01; + this->intValue02 = intValue02; + this->floatValue01 = floatValue01; + this->floatValue02 = floatValue02; + this->boolValue01 = boolValue01; + }; + TestConstructorClass(int intValue01, int* intArraySize2, float* floatArraySize2) { + this->intValue01 = intValue01; + intArraySize2[0] = 1; + intArraySize2[1] = 2; + floatArraySize2[0] = 3.1; + floatArraySize2[1] = 4.2; + }; +}; + +class TestStringConstructorClass { + private: + + public: + int intValue01; + int floatValue01; + string strValue01; + + TestStringConstructorClass(const char* strValue01) { + this->strValue01 = strValue01; + }; + TestStringConstructorClass(const char* strValue01, int intValue01) { + this->strValue01 = strValue01; + this->intValue01 = intValue01; + }; + TestStringConstructorClass(const char* strValue01, float floatValue01, int intValue01) { + this->strValue01 = strValue01; + this->floatValue01 = floatValue01; + this->intValue01 = intValue01; + }; +}; + +class TestMethodClass { + private: + int intValue01; + int intValue02; + float floatValue01; + float floatValue02; + bool boolValue01; + long long longLongValue01; + string strValue01; + const TestObjectClass* pointerObject01; + TestObjectClass* pointerObject02; + TestObjectClass** pointerObjectArray; + TestObjectClass refObject01; + TestObjectClass refObject02; + public: + TestMethodClass() { + pointerObject01 = NULL; + pointerObject02 = NULL; + }; + TestMethodClass(const char* strValue01) { + cout << "strValue01 before: " << strValue01 << endl; + this->strValue01 = strValue01; + }; + void setMethod01(int intValue01) { + this->intValue01 = intValue01; + }; + void setMethod02(float floatValue01, bool boolValue01) { + this->floatValue01 = floatValue01; + this->boolValue01 = boolValue01; + }; + void setMethod03(int intValue01, int intValue02, float floatValue01, float floatValue02, bool boolValue01 = true) { + this->intValue01 = intValue01; + this->intValue02 = intValue02; + this->floatValue01 = floatValue01; + this->floatValue02 = floatValue02; + this->boolValue01 = boolValue01; + }; + void setMethod04(int intValue01, int* intArraySize2, float* floatArraySize2) { + this->intValue01 = intValue01; + intArraySize2[0] = 1; + intArraySize2[1] = 2; + floatArraySize2[0] = 3.1; + floatArraySize2[1] = 4.2; + }; + void setMethod05(const char* strValue01) { + this->strValue01 = strValue01; + }; + void setMethod06(const TestObjectClass* pointerObject01, TestObjectClass* pointerObject02, const TestObjectClass& refObject01, TestObjectClass& refObject02) { + this->pointerObject01 = pointerObject01; + this->pointerObject02 = pointerObject02; + this->refObject01 = refObject01; + this->refObject02 = refObject02; + }; + void setMethod07(TestObjectClass* pointerObjectArray) { + this->pointerObjectArray = ((TestObjectClass** )pointerObjectArray); +// this->pointerObjectArray = &pointerObjectArray[0]; +// this->pointerObjectArray = &(*array[0]); + + TestObjectClass* obj1 = this->pointerObjectArray[0]; + TestObjectClass* obj2 = this->pointerObjectArray[1]; + obj1->intValue01 = 20; + obj1->floatValue01 = 10.4; + obj2->intValue01 = 40; + obj2->floatValue01 = 30.8; + }; + void setMethod08(long long longLongValue01) { + this->longLongValue01 = longLongValue01; + }; + + int getIntValue01() { return intValue01; }; + int getIntValue02() { return intValue02; }; + float getFloatValue01() { return floatValue01; }; + float getFloatValue02() { return floatValue02; }; + bool getBoolValue01() { return boolValue01; }; + const char* getStrValue01() { return strValue01.c_str(); }; + const string& getRefStrValue01() { return strValue01; }; + const TestObjectClass* getPointerObject01() { return pointerObject01; }; + TestObjectClass* getPointerObject02() { return pointerObject02; }; + const TestObjectClass& getRefObject01() { return refObject01; }; + TestObjectClass& getRefObject02() { return refObject02; }; + TestObjectClass getValueObject() { return refObject02; }; + long long getLongLongValue01() { return longLongValue01; }; +}; + +class TestOperatorClass { +private: + float value; + +public: + // Constructor + TestOperatorClass() { value = 0; } + TestOperatorClass(float value) { this->value = value; } + + // Arithmetic Operators + TestOperatorClass operator+(const TestOperatorClass& other) const { return TestOperatorClass(value + other.value); } + TestOperatorClass operator-(const TestOperatorClass& other) const { return TestOperatorClass(value - other.value); } + TestOperatorClass operator*(const TestOperatorClass& other) const { return TestOperatorClass(value * other.value); } + TestOperatorClass operator/(const TestOperatorClass& other) const { + if (other.value != 0) return TestOperatorClass(value / other.value); + cout << "Error: Division by zero!" << endl; + return *this; + } + TestOperatorClass operator-() const { return TestOperatorClass(-value); } // Unary minus + + // Compound Assignment Operators + TestOperatorClass& operator+=(const TestOperatorClass& other) { value += other.value; return *this; } + TestOperatorClass& operator-=(const TestOperatorClass& other) { value -= other.value; return *this; } + TestOperatorClass& operator*=(const TestOperatorClass& other) { value *= other.value; return *this; } + TestOperatorClass& operator/=(const TestOperatorClass& other) { + if (other.value != 0) value /= other.value; + else cout << "Error: Division by zero!" << endl; + return *this; + } + + // Comparison Operators + bool operator==(const TestOperatorClass& other) const { return value == other.value; } + bool operator!=(const TestOperatorClass& other) const { return value != other.value; } + bool operator<(const TestOperatorClass& other) const { return value < other.value; } + bool operator>(const TestOperatorClass& other) const { return value > other.value; } + bool operator<=(const TestOperatorClass& other) const { return value <= other.value; } + bool operator>=(const TestOperatorClass& other) const { return value >= other.value; } + + // Increment and Decrement Operators + TestOperatorClass& operator++() { value += 1.0; return *this; } // Prefix increment + TestOperatorClass operator++(int) { TestOperatorClass temp = *this; value += 1.0; return temp; } // Postfix increment + TestOperatorClass& operator--() { value -= 1.0; return *this; } // Prefix decrement + TestOperatorClass operator--(int) { TestOperatorClass temp = *this; value -= 1.0; return temp; } // Postfix decrement + + // Bitwise Operators (optional, but included for completeness with float caveats) + TestOperatorClass operator&(const TestOperatorClass& other) const { return TestOperatorClass(static_cast(static_cast(value) & static_cast(other.value))); } + TestOperatorClass operator|(const TestOperatorClass& other) const { return TestOperatorClass(static_cast(static_cast(value) | static_cast(other.value))); } + TestOperatorClass operator^(const TestOperatorClass& other) const { return TestOperatorClass(static_cast(static_cast(value) ^ static_cast(other.value))); } + TestOperatorClass operator~() const { return TestOperatorClass(static_cast(~static_cast(value))); } + TestOperatorClass operator<<(const TestOperatorClass& other) const { return TestOperatorClass(static_cast(static_cast(value) << static_cast(other.value))); } + TestOperatorClass operator>>(const TestOperatorClass& other) const { return TestOperatorClass(static_cast(static_cast(value) >> static_cast(other.value))); } + + // Compound Bitwise Assignment Operators + TestOperatorClass& operator&=(const TestOperatorClass& other) { value = static_cast(static_cast(value) & static_cast(other.value)); return *this; } + TestOperatorClass& operator|=(const TestOperatorClass& other) { value = static_cast(static_cast(value) | static_cast(other.value)); return *this; } + TestOperatorClass& operator^=(const TestOperatorClass& other) { value = static_cast(static_cast(value) ^ static_cast(other.value)); return *this; } + TestOperatorClass& operator<<=(const TestOperatorClass& other) { value = static_cast(static_cast(value) << static_cast(other.value)); return *this; } + TestOperatorClass& operator>>=(const TestOperatorClass& other) { value = static_cast(static_cast(value) >> static_cast(other.value)); return *this; } + + // Accessor + float getValue() const { return value; } + void setValue(float val) { this->value = val; } +}; + +class TestStaticMethodClass { + private: + inline static int intValue01; + inline static int intValue02; + inline static float floatValue01; + inline static float floatValue02; + inline static bool boolValue01; + inline static string strValue01; + inline static const TestObjectClass* pointerObject01 = NULL; + inline static TestObjectClass* pointerObject02 = NULL; + inline static TestObjectClass refObject01; + inline static TestObjectClass refObject02; + public: + static void setMethod01(int intValue01) { + TestStaticMethodClass::intValue01 = intValue01; + }; + static void setMethod02(float floatValue01, bool boolValue01) { + TestStaticMethodClass::floatValue01 = floatValue01; + TestStaticMethodClass::boolValue01 = boolValue01; + }; + static void setMethod03(int intValue01, int intValue02, float floatValue01, float floatValue02, bool boolValue01 = true) { + TestStaticMethodClass::intValue01 = intValue01; + TestStaticMethodClass::intValue02 = intValue02; + TestStaticMethodClass::floatValue01 = floatValue01; + TestStaticMethodClass::floatValue02 = floatValue02; + TestStaticMethodClass::boolValue01 = boolValue01; + }; + static void setMethod04(int intValue01, int* intArraySize2, float* floatArraySize2) { + TestStaticMethodClass::intValue01 = intValue01; + intArraySize2[0] = 1; + intArraySize2[1] = 2; + floatArraySize2[0] = 3.1; + floatArraySize2[1] = 4.2; + }; + static void setMethod05(const char* strValue01) { + TestStaticMethodClass::strValue01 = strValue01; + }; + static void setMethod06(const TestObjectClass* pointerObject01, TestObjectClass* pointerObject02, const TestObjectClass& refObject01, TestObjectClass& refObject02) { + TestStaticMethodClass::pointerObject01 = pointerObject01; + TestStaticMethodClass::pointerObject02 = pointerObject02; + TestStaticMethodClass::refObject01 = refObject01; + TestStaticMethodClass::refObject02 = refObject02; + }; + + static int getIntValue01() { return TestStaticMethodClass::intValue01; }; + static int getIntValue02() { return TestStaticMethodClass::intValue02; }; + static float getFloatValue01() { return TestStaticMethodClass::floatValue01; }; + static float getFloatValue02() { return TestStaticMethodClass::floatValue02; }; + static bool getBoolValue01() { return TestStaticMethodClass::boolValue01; }; + static const char* getStrValue01() { return TestStaticMethodClass::strValue01.c_str(); }; + static const TestObjectClass* getPointerObject01() { return TestStaticMethodClass::pointerObject01; }; + static TestObjectClass* getPointerObject02() { return TestStaticMethodClass::pointerObject02; }; + static const TestObjectClass& getRefObject01() { return TestStaticMethodClass::refObject01; }; + static TestObjectClass& getRefObject02() { return TestStaticMethodClass::refObject02; }; + static TestObjectClass getValueObject() { return TestStaticMethodClass::refObject02; }; +}; + +class CallbackClass +{ +public: + virtual ~CallbackClass() {} + + virtual void onVoidCallback(TestObjectClass& refData, TestObjectClass* pointerData) const = 0; + virtual int onIntCallback(int intValue01, int intValue02) const = 0; + virtual float onFloatCallback(float floatValue01, float Value02) const = 0; + virtual bool onBoolCallback(bool boolValue01) const = 0; + virtual void onStringCallback(const char* strValue01) const = 0; + virtual unsigned int onUnsignedIntCallback(unsigned int unsignedInt) = 0; + virtual unsigned short onUnsignedShortCallback(unsigned short unsignedShort) const = 0; + virtual void onAnyCallback_1(void * anyPtr) const = 0; + virtual void onAnyCallback_2(void * anyPtr, int value) const = 0; + virtual void onLongLongValue(unsigned long long longLongValue) const = 0; + + int addInt(int a, int b) + { + return a + b; + } +}; + +class DefaultCallbackClass : public CallbackClass +{ +public: + DefaultCallbackClass() { + }; + + virtual void onVoidCallback(TestObjectClass& refData, TestObjectClass* pointerData) const { + refData.intValue01 = 7; + refData.floatValue01 = 7.77; + pointerData->intValue01 = 10; + pointerData->floatValue01 = 10.77; + } + virtual int onIntCallback(int intValue01, int intValue02) const { + return intValue01 - intValue02; + } + virtual float onFloatCallback(float floatValue01, float floatValue02) const { + return floatValue01 + floatValue02; + } + virtual bool onBoolCallback(bool boolValue01) const { + return !boolValue01; + } + virtual void onStringCallback(const char* strValue01) const { + } + virtual unsigned int onUnsignedIntCallback(unsigned int unsignedInt) { + return 10; + } + virtual unsigned short onUnsignedShortCallback(unsigned short unsignedShort) const { + return 20; + } + virtual void onAnyCallback_1(void * anyPtr) const { + } + virtual void onAnyCallback_2(void * anyPtr, int value) const { + } + virtual void onLongLongValue(unsigned long long longLongValue) const { + } +}; + +class CallbackClassManual +{ +public: + virtual ~CallbackClassManual() {} + + virtual void onVoidCallback(TestObjectClass& refData, TestObjectClass* pointerData) const = 0; + virtual int onIntCallback(int intValue01, int intValue02) const = 0; + virtual float onFloatCallback(float floatValue01, float Value02) const = 0; + virtual bool onBoolCallback(bool boolValue01) const = 0; + virtual void onStringCallback(const char* strValue01) const = 0; + + int addInt(int a, int b) + { + return a + b; + } +}; + +class TestCallbackClass { + private: + public: + int intValue01; + int intValue02; + float floatValue01; + float floatValue02; + bool boolValue01; + string strValue01; + TestObjectClass valueObject; + TestObjectClass* pointerObject; + + void callVoidCallback(CallbackClass* callback) { + callback->onVoidCallback(valueObject, pointerObject); + }; + int callIntCallback(CallbackClass* callback) { + return callback->onIntCallback(intValue01, intValue02); + }; + float callFloatCallback(CallbackClass* callback) { + return callback->onFloatCallback(floatValue01, floatValue02); + }; + bool callBoolCallback(CallbackClass* callback) { + return callback->onBoolCallback(boolValue01); + }; + void callStringCallback(CallbackClass* callback) { + const char* text = strValue01.c_str(); + callback->onStringCallback(text); + }; + unsigned int callUnsignedIntCallback(CallbackClass* callback) { + unsigned int value = 13; + return callback->onUnsignedIntCallback(value); + }; + unsigned short callUnsignedShortCallback(CallbackClass* callback) { + unsigned short value = 12; + return callback->onUnsignedShortCallback(value); + }; + + void callManualVoidCallback(CallbackClassManual* callback) { + callback->onVoidCallback(valueObject, pointerObject); + }; + int callManualIntCallback(CallbackClassManual* callback) { + return callback->onIntCallback(intValue01, intValue02); + }; + float callManualFloatCallback(CallbackClassManual* callback) { + return callback->onFloatCallback(floatValue01, floatValue02); + }; + bool callManualBoolCallback(CallbackClassManual* callback) { + return callback->onBoolCallback(boolValue01); + }; + void callManualStringCallback(CallbackClassManual* callback) { + const char* text = strValue01.c_str(); + callback->onStringCallback(text); + }; +}; + + +namespace TestNamespace { + class TestNamespaceClass { + private: + public: + int intValue01; + + void setMethod01Value(int intValue01) { + this->intValue01 = intValue01; + } + int getMethod01Value() { + return intValue01; + } + }; +}; + +class TestEnumClass { + private: + + public: + enum TestEnumWithinClass { + e_val = 34 + }; + + enum class TestEnumClassWithinClass { + testEnum = 35 + }; +}; + +namespace TestEnumNamespace { + enum TestEnumInNamespace { + e_namespace_val = 78 + }; +}; + +enum TestEnumLib : int { + TEST_DEFAULT = 7, + TEST_FIRST, + TEST_SECOND +}; \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultInterface.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultInterface.h deleted file mode 100644 index 11619fbd..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultInterface.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "InterfaceClass.h" - -class DefaultInterface : public InterfaceClass -{ -public: - virtual void onParamCall(ParamData& data) const { - data.intData = 99; - data.floatData = 99.9; - } -}; diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultParamsClass.cpp b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultParamsClass.cpp deleted file mode 100644 index 6b972041..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultParamsClass.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "DefaultParamsClass.h" - -DefaultParamsClass::DefaultParamsClass(int a, int b, float c, float d) -{ - -} - -void DefaultParamsClass::defaultMethodParams(int a, int b, float c, float d) -{ - -} \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultParamsClass.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultParamsClass.h deleted file mode 100644 index 91f7ded9..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/DefaultParamsClass.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "ParentClass.h" -#include "subpackage/ParamData.h" -#include "ReturnClass.h" -#include "InterfaceClass.h" -#include "OperatorClass.h" - -class DefaultParamsClass -{ - - -public: - DefaultParamsClass(int a, int b, float c = 0, float d = 0); - - void defaultMethodParams(int a, int b, float c = 0, float d = 0); -}; diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/InterfaceClass.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/InterfaceClass.h deleted file mode 100644 index 8528ac82..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/InterfaceClass.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "subpackage/ParamData.h" - -class InterfaceClass -{ -public: - virtual ~InterfaceClass() {} - - virtual void onParamCall(ParamData& data) const = 0; -}; diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/NormalClass.cpp b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/NormalClass.cpp deleted file mode 100644 index 296027b8..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/NormalClass.cpp +++ /dev/null @@ -1,168 +0,0 @@ -#include "NormalClass.h" -#include - -NormalClass::NormalClass() -{ - valueReturnClass.value = 10; - nullPointerReturnClass = 0; - pointerReturnClass = new ReturnClass(); -} - -NormalClass::NormalClass(EnumNamespace::EnumInNamespace enumParam) -{ - -} - -NormalClass::NormalClass(int c, ParamData & refParamData) -{ - valueReturnClass.value = 10; - nullPointerReturnClass = 0; - pointerReturnClass = new ReturnClass(); -} - -NormalClass::NormalClass(ParamData * pointerParamData, ParamData & refParamData, ParamData valueParamData) -{ - valueReturnClass.value = 10; - nullPointerReturnClass = 0; - pointerReturnClass = new ReturnClass(); -} - -int NormalClass::getVersion() -{ - return 7; -} - -void NormalClass::setString(char* text) -{ - -} - -int NormalClass::subIntValue(int a, int b, int subValue) -{ - return (a - b) - subValue; -} - -int NormalClass::addIntValue(int a, int b) -{ - return (a + b) * hiddenInt * hiddenParentInt; -} - -ReturnClass NormalClass::getStaticReturnValueClass(ParamData * paramData) -{ - ReturnClass temp; - return temp; -} - -ReturnClass NormalClass::getReturnValueClass(ParamData * paramData) -{ - return valueReturnClass; -} - -ReturnClass NormalClass::getReturnValueObject() -{ - return valueReturnClass; -} - -ReturnClass & NormalClass::getReturnRefClass() -{ - return valueReturnClass; -} - -ReturnClass * NormalClass::getReturnPointerClass() -{ - return pointerReturnClass; -} - -ReturnClass * NormalClass::getReturnNullPointerClass() -{ - return nullPointerReturnClass; -} - -void NormalClass::refParam(ParamData & refParamOne, ParamData & refParamTwo, ParamData & refParamThree) -{ -} - -void NormalClass::pointerParam(ParamData * pointerParamData) -{ -} - -void NormalClass::valueParam(ParamData valueParamData) -{ -} - -void NormalClass::addIntArrayItems(int* array, int valueToAdd) -{ - int value = array[0]; - array[0] = value + valueToAdd; -} - -void NormalClass::callInterface(InterfaceClass & obj) -{ - obj.onParamCall(data); -} - -int NormalClass::enumParam(EnumLib value) -{ - if(value == FIRST) { - return 111; - } - if(value == SECOND) { - return 222; - } - return 0; -} - -void NormalClass::enumVoidParam(EnumLib value) -{ -} - -EnumLib NormalClass::enumReturn(int value) -{ - if(value == 1) { - return FIRST; - } - if(value == 2) { - return SECOND; - } - return DEFAULT; -} - -void NormalClass::enumTwoVoidParam(EnumTwoLib value) -{ -} - -bool NormalClass::printText(int dummyParam, const char* text) -{ - std::cout << text << std::endl; - return true; -} - -void NormalClass::setArray(float* array) -{ - array[0] = 1.2; -} - -void NormalClass::setString(std::string& text) -{ -} - -std::string& NormalClass::getString() -{ - std::string* test = new std::string("HELLO STRING"); - return *test; -} - -std::string NormalClass::getStringValue() -{ - std::string test = "HELLO STRING VALUE"; - return test; -} - -void NormalClass::setVoidParam(void* param) -{ -} - -void* NormalClass::getVoidParam() -{ - return NULL; -} diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/NormalClass.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/NormalClass.h deleted file mode 100644 index 1184f80a..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/NormalClass.h +++ /dev/null @@ -1,88 +0,0 @@ -#pragma once - -#include "ParentClass.h" -#include "subpackage/ParamData.h" -#include "ReturnClass.h" -#include "InterfaceClass.h" -#include -#include -#include - -enum EnumLib : int { - DEFAULT = 10, - FIRST, - SECOND, -}; - -enum EnumTwoLib { - EnumTwoLib_THIRD = 15, - EnumTwoLib_FOURTH -}; - -namespace EnumNamespace { - enum EnumInNamespace { - e_namespace_val = 78 - }; -}; - -class NormalClass : public ParentClass -{ - -private: - ParamData data; - -public: - enum EnumWithinClass { - e_val = 34 - }; - - enum class EnumClassWithinClass { - testEnum = 35 - }; - - int hiddenInt = 1; - - ReturnClass valueReturnClass; - ReturnClass * pointerReturnClass; - ReturnClass * nullPointerReturnClass; - - inline static int hiddenInt_static = 0; - inline static ReturnClass valueReturnClass_static; - inline static ReturnClass * pointerReturnClass_static = new ReturnClass(); - inline static ReturnClass * nullPointerReturnClass_static = NULL; - - NormalClass(); - NormalClass(EnumNamespace::EnumInNamespace); - NormalClass(int c, ParamData & refParamData); - NormalClass(ParamData * pointerParamData, ParamData & refParamData, ParamData valueParamData); - - int getVersion(); - void setString(char* text); - static int subIntValue(int a, int b, int subValue = 0); - int addIntValue(int a, int b); - - static ReturnClass getStaticReturnValueClass(ParamData * paramData); - ReturnClass getReturnValueClass(ParamData * paramData); - ReturnClass getReturnValueObject(); - - ReturnClass & getReturnRefClass(); - ReturnClass * getReturnPointerClass(); - ReturnClass * getReturnNullPointerClass(); - void refParam(ParamData & refParamOne, ParamData & refParamTwo, ParamData & refParamThree); - void pointerParam(ParamData * pointerParamData); - void valueParam(ParamData valueParamData); - void addIntArrayItems(int* array, int valueToAdd); - void callInterface(InterfaceClass & obj); - int enumParam(EnumLib value); - void enumVoidParam(EnumLib value); - EnumLib enumReturn(int value); - void enumTwoVoidParam(EnumTwoLib value); - bool printText(int dummyParam, const char* text); - void setArray(float* array); - - void setString(std::string& text); - std::string& getString(); - std::string getStringValue(); - void setVoidParam(void* param); - void* getVoidParam(); -}; diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/OperatorClass.cpp b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/OperatorClass.cpp deleted file mode 100644 index ef3e1d2d..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/OperatorClass.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "OperatorClass.h" - -OperatorClass& OperatorClass::operator=(const OperatorClass& other) { - this->value = other.value; - return *this; -} - -float OperatorClass::operator+(OperatorClass toAdd) { - return value + toAdd.value; -} \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/OperatorClass.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/OperatorClass.h deleted file mode 100644 index 8997f124..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/OperatorClass.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -class OperatorClass -{ -public: - float value = 0; - OperatorClass& operator=(const OperatorClass& other); - float operator+(OperatorClass toAdd); -}; \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ParentClass.cpp b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ParentClass.cpp deleted file mode 100644 index dcad3c9b..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ParentClass.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "ParentClass.h" - -ParentClass::ParentClass() -{ - int a = 1; - int b = 2; - int c = a + b; - c++; -} - -float ParentClass::addFloatValue(float a, float b) -{ - return (a + b) * hiddenParentInt; -// return (a + b); -} - -bool ParentClass::invertBoolean(bool value) -{ - return !(bool)(value * hiddenParentInt); -// return !value; -} \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ParentClass.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ParentClass.h deleted file mode 100644 index 681170ab..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ParentClass.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -class ParentClass -{ -protected: - int hiddenParentInt = 1; -public: - ParentClass(); - float addFloatValue(float a, float b); - bool invertBoolean(bool value); -}; diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ReturnClass.cpp b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ReturnClass.cpp deleted file mode 100644 index 1f6d145d..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ReturnClass.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "ReturnClass.h" - -ReturnClass& ReturnClass::operator=(const ReturnClass& other) { - this->value = other.value; - return *this; -} \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ReturnClass.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ReturnClass.h deleted file mode 100644 index ee7dd64e..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/ReturnClass.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -class ReturnClass -{ -public: - float value = 0; - ReturnClass& operator=(const ReturnClass& other); -}; diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/subpackage/ParamData.cpp b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/subpackage/ParamData.cpp deleted file mode 100644 index 5da04347..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/subpackage/ParamData.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "ParamData.h" \ No newline at end of file diff --git a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/subpackage/ParamData.h b/example/lib/lib-build/src/main/cpp/source/exampleLib/src/subpackage/ParamData.h deleted file mode 100644 index ec36b2e6..00000000 --- a/example/lib/lib-build/src/main/cpp/source/exampleLib/src/subpackage/ParamData.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef PARAMDATA_H -#define PARAMDATA_H - -class ParamData -{ -public: - int intData = 1; - float floatData = 3; -}; - -#endif //PARAMDATA_H diff --git a/example/lib/lib-build/src/main/java/BuildLib.java b/example/lib/lib-build/src/main/java/BuildLib.java index 16d39d46..8cc987c6 100644 --- a/example/lib/lib-build/src/main/java/BuildLib.java +++ b/example/lib/lib-build/src/main/java/BuildLib.java @@ -1,9 +1,11 @@ import com.github.xpenatan.jparser.builder.BuildMultiTarget; +import com.github.xpenatan.jparser.builder.targets.AndroidTargetOld; import com.github.xpenatan.jparser.builder.targets.AndroidTarget; import com.github.xpenatan.jparser.builder.targets.EmscriptenTarget; import com.github.xpenatan.jparser.builder.targets.IOSTarget; import com.github.xpenatan.jparser.builder.targets.LinuxTarget; import com.github.xpenatan.jparser.builder.targets.MacTarget; +import com.github.xpenatan.jparser.builder.targets.WindowsMSVCTarget; import com.github.xpenatan.jparser.builder.targets.WindowsTarget; import com.github.xpenatan.jparser.builder.tool.BuildToolListener; import com.github.xpenatan.jparser.builder.tool.BuildToolOptions; @@ -14,10 +16,14 @@ public class BuildLib { public static void main(String[] args) throws Exception { - String libName = "exampleLib"; + String libName = "TestLib"; String modulePrefix = "lib"; - String basePackage = "com.github.xpenatan.jparser.example.lib"; - String sourceDir = "/src/main/cpp/source/exampleLib/src"; + String basePackage = "com.github.xpenatan.jparser.example.testlib"; + String sourceDir = "/src/main/cpp/source/TestLib/src"; + + WindowsMSVCTarget.DEBUG_BUILD = true; +// NativeCPPGenerator.SKIP_GLUE_CODE = true; + BuildToolOptions op = new BuildToolOptions(libName, basePackage, modulePrefix, sourceDir, args); BuilderTool.build(op, new BuildToolListener() { @Override @@ -26,6 +32,7 @@ public void onAddTarget(BuildToolOptions op, IDLReader idlReader, ArrayList targets = new ArrayList<>(); + + targets.add(AndroidTarget.Target.x86); + targets.add(AndroidTarget.Target.x86_64); + targets.add(AndroidTarget.Target.armeabi_v7a); + targets.add(AndroidTarget.Target.arm64_v8a); + + for(int i = 0; i < targets.size(); i++) { + AndroidTarget.Target target = targets.get(i); + + // Make a static library + AndroidTarget compileStaticTarget = new AndroidTarget(target, apiLevel); + compileStaticTarget.isStatic = true; + compileStaticTarget.headerDirs.add("-I" + sourceDir); + compileStaticTarget.cppInclude.add(sourceDir + "**.cpp"); + multiTarget.add(compileStaticTarget); + + AndroidTarget linkTarget = new AndroidTarget(target, apiLevel); + linkTarget.addJNIHeaders(); + linkTarget.headerDirs.add("-I" + sourceDir); + linkTarget.headerDirs.add("-I" + op.getCustomSourceDir()); + linkTarget.headerDirs.add("-I" + libBuildCPPPath + "/src/jniglue"); + linkTarget.linkerFlags.add(libBuildCPPPath + "/libs/android/" + target.getFolder() +"/lib" + op.libName + ".a"); + linkTarget.cppInclude.add(libBuildCPPPath + "/src/jniglue/JNIGlue.cpp"); + multiTarget.add(linkTarget); + } + + return multiTarget; + } + + private static BuildMultiTarget getIOSTarget(BuildToolOptions op) { BuildMultiTarget multiTarget = new BuildMultiTarget(); + String sourceDir = op.getSourceDir(); + String libBuildCPPPath = op.getModuleBuildCPPPath(); + + // TODO WIP/not working // Make a static library IOSTarget compileStaticTarget = new IOSTarget(); compileStaticTarget.isStatic = true; - compileStaticTarget.headerDirs.add("-I" + libBuildCPPPath + "/src/exampleLib"); - compileStaticTarget.cppInclude.add(libBuildCPPPath + "/src/exampleLib/**.cpp"); + compileStaticTarget.headerDirs.add("-I" + sourceDir); + compileStaticTarget.cppInclude.add(sourceDir + "**.cpp"); multiTarget.add(compileStaticTarget); IOSTarget linkTarget = new IOSTarget(); linkTarget.addJNIHeaders(); - linkTarget.headerDirs.add("-I" + libBuildCPPPath + "/src/exampleLib"); + linkTarget.headerDirs.add("-I" + sourceDir); + linkTarget.headerDirs.add("-I" + op.getCustomSourceDir()); linkTarget.headerDirs.add("-I" + libBuildCPPPath + "/src/jniglue"); - linkTarget.linkerFlags.add(libBuildCPPPath + "/libs/ios/lib" + op.libName + ".a"); + linkTarget.linkerFlags.add(libBuildCPPPath + "/libs/ios/lib" + op.libName + "_.a"); linkTarget.cppInclude.add(libBuildCPPPath + "/src/jniglue/JNIGlue.cpp"); - multiTarget.add(linkTarget); return multiTarget; diff --git a/example/lib/lib-core/build.gradle.kts b/example/lib/lib-core/build.gradle.kts index eba178a5..43b6ae4f 100644 --- a/example/lib/lib-core/build.gradle.kts +++ b/example/lib/lib-core/build.gradle.kts @@ -1,13 +1,14 @@ plugins { id("java") + id("java-library") } dependencies { if(LibExt.exampleUseRepoLibs) { - implementation("com.github.xpenatan.jParser:loader-core:${LibExt.libVersion}") + api("com.github.xpenatan.jParser:loader-core:${LibExt.libVersion}") } else { - implementation(project(":jParser:loader:loader-core")) + api(project(":jParser:loader:loader-core")) } } diff --git a/example/lib/lib-desktop/build.gradle.kts b/example/lib/lib-desktop/build.gradle.kts index 85cd59ba..f26010e4 100644 --- a/example/lib/lib-desktop/build.gradle.kts +++ b/example/lib/lib-desktop/build.gradle.kts @@ -3,10 +3,11 @@ plugins { } val libDir = "${projectDir}/../lib-build/build/c++/libs" -val windowsFile = "$libDir/windows/exampleLib64.dll" -val linuxFile = "$libDir/linux/libexampleLib64.so" -val macFile = "$libDir/mac/libexampleLib64.dylib" -val macArmFile = "$libDir/mac/arm/libexampleLibarm64.dylib" +//val windowsFile = "$libDir/windows/TestLib64.dll" +val windowsFile = "$libDir/windows/vc/TestLib64.dll" +val linuxFile = "$libDir/linux/libTestLib64.so" +val macFile = "$libDir/mac/libTestLib64.dylib" +val macArmFile = "$libDir/mac/arm/libTestLibarm64.dylib" tasks.jar { from(windowsFile) diff --git a/example/lib/lib-desktop/src/test/java/com/github/xpenatan/jparser/example/NormalClassTest.java b/example/lib/lib-desktop/src/test/java/com/github/xpenatan/jparser/example/NormalClassTest.java index adfbb717..9f38f5dd 100644 --- a/example/lib/lib-desktop/src/test/java/com/github/xpenatan/jparser/example/NormalClassTest.java +++ b/example/lib/lib-desktop/src/test/java/com/github/xpenatan/jparser/example/NormalClassTest.java @@ -1,9 +1,6 @@ package com.github.xpenatan.jparser.example; -import com.github.xpenatan.jparser.example.lib.NormalClass; -import com.github.xpenatan.jparser.loader.JParserLibraryLoader; -import org.junit.BeforeClass; -import org.junit.Test; +import com.github.xpenatan.jparser.example.testlib.NormalClass; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; diff --git a/example/lib/lib-teavm/build.gradle.kts b/example/lib/lib-teavm/build.gradle.kts index 45c5b019..1a527f03 100644 --- a/example/lib/lib-teavm/build.gradle.kts +++ b/example/lib/lib-teavm/build.gradle.kts @@ -2,8 +2,8 @@ plugins { id("java") } -val emscriptenFile = "$projectDir/../lib-build/build/c++/libs/emscripten/exampleLib.wasm.js" -val emscriptenSideFile = "$projectDir/../lib-build/build/c++/libs/emscripten/exampleLibside.wasm" +val emscriptenFile = "$projectDir/../lib-build/build/c++/libs/emscripten/TestLib.wasm.js" +val emscriptenSideFile = "$projectDir/../lib-build/build/c++/libs/emscripten/TestLibside.wasm" tasks.jar { from(emscriptenFile, emscriptenSideFile) @@ -21,17 +21,17 @@ dependencies { else { implementation(project(":jParser:loader:loader-core")) } - testImplementation(project(":example:lib:lib-core")) - testImplementation("junit:junit:${LibExt.jUnitVersion}") - testImplementation("org.teavm:teavm-core:${LibExt.teaVMVersion}") - testImplementation("org.teavm:teavm-jso-apis:${LibExt.teaVMVersion}") - testImplementation("org.teavm:teavm-classlib:${LibExt.teaVMVersion}") - testImplementation("org.teavm:teavm-junit:${LibExt.teaVMVersion}") +// testImplementation(project(":example:lib:lib-core")) +// testImplementation("junit:junit:${LibExt.jUnitVersion}") +// testImplementation("org.teavm:teavm-core:${LibExt.teaVMVersion}") +// testImplementation("org.teavm:teavm-jso-apis:${LibExt.teaVMVersion}") +// testImplementation("org.teavm:teavm-classlib:${LibExt.teaVMVersion}") +// testImplementation("org.teavm:teavm-junit:${LibExt.teaVMVersion}") } tasks.named("clean") { doFirst { - val srcPath = "$projectDir/src/main/java/gen" + val srcPath = "$projectDir/src/main/java" project.delete(files(srcPath)) } } diff --git a/gradle.properties b/gradle.properties index d868684e..761b652c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ android.useAndroidX=true -version=1.0.0-b5 \ No newline at end of file +version=1.0.0-b6 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a..e18bc253 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/jParser/base/src/main/java/idl/IDLBase.java b/jParser/base/src/main/java/idl/IDLBase.java index 36883d22..80985104 100644 --- a/jParser/base/src/main/java/idl/IDLBase.java +++ b/jParser/base/src/main/java/idl/IDLBase.java @@ -5,40 +5,45 @@ */ public abstract class IDLBase { - public static boolean USE_REF_COUNTING = false; public static boolean ENABLE_LOGGING = true; protected final IDLNativeData nativeData = new IDLNativeData(this); public IDLBase() { } - public final void initNative(long cPtr, boolean cMemoryOwn) { - nativeData.initNative(cPtr, cMemoryOwn); - } - - public final void setCPointer(long cPtr) { - nativeData.setCPointer(cPtr); - } - - public final long getCPointer() { - return nativeData.getCPointer(); - } - public final IDLNativeData getNativeData() { return nativeData; } - public boolean isDisposed() { + protected boolean isDisposed() { return nativeData.isDisposed(); } - public void dispose() { + protected void dispose() { nativeData.dispose(); } + @Override + public String toString() { + return getClass().getSimpleName() + " " + nativeData; + } + /** * Deletes the IDL object this class encapsulates. Do not call directly, instead use the {@link #dispose()} method. */ protected void deleteNative() { } + + /*[-TEAVM;-REPLACE] + @org.teavm.jso.JSBody(params = { "addr" }, script = "return [MODULE].UTF8ToString(addr);") + public static native String getJSString(int addr); + */ + public static String getJSString(long addr) { + return null; + } + + @Override + public boolean equals(Object obj) { + return nativeData.equals(obj); + } } \ No newline at end of file diff --git a/jParser/base/src/main/java/idl/IDLNativeData.java b/jParser/base/src/main/java/idl/IDLNativeData.java index b92a8e69..d55a088f 100644 --- a/jParser/base/src/main/java/idl/IDLNativeData.java +++ b/jParser/base/src/main/java/idl/IDLNativeData.java @@ -6,71 +6,33 @@ public class IDLNativeData { private long cPointer; private boolean cMemOwn; private boolean disposed; - private boolean destroyed; - private int refCount; public IDLNativeData(IDLBase idlBase) { this.idlBase = idlBase; } - public void initNative(long cPtr, boolean cMemoryOwn) { - cMemOwn = cMemoryOwn; - cPointer = cPtr; - } - - /** - * Set pointer if it's not owned by this object. Useful for setting temp objets - */ - public void setCPointer(long cPtr) { - if(!cMemOwn) { - cPointer = cPtr; - } - else { - String className = getClass().getSimpleName(); - throw new RuntimeException("Cannot change " + className + " pointer owned by native code"); - } - } - - /** - * Obtains a reference to this object, call release to free the reference. - */ - public void obtain() { - refCount++; - } - - /** - * Release a previously obtained reference, causing the object to be disposed when this was the last reference. - */ - public void release() { - if(--refCount <= 0 && IDLBase.USE_REF_COUNTING) dispose(); - } - - /** - * @return Whether this instance is obtained using the {@link #obtain()} method. - */ - public boolean isObtained() { - return refCount > 0; - } - - protected void construct() { - destroyed = false; - } - public void reset(long cPtr, boolean cMemoryOwn) { - if(!destroyed) destroy(); + dispose(); cMemOwn = cMemoryOwn; cPointer = cPtr; - construct(); + disposed = false; } - @Override - public boolean equals(Object obj) { - return (obj instanceof IDLBase) && (((IDLNativeData)obj).cPointer == this.cPointer); + public void reset(IDLBase idlBase, boolean cMemoryOwn) { + reset(idlBase.nativeData.getCPointer(), cMemoryOwn); } @Override - public int hashCode() { - return (int)cPointer; + public boolean equals(Object obj) { + if(obj instanceof IDLBase) { + IDLBase idlBase = (IDLBase)obj; + return idlBase.nativeData.cPointer == this.cPointer; + } + else if(obj instanceof IDLNativeData) { + IDLNativeData nativeData = (IDLNativeData)obj; + return nativeData.cPointer == this.cPointer; + } + return false; } /** @@ -81,36 +43,43 @@ public long getCPointer() { } /** - * Take ownership of the native instance, causing the native object to be deleted when this object gets out of scope. + * Take ownership of the native instance, causing the native object to be warned when this object gets out of scope. */ public void takeOwnership() { cMemOwn = true; } /** - * Release ownership of the native instance, causing the native object NOT to be deleted when this object gets out of + * Release ownership of the native instance, causing the native object NOT to be warned when this object gets out of * scope. */ public void releaseOwnership() { cMemOwn = false; } - /** - * @return True if the native is destroyed when this object gets out of scope, false otherwise. - */ public boolean hasOwnership() { return cMemOwn; } public void dispose() { - if(refCount > 0 && IDLBase.USE_REF_COUNTING && IDLBase.ENABLE_LOGGING) { - error("IDL", "Disposing " + toString() + " while it still has " + refCount + " references."); - } if(cMemOwn) { - // Don't try to delete if this object did not create the pointer - disposed = true; - idlBase.deleteNative(); - cPointer = 0; + if(!disposed) { + if(cPointer != 0) { + disposed = true; + idlBase.deleteNative(); + cPointer = 0; + } + else { + if(IDLBase.ENABLE_LOGGING) { + error("IDL", "Disposing error - " + toString() + " cPointer is 0"); + } + } + } + else { + if(IDLBase.ENABLE_LOGGING) { + error("IDL", "Disposing error - " + toString() + " is already disposed"); + } + } } } @@ -126,28 +95,10 @@ public String toString() { return getClass().getSimpleName() + "(" + cPointer + "," + cMemOwn + ")"; } - public void destroy() { - try { - if(destroyed && IDLBase.ENABLE_LOGGING) { - error("IDL", "Already destroyed " + toString()); - } - destroyed = true; - - if(cMemOwn && !disposed) { - if(IDLBase.ENABLE_LOGGING) { - error("IDL", "Disposing " + toString() + " due to garbage collection."); - } - dispose(); - } - } catch(Throwable e) { - error("IDL", "Exception while destroying " + toString(), e); - } - } - @Override protected void finalize() throws Throwable { - if(!destroyed && IDLBase.ENABLE_LOGGING) { - error("IDL", "The " + getClass().getSimpleName() + " class does not override the finalize method."); + if(cMemOwn && !disposed && IDLBase.ENABLE_LOGGING) { + error("IDL", "Memory Leak - " + idlBase.getClass().getSimpleName() + " was not disposed correctly."); } super.finalize(); } @@ -156,13 +107,6 @@ protected void finalize() throws Throwable { * Logs an error message to the console or logcat */ public static void error(String tag, String message) { - //TODO impl - } - - /** - * Logs an error message to the console or logcat - */ - public static void error(String tag, String message, Throwable exception) { - //TODO impl + System.err.println(tag + ": " + message); } } diff --git a/jParser/base/src/main/java/idl/helper/IDLLong.java b/jParser/base/src/main/java/idl/helper/IDLLong.java new file mode 100644 index 00000000..a5d4696f --- /dev/null +++ b/jParser/base/src/main/java/idl/helper/IDLLong.java @@ -0,0 +1,39 @@ +package idl.helper; + +public class IDLLong extends IDLLongArray { + + public static IDLLong TMP_1 = new IDLLong(); + public static IDLLong TMP_2 = new IDLLong(); + public static IDLLong TMP_3 = new IDLLong(); + public static IDLLong TMP_4 = new IDLLong(); + + public static void disposeTEMP() { + TMP_1.dispose(); + TMP_2.dispose(); + TMP_3.dispose(); + TMP_4.dispose(); + } + + public IDLLong() { + super(1); + } + + public IDLLong(int value) { + this(); + set(value); + } + + public IDLLong set(long value) { + setValue(0, value); + return this; + } + + public long getValue() { + return getValue(0); + } + + @Override + public String toString() { + return String.valueOf(getValue()); + } +} \ No newline at end of file diff --git a/jParser/base/src/main/java/idl/helper/IDLLong2.java b/jParser/base/src/main/java/idl/helper/IDLLong2.java new file mode 100644 index 00000000..cae3f588 --- /dev/null +++ b/jParser/base/src/main/java/idl/helper/IDLLong2.java @@ -0,0 +1,45 @@ +package idl.helper; + +public class IDLLong2 extends IDLLongArray { + + public static IDLLong2 TMP_1 = new IDLLong2(); + public static IDLLong2 TMP_2 = new IDLLong2(); + + public static void disposeTEMP() { + TMP_1.dispose(); + TMP_2.dispose(); + } + + public IDLLong2() { + super(2); + } + + public IDLLong2 set(long value0, long value1) { + setValue(0, value0); + setValue(1, value1); + return this; + } + + public IDLLong2 set0(long value) { + setValue(0, value); + return this; + } + + public IDLLong2 set1(long value) { + setValue(1, value); + return this; + } + + public long get0() { + return getValue(0); + } + + public long get1() { + return getValue(1); + } + + @Override + public String toString() { + return get0() + ", " + get1(); + } +} \ No newline at end of file diff --git a/jParser/base/src/main/java/idl/helper/IDLLong3.java b/jParser/base/src/main/java/idl/helper/IDLLong3.java new file mode 100644 index 00000000..4c21b89d --- /dev/null +++ b/jParser/base/src/main/java/idl/helper/IDLLong3.java @@ -0,0 +1,55 @@ +package idl.helper; + +public class IDLLong3 extends IDLLongArray { + + public static IDLLong3 TMP_1 = new IDLLong3(); + public static IDLLong3 TMP_2 = new IDLLong3(); + + public static void disposeTEMP() { + TMP_1.dispose(); + TMP_2.dispose(); + } + + public IDLLong3() { + super(3); + } + + public IDLLong3 set(long value0, long value1, long value2) { + setValue(0, value0); + setValue(1, value1); + setValue(2, value2); + return this; + } + + public IDLLong3 set0(long value) { + setValue(0, value); + return this; + } + + public IDLLong3 set1(long value) { + setValue(1, value); + return this; + } + + public IDLLong3 set2(long value) { + setValue(2, value); + return this; + } + + public long get0() { + return getValue(0); + } + + public long get1() { + return getValue(1); + } + + public long get2() { + return getValue(2); + } + + @Override + public String toString() { + return get0() + ", " + get1() + ", " + get2(); + } +} \ No newline at end of file diff --git a/jParser/base/src/main/java/idl/helper/IDLLong4.java b/jParser/base/src/main/java/idl/helper/IDLLong4.java new file mode 100644 index 00000000..4a96a709 --- /dev/null +++ b/jParser/base/src/main/java/idl/helper/IDLLong4.java @@ -0,0 +1,65 @@ +package idl.helper; + +public class IDLLong4 extends IDLLongArray { + + public static IDLLong4 TMP_1 = new IDLLong4(); + public static IDLLong4 TMP_2 = new IDLLong4(); + + public static void disposeTEMP() { + TMP_1.dispose(); + TMP_2.dispose(); + } + + public IDLLong4() { + super(4); + } + + public IDLLong4 set(long value0, long value1, long value2, long value3) { + setValue(0, value0); + setValue(1, value1); + setValue(2, value2); + setValue(3, value3); + return this; + } + + public IDLLong4 set0(long value) { + setValue(0, value); + return this; + } + + public IDLLong4 set1(long value) { + setValue(1, value); + return this; + } + + public IDLLong4 set2(long value) { + setValue(2, value); + return this; + } + + public IDLLong4 set3(long value) { + setValue(3, value); + return this; + } + + public long get0() { + return getValue(0); + } + + public long get1() { + return getValue(1); + } + + public long get2() { + return getValue(2); + } + + public long get3() { + return getValue(3); + } + + @Override + public String toString() { + return get0() + ", " + get1() + ", " + get2() + ", " + get3(); + } +} \ No newline at end of file diff --git a/jParser/base/src/main/java/idl/helper/IDLLongArray.java b/jParser/base/src/main/java/idl/helper/IDLLongArray.java new file mode 100644 index 00000000..b64484ff --- /dev/null +++ b/jParser/base/src/main/java/idl/helper/IDLLongArray.java @@ -0,0 +1,24 @@ +package idl.helper; + +import idl.IDLBase; + +public class IDLLongArray extends IDLBase { + + public IDLLongArray(int size) { + } + + public void copy(long[] array) { + int length = array.length; + resize(length); + for(int i = 0; i < length; i++) { + long value = array[i]; + setValue(i, value); + } + } + + public native void setValue(int index, long value); + public native void resize(int size); + public native long getValue(int index); + public native long getPointer(); + public native int getSize(); +} \ No newline at end of file diff --git a/jParser/base/src/main/java/idl/helper/IDLString.java b/jParser/base/src/main/java/idl/helper/IDLString.java index b72f085a..2a18efbc 100644 --- a/jParser/base/src/main/java/idl/helper/IDLString.java +++ b/jParser/base/src/main/java/idl/helper/IDLString.java @@ -20,7 +20,7 @@ public IDLString() { public IDLString(byte b, char c) {} public String c_str() { - String text = c_strNATIVE(getCPointer()); + String text = internal_native_c_str(getNativeData().getCPointer()); return text; } @@ -35,5 +35,23 @@ public String c_str() { var returnedJSObj = jsObj.c_str(); return returnedJSObj; */ - private static native String c_strNATIVE(long this_addr); + private static native String internal_native_c_str(long this_addr); + + public String data() { + String text = internal_native_data(getNativeData().getCPointer()); + return text; + } + + /*[-JNI;-NATIVE] + IDLString* nativeObject = (IDLString*)this_addr; + const char* str = nativeObject->data(); + jstring jstrBuf = env->NewStringUTF(str); + return jstrBuf; + */ + /*[-TEAVM;-NATIVE] + var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].IDLString); + var returnedJSObj = jsObj.data(); + return returnedJSObj; + */ + private static native String internal_native_data(long this_addr); } \ No newline at end of file diff --git a/jParser/base/src/main/java/idl/helper/IDLStringView.java b/jParser/base/src/main/java/idl/helper/IDLStringView.java new file mode 100644 index 00000000..4f5c5f12 --- /dev/null +++ b/jParser/base/src/main/java/idl/helper/IDLStringView.java @@ -0,0 +1,39 @@ +package idl.helper; + +import idl.IDLBase; + +public class IDLStringView extends IDLBase { + + public static IDLStringView TMP_EMPTY_1 = new IDLStringView((byte)0, '0'); + + public static IDLStringView TMP_1 = new IDLStringView(); + public static IDLStringView TMP_2 = new IDLStringView(); + + public static void disposeTEMP() { + TMP_1.dispose(); + TMP_2.dispose(); + } + + public IDLStringView() { + } + + public IDLStringView(byte b, char c) {} + + public String data() { + String text = internal_native_data(getNativeData().getCPointer()); + return text; + } + + /*[-JNI;-NATIVE] + IDLStringView* nativeObject = (IDLStringView*)this_addr; + const char* str = nativeObject->data(); + jstring jstrBuf = env->NewStringUTF(str); + return jstrBuf; + */ + /*[-TEAVM;-NATIVE] + var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].IDLStringView); + var returnedJSObj = jsObj.data(); + return returnedJSObj; + */ + private static native String internal_native_data(long this_addr); +} \ No newline at end of file diff --git a/jParser/base/src/main/resources/IDLHelper.h b/jParser/base/src/main/resources/IDLHelper.h index c8c3617a..b7453cbb 100644 --- a/jParser/base/src/main/resources/IDLHelper.h +++ b/jParser/base/src/main/resources/IDLHelper.h @@ -1,147 +1,58 @@ #pragma once #include +#include #include // NULL #include // intptr_t +#include +#include -typedef std::string IDLString; - -class IDLBoolArray { +template +class IDLArray { private: int size; - public: - bool * data; - IDLBoolArray(int size) { data = NULL; resize(size); } - ~IDLBoolArray() { if(data != NULL) { deleteData(); } } - void resize(int newSize) { - if(this->data != NULL) { - deleteData(); - } - bool * newData = new bool[newSize]; - this->data = newData; - size = newSize; - clear(); - } - void clear() { - for(int i = 0; i < size; i++) { - data[i] = 0; - } - } - void deleteData() { delete data; } - bool getValue(int index) { return data[index]; } - void setValue(int index, bool value) { data[index] = value; } - intptr_t getPointer() { return (intptr_t)data; } - int getSize() { return size; } -}; + T* data; -class IDLIntArray { - private: - int size; + void deleteData() { delete[] data; data = nullptr; } public: - int * data; - IDLIntArray(int size) { data = NULL; resize(size); } - ~IDLIntArray() { if(data != NULL) { deleteData(); } } + IDLArray(int size) : size(0), data(nullptr) { resize(size); } + ~IDLArray() { deleteData(); } void resize(int newSize) { - if(this->data != NULL) { - deleteData(); + if(newSize > 0 && size != newSize) { + T* newData = new T[newSize]; + if (data != nullptr) { + deleteData(); // Delete the old array + } + data = newData; // Update the data pointer + size = newSize; // Update the size + clear(); } - int * newData = new int[newSize]; - this->data = newData; - size = newSize; - clear(); } void clear() { - for(int i = 0; i < size; i++) { - data[i] = 0; - } + std::fill(data, data + size, T()); } - void deleteData() { delete data; } - int getValue(int index) { return data[index]; } - void setValue(int index, int value) { data[index] = value; } - intptr_t getPointer() { return (intptr_t)data; } - int getSize() { return size; } -}; - -class IDLFloatArray { - private: - int size; - public: - float * data; - IDLFloatArray(int size) { data = NULL; resize(size); } - ~IDLFloatArray() { if(data != NULL) { deleteData(); } } - void resize(int newSize) { - if(this->data != NULL) { - deleteData(); - } - float * newData = new float[newSize]; - this->data = newData; - size = newSize; - clear(); + void copy(IDLArray& src, int srcPos, int destPos, int length) { + assert(!(srcPos < 0 || destPos < 0 || length < 0 || srcPos + length > src.size || destPos + length > size)); + std::copy(src.data + srcPos, src.data + srcPos + length, data + destPos); } - void clear() { - for(int i = 0; i < size; i++) { - data[i] = 0; - } + T getValue(int index) { + assert(!(index < 0 || index >= size)); + return data[index]; + } + void setValue(int index, T value) { + assert(!(index < 0 || index >= size)); + data[index] = value; } - void deleteData() { delete data; } - float getValue(int index) { return data[index]; } - void setValue(int index, float value) { data[index] = value; } - intptr_t getPointer() { return (intptr_t)data; } int getSize() { return size; } + void* getPointer() { return (void*)data; } + T* getData() { return data; } }; -class IDLDoubleArray { - private: - int size; - public: - double * data; - IDLDoubleArray(int size) { data = NULL; resize(size); } - ~IDLDoubleArray() { if(data != NULL) { deleteData(); } } - void resize(int newSize) { - if(this->data != NULL) { - deleteData(); - } - double * newData = new double[newSize]; - this->data = newData; - size = newSize; - clear(); - } - void clear() { - for(int i = 0; i < size; i++) { - data[i] = 0; - } - } - void deleteData() { delete data; } - double getValue(int index) { return data[index]; } - void setValue(int index, double value) { data[index] = value; } - intptr_t getPointer() { return (intptr_t)data; } - int getSize() { return size; } -}; - -class IDLByteArray { - private: - int size; - public: - char * data; - IDLByteArray(int size) { data = NULL; resize(size); } - ~IDLByteArray() { if(data != NULL) { deleteData(); } } - void resize(int newSize) { - if(this->data != NULL) { - deleteData(); - } - char * newData = new char[newSize]; - this->data = newData; - size = newSize; - clear(); - } - void clear() { - for(int i = 0; i < size; i++) { - data[i] = 0; - } - } - void deleteData() { delete data; } - char getValue(int index) { return data[index]; } - void setValue(int index, char value) { data[index] = value; } - intptr_t getPointer() { return (intptr_t)data; } - int getSize() { return size; } -}; \ No newline at end of file +typedef std::string IDLString; +typedef std::string_view IDLStringView; +typedef IDLArray IDLBoolArray; +typedef IDLArray IDLIntArray; +typedef IDLArray IDLLongArray; +typedef IDLArray IDLFloatArray; +typedef IDLArray IDLDoubleArray; +typedef IDLArray IDLByteArray; \ No newline at end of file diff --git a/jParser/base/src/main/resources/IDLHelper.idl b/jParser/base/src/main/resources/IDLHelper.idl index a2bda44e..02512673 100644 --- a/jParser/base/src/main/resources/IDLHelper.idl +++ b/jParser/base/src/main/resources/IDLHelper.idl @@ -6,50 +6,80 @@ interface IDLString { void append([Const] DOMString text, long size); long size(); byte at(long index); + [Const] DOMString data(); [Const] DOMString c_str(); }; +interface IDLStringView { + void IDLStringView([Const] DOMString text); + void IDLStringView([Const] DOMString text, long size); + long size(); + byte at(long index); + [Const] DOMString data(); +}; + interface IDLBoolArray { void IDLBoolArray(long size); void resize(long size); + void clear(); boolean getValue(long index); void setValue(long index, boolean value); - long getPointer(); long getSize(); + any getPointer(); + void copy([Ref] IDLBoolArray src, long srcOffset, long destOffset, long length); }; interface IDLIntArray { void IDLIntArray(long size); void resize(long size); + void clear(); long getValue(long index); void setValue(long index, long value); - long getPointer(); long getSize(); + any getPointer(); + void copy([Ref] IDLIntArray src, long srcOffset, long destOffset, long length); +}; + +interface IDLLongArray { + void IDLLongArray(long size); + void resize(long size); + void clear(); + long long getValue(long index); + void setValue(long index, long long value); + long getSize(); + any getPointer(); + void copy([Ref] IDLLongArray src, long srcOffset, long destOffset, long length); }; interface IDLFloatArray { void IDLFloatArray(long size); void resize(long size); + void clear(); float getValue(long index); void setValue(long index, float value); - long getPointer(); long getSize(); + any getPointer(); + void copy([Ref] IDLFloatArray src, long srcOffset, long destOffset, long length); }; interface IDLDoubleArray { void IDLDoubleArray(long size); void resize(long size); + void clear(); double getValue(long index); void setValue(long index, double value); - long getPointer(); long getSize(); + any getPointer(); + void copy([Ref] IDLDoubleArray src, long srcOffset, long destOffset, long length); }; interface IDLByteArray { void IDLByteArray(long size); void resize(long size); + void clear(); byte getValue(long index); void setValue(long index, byte value); - long getPointer(); long getSize(); + any getPointer(); + void copy([Ref] IDLByteArray src, long srcOffset, long destOffset, long length); }; \ No newline at end of file diff --git a/jParser/builder-tool/src/main/java/com/github/xpenatan/jparser/builder/tool/BuilderTool.java b/jParser/builder-tool/src/main/java/com/github/xpenatan/jparser/builder/tool/BuilderTool.java index 914ab86b..b40d73bf 100644 --- a/jParser/builder-tool/src/main/java/com/github/xpenatan/jparser/builder/tool/BuilderTool.java +++ b/jParser/builder-tool/src/main/java/com/github/xpenatan/jparser/builder/tool/BuilderTool.java @@ -4,10 +4,10 @@ import com.github.xpenatan.jparser.builder.BuildMultiTarget; import com.github.xpenatan.jparser.builder.JBuilder; import com.github.xpenatan.jparser.core.JParser; -import com.github.xpenatan.jparser.core.util.FileHelper; import com.github.xpenatan.jparser.cpp.CppCodeParser; import com.github.xpenatan.jparser.cpp.CppGenerator; import com.github.xpenatan.jparser.cpp.NativeCPPGenerator; +import com.github.xpenatan.jparser.idl.IDLPackageRenaming; import com.github.xpenatan.jparser.idl.IDLReader; import com.github.xpenatan.jparser.teavm.TeaVMCodeParser; import java.util.ArrayList; @@ -15,50 +15,43 @@ public class BuilderTool { public static void build(BuildToolOptions op, BuildToolListener listener) { + build(op, listener, null); + } + + public static void build(BuildToolOptions op, BuildToolListener listener, IDLPackageRenaming packageRenaming) { try { - generateAndBuild(op, listener); + generateAndBuild(op, listener, packageRenaming); } catch(Exception e) { throw new RuntimeException(e); } } - private static void generateAndBuild(BuildToolOptions op, BuildToolListener listener) throws Exception { + private static void generateAndBuild(BuildToolOptions op, BuildToolListener listener, IDLPackageRenaming packageRenaming) throws Exception { op.setup(); IDLReader idlReader = IDLReader.readIDL(op.getIDLPath()); - if(op.generateCPP || op.generateTeaVM) { - // Move original source code to destination build directory - FileHelper.copyDir(op.getCPPSourceDir(), op.getLibDestinationPath()); - - // Move custom code to destination build directory - FileHelper.copyDir(op.getCustomSourceDir(), op.getLibDestinationPath()); - } + ArrayList targets = new ArrayList<>(); + listener.onAddTarget(op, idlReader, targets); + IDLReader.setupClasses(idlReader); if(op.generateCPP) { // NativeCPPGenerator.SKIP_GLUE_CODE = true; - CppGenerator cppGenerator = new NativeCPPGenerator(op.getLibDestinationPath()); - CppCodeParser cppParser = new CppCodeParser(cppGenerator, idlReader, op.libBasePackage, op.getCPPSourceDir()); + CppGenerator cppGenerator = new NativeCPPGenerator(op.getCPPDestinationPath()); + CppCodeParser cppParser = new CppCodeParser(cppGenerator, idlReader, op.libBasePackage, op.getSourceDir()); cppParser.generateClass = true; + cppParser.packageRenaming = packageRenaming; JParser.generate(cppParser, op.getModuleBaseJavaDir(), op.getModuleCorePath() + "/src/main/java"); } if(op.generateTeaVM) { // EmscriptenTarget.SKIP_GLUE_CODE = true; - TeaVMCodeParser teavmParser = new TeaVMCodeParser(idlReader, op.moduleName, op.libBasePackage, op.getCPPSourceDir()); + TeaVMCodeParser teavmParser = new TeaVMCodeParser(idlReader, op.moduleName, op.libBasePackage, op.getSourceDir()); + teavmParser.packageRenaming = packageRenaming; JParser.generate(teavmParser, op.getModuleBaseJavaDir(), op.getModuleTeaVMPath() + "/src/main/java/"); } - ArrayList targets = new ArrayList<>(); - - listener.onAddTarget(op, idlReader, targets); - - BuildConfig buildConfig = new BuildConfig( - op.getCPPDestinationPath(), - op.getModuleBuildCPPPath(), - op.getLibsDir(), - op.libName - ); + BuildConfig buildConfig = new BuildConfig(op); JBuilder.build(buildConfig, targets); } } \ No newline at end of file diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildConfig.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildConfig.java index 019f39f3..9acc5222 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildConfig.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildConfig.java @@ -1,18 +1,28 @@ package com.github.xpenatan.jparser.builder; +import com.github.xpenatan.jparser.builder.tool.BuildToolOptions; import com.github.xpenatan.jparser.core.util.CustomFileDescriptor; import java.util.ArrayList; public class BuildConfig { - public CustomFileDescriptor buildDir; - public CustomFileDescriptor sourceDir; - public ArrayList additionalSourceDirs = new ArrayList<>(); - public CustomFileDescriptor libDir; - public String libName; - - public BuildConfig(String sourceDir, String buildDir, String libsDir, String libName) { - this.sourceDir = new CustomFileDescriptor(sourceDir); + public final CustomFileDescriptor buildDir; + public final CustomFileDescriptor buildSourceDir; + public final ArrayList additionalSourceDirs = new ArrayList<>(); + public final CustomFileDescriptor libDir; + public final String libName; + private final BuildToolOptions op; + + public BuildConfig(BuildToolOptions op) { + this.op = op; + String buildSourceDir = op.getCPPDestinationPath(); + String buildDir = op.getModuleBuildCPPPath(); + String libsDir = op.getLibsDir(); + String libName = op.libName; + String sourcePath = op.getSourceDir(); + this.buildDir = new CustomFileDescriptor(buildDir); + this.buildSourceDir = new CustomFileDescriptor(buildSourceDir); + additionalSourceDirs.add(new CustomFileDescriptor(sourcePath)); this.libDir = new CustomFileDescriptor(libsDir); this.libName = libName; diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildTarget.java index 60cd94c6..9acf3790 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/BuildTarget.java @@ -16,5 +16,5 @@ public static boolean isUnix() { return (OS.contains("nix") || OS.contains("nux") || OS.contains("aix") || OS.contains("Linux")); } - protected abstract boolean build(BuildConfig config); + protected abstract boolean buildInternal(BuildConfig config); } \ No newline at end of file diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/DefaultBuildTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/DefaultBuildTarget.java index de1e59db..8adc1924 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/DefaultBuildTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/DefaultBuildTarget.java @@ -5,9 +5,16 @@ import java.nio.file.Path; import java.nio.file.PathMatcher; import java.util.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; public abstract class DefaultBuildTarget extends BuildTarget { + private static String helperName = "IDLHelper.h"; + + public boolean multiCoreCompile = true; + public String tempBuildDir; private final ArrayList compilerCommands = new ArrayList<>(); @@ -33,46 +40,62 @@ public abstract class DefaultBuildTarget extends BuildTarget { public boolean shouldCompile = true; public boolean shouldLink = true; - public boolean isStatic = false; + protected CustomFileDescriptor idlDir; + protected CustomFileDescriptor idlHelperHFile; + protected DefaultBuildTarget() { cppCompiler.add("x86_64-w64-mingw32-g++"); linkerCompiler.add("x86_64-w64-mingw32-g++"); } - protected void setup(BuildConfig config) {} - - protected boolean build(BuildConfig config) { + @Override + protected boolean buildInternal(BuildConfig config) { CustomFileDescriptor childTarget = config.buildDir.child(tempBuildDir); if(childTarget.exists()) { childTarget.deleteDirectory(); } childTarget.mkdirs(); + idlDir = config.buildSourceDir.child("idl"); + if(!idlDir.exists()) { + idlDir.mkdirs(); + } + + CustomFileDescriptor idlHelperCPP = new CustomFileDescriptor(helperName, CustomFileDescriptor.FileType.Classpath); + idlHelperCPP.copyTo(idlDir, false); + idlHelperHFile = idlDir.child(idlHelperCPP.name()); + headerDirs.add("-I" + idlDir.path()); + setup(config); + return build(config, childTarget); + } + + protected void setup(BuildConfig config) {} - ArrayList cppFiles = new ArrayList<>(getCPPFiles(config.sourceDir, cppInclude, cppExclude, filterCPPSuffix)); + protected boolean build(BuildConfig config, CustomFileDescriptor buildTargetTemp) { + ArrayList cppFiles = getCPPFiles(config.buildSourceDir, cppInclude, cppExclude, filterCPPSuffix); for(CustomFileDescriptor sourceDir : config.additionalSourceDirs) { ArrayList cppFiles1 = getCPPFiles(sourceDir, cppInclude, cppExclude, filterCPPSuffix); cppFiles.addAll(cppFiles1); } - if(shouldCompile && shouldLink && compile(config, childTarget, cppFiles)) { - return link(config, childTarget); + if(shouldCompile && shouldLink && compile(config, buildTargetTemp, cppFiles)) { + return link(config, buildTargetTemp); } else if(shouldCompile && !shouldLink) { - return compile(config, childTarget, cppFiles); + return compile(config, buildTargetTemp, cppFiles); } else if(!shouldCompile && shouldLink) { - return link(config, childTarget); + return link(config, buildTargetTemp); } else { return false; } } - private boolean compile(BuildConfig config, CustomFileDescriptor childTarget, ArrayList cppFiles) { + protected boolean compile(BuildConfig config, CustomFileDescriptor buildTargetTemp, ArrayList cppFiles) { boolean retFlag = false; String compiledPaths = ""; @@ -80,18 +103,66 @@ private boolean compile(BuildConfig config, CustomFileDescriptor childTarget, Ar String path = file.path(); compiledPaths = compiledPaths + "\n" + path; } - CustomFileDescriptor cppList = childTarget.child("cpp.txt"); + CustomFileDescriptor cppList = buildTargetTemp.child("cpp.txt"); cppList.writeString(compiledPaths.trim(), false); - compilerCommands.clear(); - compilerCommands.addAll(cppCompiler); - compilerCommands.addAll(cppFlags); - compilerCommands.addAll(headerDirs); - compilerCommands.add("@" + cppList.path()); - System.err.println("##### COMPILE #####"); - boolean flag = JProcess.startProcess(config.buildDir.file(), compilerCommands); - if(!flag) { - return false; + if(multiCoreCompile) { + System.out.println("##### COMPILE #####"); + + int threads = Runtime.getRuntime().availableProcessors(); + ExecutorService executorService = Executors.newFixedThreadPool(threads); + ArrayList> futures = new ArrayList<>(); + + for(CustomFileDescriptor file : cppFiles) { + String path = file.path(); + + Future submit = executorService.submit(() -> { + if(multiCoreCompile) { + ArrayList threadCommands = new ArrayList<>(); + threadCommands.addAll(cppCompiler); + threadCommands.addAll(cppFlags); + threadCommands.addAll(headerDirs); + threadCommands.add(path); + boolean flag = JProcess.startProcess(config.buildDir.file(), threadCommands); + if(!flag) { + multiCoreCompile = false; + throw new RuntimeException("Compile Error"); + } + } + }); + futures.add(submit); + } + + for (Future future : futures) { + if(multiCoreCompile) { + try { + future.get(); + } catch (Exception e) { + e.printStackTrace(); + multiCoreCompile = false; + break; + } + } + else { + break; + } + } + executorService.shutdown(); + if(!multiCoreCompile) { + return false; + } + } + else { + compilerCommands.clear(); + compilerCommands.addAll(cppCompiler); + compilerCommands.addAll(cppFlags); + compilerCommands.addAll(headerDirs); + compilerCommands.add("@" + cppList.path()); + System.out.println("##### COMPILE #####"); + boolean flag = JProcess.startProcess(config.buildDir.file(), compilerCommands); + if(!flag) { + return false; + } } retFlag = true; @@ -99,7 +170,7 @@ private boolean compile(BuildConfig config, CustomFileDescriptor childTarget, Ar ArrayList files = new ArrayList<>(); getObjectFiles(config.buildDir, files); for(CustomFileDescriptor file : files) { - file.moveTo(childTarget); + file.moveTo(buildTargetTemp); } return retFlag; } @@ -133,7 +204,7 @@ private boolean link(BuildConfig config, CustomFileDescriptor childTarget) { linkerCommands.clear(); onLink(compiledObjects, objList.path(), libPath); - System.err.println("##### LINK #####"); + System.out.println("##### LINK #####"); return JProcess.startProcess(childTarget.file(), linkerCommands); } @@ -167,6 +238,7 @@ public static ArrayList getCPPFiles(CustomFileDescriptor d Path of = Path.of(path); boolean remove = true; for(String cppInclude : cppIncludes) { + cppInclude = cppInclude.replace("//", "/"); PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + cppInclude); boolean matches = pathMatcher.matches(of); if(matches) { @@ -175,6 +247,7 @@ public static ArrayList getCPPFiles(CustomFileDescriptor d } } for(String cppExclude : cppExcludes) { + cppExclude = cppExclude.replace("//", "/"); PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + cppExclude); boolean matches = pathMatcher.matches(of); if(matches) { diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JBuilder.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JBuilder.java index 156013e7..97394e44 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JBuilder.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JBuilder.java @@ -16,8 +16,8 @@ public static void build(BuildConfig config, BuildMultiTarget ... targets) { if(target != null) { for(BuildTarget buildTarget : target.multiTarget) { String targetName = buildTarget.getClass().getSimpleName(); - System.err.println("##### Building: " + targetName + " #####"); - if(!buildTarget.build(config)) { + System.out.println("##### Building: " + targetName + " #####"); + if(!buildTarget.buildInternal(config)) { throw new RuntimeException(); } } diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JProcess.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JProcess.java index e77b970a..3afb54cc 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JProcess.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/JProcess.java @@ -37,7 +37,6 @@ public static boolean startProcess (File directory, String[] commands) { String command = commands[i]; System.out.println("Param: " + command); } - System.out.println(); final Process process = new ProcessBuilder(commands) .redirectErrorStream(true) diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/AndroidTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/AndroidTarget.java index 69c74a66..ed481c68 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/AndroidTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/AndroidTarget.java @@ -2,117 +2,144 @@ import com.github.xpenatan.jparser.builder.BuildConfig; import com.github.xpenatan.jparser.builder.DefaultBuildTarget; -import com.github.xpenatan.jparser.builder.JProcess; import com.github.xpenatan.jparser.core.util.CustomFileDescriptor; -import com.github.xpenatan.jparser.core.util.CustomFileDescriptor.FileType; import java.util.ArrayList; public class AndroidTarget extends DefaultBuildTarget { - public String androidABIS = "all"; - public String androidPlatform = "android-19"; + public static boolean DEBUG_BUILD; - public AndroidTarget() { - this.libDirSuffix = "android/"; - this.tempBuildDir = "target/android"; + private String ndkHome = System.getenv("ANDROID_NDK_HOME"); + private String target; + private String apiLevel; + private String sysroot; + private String archiver; + public AndroidTarget(Target target, ApiLevel apiLevel) { + cppCompiler.clear(); + linkerCompiler.clear(); + + if(ndkHome == null) { + return; + } + this.libPrefix = "lib"; + + String osFolder = "windows-x86_64"; + if(isUnix()) { + osFolder = "linux-x86_64"; + } + else if(isMac()) { + // TODO Verify if this is correct + osFolder = "mac-x86_64"; + } + String toolchain = ndkHome + "/toolchains/llvm/prebuilt/" + osFolder; + String compiler = toolchain + "/bin/clang++"; // C++ compiler + archiver = toolchain + "/bin/llvm-ar"; // Archiver for static libraries + sysroot = toolchain + "/sysroot"; // System root for Android libraries + + // Target settings + this.target = target.value; + this.apiLevel = apiLevel.value; // Android API level (e.g., Android 10) + + String targetPath = target.folder; + + this.libDirSuffix = "android/" + targetPath; + this.tempBuildDir = "target/" + targetPath; + linkObjSuffix = ".o"; + + cppCompiler.add(compiler); + linkerCompiler.add(compiler); + cppCompiler.add("--target=" + this.target + this.apiLevel); + cppCompiler.add("--sysroot=" + sysroot); + cppCompiler.add("-fPIC"); cppFlags.add("-O2"); cppFlags.add("-Wall"); cppFlags.add("-D__ANDROID__"); cppFlags.add("-fvisibility=hidden"); - linkerFlags.add("-lm"); + cppFlags.add("-std=c++17"); - cppInclude.add("**/jniglue/JNIGlue.cpp"); - headerDirs.add("jni-headers/"); - headerDirs.add("jni-headers/linux"); + cppFlags.add("-c"); + libSuffix = "64.o"; } @Override - protected boolean build(BuildConfig config) { - CustomFileDescriptor androidDir = config.buildDir; - if(!androidDir.exists()) { - androidDir.mkdirs(); - } - - CustomFileDescriptor applicationTemplate = new CustomFileDescriptor("android/Application.mk", FileType.Classpath); - String applicationStr = applicationTemplate.readString(); - applicationStr = applicationStr.replace("%androidABIs%", androidABIS); - applicationStr = applicationStr.replace("%androidPlat%", androidPlatform); - CustomFileDescriptor applicationFile = androidDir.child(applicationTemplate.name()); - applicationFile.writeString(applicationStr, false); - - CustomFileDescriptor androidTemplate = new CustomFileDescriptor("android/Android.mk", FileType.Classpath); - String androidStr = androidTemplate.readString(); - - String headerDirsStr = ""; - for(String headerDir : headerDirs) { - headerDirsStr += headerDir + " "; + protected void setup(BuildConfig config) { + if(ndkHome == null) { + return; } - headerDirsStr = headerDirsStr.trim(); - String cppFlagsStr = ""; - - for(String cppFlag : cppFlags) { - cppFlagsStr += cppFlag + " "; + if(isStatic) { + linkerCompiler.clear(); + linkerCompiler.add(archiver); + String staticLib = "libmystaticlib.a"; + linkerFlags.add("rcs"); + libSuffix = ".a"; } - cppFlagsStr = cppFlagsStr.trim(); - - String linkerFlagsStr = ""; - - for(String linkerFlag : linkerFlags) { - linkerFlagsStr += linkerFlag + " "; + else { + linkerFlags.add("-lm"); + linkerFlags.add("--target=" + target + apiLevel); + linkerFlags.add("--sysroot=" + sysroot); + linkerFlags.add("-shared"); + linkerFlags.add("-static-libstdc++"); // Statically link C++ runtime + libSuffix = ".so"; } - linkerFlagsStr = linkerFlagsStr.trim(); + } - ArrayList cppFiles = new ArrayList<>(getCPPFiles(config.sourceDir, cppInclude, cppExclude, filterCPPSuffix)); - for(CustomFileDescriptor sourceDir : config.additionalSourceDirs) { - ArrayList cppFiles1 = getCPPFiles(sourceDir, cppInclude, cppExclude, filterCPPSuffix); - cppFiles.addAll(cppFiles1); + @Override + protected void onLink(ArrayList compiledObject, String objFilePath, String libPath) { + if(isStatic) { + linkerCommands.addAll(linkerCompiler); + linkerCommands.addAll(linkerFlags); + linkerCommands.add(libPath); + linkerCommands.add("@" + objFilePath); } - - String srcFilesStr = ""; - for(CustomFileDescriptor file : cppFiles) { - String path = file.path(); - String sourceBasePath = config.buildDir.path(); - String pathWithoutBase = path.replace(sourceBasePath, ""); - pathWithoutBase = pathWithoutBase.replaceFirst("/", ""); - srcFilesStr += "FILE_LIST += $(wildcard $(LOCAL_PATH)/" + pathWithoutBase + ")\n"; + else { + super.onLink(compiledObject, objFilePath, libPath); } + } - srcFilesStr = srcFilesStr.trim(); - - androidStr = androidStr.replace("%libName%", config.libName); - androidStr = androidStr.replace("%headerDirs%", headerDirsStr); - androidStr = androidStr.replace("%cppFlags%", cppFlagsStr); - androidStr = androidStr.replace("%linkerFlags%", linkerFlagsStr); - androidStr = androidStr.replace("%srcFiles%", srcFilesStr); + public void addJNIHeaders() { + headerDirs.add("-Ijni-headers/"); + headerDirs.add("-Ijni-headers/linux"); + headerDirs.add("-Ijni-headers/win32"); + headerDirs.add("-Ijni-headers/mac"); + } - CustomFileDescriptor androidFile = androidDir.child(androidTemplate.name()); - androidFile.writeString(androidStr, false); + public enum Target { + arm64_v8a("aarch64-linux-android", "arm64-v8a"), + armeabi_v7a("armv7a-linux-androideabi", "armeabi-v7a"), + x86_64("x86_64-linux-android", "x86_64"), + x86("i686-linux-android", "x86"); - String ndkHome = System.getenv("NDK_HOME"); + private String value; + private String folder; - if(ndkHome != null) { - ndkHome += "/"; - } - else { - ndkHome = ""; + Target(String value, String folder) { + this.value = value; + this.folder = folder; } - String androidCommand = ndkHome + "ndk-build"; - if(isWindows()) { - androidCommand += ".cmd"; + public String getFolder() { + return folder; } - CustomFileDescriptor childTarget = config.libDir.child("android"); - ArrayList commands = new ArrayList<>(); - commands.add(androidCommand); - commands.add("NDK_PROJECT_PATH=."); - commands.add("NDK_APPLICATION_MK=Application.mk"); - commands.add(" NDK_LIBS_OUT=" + childTarget.path()); - if(!JProcess.startProcess(androidDir.file(), commands)) { - return false; + } + + public enum ApiLevel { + Android_16_36("36"), + Android_15_35("35"), + Android_14_34("34"), + Android_13_33("33"), + Android_12_32("32"), + Android_12_31("31"), + Android_11_30("30"), + Android_10_29("29"), + Android_09_28("28"); + + private String value; + + ApiLevel(String value) { + this.value = value; } - return true; } } diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/AndroidTargetOld.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/AndroidTargetOld.java new file mode 100644 index 00000000..96cee793 --- /dev/null +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/AndroidTargetOld.java @@ -0,0 +1,128 @@ +package com.github.xpenatan.jparser.builder.targets; + +import com.github.xpenatan.jparser.builder.BuildConfig; +import com.github.xpenatan.jparser.builder.DefaultBuildTarget; +import com.github.xpenatan.jparser.builder.JProcess; +import com.github.xpenatan.jparser.core.util.CustomFileDescriptor; +import com.github.xpenatan.jparser.core.util.CustomFileDescriptor.FileType; +import java.util.ArrayList; + +@Deprecated +public class AndroidTargetOld extends DefaultBuildTarget { + + public String androidABIS = "all"; + public String androidPlatform = "android-19"; + + public ArrayList customArgs = new ArrayList<>(); + + public AndroidTargetOld() { + this.libDirSuffix = "android/"; + this.tempBuildDir = "target/android"; + + cppFlags.add("-O2"); + cppFlags.add("-Wall"); + cppFlags.add("-D__ANDROID__"); + cppFlags.add("-fvisibility=hidden"); + cppFlags.add("-std=c++17"); + linkerFlags.add("-lm"); + + cppInclude.add("**/jniglue/JNIGlue.cpp"); + headerDirs.add("jni-headers/linux"); + } + + @Override + protected boolean build(BuildConfig config, CustomFileDescriptor buildTargetTemp) { + CustomFileDescriptor androidDir = config.buildDir; + if(!androidDir.exists()) { + androidDir.mkdirs(); + } + + CustomFileDescriptor applicationTemplate = new CustomFileDescriptor("android/Application.mk", FileType.Classpath); + String applicationStr = applicationTemplate.readString(); + applicationStr = applicationStr.replace("%androidABIs%", androidABIS); + applicationStr = applicationStr.replace("%androidPlat%", androidPlatform); + CustomFileDescriptor applicationFile = androidDir.child(applicationTemplate.name()); + applicationFile.writeString(applicationStr, false); + + CustomFileDescriptor androidTemplate = new CustomFileDescriptor("android/Android.mk", FileType.Classpath); + String androidStr = androidTemplate.readString(); + + String headerDirsStr = ""; + for(String headerDir : headerDirs) { + headerDir = headerDir.replace("-I", ""); + headerDirsStr += headerDir + " "; + } + headerDirsStr = headerDirsStr.trim(); + + String cppFlagsStr = ""; + + for(String cppFlag : cppFlags) { + cppFlagsStr += cppFlag + " "; + } + cppFlagsStr = cppFlagsStr.trim(); + + String linkerFlagsStr = ""; + + for(String linkerFlag : linkerFlags) { + linkerFlagsStr += linkerFlag + " "; + } + linkerFlagsStr = linkerFlagsStr.trim(); + + ArrayList cppFiles = new ArrayList<>(getCPPFiles(config.buildSourceDir, cppInclude, cppExclude, filterCPPSuffix)); + for(CustomFileDescriptor sourceDir : config.additionalSourceDirs) { + ArrayList cppFiles1 = getCPPFiles(sourceDir, cppInclude, cppExclude, filterCPPSuffix); + cppFiles.addAll(cppFiles1); + } + + String srcFilesStr = ""; + for(CustomFileDescriptor file : cppFiles) { + String path = file.path(); + String sourceBasePath = config.buildDir.path(); + String pathWithoutBase = path.replace(sourceBasePath, ""); + pathWithoutBase = pathWithoutBase.replaceFirst("/", ""); + srcFilesStr += "FILE_LIST += $(wildcard $(LOCAL_PATH)/" + pathWithoutBase + ")\n"; + } + + srcFilesStr = srcFilesStr.trim(); + + androidStr = androidStr.replace("%libName%", config.libName); + androidStr = androidStr.replace("%headerDirs%", headerDirsStr); + androidStr = androidStr.replace("%cppFlags%", cppFlagsStr); + androidStr = androidStr.replace("%linkerFlags%", linkerFlagsStr); + androidStr = androidStr.replace("%srcFiles%", srcFilesStr); + + CustomFileDescriptor androidFile = androidDir.child(androidTemplate.name()); + androidFile.writeString(androidStr, false); + + String ndkHome = System.getenv("NDK_HOME"); + + if(ndkHome != null) { + ndkHome += "/"; + } + else { + ndkHome = ""; + } + + String androidCommand = ndkHome + "ndk-build"; + if(isWindows()) { + androidCommand += ".cmd"; + } + + if(multiCoreCompile) { + int i = Runtime.getRuntime().availableProcessors(); + customArgs.add("-j" + i ); + } + + CustomFileDescriptor libTarget = config.libDir.child("android"); + ArrayList commands = new ArrayList<>(); + commands.add(androidCommand); + commands.addAll(customArgs); + commands.add("NDK_PROJECT_PATH=."); + commands.add("NDK_APPLICATION_MK=Application.mk"); + commands.add(" NDK_LIBS_OUT=" + libTarget.path()); + if(!JProcess.startProcess(androidDir.file(), commands)) { + return false; + } + return true; + } +} diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenLibTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenLibTarget.java index e1b7f5d7..1c93407a 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenLibTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenLibTarget.java @@ -4,7 +4,6 @@ import com.github.xpenatan.jparser.builder.DefaultBuildTarget; import com.github.xpenatan.jparser.core.util.CustomFileDescriptor; import java.io.File; -import static com.github.xpenatan.jparser.builder.BuildTarget.isWindows; // Test Target @Deprecated @@ -55,14 +54,8 @@ public EmscriptenLibTarget() { } @Override - protected boolean build(BuildConfig config) { - CustomFileDescriptor childTarget = config.buildDir.child(tempBuildDir); - if(childTarget.exists()) { - childTarget.delete(); - } - childTarget.mkdirs(); - - CustomFileDescriptor jsglueDir = config.sourceDir.child("jsglue"); + protected boolean build(BuildConfig config, CustomFileDescriptor buildTargetTemp) { + CustomFileDescriptor jsglueDir = config.buildSourceDir.child("jsglue"); if(!jsglueDir.exists()) { jsglueDir.mkdirs(); } @@ -88,6 +81,6 @@ protected boolean build(BuildConfig config) { linkerFlags.add("-s"); linkerFlags.add("EXPORT_NAME='" + libName + "'"); cppFlags.add("-c"); - return super.build(config); + return super.build(config, buildTargetTemp); } } diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenTarget.java index eff7a299..ad57b2d1 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/EmscriptenTarget.java @@ -9,16 +9,22 @@ public class EmscriptenTarget extends DefaultBuildTarget { - public static boolean SKIP_GLUE_CODE; - public final static String EMSCRIPTEN_ROOT = System.getenv("EMSDK") + "/upstream/emscripten/"; + public static boolean SKIP_GLUE_CODE = false; + public final static String EMSCRIPTEN_ROOT = (System.getenv("EMSDK") + "/upstream/emscripten/").replace("\\", "/").replace("//", "/"); public IDLReader idlReader; + public static boolean DEBUG_BUILD = false; + public static boolean IS_WASM = true; + public boolean isStatic = false; public boolean compileGlueCode = true; String WEBIDL_BINDER_SCRIPT = EMSCRIPTEN_ROOT + "tools/webidl_binder.py"; + public long initialMemory = 64 * 1024 * 1024; + public long stackSize = 1048576; + public EmscriptenTarget() { this(null); } @@ -38,35 +44,40 @@ public EmscriptenTarget(IDLReader idlReader) { cppCompiler.add(cppCompilerr); linkerCompiler.add(cppCompilerr); - libSuffix = ".wasm.js"; + if(IS_WASM) { + libSuffix = ".wasm.js"; + } + else { + libSuffix = ".js"; + } cppFlags.add("-c"); cppFlags.add("-std=c++17"); - cppFlags.add("-Os"); - cppFlags.add("-g0"); + + if(DEBUG_BUILD) { + cppFlags.add("-O0"); + cppFlags.add("-g2"); + } + else { + cppFlags.add("-O3"); + } } @Override - protected boolean build(BuildConfig config) { + protected boolean build(BuildConfig config, CustomFileDescriptor buildTargetTemp) { String libName = this.libName; if(libName.isEmpty()) { libName = config.libName; } - CustomFileDescriptor childTarget = config.buildDir.child(tempBuildDir); - if(childTarget.exists()) { - childTarget.delete(); - } - childTarget.mkdirs(); - - CustomFileDescriptor jsglueDir = config.sourceDir.child("jsglue"); + CustomFileDescriptor jsglueDir = config.buildSourceDir.child("jsglue"); if(!jsglueDir.exists()) { jsglueDir.mkdirs(); } if(compileGlueCode && !isStatic) { cppInclude.add("**/jsglue/*.cpp"); - copyHelperClass(jsglueDir); + headerDirs.add("-include" + idlHelperHFile.path()); } if(idlReader != null) { @@ -86,11 +97,10 @@ protected boolean build(BuildConfig config) { linkerCompiler.add(cppCompilerr); linkerFlags.add("rcs"); - libSuffix = ".a"; + libSuffix = "_.a"; } else { String postPath = createPostJS(jsglueDir, libName); - long initialMemory = 64 * 1024 * 1024; linkerFlags.add("--llvm-lto"); linkerFlags.add("1"); linkerFlags.add("-s"); @@ -104,11 +114,29 @@ protected boolean build(BuildConfig config) { linkerFlags.add("-s"); linkerFlags.add("INITIAL_MEMORY=" + initialMemory); linkerFlags.add("-s"); + linkerFlags.add("STACK_SIZE=" + stackSize); + linkerFlags.add("-s"); linkerFlags.add("EXPORTED_FUNCTIONS=['_free','_malloc']"); linkerFlags.add("-s"); linkerFlags.add("EXPORTED_RUNTIME_METHODS=['UTF8ToString']"); - linkerFlags.add("-s"); - linkerFlags.add("WASM=1"); + if(DEBUG_BUILD) { + linkerFlags.add("-s"); + linkerFlags.add("ASSERTIONS=1"); + linkerFlags.add("-s"); + linkerFlags.add("SAFE_HEAP=1"); + } + if(IS_WASM) { + linkerFlags.add("-s"); + linkerFlags.add("WASM=1"); + linkerFlags.add("-s"); + + // Disable big int because of conversion bug + linkerFlags.add("WASM_BIGINT=0"); + } + else { + linkerFlags.add("-s"); + linkerFlags.add("WASM=0"); + } linkerFlags.add("-s"); linkerFlags.add("SINGLE_FILE=1"); @@ -120,7 +148,7 @@ protected boolean build(BuildConfig config) { linkerFlags.add("EXPORT_NAME='" + libName + "'"); } - return super.build(config); + return super.build(config, buildTargetTemp); } @Override @@ -159,14 +187,6 @@ private boolean createGlueCode(CustomFileDescriptor mergedIDLFile, CustomFileDes return JProcess.startProcess(jsglueDir.file(), generateGlueCommand); } - private void copyHelperClass(CustomFileDescriptor jsglueDir) { - // Copy IDLHelper from base module. - CustomFileDescriptor idlHelperCPP = new CustomFileDescriptor("IDLHelper.h", CustomFileDescriptor.FileType.Classpath); - idlHelperCPP.copyTo(jsglueDir, false); - CustomFileDescriptor cppFile = jsglueDir.child(idlHelperCPP.name()); - headerDirs.add("-include" + cppFile.path()); - } - private CustomFileDescriptor mergeIDLFile(CustomFileDescriptor jsglueDir) { String idlStr = idlReader.mergeIDLFiles(); CustomFileDescriptor mergedIdlFile = jsglueDir.child("IDLMerged.idl"); diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/IOSTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/IOSTarget.java index e74da495..9cc11924 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/IOSTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/IOSTarget.java @@ -57,7 +57,7 @@ protected void setup(BuildConfig config) { linkerCompiler.add("libtool"); linkerFlags.add("-static"); linkerFlags.add("-o"); - libSuffix = "64.a"; + libSuffix = "64_.a"; } else { linkerFlags.add("-isysroot" + iphoneSimulatorSdk); diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/LinuxTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/LinuxTarget.java index 12fe4d22..c6877610 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/LinuxTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/LinuxTarget.java @@ -30,6 +30,7 @@ public LinuxTarget() { cppFlags.add("-Wno-unused-but-set-variable"); cppFlags.add("-w"); cppFlags.add("-Wno-format"); +// -static-libgcc } @Override @@ -38,7 +39,7 @@ protected void setup(BuildConfig config) { linkerCompiler.clear(); linkerCompiler.add("ar"); linkerFlags.add("rcs"); - libSuffix = "64.a"; + libSuffix = "64_.a"; } else { // Note: diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/MacTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/MacTarget.java index 5a18756e..a281bf87 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/MacTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/MacTarget.java @@ -9,12 +9,21 @@ public class MacTarget extends DefaultBuildTarget { private boolean isArm = false; + private final String macMinTarget; + + public static String MIN_MAC_VERSION = "10.13"; + public MacTarget() { this(false); } public MacTarget(boolean isArm) { + this(isArm, MIN_MAC_VERSION); + } + + public MacTarget(boolean isArm, String macMinTarget) { this.isArm = isArm; + this.macMinTarget = macMinTarget; if(isArm) { this.libDirSuffix = "mac/arm/"; @@ -54,7 +63,7 @@ public MacTarget(boolean isArm) { cppFlags.add("-w"); cppFlags.add("-Wno-format"); - cppFlags.add("-mmacosx-version-min=10.7"); + cppFlags.add("-mmacosx-version-min=" + macMinTarget); cppFlags.add("-stdlib=libc++"); } @@ -65,7 +74,7 @@ protected void setup(BuildConfig config) { linkerCompiler.add("libtool"); linkerFlags.add("-static"); linkerFlags.add("-o"); - libSuffix = "64.a"; + libSuffix = "64_.a"; } else { linkerFlags.add("-shared"); @@ -79,7 +88,7 @@ protected void setup(BuildConfig config) { cppFlags.add("x86_64"); libSuffix = "64.dylib"; } - linkerFlags.add("-mmacosx-version-min=10.7"); + linkerFlags.add("-mmacosx-version-min=" + macMinTarget); linkerFlags.add("-stdlib=libc++"); } } diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsMSVCTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsMSVCTarget.java new file mode 100644 index 00000000..c3d73c92 --- /dev/null +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsMSVCTarget.java @@ -0,0 +1,76 @@ +package com.github.xpenatan.jparser.builder.targets; + +import com.github.xpenatan.jparser.builder.BuildConfig; +import com.github.xpenatan.jparser.builder.DefaultBuildTarget; +import com.github.xpenatan.jparser.core.util.CustomFileDescriptor; +import java.util.ArrayList; + +public class WindowsMSVCTarget extends DefaultBuildTarget { + + public static boolean DEBUG_BUILD; + + // https://learn.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-by-category?view=msvc-170 + + public WindowsMSVCTarget() { + this.libDirSuffix = "windows/vc/"; + this.tempBuildDir = "target/windows"; + linkObjSuffix = ".obj"; + + cppCompiler.clear(); + linkerCompiler.clear(); + + cppCompiler.add("cmd"); + cppCompiler.add("/c"); + cppCompiler.add("vcvarsall"); + cppCompiler.add("x64"); + cppCompiler.add("&"); + cppCompiler.add("cl"); + compilerOutputCommand = "-Fo:"; + cppFlags.add("-std:c++17"); + cppFlags.add("-c"); + if(DEBUG_BUILD) { + cppFlags.add("/Z7"); // add debug information in .obj to work in visual studio + cppFlags.add("/Od"); + } + else { + cppFlags.add("/O2"); + } + linkerOutputCommand = "/OUT:"; + libSuffix = "64.dll"; + } + + @Override + protected void setup(BuildConfig config) { + linkerCompiler.add("cmd"); + linkerCompiler.add("/c"); + linkerCompiler.add("vcvarsall"); + linkerCompiler.add("x64"); + linkerCompiler.add("&"); + if(isStatic) { + linkerCompiler.add("lib"); + libSuffix = "64_.lib"; + } + else { + linkerCompiler.add("link"); + if(DEBUG_BUILD) { + linkerCompiler.add("/DEBUG"); // Generates .pbd file + } + linkerFlags.add("-DLL"); + } + linkerCompiler.add("/NOLOGO"); + linkerCompiler.add("/MACHINE:X64"); + } + + @Override + protected boolean compile(BuildConfig config, CustomFileDescriptor buildTargetTemp, ArrayList cppFiles) { + boolean multiCoreCompile = this.multiCoreCompile; + this.multiCoreCompile = false; + if(multiCoreCompile) { + // Use native MSVC multi core support + cppCompiler.add("/MP"); + } + boolean compile = super.compile(config, buildTargetTemp, cppFiles); + this.multiCoreCompile = multiCoreCompile; + return compile; + } +} diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsMSVSTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsMSVSTarget.java deleted file mode 100644 index 40d3a49c..00000000 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsMSVSTarget.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.github.xpenatan.jparser.builder.targets; - -import com.github.xpenatan.jparser.builder.BuildConfig; -import com.github.xpenatan.jparser.builder.DefaultBuildTarget; - -public class WindowsMSVSTarget extends DefaultBuildTarget { - - public WindowsMSVSTarget() { - this.libDirSuffix = "windows/"; - this.tempBuildDir = "target/windows"; - linkObjSuffix = ".obj"; - - cppCompiler.clear(); - linkerCompiler.clear(); - - cppCompiler.add("cmd"); - cppCompiler.add("/c"); - cppCompiler.add("vcvars64.bat"); - cppCompiler.add("&"); - cppCompiler.add("cl"); - compilerOutputCommand = "-Fo:"; - cppFlags.add("-std:c++17"); - cppFlags.add("-c"); - linkerOutputCommand = "/OUT:"; - libSuffix = "64.dll"; - } - - @Override - protected void setup(BuildConfig config) { - linkerCompiler.add("vcvars64.bat"); - linkerCompiler.add("&"); - if(isStatic) { - linkerCompiler.add("lib"); - } - else { - linkerCompiler.add("link"); - linkerFlags.add("-DLL"); - } - linkerCompiler.add("/NOLOGO"); - linkerCompiler.add("/MACHINE:X64"); - } -} diff --git a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsTarget.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsTarget.java index e1e7eb7e..5076c23a 100644 --- a/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsTarget.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/targets/WindowsTarget.java @@ -38,7 +38,7 @@ protected void setup(BuildConfig config) { linkerCompiler.clear(); linkerCompiler.add("ar"); linkerFlags.add("rcs"); - libSuffix = "64.a"; + libSuffix = "64_.a"; } else { // linkerFlags.add("-fPIC"); diff --git a/jParser/builder-tool/src/main/java/com/github/xpenatan/jparser/builder/tool/BuildToolOptions.java b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/tool/BuildToolOptions.java similarity index 85% rename from jParser/builder-tool/src/main/java/com/github/xpenatan/jparser/builder/tool/BuildToolOptions.java rename to jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/tool/BuildToolOptions.java index 89230d7d..672c8f4c 100644 --- a/jParser/builder-tool/src/main/java/com/github/xpenatan/jparser/builder/tool/BuildToolOptions.java +++ b/jParser/builder/src/main/java/com/github/xpenatan/jparser/builder/tool/BuildToolOptions.java @@ -1,6 +1,7 @@ package com.github.xpenatan.jparser.builder.tool; import com.github.xpenatan.jparser.builder.BuildTarget; +import com.github.xpenatan.jparser.core.util.CustomFileDescriptor; import java.io.File; import java.io.IOException; @@ -9,7 +10,6 @@ public class BuildToolOptions { public String libName; public String moduleName; public String libBasePackage; - public String buildSourceDir; public boolean generateTeaVM = true; public boolean generateCPP = true; @@ -24,11 +24,10 @@ public class BuildToolOptions { private String moduleTeavmPath; private String idlPath; private String moduleBaseJavaDir; - private String cppSourceDir; + private String sourcePath; private String customSourceDir; private String libsDir; private String cppDestinationPath; - private String libDestinationPath; public final boolean windows64; public final boolean linux64; @@ -43,14 +42,28 @@ public class BuildToolOptions { * @param libName module name * @param libBasePackage module package that all classes will be in * @param modulePrefix module prefix name. ex: imgui. So it will be imgui-core, imgui-teavm, etc. - * @param buildSourceDir path inside lib-build module + * @param cppSourcePath full path where the source is located * @param platform windows64, linux64, mac64, mac64arm, android, ios, teavm */ - public BuildToolOptions(String libName, String libBasePackage, String modulePrefix, String buildSourceDir, String ... platform) { + public BuildToolOptions(String libName, String libBasePackage, String modulePrefix, String cppSourcePath, String ... platform) { this.libName = libName; this.libBasePackage = libBasePackage; this.modulePrefix = modulePrefix; - this.buildSourceDir = buildSourceDir; + + boolean exists = new CustomFileDescriptor(cppSourcePath).exists(); + if(exists) { + this.sourcePath = cppSourcePath.replace("\\", "/"); + } + else { + try { + this.sourcePath = new File(".", cppSourcePath).getCanonicalPath().replace("\\", "/"); + } catch(IOException e) { + throw new RuntimeException(e); + } + } + if(!this.sourcePath.endsWith("/")) { + this.sourcePath += "/"; + } this.idlName = libName; this.moduleName = libName; @@ -63,7 +76,7 @@ public BuildToolOptions(String libName, String libBasePackage, String modulePref boolean teavmtmp = false; for(int i = 0; i < platform.length; i++) { String arg = platform[i]; - if(arg.equals("windows64") && (BuildTarget.isWindows() || BuildTarget.isUnix())) { + if(arg.equals("windows64") && (BuildTarget.isWindows())) { windows64tmp = true; } else if(arg.equals("linux64") && BuildTarget.isUnix()) { @@ -109,13 +122,11 @@ void setup() { moduleBaseJavaDir = moduleBasePath + "/src/main/java"; idlPath = moduleBuildPath + "/src/main/cpp/" + idlName + ".idl"; - cppSourceDir = moduleBuildPath + buildSourceDir; - customSourceDir = moduleBuildPath + "/src/main/cpp/custom"; + customSourceDir = moduleBuildPath + "/src/main/cpp/custom/"; moduleBuildCPPPath = moduleBuildPath + "/build/c++"; libsDir = moduleBuildCPPPath + "/libs"; cppDestinationPath = moduleBuildCPPPath + "/src"; - libDestinationPath = cppDestinationPath + "/" + libName; } public String getModulePrefix() { @@ -150,8 +161,8 @@ public String getModuleBaseJavaDir() { return moduleBaseJavaDir; } - public String getCPPSourceDir() { - return cppSourceDir; + public String getSourceDir() { + return sourcePath; } /** @@ -168,8 +179,4 @@ public String getLibsDir() { public String getCPPDestinationPath() { return cppDestinationPath; } - - public String getLibDestinationPath() { - return libDestinationPath; - } } \ No newline at end of file diff --git a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParser.java b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParser.java index 9ea6c9dc..45c71e3f 100644 --- a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParser.java +++ b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParser.java @@ -6,6 +6,9 @@ import com.github.javaparser.ast.PackageDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.comments.BlockComment; +import com.github.javaparser.symbolsolver.JavaSymbolSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver; +import com.github.javaparser.symbolsolver.resolution.typesolvers.ReflectionTypeSolver; import com.github.javaparser.utils.PositionUtils; import com.github.xpenatan.jparser.core.codeparser.CodeParser; import com.github.xpenatan.jparser.core.codeparser.CodeParserItem; @@ -87,6 +90,13 @@ public static void generate(CodeParser wrapper, String sourceDir, String genDir, } System.out.println("***** GENERATING CODE *****"); JParser jParser = new JParser(sourceD, genD); + + CombinedTypeSolver combinedTypeSolver = new CombinedTypeSolver(); + combinedTypeSolver.add(new ReflectionTypeSolver()); + // Configure JavaParser to use type resolution + JavaSymbolSolver symbolSolver = new JavaSymbolSolver(combinedTypeSolver); + StaticJavaParser.getParserConfiguration().setSymbolResolver(symbolSolver); + processDirectory(jParser, fileSourceDir, fileGenDir, excludes, fileSourceDir); wrapper.onParseStart(jParser); parseJavaFiles(jParser, wrapper); @@ -166,13 +176,11 @@ else if(path.contains(exclude)) { continue; } String javaContent = file.readString(); - File file1 = file.file(); CompilationUnit unit = StaticJavaParser.parse(new ByteArrayInputStream(javaContent.getBytes())); unit.printer(new CustomPrettyPrinter()); - String absolutePath = file1.getAbsolutePath(); String genPath = fileGenDir.file().getAbsolutePath(); - jParser.unitArray.add(new JParserItem(unit, absolutePath, genPath)); + jParser.unitArray.add(new JParserItem(unit, genPath)); } } } @@ -184,7 +192,8 @@ private static void generateFile(String destinationPath, String javaContent) { } private static String getFullyQualifiedClassName(CustomFileDescriptor fileSourceDir, CustomFileDescriptor file) { - String className = file.path().replace(fileSourceDir.path(), "").replace('\\', '.').replace('/', '.').replace(".java", ""); + String replacePath = file.path().replace(fileSourceDir.path(), "").replace("\\", "/"); + String className = replacePath.replace("/", ".").replace('/', '.').replace(".java", ""); if(className.startsWith(".")) className = className.substring(1); return className; } diff --git a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserHelper.java b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserHelper.java index 80887c29..7d17a3df 100644 --- a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserHelper.java +++ b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserHelper.java @@ -41,6 +41,10 @@ public static boolean isInt(Type type) { return JParserHelper.isType(type, "int"); } + public static boolean isShort(Type type) { + return JParserHelper.isType(type, "short"); + } + public static boolean isFloat(Type type) { return JParserHelper.isType(type, "float"); } diff --git a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserItem.java b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserItem.java index 939a2698..ee8721a6 100644 --- a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserItem.java +++ b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/JParserItem.java @@ -15,16 +15,14 @@ */ public class JParserItem { public CompilationUnit unit; - public String inputPath; public final String destinationBaseDir; public String packagePathName; public String className = ""; public boolean notAllowed; public boolean isIDL; - public JParserItem(CompilationUnit unit, String inputPath, String destinationBaseDir) { + public JParserItem(CompilationUnit unit, String destinationBaseDir) { this.unit = unit; - this.inputPath = inputPath; this.destinationBaseDir = destinationBaseDir; List allEnum = unit.findAll(EnumDeclaration.class); List all = unit.findAll(ClassOrInterfaceDeclaration.class); @@ -32,7 +30,7 @@ public JParserItem(CompilationUnit unit, String inputPath, String destinationBas if(all.size() > 0) { className = all.get(0).getNameAsString(); String packageName = unit.getPackageDeclaration().get().getNameAsString(); - this.packagePathName = packageName.replace(".", File.separator); + this.packagePathName = packageName.replace(".", "/"); } //TODO support enum // else if(allEnum.size() > 0) { diff --git a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/codeparser/DefaultCodeParser.java b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/codeparser/DefaultCodeParser.java index 8c3f88cb..c97ad9b9 100644 --- a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/codeparser/DefaultCodeParser.java +++ b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/codeparser/DefaultCodeParser.java @@ -10,6 +10,7 @@ import com.github.javaparser.ast.body.TypeDeclaration; import com.github.javaparser.ast.comments.BlockComment; import com.github.javaparser.ast.comments.Comment; +import com.github.javaparser.ast.stmt.BlockStmt; import com.github.xpenatan.jparser.core.JParser; import com.github.xpenatan.jparser.core.JParserItem; import com.github.xpenatan.jparser.core.util.RawCodeBlock; @@ -27,6 +28,7 @@ public abstract class DefaultCodeParser implements CodeParser { public static final String CMD_ADD_RAW = "-ADD_RAW"; public static final String CMD_REMOVE = "-REMOVE"; public static final String CMD_REPLACE = "-REPLACE"; + public static final String CMD_REPLACE_BLOCK = "-REPLACE_BLOCK"; public static final String CMD_NATIVE = "-NATIVE"; private ArrayList cache = new ArrayList<>(); @@ -163,19 +165,28 @@ private boolean parserBlock(Node node, BlockComment blockComment) { protected boolean parseCodeBlock(Node node, String headerCommands, String content) { if(headerCommands.contains(CMD_ADD_RAW)) { - setAddReplaceCMD(node, content, false, true); + setAddReplaceCMD(node, content, false, true, false); return true; } else if(headerCommands.contains(CMD_ADD)) { - setAddReplaceCMD(node, content, false, false); + setAddReplaceCMD(node, content, false, false, false); return true; } else if(headerCommands.contains(CMD_REMOVE)) { node.remove(); return true; } + else if(headerCommands.contains(CMD_REPLACE_BLOCK)) { + if(node instanceof MethodDeclaration) { + MethodDeclaration methodDeclaration = (MethodDeclaration)node; + BlockStmt blockStmt = StaticJavaParser.parseBlock(content); + methodDeclaration.setBody(blockStmt); + return true; + } + return false; + } else if(headerCommands.contains(CMD_REPLACE)) { - setAddReplaceCMD(node, content, true, false); + setAddReplaceCMD(node, content, true, false, false); return true; } else if(headerCommands.contains(CMD_NATIVE)) { @@ -190,7 +201,7 @@ else if(headerCommands.contains(CMD_NATIVE)) { return false; } - private void setAddReplaceCMD(Node node, String content, boolean replace, boolean rawAdd) { + private void setAddReplaceCMD(Node node, String content, boolean replace, boolean rawAdd, boolean replaceBlock) { Node parentNode = null; Optional parentNodeOptional = node.getParentNode(); if(parentNodeOptional.isPresent()) { @@ -211,7 +222,6 @@ private void setAddReplaceCMD(Node node, String content, boolean replace, boolea else { BodyDeclaration newCode = StaticJavaParser.parseBodyDeclaration(content); typeDeclaration.getMembers().add(newCode); - } } catch(Throwable t) { diff --git a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/util/FileHelper.java b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/util/FileHelper.java index 39185a6d..2936fe3c 100644 --- a/jParser/core/src/main/java/com/github/xpenatan/jparser/core/util/FileHelper.java +++ b/jParser/core/src/main/java/com/github/xpenatan/jparser/core/util/FileHelper.java @@ -68,7 +68,8 @@ public FileVisitResult postVisitDirectory(Path directory, IOException ioExceptio } public static ArrayList getFilesFromDir(String src) { - Path srcPath = new File(src).toPath(); + src = src.replace("\\", "/"); + Path srcPath = Path.of(src); try { return copyDir(srcPath); } catch(IOException e) { @@ -78,15 +79,13 @@ public static ArrayList getFilesFromDir(String src) { public static ArrayList copyDir(Path src) throws IOException { ArrayList outPath = new ArrayList<>(); - String srcFullPath = src.toFile().getCanonicalPath(); - if(Files.exists(src)) { + boolean exists = Files.exists(src); + if(exists) { Files.walkFileTree(src, new SimpleFileVisitor() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) throws IOException { - File file = path.toFile(); - String fullPath = file.getCanonicalPath(); - String name = fullPath.replace(srcFullPath, ""); - outPath.add(file.getCanonicalPath()); + String fullPath = path.toFile().getCanonicalPath().replace("\\", "/"); + outPath.add(fullPath); return FileVisitResult.CONTINUE; } diff --git a/jParser/cpp/src/main/java/com/github/xpenatan/jparser/cpp/CppCodeParser.java b/jParser/cpp/src/main/java/com/github/xpenatan/jparser/cpp/CppCodeParser.java index 4f318d8e..c037d2c9 100644 --- a/jParser/cpp/src/main/java/com/github/xpenatan/jparser/cpp/CppCodeParser.java +++ b/jParser/cpp/src/main/java/com/github/xpenatan/jparser/cpp/CppCodeParser.java @@ -1,6 +1,7 @@ package com.github.xpenatan.jparser.cpp; import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; @@ -8,8 +9,12 @@ import com.github.javaparser.ast.body.FieldDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.type.Type; +import com.github.javaparser.utils.Pair; import com.github.xpenatan.jparser.core.JParser; +import com.github.xpenatan.jparser.core.JParserHelper; import com.github.xpenatan.jparser.core.JParserItem; import com.github.xpenatan.jparser.idl.IDLAttribute; import com.github.xpenatan.jparser.idl.IDLConstructor; @@ -23,6 +28,7 @@ import com.github.xpenatan.jparser.idl.IDLParameter; import com.github.xpenatan.jparser.idl.IDLReader; import com.github.xpenatan.jparser.idl.parser.IDLMethodOperation; +import com.github.xpenatan.jparser.idl.parser.IDLMethodParser; import java.util.ArrayList; public class CppCodeParser extends IDLDefaultCodeParser { @@ -35,6 +41,8 @@ public class CppCodeParser extends IDLDefaultCodeParser { protected static final String TEMPLATE_TAG_ATTRIBUTE = "[ATTRIBUTE]"; protected static final String TEMPLATE_TAG_ENUM = "[ENUM]"; protected static final String TEMPLATE_TAG_ATTRIBUTE_TYPE = "[ATTRIBUTE_TYPE]"; + protected static final String TEMPLATE_TAG_RETURN_TYPE = "[RETURN_TYPE]"; + protected static final String TEMPLATE_TAG_CONST = "[CONST]"; protected static final String TEMPLATE_TAG_COPY_TYPE = "[COPY_TYPE]"; protected static final String TEMPLATE_TAG_COPY_PARAM = "[COPY_PARAM]"; protected static final String TEMPLATE_TAG_CONSTRUCTOR = "[CONSTRUCTOR]"; @@ -50,44 +58,88 @@ public class CppCodeParser extends IDLDefaultCodeParser { protected static final String ATTRIBUTE_SET_PRIMITIVE_STATIC_TEMPLATE = "\n[TYPE]::[ATTRIBUTE] = [ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_ARRAY_SET_PRIMITIVE_STATIC_TEMPLATE = + "\n[TYPE]::[ATTRIBUTE][index] = [ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_SET_PRIMITIVE_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + "nativeObject->[ATTRIBUTE] = [CAST][ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_ARRAY_SET_PRIMITIVE_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "nativeObject->[ATTRIBUTE][index] = [CAST][ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_SET_OBJECT_POINTER_STATIC_TEMPLATE = "\n[TYPE]::[ATTRIBUTE] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_STATIC_TEMPLATE = + "\n[TYPE]::[ATTRIBUTE][index] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n"; + protected static final String ATTRIBUTE_SET_OBJECT_POINTER_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + "nativeObject->[ATTRIBUTE] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "nativeObject->[ATTRIBUTE][index] = ([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr;\n"; + protected static final String ATTRIBUTE_SET_OBJECT_VALUE_STATIC_TEMPLATE = "\n[TYPE]::[ATTRIBUTE] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_STATIC_TEMPLATE = + "\n[TYPE]::[ATTRIBUTE][index] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_SET_OBJECT_VALUE_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + "nativeObject->[ATTRIBUTE] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "nativeObject->[ATTRIBUTE][index] = *(([ATTRIBUTE_TYPE]*)[ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_GET_OBJECT_VALUE_STATIC_TEMPLATE = "\nreturn (jlong)&[TYPE]::[ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_STATIC_TEMPLATE = + "\nreturn (jlong)&[TYPE]::[ATTRIBUTE][index];\n"; + protected static final String ATTRIBUTE_GET_OBJECT_VALUE_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + "return (jlong)&nativeObject->[ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "return (jlong)&nativeObject->[ATTRIBUTE][index];\n"; + protected static final String ATTRIBUTE_GET_OBJECT_POINTER_STATIC_TEMPLATE = "\nreturn (jlong)[TYPE]::[ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_STATIC_TEMPLATE = + "\nreturn (jlong)([TYPE]::[ATTRIBUTE][index]);\n"; + protected static final String ATTRIBUTE_GET_OBJECT_POINTER_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + - "return (jlong)nativeObject->[ATTRIBUTE];\n"; + "[CONST][ATTRIBUTE_TYPE]* attr = nativeObject->[ATTRIBUTE];\n" + + "return (jlong)attr;\n"; + + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "[CONST][ATTRIBUTE_TYPE]* attr = (nativeObject->[ATTRIBUTE][index]);\n" + + "return (jlong)attr;\n"; protected static final String ATTRIBUTE_GET_PRIMITIVE_STATIC_TEMPLATE = "\nreturn [TYPE]::[ATTRIBUTE];\n"; + protected static final String ATTRIBUTE_ARRAY_GET_PRIMITIVE_STATIC_TEMPLATE = + "\nreturn [TYPE]::[ATTRIBUTE][index];\n"; + protected static final String ATTRIBUTE_GET_PRIMITIVE_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + - "return nativeObject->[ATTRIBUTE];\n"; + "return [CAST]nativeObject->[ATTRIBUTE];\n"; + + protected static final String ATTRIBUTE_ARRAY_GET_PRIMITIVE_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "return [CAST]nativeObject->[ATTRIBUTE][index];\n"; protected static final String METHOD_GET_OBJ_VALUE_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + @@ -95,6 +147,12 @@ public class CppCodeParser extends IDLDefaultCodeParser { "[COPY_PARAM] = nativeObject->[METHOD];\n" + "return (jlong)&[COPY_PARAM];"; + protected static final String METHOD_GET_OBJ_VALUE_ARITHMETIC_OPERATOR_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "static [COPY_TYPE] [COPY_PARAM];\n" + + "[COPY_PARAM] = [OPERATOR];\n" + + "return (jlong)&[COPY_PARAM];"; + protected static final String METHOD_GET_OBJ_VALUE_STATIC_TEMPLATE = "\nstatic [COPY_TYPE] [COPY_PARAM];\n" + "[COPY_PARAM] = [TYPE]::[METHOD];\n" + @@ -112,7 +170,8 @@ public class CppCodeParser extends IDLDefaultCodeParser { protected static final String METHOD_GET_OBJ_POINTER_TEMPLATE = "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + - "return (jlong)nativeObject->[METHOD];\n"; + "[CONST][RETURN_TYPE]* obj = nativeObject->[METHOD];\n" + + "return (jlong)obj;\n"; protected static final String METHOD_GET_REF_OBJ_POINTER_STATIC_TEMPLATE = "\nreturn (jlong)&[TYPE]::[METHOD];\n"; @@ -132,6 +191,10 @@ public class CppCodeParser extends IDLDefaultCodeParser { "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + "return [CAST]nativeObject->[METHOD];\n"; + protected static final String METHOD_GET_PRIMITIVE_OPERATOR_TEMPLATE = + "\n[TYPE]* nativeObject = ([TYPE]*)this_addr;\n" + + "return ([OPERATOR]);"; + protected static final String ENUM_GET_INT_TEMPLATE = "\nreturn (jlong)[ENUM];\n"; @@ -148,12 +211,9 @@ public CppCodeParser(CppGenerator cppGenerator, IDLReader idlReader, String base @Override public void onIDLConstructorGenerated(JParser jParser, IDLConstructor idlConstructor, ClassOrInterfaceDeclaration classDeclaration, ConstructorDeclaration constructorDeclaration, MethodDeclaration nativeMethodDeclaration) { - String classTypeName = classDeclaration.getNameAsString(); + IDLClass idlClass = idlConstructor.idlClass; - IDLClass idlClass = idlConstructor.idlFile.getClass(classTypeName); - if(idlClass != null) { - classTypeName = idlClass.classHeader.prefixName + classTypeName; - } + String classTypeName = idlClass.getCPPName(); NodeList parameters = constructorDeclaration.getParameters(); ArrayList idParameters = idlConstructor.parameters; @@ -169,7 +229,14 @@ public void onIDLConstructorGenerated(JParser jParser, IDLConstructor idlConstru @Override public void onIDLDeConstructorGenerated(JParser jParser, IDLClass idlClass, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration nativeMethodDeclaration) { - String classTypeName = idlClass.classHeader.prefixName + classDeclaration.getNameAsString(); + String classTypeName; + + if(idlClass.callbackImpl == null) { + classTypeName = idlClass.getCPPName(); + } + else { + classTypeName = idlClass.callbackImpl.name; + } String content = METHOD_DELETE_OBJ_POINTER_TEMPLATE.replace(TEMPLATE_TAG_TYPE, classTypeName); @@ -190,14 +257,19 @@ public void onIDLAttributeGenerated(JParser jParser, IDLAttribute idlAttribute, String classTypeName = classDeclaration.getNameAsString(); IDLClass idlClass = idlAttribute.idlFile.getClass(classTypeName); if(idlClass != null) { - classTypeName = idlClass.classHeader.prefixName + classTypeName; + classTypeName = idlClass.getCPPName(); } - String attributeType = idlAttribute.type; + String getPrimitiveCast = ""; + String attributeType = idlAttribute.getCPPType(); + String constTag = ""; + if(idlAttribute.isConst) { + constTag = "const "; + } IDLClass retTypeClass = idlAttribute.idlFile.getClass(attributeType); if(retTypeClass != null) { - attributeType = retTypeClass.classHeader.prefixName + attributeType; + attributeType = retTypeClass.getCPPName(); } String attributeReturnCast = ""; @@ -210,6 +282,7 @@ public void onIDLAttributeGenerated(JParser jParser, IDLAttribute idlAttribute, else { attributeReturnCast = "(" + idlEnum.typePrefix + "::" + attributeType + ")"; } + getPrimitiveCast = "(jint)"; } String content = null; @@ -220,49 +293,97 @@ public void onIDLAttributeGenerated(JParser jParser, IDLAttribute idlAttribute, .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) .replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case SET_ARRAY_OBJECT_VALUE: + content = ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) + .replace(TEMPLATE_TAG_TYPE, classTypeName); + break; case SET_OBJECT_VALUE_STATIC: content = ATTRIBUTE_SET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) .replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case SET_ARRAY_OBJECT_VALUE_STATIC: + content = ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) + .replace(TEMPLATE_TAG_TYPE, classTypeName); + break; case GET_OBJECT_VALUE: content = ATTRIBUTE_GET_OBJECT_VALUE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) .replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case GET_ARRAY_OBJECT_VALUE: + content = ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) + .replace(TEMPLATE_TAG_TYPE, classTypeName); + break; case GET_OBJECT_VALUE_STATIC: content = ATTRIBUTE_GET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) .replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case GET_ARRAY_OBJECT_VALUE_STATIC: + content = ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) + .replace(TEMPLATE_TAG_TYPE, classTypeName); + break; case SET_OBJECT_POINTER: content = ATTRIBUTE_SET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) .replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case SET_ARRAY_OBJECT_POINTER: + content = ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) + .replace(TEMPLATE_TAG_TYPE, classTypeName); + break; case SET_OBJECT_POINTER_STATIC: content = ATTRIBUTE_SET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) .replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case SET_ARRAY_OBJECT_POINTER_STATIC: + content = ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType) + .replace(TEMPLATE_TAG_TYPE, classTypeName); + break; case GET_OBJECT_POINTER: - content = ATTRIBUTE_GET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); + content = ATTRIBUTE_GET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType).replace(TEMPLATE_TAG_CONST, constTag); + break; + case GET_ARRAY_OBJECT_POINTER: + content = ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_ATTRIBUTE_TYPE, attributeType).replace(TEMPLATE_TAG_CONST, constTag); break; case GET_OBJECT_POINTER_STATIC: content = ATTRIBUTE_GET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case GET_ARRAY_OBJECT_POINTER_STATIC: + content = ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); + break; case SET_PRIMITIVE: content = ATTRIBUTE_SET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_CAST, attributeReturnCast); break; case SET_PRIMITIVE_STATIC: content = ATTRIBUTE_SET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case SET_ARRAY_PRIMITIVE_STATIC: + content = ATTRIBUTE_ARRAY_SET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); + break; + case SET_ARRAY_PRIMITIVE: + content = ATTRIBUTE_ARRAY_SET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_CAST, attributeReturnCast); + break; case GET_PRIMITIVE: - content = ATTRIBUTE_GET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); + content = ATTRIBUTE_GET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_CAST, getPrimitiveCast); + break; + case GET_ARRAY_PRIMITIVE: + content = ATTRIBUTE_ARRAY_GET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_CAST, getPrimitiveCast); break; case GET_PRIMITIVE_STATIC: content = ATTRIBUTE_GET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); break; + case GET_ARRAY_PRIMITIVE_STATIC: + content = ATTRIBUTE_ARRAY_GET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, classTypeName); + break; } if(content != null) { @@ -281,14 +402,257 @@ public void onIDLEnumMethodGenerated(JParser jParser, IDLEnum idlEnum, ClassOrIn nativeMethodDeclaration.setBlockComment(blockComment); } + @Override + public void onIDLCallbackGenerated(JParser jParser, IDLClass idlClass, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration callbackDeclaration, ArrayList>> methods) { + NodeList methodParameters = callbackDeclaration.getParameters(); + IDLClass idlCallbackClass = idlClass.callbackImpl; + Type methodReturnType = callbackDeclaration.getType(); + MethodDeclaration nativeMethodDeclaration = IDLMethodParser.generateNativeMethod(callbackDeclaration.getNameAsString(), methodParameters, methodReturnType, false); + if(!JParserHelper.containsMethod(classDeclaration, nativeMethodDeclaration)) { + nativeMethodDeclaration.removeModifier(Modifier.Keyword.STATIC); + + // Call setupMethod + classDeclaration.getMembers().add(nativeMethodDeclaration); + MethodCallExpr caller = IDLMethodParser.createCaller(nativeMethodDeclaration); + caller.addArgument(IDLDefaultCodeParser.CPOINTER_METHOD); + BlockStmt blockStmt = callbackDeclaration.getBody().get(); + blockStmt.addStatement(caller); + String method = callbackDeclaration.getNameAsString() + "(env, object)"; + String content = METHOD_CALL_VOID_TEMPLATE.replace(TEMPLATE_TAG_METHOD, method).replace(TEMPLATE_TAG_TYPE, idlCallbackClass.name); + String header = "[-" + HEADER_CMD + ";" + CMD_NATIVE + "]"; + String blockComment = header + content; + nativeMethodDeclaration.setBlockComment(blockComment); + + + generateCPPClass(idlClass, classDeclaration, callbackDeclaration, methods); + } + } + + + private void generateCPPClass(IDLClass idlClass, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration callbackDeclaration, ArrayList>> methods) { + IDLClass callback = idlClass.callbackImpl; + String cppClass = ""; + + String callbackCode = generateSetupCallbackMethod(idlClass, callbackDeclaration, methods); + String methodsCode = generateMethodCallers(idlClass, methods); + cppClass += "" + + "class " + callback.getCPPName() + " : public " + idlClass.getCPPName() + " {\n" + + "private:\n" + + "\tJNIEnv* env;\n" + + "\tjobject obj;\n" + + "public:\n"; + cppClass += callbackCode; + cppClass += methodsCode; + cppClass += "};\n"; + + String header = "[-" + HEADER_CMD + ";" + CMD_NATIVE + "]\n"; + String code = header + cppClass; + + classDeclaration.getConstructors().get(0).setBlockComment(code); + } + + private String generateSetupCallbackMethod(IDLClass idlClass, MethodDeclaration callbackDeclaration, ArrayList>> methods) { + String contentTemplate = "" + + "\tinline static jclass jClassID = 0;\n" + + "[VARIABLES]\n" + + "void [METHOD](JNIEnv* env, jobject obj) {\n" + + "\tthis->env = env;\n" + + "\tthis->obj = env->NewGlobalRef(obj);\n" + + "\tif([CLASS_NAME]::jClassID == 0) {\n" + + "\t\t[CLASS_NAME]::jClassID = (jclass)env->NewGlobalRef(env->GetObjectClass(obj));\n" + + "[METHOD_IDS]" + + "\t}\n" + + "}\n"; + String variableTemplate = "\tinline static jmethodID [METHOD]_ID = 0;\n"; + String methodIdTemplate = "\t\t[CLASS_NAME]::[METHOD]_ID = env->GetMethodID(jClassID, \"[INTERNAL_METHOD]\", \"[PARAM_CODE]\");\n"; + + IDLClass callbackClass = idlClass.callbackImpl; + String className = callbackClass.name; + + String staticVariables = ""; + String methodIds = ""; + String callbackMethodName = callbackDeclaration.getNameAsString(); + + for(int i = 0; i < methods.size(); i++) { + Pair> pair = methods.get(i); + IDLMethod idlMethod = pair.a; + Pair methodPair = pair.b; + MethodDeclaration internalMethod = methodPair.a; + MethodDeclaration publicMethod = methodPair.b; + String internalMethodName = internalMethod.getNameAsString(); + String paramCode = ""; + + Type returnType = internalMethod.getType(); + String returnTypeStr = returnType.asString(); + + NodeList parameters = internalMethod.getParameters(); + for(int i1 = 0; i1 < parameters.size(); i1++) { + Parameter parameter = parameters.get(i1); + Type type = parameter.getType(); + String typeStr = type.asString(); + if(type.isPrimitiveType()) { + String jniType = JNITypeSignature.getJNIType(typeStr); + paramCode += jniType; + } + else if(type.isClassOrInterfaceType()) { + if(typeStr.equals("String")) { + paramCode += JNITypeSignature.String.getJNIType(); + } + } + } + String methodCode = generateMethodID(internalMethod); + + paramCode = "(" + paramCode + ")" + JNITypeSignature.getJNIType(returnTypeStr); + + String methodName = idlMethod.getCPPName() + methodCode; + + String variable = variableTemplate.replace("[METHOD]", methodName); + String methodId = methodIdTemplate.replace("[METHOD]", methodName) + .replace("[CLASS_NAME]", className) + .replace("[INTERNAL_METHOD]", internalMethodName) + .replace("[PARAM_CODE]", paramCode); + staticVariables += variable; + methodIds += methodId; + } + + String content = contentTemplate.replace("[VARIABLES]", staticVariables) + .replace("[METHOD]", callbackMethodName) + .replace("[CLASS_NAME]", className) + .replace("[METHOD_IDS]", methodIds); + + return content; + } + + private String generateMethodID(MethodDeclaration internalMethod) { + // Method is used when there is multiple overloaded methods + String methodCode = ""; + NodeList parameters = internalMethod.getParameters(); + for(int i1 = 0; i1 < parameters.size(); i1++) { + Parameter parameter = parameters.get(i1); + Type type = parameter.getType(); + String typeStr = type.asString(); + if(type.isPrimitiveType()) { + String jniType = JNITypeSignature.getJNIType(typeStr); + methodCode += jniType; + } + else if(type.isClassOrInterfaceType()) { + if(typeStr.equals("String")) { + methodCode += "S"; + } + } + } + return methodCode; + } + + private String generateMethodCallers(IDLClass idlClass, ArrayList>> methods) { + IDLClass callback = idlClass.callbackImpl; + String cppMethods = ""; + String cppClassName = callback.name; + + String methodTemplate = "" + + "virtual [RETURN_TYPE] [METHOD_NAME]([PARAMS])[CONST] {\n" + + " [RETURN]env->[CALL_METHOD](obj, [CPP_CLASS]::[METHOD_ID]_ID[CALL_PARAMS]);\n" + + "}\n"; + + for(int i = 0; i < methods.size(); i++) { + Pair> pair = methods.get(i); + IDLMethod idlMethod = pair.a; + Pair methodPair = pair.b; + MethodDeclaration internalMethod = methodPair.a; + MethodDeclaration publicMethod = methodPair.b; + + Type type = internalMethod.getType(); + boolean isVoidType = type.isVoidType(); + String typeStr = getCPPType(idlMethod.getCPPReturnType()); + + String methodCode = generateMethodID(internalMethod); + + String methodName = idlMethod.getCPPName(); + String methodParams = ""; + String callParams = ""; + String constStr = idlMethod.isReturnConst ? " const" : ""; + + NodeList publicMethodParameters = publicMethod.getParameters(); + for(int i1 = 0; i1 < idlMethod.parameters.size(); i1++) { + IDLParameter idlParameter = idlMethod.parameters.get(i1); + Parameter parameter = publicMethodParameters.get(i1); + boolean isPrimitive = parameter.getType().isPrimitiveType(); + String paramName = idlParameter.name; + String callParamName = idlParameter.name; + String paramType = idlParameter.getCPPType(); + boolean isString = idlParameter.idlType.equals("DOMString"); + String tag = " "; + String callParamCast = ""; + + if(!isString) { + if(idlParameter.isRef) { + tag = "& "; + callParamCast = "(jlong)&"; + } + else if(!isPrimitive && !idlParameter.isValue) { + tag = "* "; + callParamCast = "(jlong)"; + } + } + else { + callParamName = "env->NewStringUTF(" + paramName + ")"; + } + paramType = getCPPType(paramType); + if(idlParameter.isConst) { + paramType = "const " + paramType; + } + callParams += ", "; + callParams += callParamCast + callParamName; + + methodParams += paramType + tag + paramName; + if(i1 < idlMethod.parameters.size() - 1) { + methodParams += ", "; + } + } + + String returnStr = ""; + if(!isVoidType) { + returnStr = "return "; + } + + if(typeStr.contains("unsigned")) { + returnStr += "(" + typeStr + ")"; + } + String callMethod = getCPPCallMethod(type); + String methodStr = methodTemplate.replace("[CALL_METHOD]", callMethod).replace("[CPP_CLASS]", cppClassName) + .replace("[METHOD_NAME]", methodName).replace("[CALL_PARAMS]", callParams).replace("[RETURN]", returnStr).replace("[METHOD_ID]", methodName + methodCode); + methodStr = methodStr.replace("[RETURN_TYPE]", typeStr).replace("[METHOD_NAME]", methodName).replace("[PARAMS]", methodParams).replace("[CONST]", constStr); + + cppMethods += methodStr; + } + return cppMethods; + } + + private String getCPPCallMethod(Type type) { + String typeString = type.asString(); + typeString = typeString.substring(0, 1).toUpperCase() + typeString.substring(1); + return "Call" + typeString + "Method"; + } + + private String getCPPType(String typeString) { + if(typeString.equals("boolean")) { + return "bool"; + } + if(typeString.equals("String")) { + return "char*"; + } + return typeString; + } + private void setupMethodGenerated(IDLMethod idlMethod, String param, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, MethodDeclaration nativeMethod) { Type returnType = methodDeclaration.getType(); - String returnTypeStr = idlMethod.returnType; - String methodName = idlMethod.name; + String returnTypeStr = idlMethod.getJavaReturnType(); + String cppReturnType = idlMethod.getCPPReturnType(); + String methodName = idlMethod.getCPPName(); String classTypeName = classDeclaration.getNameAsString(); IDLClass idlClass = idlMethod.idlFile.getClass(classTypeName); if(idlClass != null) { - classTypeName = idlClass.classHeader.prefixName + classTypeName; + classTypeName = idlClass.getCPPName(); } String returnCastStr = ""; String methodCaller = methodName + "(" + param + ")"; @@ -299,7 +663,12 @@ private void setupMethodGenerated(IDLMethod idlMethod, String param, ClassOrInte returnCastStr = "(jlong)"; } - String operator = getOperation(idlMethod.operator, param); + String constTag = ""; + if(idlMethod.isReturnConst) { + constTag = "const "; + } + + String operator = getOperator(idlMethod.operator, param); String content = null; IDLMethodOperation.Op op = IDLMethodOperation.getEnum(idlMethod, methodDeclaration, nativeMethod); switch(op) { @@ -324,7 +693,7 @@ private void setupMethodGenerated(IDLMethod idlMethod, String param, ClassOrInte String returnTypeName = returnType.asClassOrInterfaceType().asClassOrInterfaceType().getNameAsString(); IDLClass retTypeClass = idlMethod.idlFile.getClass(returnTypeName); if(retTypeClass != null) { - returnTypeName = retTypeClass.classHeader.prefixName + returnTypeName; + returnTypeName = retTypeClass.getCPPName(); } String copyParam = "copy_addr"; content = METHOD_GET_OBJ_VALUE_STATIC_TEMPLATE @@ -338,27 +707,44 @@ private void setupMethodGenerated(IDLMethod idlMethod, String param, ClassOrInte String returnTypeName = returnType.asClassOrInterfaceType().asClassOrInterfaceType().getNameAsString(); IDLClass retTypeClass = idlMethod.idlFile.getClass(returnTypeName); if(retTypeClass != null) { - returnTypeName = retTypeClass.classHeader.prefixName + returnTypeName; + returnTypeName = retTypeClass.getCPPName(); } String copyParam = "copy_addr"; - content = METHOD_GET_OBJ_VALUE_TEMPLATE - .replace(TEMPLATE_TAG_METHOD, methodCaller) - .replace(TEMPLATE_TAG_TYPE, classTypeName) - .replace(TEMPLATE_TAG_COPY_TYPE, returnTypeName) - .replace(TEMPLATE_TAG_COPY_PARAM, copyParam); + if(operator.isEmpty()) { + content = METHOD_GET_OBJ_VALUE_TEMPLATE + .replace(TEMPLATE_TAG_METHOD, methodCaller) + .replace(TEMPLATE_TAG_TYPE, classTypeName) + .replace(TEMPLATE_TAG_COPY_TYPE, returnTypeName) + .replace(TEMPLATE_TAG_COPY_PARAM, copyParam); + } + else { + content = METHOD_GET_OBJ_VALUE_ARITHMETIC_OPERATOR_TEMPLATE + .replace(TEMPLATE_TAG_OPERATOR, operator) + .replace(TEMPLATE_TAG_TYPE, classTypeName) + .replace(TEMPLATE_TAG_COPY_TYPE, returnTypeName) + .replace(TEMPLATE_TAG_COPY_PARAM, copyParam); + } } break; case GET_OBJ_POINTER_STATIC: content = METHOD_GET_OBJ_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_METHOD, methodCaller).replace(TEMPLATE_TAG_TYPE, classTypeName); break; case GET_OBJ_POINTER: - content = METHOD_GET_OBJ_POINTER_TEMPLATE.replace(TEMPLATE_TAG_METHOD, methodCaller).replace(TEMPLATE_TAG_TYPE, classTypeName); + content = METHOD_GET_OBJ_POINTER_TEMPLATE.replace(TEMPLATE_TAG_METHOD, methodCaller).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_RETURN_TYPE, cppReturnType).replace(TEMPLATE_TAG_CONST, constTag); break; case GET_PRIMITIVE_STATIC: content = METHOD_GET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_METHOD, methodCaller).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_CAST, returnCastStr); break; - case GET_PRIMITIVE: - content = METHOD_GET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_METHOD, methodCaller).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_CAST, returnCastStr); + case GET_PRIMITIVE: { + if(operator.isEmpty()) { + content = METHOD_GET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_METHOD, methodCaller).replace(TEMPLATE_TAG_TYPE, classTypeName).replace(TEMPLATE_TAG_CAST, returnCastStr); + } + else { + content = METHOD_GET_PRIMITIVE_OPERATOR_TEMPLATE + .replace(TEMPLATE_TAG_OPERATOR, operator) + .replace(TEMPLATE_TAG_TYPE, classTypeName); + } + } break; } @@ -367,25 +753,15 @@ private void setupMethodGenerated(IDLMethod idlMethod, String param, ClassOrInte nativeMethod.setBlockComment(blockComment); } - private static String getOperation(String operatorCode, String param) { + private static String getOperator(String operatorCode, String param) { String oper = ""; if(!operatorCode.isEmpty()) { if(operatorCode.equals("[]")) { - oper = "nativeObject[" + param + "]"; + oper = "(*nativeObject)[" + param + "]"; } - else if(operatorCode.equals("=")){ - oper = "(*nativeObject = " + param + ")"; + else { + oper = "(*nativeObject " + operatorCode + " " + param + ")"; } - //TODO add more operator c++ code -// else if(operatorCode.equals("+=")){ -// oper = " += " + param; -// } -// else if(operatorCode.equals("-=")){ -// oper = " -= " + param; -// } -// else if(operatorCode.equals("*=")){ -// oper = " *= " + param; -// } } return oper; } @@ -402,8 +778,7 @@ private static String getParams(NodeList parameters, ArrayList 0) { param += ", "; } @@ -412,17 +787,23 @@ private static String getParams(NodeList parameters, ArrayList classLines = new ArrayList<>(); public final ArrayList constructors = new ArrayList<>(); public final ArrayList methods = new ArrayList<>(); public final ArrayList attributes = new ArrayList<>(); public ArrayList settings = new ArrayList<>(); + public boolean isCallback; + public IDLClass callbackImpl; + public boolean idlSkip = false; + public IDLClass(IDLFile idlFile) { this.idlFile = idlFile; } public void initClass(ArrayList lines) { - classLines.addAll(lines); + setupLines(lines); setupHeader(); - setInterfaceName(); + setupInterfaceName(); + setupInterfacePackage(); setupExtendClass(); - setAttributesAndMethods(); + setupAttributesAndMethods(); } - private void setAttributesAndMethods() { + private void setupAttributesAndMethods() { for(int i = 1; i < classLines.size(); i++) { - String line = classLines.get(i); + IDLLine idlLine = classLines.get(i); + String line = idlLine.line; if(line.contains("attribute ")) { IDLAttribute attribute = new IDLAttribute(idlFile); - attribute.initAttribute(line); + attribute.initAttribute(idlLine); attributes.add(attribute); } else { - if(line.startsWith("void " + name)) { - IDLConstructor constructor = new IDLConstructor(idlFile); + if(line.contains("void " + name)) { + IDLConstructor constructor = new IDLConstructor(idlFile, this); constructor.initConstructor(line); constructors.add(constructor); @@ -55,7 +60,7 @@ private void setAttributesAndMethods() { else { if(line.contains("(") && line.contains(")")) { IDLMethod method = new IDLMethod(this, idlFile); - method.initMethod(line); + method.initMethod(idlLine); methods.add(method); int totalOptionalParams = method.getTotalOptionalParams(); @@ -72,74 +77,60 @@ private void setAttributesAndMethods() { } } - private void setInterfaceName() { - String line = searchLine("interface ", true, false); - if(line != null) { - name = line.split(" ")[1]; + private void setupInterfaceName() { + IDLLine idlLine = searchLine("interface ", true); + if(idlLine != null) { + name = idlLine.line.split(" ")[1].trim(); + } + } + + private void setupInterfacePackage() { + IDLLine idlLine = searchLine("interface ", true); + if(idlLine != null && idlLine.containsCommand(IDLLine.CMD_SUB_PACKAGE)) { + subPackage = idlLine.getCommandValue(IDLLine.CMD_SUB_PACKAGE); } } private void setupHeader() { - String line = ""; + String code = ""; if(classLines.size() > 0) { - String headerLine = classLines.get(0); + IDLLine idlLine = classLines.get(0); + String headerLine = idlLine.line; if(IDLClassHeader.isLineHeader(headerLine)) { - line = headerLine; + code = headerLine; } } - classHeader = new IDLClassHeader(line, this); + classHeader = new IDLClassHeader(code, this); } private void setupExtendClass() { - String line = searchLine(" implements ", false, false); - if(line != null && !line.startsWith("//")) { - String[] split = line.split("implements"); + IDLLine idlLine = searchLine(" implements ", false); + if(idlLine != null && !idlLine.line.startsWith("//")) { + String[] split = idlLine.line.split("implements"); extendClass = split[1].trim().replace(";", ""); } - } - - private String searchLine(String text, boolean startsWith, boolean endsWith) { - for(int i = 0; i < classLines.size(); i++) { - String line = classLines.get(i); - - if(startsWith) { - if(line.startsWith(text)) { - return line; - } - } - else if(endsWith) { - if(line.endsWith(text)) { - return line; - } - } - else { - if(line.contains(text)) { - return line; - } + if(extendClass.isEmpty()) { + // If implements is not found check for : + IDLLine interfaceLine = searchLine("interface ", true); + if(interfaceLine != null && interfaceLine.line.contains(":")) { + String[] colonSplit = interfaceLine.line.split(":"); + String[] spaceSplit = colonSplit[1].trim().split(" "); + extendClass = spaceSplit[0].trim(); } } - return null; } - public String getName() { + public String getCPPName() { return classHeader.prefixName + name; } public IDLMethod getMethod(String methodName) { for(IDLMethod method : methods) { - if(method.name.equals(methodName)) { + if(method.nameEquals(methodName)) { return method; } } return null; } - public IDLMethod getOperatorMethod(String operator) { - for(IDLMethod method : methods) { - if(method.operator.equals(operator)) { - return method; - } - } - return null; - } } \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLClassOrEnum.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLClassOrEnum.java index 84069b7d..8ca8af40 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLClassOrEnum.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLClassOrEnum.java @@ -1,11 +1,15 @@ package com.github.xpenatan.jparser.idl; +import java.util.ArrayList; + /** * @author xpenatan */ public class IDLClassOrEnum { public String name; + public String subPackage; + public final ArrayList classLines = new ArrayList<>(); public boolean isEnum() { return this instanceof IDLEnum; @@ -22,4 +26,63 @@ public IDLClass asClass() { public IDLEnum asEnum() { return (IDLEnum)this; } + + @Override + public String toString() { + return name; + } + + protected void setupLines(ArrayList lines) { + for(int i = 0; i < lines.size(); i++) { + String originalLine = lines.get(i); + int commentIndex = originalLine.indexOf("//"); + if(commentIndex != -1) { + String command = null; + String code = originalLine.substring(0, commentIndex); + String comment = originalLine.replace(code, "").replace("//", "").trim(); + code = code.trim(); + comment = comment.trim(); + if(comment.isEmpty()) { + comment = null; + } + else { + int startIdx = comment.indexOf("[-"); + int endIdx = comment.indexOf("]"); + if(startIdx != -1 && endIdx != -1 && endIdx > startIdx+2) { + String tempCommand = comment.substring(startIdx, endIdx+1); + comment = comment.replace(tempCommand, "").trim(); + command = tempCommand.trim(); + if(comment.isEmpty()) { + comment = null; + } + } + } + IDLLine idlLine = new IDLLine(code, comment, command); + classLines.add(idlLine); + } + else { + classLines.add(new IDLLine(originalLine, null, null)); + } + } + } + + + IDLLine searchLine(String text, boolean startsWith) { + for(int i = 0; i < classLines.size(); i++) { + IDLLine idlLine = classLines.get(i); + String line = idlLine.line; + + if(startsWith) { + if(line.startsWith(text)) { + return idlLine; + } + } + else { + if(line.contains(text)) { + return idlLine; + } + } + } + return null; + } } \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLConstructor.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLConstructor.java index 5c1dd017..93ce848c 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLConstructor.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLConstructor.java @@ -8,18 +8,23 @@ public class IDLConstructor { public final IDLFile idlFile; + public IDLClass idlClass; public String line; public String paramsLine; public final ArrayList parameters = new ArrayList<>(); - public IDLConstructor(IDLFile idlFile) { + public IDLConstructor(IDLFile idlFile, IDLClass idlClass) { this.idlFile = idlFile; + this.idlClass = idlClass; } public void initConstructor(String line) { this.line = line; paramsLine = IDLMethod.setParameters(idlFile, line, parameters); + for(IDLParameter parameter : parameters) { + parameter.idlConstructor = this; + } } public int getTotalOptionalParams() { @@ -40,7 +45,7 @@ public void removeLastParam(int count) { } public IDLConstructor clone() { - IDLConstructor cloned = new IDLConstructor(idlFile); + IDLConstructor cloned = new IDLConstructor(idlFile, idlClass); cloned.line = line; cloned.paramsLine = paramsLine; for(int i = 0; i < parameters.size(); i++) { diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLEnum.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLEnum.java index 134181bc..171fea74 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLEnum.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLEnum.java @@ -8,7 +8,6 @@ public class IDLEnum extends IDLClassOrEnum { public final IDLFile idlFile; - public final ArrayList classLines = new ArrayList<>(); public final ArrayList enums = new ArrayList<>(); public ArrayList settings = new ArrayList<>(); @@ -21,29 +20,31 @@ public IDLEnum(IDLFile idlFile) { } public void initEnum(ArrayList lines) { - classLines.addAll(lines); + setupLines(lines); setupInterfaceName(); + setupInterfacePackage(); setupEnumValues(); setupSettings(); } private void setupInterfaceName() { - String nameLine = null; - for(int i = 0; i < classLines.size(); i++) { - String line = classLines.get(i); - if(line.contains("enum ")) { - nameLine = line; - break; - } + IDLLine idlLine = searchLine("enum ", true); + if(idlLine != null) { + name = idlLine.line.split(" ")[1].trim(); } - if(nameLine != null) { - name = nameLine.split(" ")[1]; + } + + private void setupInterfacePackage() { + IDLLine idlLine = searchLine("enum ", true); + if(idlLine != null && idlLine.containsCommand(IDLLine.CMD_SUB_PACKAGE)) { + subPackage = idlLine.getCommandValue(IDLLine.CMD_SUB_PACKAGE); } } private void setupEnumValues() { for(int i = 1; i < classLines.size()-1; i++) { - String enumLine = classLines.get(i); + IDLLine idlLine = classLines.get(i); + String enumLine = idlLine.line; String[] split = enumLine.split(","); for(String s : split) { enumLine = s.replace("\"", "").trim(); diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLHelper.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLHelper.java index 5d4ba290..adb840ee 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLHelper.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLHelper.java @@ -4,6 +4,11 @@ import com.github.javaparser.ast.type.Type; public class IDLHelper { + + // Solution to change the default generated C++ code from webidl a custom one. Ex unsigned long long to uint64 + public static IDLTypeConverterListener cppConverter; + public static IDLTypeConverterListener javaConverter; + public static String removeMultipleSpaces(String in) { return in.replaceAll(" +", " "); } @@ -19,6 +24,9 @@ public static String getCArray(String type) { else if(type.equals("IDLIntArray")) { return "int *"; } + else if(type.equals("IDLLongArray")) { + return "long long *"; + } else if(type.equals("IDLFloatArray")) { return "float *"; } @@ -43,4 +51,142 @@ public static String convertEnumToInt(IDLReader idlReader, String type) { } return type; } + + public static String getTags(String line) { + line = line.trim(); + int startIndex = line.indexOf("["); + int endIndex = -1; + if(startIndex != -1 && line.startsWith("[")) { + int count = 0; + for(int i = startIndex; i < line.length(); i++) { + char c = line.charAt(i); + if(c == '[') { + count++; + } + else if(c == ']') { + count--; + } + if(count == 0) { + endIndex = i; + break; + } + } + } + + if(startIndex != -1 && endIndex != -1) { + return line.substring(startIndex, endIndex + 1); + } + return ""; + } + + public static String getCPPReturnType(String idlType) { + if(cppConverter != null) { + String customType = cppConverter.onConvert(idlType); + if(customType != null) { + return customType; + } + } + + String type = ""; + if(idlType.equals("any") || idlType.equals("VoidPtr")) { + type = "void*"; + } + else if(idlType.contains("long long")) { + type = idlType; + } + else if(idlType.contains("long")) { + // long in webidl means int + type = idlType.replace("long", "int"); + } + else if(idlType.equals("DOMString")) { + type = "char*"; + } + else if(idlType.equals("octet")) { + type = "unsigned char"; + } + else { + type = idlType; + } + return type; + } + + public static String getJavaType(String idlType) { + return getJavaType(true, idlType); + } + + public static String getJavaType(boolean useIDLArray, String idlType) { + if(javaConverter != null) { + String customType = javaConverter.onConvert(idlType); + if(customType != null) { + return customType; + } + } + + String type = ""; + if(idlType.contains("unsigned")) { + // Java don't have unsigned + idlType = idlType.replace("unsigned", "").trim(); + } + + boolean containsArray = idlType.contains("[]"); + if(containsArray) { + idlType = idlType.replace("[]", ""); + } + + if(idlType.equals("any") || idlType.equals("VoidPtr")) { + type = "long"; + } + else if(idlType.contains("long long")) { + type = "long"; + } + else if(idlType.contains("long")) { + type = "int"; + } + else if(idlType.equals("DOMString")) { + type = "String"; + } + else if(idlType.equals("octet")) { + type = "byte"; + } + else { + type = idlType; + } + if(containsArray) { + type = type + "[]"; + } + if(useIDLArray) { + String idlArrayOrNull = getIDLArrayOrNull(type); + if(idlArrayOrNull != null) { + type = idlArrayOrNull; + } + } + return type; + } + + public static String getIDLArrayOrNull(String type) { + // Convert array to IDL object arrays + if(type.equals("int[]")) { + type = "IDLIntArray"; + } + else if(type.equals("long[]") || type.equals("long long[]")) { + type = "IDLLongArray"; + } + else if(type.equals("float[]")) { + type = "IDLFloatArray"; + } + else if(type.equals("byte[]")) { + type = "IDLByteArray"; + } + else if(type.equals("boolean[]")) { + type = "IDLBoolArray"; + } + else if(type.equals("double[]")) { + type = "IDLDoubleArray"; + } + else { + return null; + } + + return type; + } } diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLLine.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLLine.java new file mode 100644 index 00000000..a6694760 --- /dev/null +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLLine.java @@ -0,0 +1,61 @@ +package com.github.xpenatan.jparser.idl; + +import java.util.ArrayList; + +public class IDLLine { + public static final String CMD_NEW_OBJECT = "NEW_OBJECT"; + public static final String CMD_MEM_OWN = "MEM_OWN"; + public static final String CMD_NOT_MEM_OWN = "NOT_MEM_OWN"; + public static final String CMD_SUB_PACKAGE = "SUB_PACKAGE"; + + public final String line; + public final String comment; + public final ArrayList commands = new ArrayList<>(); + + private IDLLine(String code, String comment, ArrayList commands) { + this.line = code; + this.comment = comment; + this.commands.addAll(commands); + } + + public IDLLine(String code, String comment, String command) { + this.line = code; + this.comment = comment; + + if(command != null) { + command = command.replace("[-", "").replace("]", "").trim(); + String[] commands = command.split(","); + for(int i = 0; i < commands.length; i++) { + String cmd = commands[i].trim(); + if(!cmd.isEmpty()) { + this.commands.add(cmd); + } + } + } + } + + public IDLLine copy() { + return new IDLLine(line, comment, commands); + } + + public boolean containsCommand(String command) { + for(int i = 0; i < commands.size(); i++) { + String cmd = commands.get(i); + if(cmd.startsWith(command)) { + return true; + } + } + return false; + } + + public String getCommandValue(String command) { + for(int i = 0; i < commands.size(); i++) { + String cmd = commands.get(i); + if(cmd.startsWith(command)) { + String value = cmd.split("=")[1].trim(); + return value; + } + } + return null; + } +} diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLMethod.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLMethod.java index 40d192df..13e69562 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLMethod.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLMethod.java @@ -9,17 +9,22 @@ public class IDLMethod { public final IDLFile idlFile; public final IDLClass idlClass; - public String line; + public IDLLine idlLine; public String paramsLine; public String returnType; + public IDLClassOrEnum returnClassType; public String name; public boolean isReturnArray; public boolean skip = false; public boolean isAny = false; public boolean isReturnRef; public boolean isReturnValue; + public boolean isReturnConst; + public boolean isReturnNewObject; + public boolean isReturnMemoryOwned; public boolean isStaticMethod = false; public String operator = ""; + public String bindsToName = null; public final ArrayList parameters = new ArrayList<>(); @@ -28,55 +33,91 @@ public IDLMethod(IDLClass idlClass, IDLFile idlFile) { this.idlFile = idlFile; } - public void initMethod(String line) { - this.line = line; + public void initMethod(IDLLine idlLine) { + this.idlLine = idlLine; + String line = idlLine.line; paramsLine = IDLMethod.setParameters(idlFile, line, parameters); + for(IDLParameter parameter : parameters) { + parameter.idlMethod = this; + } int index = line.indexOf("("); String leftSide = line.substring(0, index).trim(); + leftSide = IDLHelper.removeMultipleSpaces(leftSide.trim()); - String tagsStr = getTags(leftSide); - if(!tagsStr.isEmpty()) { - isReturnRef = tagsStr.contains("Ref"); - isReturnValue = tagsStr.contains("Value"); - leftSide = leftSide.replace(tagsStr, ""); + isReturnNewObject = idlLine.containsCommand(IDLLine.CMD_NEW_OBJECT); + isReturnMemoryOwned = !idlLine.containsCommand(IDLLine.CMD_NOT_MEM_OWN); + String tagsStr = IDLHelper.getTags(leftSide); + if(!tagsStr.isEmpty()) { + leftSide = leftSide.replace(tagsStr, "").trim(); tagsStr = tagsStr.substring(1, tagsStr.length()-1); for(String s : tagsStr.split(",")) { + s = s.trim(); if(s.contains("Operator")) { int first = s.indexOf("\""); int last = s.lastIndexOf("\""); operator = s.substring(first, last + 1).replace("\"", ""); } + else if(s.equals("Ref")) { + isReturnRef = true; + } + else if(s.equals("Value")) { + isReturnValue = true; + } + else if(s.equals("Const")) { + isReturnConst = true; + } + else if(s.startsWith("BindTo")) { + s = s.replace("\"", ""); + bindsToName = s.split("=")[1]; + } } } if(leftSide.contains("[]")) { - leftSide = leftSide.replace("[]", ""); + leftSide = leftSide.replace("[]", "").trim(); isReturnArray = true; } - leftSide = IDLHelper.removeMultipleSpaces(leftSide.trim()); if(leftSide.contains("static")) { + leftSide = leftSide.replace("static", "").trim(); isStaticMethod = true; } - String[] s = leftSide.split(" "); - name = s[s.length-1]; - returnType = s[s.length-2]; + String[] s1 = leftSide.split(" "); + name = s1[s1.length-1]; - if(returnType.equals("long")) { - returnType = "int"; + returnType = ""; + int sss = s1.length - 1; + for(int i = 0; i < sss; i++) { + returnType += s1[i]; + if(i < sss-1) { + returnType += " "; + } } - if(returnType.equals("DOMString")) { - returnType = "String"; + + if(isReturnArray) { + returnType = returnType + "[]"; } if(returnType.contains("any") || returnType.contains("VoidPtr")) { isAny = true; - returnType = "long"; } } + public String getCPPReturnType() { + String fullType = returnType; + if(returnClassType != null && returnClassType.isClass()) { + IDLClass aClass = returnClassType.asClass(); + fullType = aClass.getCPPName(); + } + return IDLHelper.getCPPReturnType(fullType); + } + + public String getJavaReturnType() { + return IDLHelper.getJavaType(returnType); + } + public int getTotalOptionalParams() { int count = 0; for(int i = 0; i < parameters.size(); i++) { @@ -94,14 +135,34 @@ public void removeLastParam(int count) { } } + public boolean nameEquals(String value) { + if(bindsToName != null) { + if(value.equals(bindsToName)) { + return true; + } + } + else { + return value.equals(name); + } + return false; + } + + public String getCPPName() { + if(bindsToName != null) { + return bindsToName; + } + return name; + } + public IDLMethod clone() { IDLMethod cloned = new IDLMethod(idlClass, idlFile); - cloned.line = line; + cloned.idlLine = idlLine.copy(); cloned.paramsLine = paramsLine; cloned.returnType = returnType; cloned.name = name; cloned.skip = skip; cloned.isAny = isAny; + cloned.bindsToName = bindsToName; cloned.isReturnValue = isReturnValue; cloned.isReturnArray = isReturnArray; cloned.isStaticMethod = isStaticMethod; @@ -115,32 +176,6 @@ public IDLMethod clone() { return cloned; } - private String getTags(String leftSide) { - int startIndex = leftSide.indexOf("["); - int endIndex = -1; - if(startIndex != -1 && leftSide.startsWith("[")) { - int count = 0; - for(int i = startIndex; i < leftSide.length(); i++) { - char c = leftSide.charAt(i); - if(c == '[') { - count++; - } - else if(c == ']') { - count--; - } - if(count == 0) { - endIndex = i; - break; - } - } - } - - if(startIndex != -1 && endIndex != -1) { - return leftSide.substring(startIndex, endIndex + 1); - } - return ""; - } - static String setParameters(IDLFile idlFile, String line, ArrayList out) { int firstIdx = line.indexOf("("); int lastIdx = line.indexOf(")"); diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLPackageRenaming.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLPackageRenaming.java new file mode 100644 index 00000000..7a6eeda2 --- /dev/null +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLPackageRenaming.java @@ -0,0 +1,5 @@ +package com.github.xpenatan.jparser.idl; + +public interface IDLPackageRenaming { + String obtainNewPackage(String className, String classPackage); +} \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLParameter.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLParameter.java index 5c62de24..6e1ac994 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLParameter.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLParameter.java @@ -7,9 +7,12 @@ */ public class IDLParameter { public final IDLFile idlFile; + public IDLMethod idlMethod; + public IDLConstructor idlConstructor; + public IDLClassOrEnum idlClassOrEnum; public String line; - public String type; + public String idlType; public String name; public boolean isArray; public boolean isRef; @@ -31,11 +34,13 @@ public void initParameter(String line) { optional = line.contains("optional"); isArray = line.contains("[]"); + tmpLine = tmpLine.replace("optional", "").trim(); + tmpLine = tmpLine.replace("[]", "").trim(); - int startIndex = line.indexOf("["); - int endIndex = line.indexOf("]"); + int startIndex = tmpLine.indexOf("["); + int endIndex = tmpLine.indexOf("]"); if(startIndex != -1 && endIndex != -1 && startIndex + 2 < endIndex) { - String tagsStr = line.substring(startIndex, endIndex + 1); + String tagsStr = tmpLine.substring(startIndex, endIndex + 1); isRef = tagsStr.contains("Ref"); isConst = tagsStr.contains("Const"); isValue = tagsStr.contains("Value"); @@ -53,56 +58,43 @@ public void initParameter(String line) { } String[] s1 = tmpLine.split(" "); - type = s1[s1.length - 2]; + name = s1[s1.length - 1]; - if(isArray) { - type = type + "[]"; + idlType = ""; + int sss = s1.length - 1; + for(int i = 0; i < sss; i++) { + idlType += s1[i]; + if(i < sss-1) { + idlType += " "; + } } - if(type.equals("long")) { - // long in webidl means int - type = "int"; + if(isArray) { + idlType = idlType + "[]"; } - if(type.equals("any") || type.equals("VoidPtr")) { - type = "long"; + if(idlType.equals("any") || idlType.equals("VoidPtr")) { isAny = true; } + } - if(type.equals("long[]")) { - type = "int[]"; - } - if(type.equals("DOMString")) { - type = "String"; - } - if(type.equals("octet")) { - type = "byte"; - } - - // Convert to array object - if(type.equals("int[]")) { - type = "IDLIntArray"; - } - else if(type.equals("float[]")) { - type = "IDLFloatArray"; - } - else if(type.equals("byte[]")) { - type = "IDLByteArray"; - } - else if(type.equals("boolean[]")) { - type = "IDLBoolArray"; - } - else if(type.equals("double[]")) { - type = "IDLDoubleArray"; + public String getCPPType() { + String fullType = idlType; + if(idlClassOrEnum != null && idlClassOrEnum.isClass()) { + IDLClass aClass = idlClassOrEnum.asClass(); + fullType = aClass.getCPPName(); } + return IDLHelper.getCPPReturnType(fullType); + } - name = s1[s1.length - 1]; + public String getJavaType() { + return IDLHelper.getJavaType(idlType); } public IDLParameter clone() { IDLParameter clonedParam = new IDLParameter(idlFile); clonedParam.line = line; - clonedParam.type = type; + clonedParam.idlType = idlType; clonedParam.name = name; clonedParam.isRef = isRef; clonedParam.isAny = isAny; diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLReader.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLReader.java index 550a653e..a9ce7032 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLReader.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLReader.java @@ -61,15 +61,44 @@ public IDLEnum getEnum(String name) { return null; } - public static IDLReader readIDL(String idlDir) { + public IDLClassOrEnum getClassOrEnum(String name) { + for(int i = 0; i < fileArray.size(); i++) { + IDLFile idlFile = fileArray.get(i); + IDLClass idlClass = idlFile.getClass(name); + if(idlClass != null) { + return idlClass; + } + IDLEnum idlEnum = idlFile.getEnum(name); + if(idlEnum != null) { + return idlEnum; + } + } + return null; + } + + public ArrayList getAllClasses() { + ArrayList classes = new ArrayList<>(); + for(int i = 0; i < fileArray.size(); i++) { + IDLFile idlFile = fileArray.get(i); + classes.addAll(idlFile.classArray); + } + return classes; + } + + public static IDLReader readIDL(String ...idlDirs) { IDLReader reader = new IDLReader(); - try { - idlDir = new File(idlDir).getCanonicalPath() + File.separator; - } catch(IOException e) { - throw new RuntimeException("IDL file not found: " + idlDir); + + for(int i = 0; i < idlDirs.length; i++) { + String idlDir = idlDirs[i]; + try { + idlDir = new File(idlDir).getCanonicalPath() + File.separator; + IDLFile idlFile = parseFile(idlDir); + reader.fileArray.add(idlFile); + } catch(IOException e) { + throw new RuntimeException("IDL file not found: " + idlDir); + } } - IDLFile idlFile = parseFile(idlDir); - reader.fileArray.add(idlFile); + return reader; } @@ -83,15 +112,6 @@ public static void addIDL(IDLReader reader, String idlDir) { reader.fileArray.add(idlFile); } - public static IDLReader readIDL(ArrayList idlDirs) { - IDLReader reader = new IDLReader(); - for(String idlDir : idlDirs) { - IDLFile idlFile = parseFile(idlDir); - reader.fileArray.add(idlFile); - } - return reader; - } - public static IDLFile parseFile(String path) { path = path.replace("\\", File.separator); File file = new File(path); //creates a new file instance @@ -138,12 +158,11 @@ private static void parseFile(IDLFile idlFile, ArrayList classLi ArrayList settings = new ArrayList<>(); int size = idlFile.lines.size(); for(int i = 0; i < size; i++) { - String line = idlFile.lines.get(i).trim(); - String nextLine = ""; - if(i+1 < size) { - nextLine = idlFile.lines.get(i+1).trim(); - } - if(line.startsWith("//") || line.isEmpty()) { + String originalLine = idlFile.lines.get(i).trim(); + String line = removeComment(originalLine); + String nextLine = getNextLine(idlFile.lines, i); + + if(line.isEmpty()) { if(foundStartClass || foundStartEnum) { String cmd = line.replace("//", "").trim(); if(cmd.startsWith("[-") && cmd.endsWith("]")) { @@ -163,7 +182,7 @@ private static void parseFile(IDLFile idlFile, ArrayList classLi } if(foundStartEnum) { - classLines.add(line); + classLines.add(originalLine); if(line.endsWith("};")) { foundStartEnum = false; @@ -181,21 +200,18 @@ private static void parseFile(IDLFile idlFile, ArrayList classLi foundStartClass = true; classLines.clear(); justAdded = true; - classLines.add(line); + classLines.add(originalLine); } } if(foundStartClass) { if(!justAdded) { - classLines.add(line); + classLines.add(originalLine); } if(line.endsWith("};")) { - int nextLineIdx = i + 1; - if(nextLineIdx < size) { - String nextL = idlFile.lines.get(nextLineIdx); - if(nextL.contains(" implements ")) { - classLines.add(nextL.trim()); - i++; // add i so nextLine is not skipped on next loop - } + String nextL = getNextLine(idlFile.lines, i);; + if(nextL.contains(" implements ")) { + classLines.add(nextL.trim()); + i++; // add i so nextLine is not skipped on next loop } foundStartClass = false; IDLClass parserLineClass = new IDLClass(idlFile); @@ -208,4 +224,83 @@ private static void parseFile(IDLFile idlFile, ArrayList classLi } } } + + public static void setupClasses(IDLReader idlReader) { + ArrayList classList = idlReader.getAllClasses(); + configClassType(idlReader, classList); + configCallbacks(idlReader, classList); + } + + private static void configClassType(IDLReader idlReader, ArrayList classList) { + // Setup all attributes and parameters type + for(int i = 0; i < classList.size(); i++) { + IDLClassOrEnum idlClassOrEnum = classList.get(i); + if(idlClassOrEnum.isClass()) { + IDLClass idlClass = idlClassOrEnum.asClass(); + for(IDLAttribute attribute : idlClass.attributes) { + String idlType = attribute.idlType; + IDLClassOrEnum childClassOrEnum = idlReader.getClassOrEnum(idlType); + attribute.idlClassOrEnum = childClassOrEnum; + } + for(IDLMethod method : idlClass.methods) { + for(IDLParameter parameter : method.parameters) { + String idlType = parameter.idlType; + IDLClassOrEnum childClassOrEnum = idlReader.getClassOrEnum(idlType); + parameter.idlClassOrEnum = childClassOrEnum; + } + String returnType = method.returnType; + IDLClassOrEnum childClassOrEnum = idlReader.getClassOrEnum(returnType); + method.returnClassType = childClassOrEnum; + } + } + } + } + + private static void configCallbacks(IDLReader idlReader, ArrayList classList) { + for(int i = 0; i < classList.size(); i++) { + IDLClassOrEnum idlClassOrEnum = classList.get(i); + if(idlClassOrEnum.isClass()) { + IDLClass idlCallbackImpl = idlClassOrEnum.asClass(); + String jsImplementation = idlCallbackImpl.classHeader.jsImplementation; + if(jsImplementation != null) { + jsImplementation = jsImplementation.trim(); + if(!jsImplementation.isEmpty()) { + IDLClass callbackClass = idlReader.getClass(jsImplementation); + if(callbackClass != null) { + if(callbackClass.callbackImpl == null) { + callbackClass.callbackImpl = idlCallbackImpl; + callbackClass.isCallback = true; + } + else { + throw new RuntimeException("Class " + callbackClass.name + " cannot have multiple JSImplementation"); + } + } + } + } + } + } + } + + private static String removeComment(String line) { + int commentIndex = line.indexOf("//"); + if(commentIndex != -1) { + line = line.substring(0, commentIndex); + line = line.trim(); + } + return line; + } + + private static String getNextLine(ArrayList lines, int index) { + String nextLine = ""; + int size = lines.size(); + if(index + 1 < size) { + nextLine = lines.get(index+1).trim(); + nextLine = removeComment(nextLine); + if(nextLine.isEmpty() && index + 2 < size) { + nextLine = lines.get(index+2).trim(); + nextLine = removeComment(nextLine); + } + } + return nextLine; + } } \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLTypeConverterListener.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLTypeConverterListener.java new file mode 100644 index 00000000..a1ff8f5e --- /dev/null +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/IDLTypeConverterListener.java @@ -0,0 +1,5 @@ +package com.github.xpenatan.jparser.idl; + +public interface IDLTypeConverterListener { + String onConvert(String idlType); +} \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeOperation.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeOperation.java index d5505a24..b13be31c 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeOperation.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeOperation.java @@ -10,8 +10,8 @@ public class IDLAttributeOperation { public static Op getEnum(boolean isSet, IDLAttribute idlAttribute, MethodDeclaration methodDeclaration, MethodDeclaration nativeMethod) { boolean isStatic = methodDeclaration.isStatic(); - Type nativeReturnType = nativeMethod.getType(); boolean isValue = idlAttribute.isValue; + boolean isArray = idlAttribute.isArray; Type returnType = methodDeclaration.getType(); NodeList parameters = methodDeclaration.getParameters(); @@ -46,31 +46,90 @@ public static Op getEnum(boolean isSet, IDLAttribute idlAttribute, MethodDeclara } } } + else if(isArray) { + if(parameters.get(1).getType().isClassOrInterfaceType()) { + if(isValue) { + if(isStatic) { + return Op.SET_ARRAY_OBJECT_VALUE_STATIC; + } + else { + return Op.SET_ARRAY_OBJECT_VALUE; + } + } + else { + // is pointer + if(isStatic) { + return Op.SET_ARRAY_OBJECT_POINTER_STATIC; + } + else { + return Op.SET_ARRAY_OBJECT_POINTER; + } + } + } + else { + if(isStatic) { + return Op.SET_ARRAY_PRIMITIVE_STATIC; + } + else { + return Op.SET_ARRAY_PRIMITIVE; + } + } + } } else if(returnType.isClassOrInterfaceType()) { - if(isValue) { - if(isStatic) { - return Op.GET_OBJECT_VALUE_STATIC; + if(isArray) { + if(isValue) { + if(isStatic) { + return Op.GET_ARRAY_OBJECT_VALUE_STATIC; + } + else { + return Op.GET_ARRAY_OBJECT_VALUE; + } } else { - return Op.GET_OBJECT_VALUE; + if(isStatic) { + return Op.GET_ARRAY_OBJECT_POINTER_STATIC; + } + else { + return Op.GET_ARRAY_OBJECT_POINTER; + } } } else { - if(isStatic) { - return Op.GET_OBJECT_POINTER_STATIC; + if(isValue) { + if(isStatic) { + return Op.GET_OBJECT_VALUE_STATIC; + } + else { + return Op.GET_OBJECT_VALUE; + } } else { - return Op.GET_OBJECT_POINTER; + if(isStatic) { + return Op.GET_OBJECT_POINTER_STATIC; + } + else { + return Op.GET_OBJECT_POINTER; + } } } } else { - if(isStatic) { - return Op.GET_PRIMITIVE_STATIC; + if(isArray) { + if(isStatic) { + return Op.GET_ARRAY_PRIMITIVE_STATIC; + } + else { + return Op.GET_ARRAY_PRIMITIVE; + } } else { - return Op.GET_PRIMITIVE; + if(isStatic) { + return Op.GET_PRIMITIVE_STATIC; + } + else { + return Op.GET_PRIMITIVE; + } } } return null; @@ -91,5 +150,22 @@ public enum Op { SET_PRIMITIVE_STATIC, GET_PRIMITIVE, GET_PRIMITIVE_STATIC, + + // Array + + SET_ARRAY_OBJECT_VALUE, + SET_ARRAY_OBJECT_VALUE_STATIC, + GET_ARRAY_OBJECT_VALUE, + GET_ARRAY_OBJECT_VALUE_STATIC, + + SET_ARRAY_OBJECT_POINTER, + SET_ARRAY_OBJECT_POINTER_STATIC, + GET_ARRAY_OBJECT_POINTER, + GET_ARRAY_OBJECT_POINTER_STATIC, + + SET_ARRAY_PRIMITIVE, + SET_ARRAY_PRIMITIVE_STATIC, + GET_ARRAY_PRIMITIVE, + GET_ARRAY_PRIMITIVE_STATIC, } } \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeParser.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeParser.java index fd7f4e1b..2e150508 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeParser.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLAttributeParser.java @@ -33,7 +33,7 @@ public static void generateAttribute(IDLDefaultCodeParser idlParser, JParser jPa MethodDeclaration containsGetMethod = containsGetMethod(classOrInterfaceDeclaration, idlAttribute); String attributeName = idlAttribute.name; - String attributeType = idlAttribute.type; + String attributeType = idlAttribute.getJavaType(); attributeType = IDLHelper.convertEnumToInt(idlParser.idlReader, attributeType); @@ -42,8 +42,8 @@ public static void generateAttribute(IDLDefaultCodeParser idlParser, JParser jPa type = StaticJavaParser.parseType(attributeType); } catch(Exception e) { - e.printStackTrace(); - return; + System.err.println("Type error: " + attributeType); + throw e; } JParserItem parserUnitItem = jParser.getParserUnitItem(type.toString()); @@ -94,15 +94,20 @@ public static void generateAttribute(IDLDefaultCodeParser idlParser, JParser jPa if(getMethodDeclaration != null) { getMethodDeclaration.remove(); } - String getMethodName = attributeName; + String getMethodName = ATTRIBUTE_PREFIX_GET + attributeName; getMethodDeclaration = classOrInterfaceDeclaration.addMethod(getMethodName, Modifier.Keyword.PUBLIC); getMethodDeclaration.setStatic(idlAttribute.isStatic); + + if(idlAttribute.isArray) { + getMethodDeclaration.addAndGetParameter("int", "index"); + } + getMethodDeclaration.setType(type); JParserHelper.addMissingImportType(jParser, unit, type); IDLDefaultCodeParser.setDefaultReturnValues(jParser, unit, type, getMethodDeclaration); if(idlParser.generateClass) { - setupAttributeMethod(idlParser, jParser, idlAttribute, false, classOrInterfaceDeclaration, getMethodDeclaration, ATTRIBUTE_PREFIX_GET + getMethodName); + setupAttributeMethod(idlParser, jParser, idlAttribute, false, classOrInterfaceDeclaration, getMethodDeclaration, getMethodName); } } @@ -114,27 +119,30 @@ public static void generateAttribute(IDLDefaultCodeParser idlParser, JParser jPa if(setMethodDeclaration != null) { setMethodDeclaration.remove(); } - String setMethodName = attributeName; + String setMethodName = ATTRIBUTE_PREFIX_SET + attributeName; setMethodDeclaration = classOrInterfaceDeclaration.addMethod(setMethodName, Modifier.Keyword.PUBLIC); setMethodDeclaration.setStatic(idlAttribute.isStatic); + if(idlAttribute.isArray) { + setMethodDeclaration.addAndGetParameter("int", "index"); + } Parameter parameter = setMethodDeclaration.addAndGetParameter(type, attributeName); Type paramType = parameter.getType(); JParserHelper.addMissingImportType(jParser, unit, paramType); if(idlParser.generateClass) { - setupAttributeMethod(idlParser, jParser, idlAttribute, true, classOrInterfaceDeclaration, setMethodDeclaration, ATTRIBUTE_PREFIX_SET + setMethodName); + setupAttributeMethod(idlParser, jParser, idlAttribute, true, classOrInterfaceDeclaration, setMethodDeclaration, setMethodName); } } } private static void setupAttributeMethod(IDLDefaultCodeParser idlParser, JParser jParser, IDLAttribute idlAttribute, boolean isSet, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, String methodName) { - boolean isValue = idlAttribute.isValue; - boolean addCopyParam = false; - if(isValue && !isSet) { - // When it's a get attribute method we pass a temp c++ object to copy to the returned temp c++ object. + IDLMethodParser.NativeMethodData methodData = new IDLMethodParser.NativeMethodData(); + methodData.isStatic = idlAttribute.isStatic; + if(idlAttribute.idlClassOrEnum != null && idlAttribute.idlClassOrEnum.isClass()) { + IDLClass aClass = idlAttribute.idlClassOrEnum.asClass(); + methodData.isNoDelete = aClass.classHeader.isNoDelete; } - isValue = false; - MethodDeclaration nativeMethod = IDLMethodParser.prepareNativeMethod(idlAttribute.isStatic, isValue, classDeclaration, methodDeclaration, methodName, ""); + MethodDeclaration nativeMethod = IDLMethodParser.prepareNativeMethod(methodData, classDeclaration, methodDeclaration, methodName, "", null); if(nativeMethod != null) { idlParser.onIDLAttributeGenerated(jParser, idlAttribute, isSet, classDeclaration, methodDeclaration, nativeMethod); } @@ -143,8 +151,6 @@ private static void setupAttributeMethod(IDLDefaultCodeParser idlParser, JParser public static boolean shouldSkipMethod(MethodDeclaration containsMethod) { if(containsMethod != null) { boolean isNative = containsMethod.isNative(); - boolean isStatic = containsMethod.isStatic(); - boolean containsBlockComment = false; Optional optionalComment = containsMethod.getComment(); if(optionalComment.isPresent()) { Comment comment = optionalComment.get(); @@ -181,8 +187,8 @@ public static boolean shouldSkipMethod(MethodDeclaration containsMethod) { private static MethodDeclaration containsSetMethod(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLAttribute idlAttribute) { String[] paramTypes = new String[1]; - paramTypes[0] = idlAttribute.type; - String methodName = idlAttribute.name; + paramTypes[0] = idlAttribute.getJavaType(); + String methodName = ATTRIBUTE_PREFIX_SET + idlAttribute.name; List methods = classOrInterfaceDeclaration.getMethodsBySignature(methodName, paramTypes); if(methods.size() > 0) { @@ -193,7 +199,7 @@ private static MethodDeclaration containsSetMethod(ClassOrInterfaceDeclaration c private static MethodDeclaration containsGetMethod(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLAttribute idlAttribute) { String[] paramTypes = new String[0]; - String methodName = idlAttribute.name; + String methodName = ATTRIBUTE_PREFIX_GET + idlAttribute.name; List methods = classOrInterfaceDeclaration.getMethodsBySignature(methodName, paramTypes); if(methods.size() > 0) { diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLCallbackParser.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLCallbackParser.java new file mode 100644 index 00000000..fbd0b683 --- /dev/null +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLCallbackParser.java @@ -0,0 +1,112 @@ +package com.github.xpenatan.jparser.idl.parser; + +import com.github.javaparser.StaticJavaParser; +import com.github.javaparser.ast.CompilationUnit; +import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.ConstructorDeclaration; +import com.github.javaparser.ast.body.MethodDeclaration; +import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.expr.MethodCallExpr; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ReturnStmt; +import com.github.javaparser.ast.type.PrimitiveType; +import com.github.javaparser.ast.type.Type; +import com.github.javaparser.utils.Pair; +import com.github.xpenatan.jparser.core.JParser; +import com.github.xpenatan.jparser.idl.IDLClass; +import com.github.xpenatan.jparser.idl.IDLConstructor; +import com.github.xpenatan.jparser.idl.IDLMethod; +import java.util.ArrayList; + +public class IDLCallbackParser { + + private final static String callbackMethodName = "setupCallback"; + + public static void generateCallback(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classDeclaration, IDLClass idlClass) { + ArrayList constructors = idlClass.callbackImpl.constructors; + if(constructors.size() == 1) { + IDLConstructor idlConstructor = constructors.get(0); + ConstructorDeclaration constructorDeclaration = IDLConstructorParser.getOrCreateConstructorDeclaration(idlParser, jParser, unit, classDeclaration, idlConstructor); + + if(constructorDeclaration.getBody().isEmpty()) { + MethodDeclaration callbackSetupDeclaration = classDeclaration.addMethod(callbackMethodName, Modifier.Keyword.PRIVATE); + ArrayList>> methods = createCallbackMethods(idlParser, jParser, unit, classDeclaration, idlClass); + MethodDeclaration nativeMethod = IDLConstructorParser.setupConstructor(idlConstructor, classDeclaration, constructorDeclaration); + idlParser.onIDLConstructorGenerated(jParser, idlConstructor, classDeclaration, constructorDeclaration, nativeMethod); + MethodCallExpr caller = IDLMethodParser.createCaller(callbackSetupDeclaration); + constructorDeclaration.getBody().addStatement(caller); + idlParser.onIDLCallbackGenerated(jParser, idlClass, classDeclaration, callbackSetupDeclaration, methods); + + // Add super methods when its needed + IDLConstructorParser.addSuperTempConstructor(classDeclaration, constructorDeclaration); + } + } + else { + throw new RuntimeException("Callback need to have 1 constructor"); + } + } + + + private static ArrayList>> createCallbackMethods(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classDeclaration, IDLClass idlClass) { + ArrayList>> methods = new ArrayList<>(); + IDLClass callbackClass = idlClass.callbackImpl; + + for(IDLMethod method : callbackClass.methods) { + MethodDeclaration methodDeclaration = IDLMethodParser.generateAndAddMethodOnly(idlParser, jParser, unit, classDeclaration, method); + MethodDeclaration internalMethod = methodDeclaration.clone(); + methodDeclaration.removeModifier(Modifier.Keyword.PUBLIC); + methodDeclaration.addModifier(Modifier.Keyword.PROTECTED); + + internalMethod.removeModifier(Modifier.Keyword.PUBLIC); + internalMethod.addModifier(Modifier.Keyword.PRIVATE); + + NodeList parameters = internalMethod.getParameters(); + + MethodCallExpr caller = IDLMethodParser.createCaller(methodDeclaration); + + String createFieldObjectCode = ""; + for(int i = 0; i < parameters.size(); i++) { + Parameter parameter = parameters.get(i); + String paramName = parameter.getNameAsString(); + Type type = parameter.getType(); + String typeStr = type.asString(); + String fieldName = paramName; + + if(type.isClassOrInterfaceType() && !typeStr.equals("String")) { + parameter.setType(PrimitiveType.longType()); + fieldName = IDLMethodParser.generateFieldName(classDeclaration, typeStr, true); + String newBody = IDLMethodParser.CALLBACK_PARAM_TEMPLATE + .replace(IDLMethodParser.TEMPLATE_TEMP_FIELD, fieldName) + .replace(IDLMethodParser.TEMPLATE_TAG_TYPE, typeStr) + .replace(IDLMethodParser.TEMPLATE_TAG_PARAM, paramName); + + createFieldObjectCode += newBody; + } + caller.addArgument(fieldName); + } + createFieldObjectCode = "{\n" + createFieldObjectCode + "}"; + BlockStmt blockStmt = StaticJavaParser.parseBlock(createFieldObjectCode); + + if(internalMethod.getType().isVoidType()) { + blockStmt.addStatement(caller); + } + else { + ReturnStmt returnStmt = new ReturnStmt(); + returnStmt.setExpression(caller); + blockStmt.addStatement(returnStmt); + } + String internName = internalMethod.getNameAsString(); + internalMethod.setName("internal_" + internName); + internalMethod.setBody(blockStmt); + classDeclaration.addMember(internalMethod); + + Pair methodDeclarationPair = new Pair<>(internalMethod, methodDeclaration); + + Pair> methodPair = new Pair<>(method, methodDeclarationPair); + methods.add(methodPair); + } + return methods; + } +} \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLClassGeneratorParser.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLClassGeneratorParser.java index 4efae3c4..01bca773 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLClassGeneratorParser.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLClassGeneratorParser.java @@ -4,14 +4,23 @@ import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.Modifier; +import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; +import com.github.javaparser.ast.body.BodyDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.github.javaparser.ast.body.ConstructorDeclaration; import com.github.javaparser.ast.body.FieldDeclaration; +import com.github.javaparser.ast.body.InitializerDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; +import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.Name; import com.github.javaparser.ast.type.ClassOrInterfaceType; +import com.github.javaparser.ast.type.PrimitiveType; import com.github.javaparser.ast.type.Type; +import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration; +import com.github.javaparser.symbolsolver.javaparsermodel.declarations.JavaParserMethodDeclaration; +import com.github.javaparser.utils.Pair; import com.github.xpenatan.jparser.core.JParser; import com.github.xpenatan.jparser.core.JParserHelper; import com.github.xpenatan.jparser.core.JParserItem; @@ -24,8 +33,8 @@ import com.github.xpenatan.jparser.idl.IDLFile; import com.github.xpenatan.jparser.idl.IDLReader; import com.github.xpenatan.jparser.core.util.ResourceList; +import com.github.xpenatan.jparser.idl.IDLPackageRenaming; import idl.IDLBase; -import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; @@ -33,6 +42,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Optional; import java.util.regex.Pattern; /** @@ -55,12 +65,13 @@ public abstract class IDLClassGeneratorParser extends DefaultCodeParser { protected String includeDir; + public IDLPackageRenaming packageRenaming; + /** - * * @param basePackage Base module source. This is used to generate other sources - * @param headerCMD This is the first command option that this parser will use. Ex teavm, C++. - * @param idlReader Contains the parsed idl files - * @param includeDir This is used to add java subpackages from c++ tree. Without this all java source will be at the root package. + * @param headerCMD This is the first command option that this parser will use. Ex teavm, C++. + * @param idlReader Contains the parsed idl files + * @param includeDir This is used to add java subpackages from c++ tree. Without this all java source will be at the root package. */ public IDLClassGeneratorParser(String basePackage, String headerCMD, IDLReader idlReader, String includeDir) { super(headerCMD); @@ -68,7 +79,7 @@ public IDLClassGeneratorParser(String basePackage, String headerCMD, IDLReader i this.basePackage = basePackage; this.idlReader = idlReader; if(this.includeDir != null) { - this.includeDir = this.includeDir.replace("\\", "/").replace("//", "/");; + this.includeDir = this.includeDir.replace("\\", "/").replace("//", "/"); } } @@ -96,7 +107,7 @@ private void createBaseUnitFromResources(JParser jParser) { } String newPackage = basePackage + originalPackage; compilationUnit.setPackageDeclaration(newPackage); - JParserItem jParserItem = new JParserItem(compilationUnit, jParser.genDir, jParser.genDir); + JParserItem jParserItem = new JParserItem(compilationUnit, jParser.genDir); if(!JParser.CREATE_IDL_HELPER) { jParserItem.notAllowed = true; } @@ -114,6 +125,9 @@ private void createBaseUnitFromResources(JParser jParser) { } private void generateIDLJavaClasses(JParser jParser, String genPath) { + System.out.println("Class Mapping: "); + System.out.println(classCppPath); + for(IDLFile idlFile : idlReader.fileArray) { for(IDLClassOrEnum idlClassOrEnum : idlFile.classArray) { String className = idlClassOrEnum.name; @@ -133,12 +147,18 @@ private void generateIDLJavaClasses(JParser jParser, String genPath) { Path p = Paths.get(includeClass); Path parent = p.getParent(); if(parent != null) { - String string = parent.toString(); - subPackage = string.replace(File.separator, ".").toLowerCase(); + String string = parent.toString().replace("\\", "/"); + subPackage = string.replace("/", ".").toLowerCase(); } } + if(idlClassOrEnum.subPackage != null) { + subPackage = idlClassOrEnum.subPackage; + } + if(packageRenaming != null) { + subPackage = packageRenaming.obtainNewPackage(className, subPackage); + } CompilationUnit compilationUnit = setupClass(idlClassOrEnum, subPackage); - parserItem = new JParserItem(compilationUnit, genPath, genPath); + parserItem = new JParserItem(compilationUnit, genPath); jParser.unitArray.add(parserItem); } } @@ -147,8 +167,10 @@ private void generateIDLJavaClasses(JParser jParser, String genPath) { private HashMap getClassCppPath() { HashMap mapPackage = new HashMap<>(); + System.out.println("includeDir: " + includeDir); if(includeDir != null) { ArrayList filesFromDir = FileHelper.getFilesFromDir(includeDir); + System.out.println("FilesFromDir: " + filesFromDir.size()); for(String path : filesFromDir) { if(!path.endsWith(".h")) continue; @@ -179,13 +201,19 @@ private CompilationUnit setupClass(IDLClassOrEnum idlClass, String subPackage) { classDeclaration.setPublic(true); if(idlClass.isClass()) { - // For every class we generate empty object that can be used when needed. - IDLMethodParser.generateFieldName("T_01", classDeclaration, className, true, Modifier.Keyword.PUBLIC, true); - IDLMethodParser.generateFieldName("T_02", classDeclaration, className, true, Modifier.Keyword.PUBLIC, true); - IDLMethodParser.generateFieldName("T_03", classDeclaration, className, true, Modifier.Keyword.PUBLIC, true); + IDLClass aClass = idlClass.asClass(); + if(aClass.isCallback) { + // Do nothing + } + else { + // For every class we generate empty object that can be used when needed. + IDLMethodParser.generateFieldName("T_01", classDeclaration, className, true, Modifier.Keyword.PUBLIC, true); + IDLMethodParser.generateFieldName("T_02", classDeclaration, className, true, Modifier.Keyword.PUBLIC, true); + IDLMethodParser.generateFieldName("T_03", classDeclaration, className, true, Modifier.Keyword.PUBLIC, true); + } } - - return compilationUnit; + // Hack to inject internal dependencies + return StaticJavaParser.parse(compilationUnit.toString()); } @Override @@ -308,6 +336,7 @@ public void onParserComplete(JParser jParser, ArrayList parserItems boolean skipUnit = false; if(!JParser.CREATE_IDL_HELPER) { + //TODO implement better class renaming // Hack to look for idl classes that was generated with the main lib ArrayList baseIDLClasses = getBaseIDLClasses(); for(String baseIDLClass : baseIDLClasses) { @@ -329,8 +358,158 @@ public void onParserComplete(JParser jParser, ArrayList parserItems } } } + + // Add additional method to call natives + makeNativesPublic(parserItems); + } + + private void makeNativesPublic(ArrayList parserItems) { + for(int i = 0; i < parserItems.size(); i++) { + JParserItem parserItem = parserItems.get(i); + String className = parserItem.className; + IDLClass idlClass = idlReader.getClass(className); + if(idlClass != null && idlClass.idlSkip) { + continue; + } + + CompilationUnit unit = parserItem.unit; + List classDeclarations = unit.findAll(ClassOrInterfaceDeclaration.class); + + for(int i1 = 0; i1 < classDeclarations.size(); i1++) { + ClassOrInterfaceDeclaration classDeclaration = classDeclarations.get(i1); + + ArrayList> pairList = new ArrayList<>(); + + List methodCalls = classDeclaration.findAll(MethodCallExpr.class); + + for(int i2 = 0; i2 < methodCalls.size(); i2++) { + MethodCallExpr methodCallExpr = methodCalls.get(i2); + + try { + ResolvedMethodDeclaration resolve = methodCallExpr.resolve(); + if(resolve instanceof JavaParserMethodDeclaration) { + JavaParserMethodDeclaration jpmd = (JavaParserMethodDeclaration)resolve; + MethodDeclaration nativeMethod = jpmd.getWrappedNode(); + if(nativeMethod.isNative()) { + Node node = methodCallExpr.getParentNode().get(); + while(node != null) { + if(node instanceof MethodDeclaration) { + MethodDeclaration callMethod = (MethodDeclaration)node; + pairList.add(new Pair<>(callMethod, nativeMethod)); + break; + } + else if(node instanceof ConstructorDeclaration) { + pairList.add(new Pair<>(null, nativeMethod)); + break; + } + Optional parentNode = node.getParentNode(); + node = parentNode.orElse(null); + } + } + } + } catch(Throwable t) { + } + } + + for(int i2 = 0; i2 < pairList.size(); i2++) { + Pair pair = pairList.get(i2); + MethodDeclaration methodDeclaration = pair.a; + MethodDeclaration nativeMethod = pair.b; + duplicateNativeMethodToLong(classDeclaration, methodDeclaration, nativeMethod); + } + } + } } + private void duplicateNativeMethodToLong(ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, MethodDeclaration nativeMethod) { + // Because all native code convert int to long. If it's called from outside the library teavm will give errors. + // This is to duplicate all native code method to keep the long address parameters. + + MethodDeclaration clone = nativeMethod.clone(); + clone.getAnnotations().clear(); + clone.removeModifier(Modifier.Keyword.NATIVE); + clone.removeModifier(Modifier.Keyword.PRIVATE); + clone.removeModifier(Modifier.Keyword.STATIC); + clone.addModifier(Modifier.Keyword.PUBLIC); + clone.addModifier(Modifier.Keyword.STATIC); + clone.removeComment(); + NodeList parameters = clone.getParameters(); + int paramSize = parameters.size(); + for(int i1 = 0; i1 < paramSize; i1++) { + Parameter parameter = parameters.get(i1); + String paramName = parameter.getNameAsString(); + if(paramName.endsWith("_addr")) { + parameter.setType(PrimitiveType.longType()); + } + } + if(!clone.getNameAsString().contains(IDLMethodParser.NATIVE_METHOD)) { + return; + } + String newName = clone.getNameAsString().replace(IDLMethodParser.NATIVE_METHOD, "native_"); + clone.setName(newName); + + String returnStr = "\t"; + + if(methodDeclaration == null) { + // Is constructor + Type type = nativeMethod.getType(); + if(JParserHelper.isLong(type)) { + returnStr += "return "; + clone.setType(PrimitiveType.longType()); + } + } + else { + Type type = methodDeclaration.getType(); + if(type.isClassOrInterfaceType() && !nativeMethod.isClassOrInterfaceDeclaration()) { + returnStr += "return "; + clone.setType(PrimitiveType.longType()); + } + else if(!type.isVoidType()) { + returnStr += "return "; + } + } + String methodStr = getMethodStr(nativeMethod, paramSize, parameters); + String body = "{\n"; + body += returnStr; + body += methodStr; + body += "\n}"; + + BodyDeclaration bodyDeclaration = StaticJavaParser.parseBodyDeclaration(body); + InitializerDeclaration initializerDeclaration = (InitializerDeclaration)bodyDeclaration; + clone.setBody(initializerDeclaration.getBody()); + + NodeList parameters1 = clone.getParameters(); + String[] param = new String[parameters1.size()]; + for(int i = 0; i < parameters1.size(); i++) { + Parameter parameter = parameters1.get(i); + String nameAsString = parameter.getType().asString(); + param[i] = nameAsString; + } + List methodsBySignature = classDeclaration.getMethodsBySignature(clone.getNameAsString(), param); + if(methodsBySignature.isEmpty()) { + classDeclaration.addMember(clone); + } + } + + private static String getMethodStr(MethodDeclaration nativeMethod, int paramSize, NodeList parameters) { + String methodStr = nativeMethod.getNameAsString(); + String params = ""; + for(int i1 = 0; i1 < paramSize; i1++) { + String comma = ""; + if(i1 < paramSize - 1) { + comma = ", "; + } + Parameter parameter = parameters.get(i1); + String paramName = parameter.getNameAsString(); + params += paramName; + params += comma; + } + + methodStr += "(" + params + ");"; + return methodStr; + } + + private static void addImport(JParser jParser, CompilationUnit unit, Type elementType) { if(elementType.isClassOrInterfaceType()) { if(!JParserHelper.addMissingImportType(jParser, unit, elementType)) { diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLConstructorParser.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLConstructorParser.java index f47ca0c1..5832473b 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLConstructorParser.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLConstructorParser.java @@ -26,9 +26,17 @@ public class IDLConstructorParser { public static void generateConstructor(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLClass idlClass) { ArrayList constructors = idlClass.constructors; - for(int i = 0; i < constructors.size(); i++) { - IDLConstructor idlConstructor = constructors.get(i); - generateConstructor(idlParser, jParser, unit, classOrInterfaceDeclaration, idlConstructor); + if(idlClass.callbackImpl == null) { + // Generate constructors only if it's not callback + for(int i = 0; i < constructors.size(); i++) { + IDLConstructor idlConstructor = constructors.get(i); + ConstructorDeclaration constructorDeclaration = IDLConstructorParser.getOrCreateConstructorDeclaration(idlParser, jParser, unit, classOrInterfaceDeclaration, idlConstructor); + + if(constructorDeclaration.getBody().isEmpty()) { + MethodDeclaration nativeMethod = IDLConstructorParser.setupConstructor(idlConstructor, classOrInterfaceDeclaration, constructorDeclaration); + idlParser.onIDLConstructorGenerated(jParser, idlConstructor, classOrInterfaceDeclaration, constructorDeclaration, nativeMethod); + } + } } // All classes contain a temp constructor so temp objects can be reused @@ -40,6 +48,8 @@ public static void generateConstructor(IDLDefaultCodeParser idlParser, JParser j ConstructorDeclaration constructorDeclaration = classDeclaration.addConstructor(Modifier.Keyword.PUBLIC); constructorDeclaration.addParameter("byte", "b"); constructorDeclaration.addParameter("char", "c"); + constructorDeclaration.addAnnotation(Deprecated.class); + constructorDeclaration.setJavadocComment("Dummy constructor, used internally to creates objects without C++ pointer"); } } @@ -48,7 +58,7 @@ public static void generateConstructor(IDLDefaultCodeParser idlParser, JParser j } } - private static void addSuperTempConstructor(ClassOrInterfaceDeclaration classDeclaration, ConstructorDeclaration constructorDeclaration) { + public static void addSuperTempConstructor(ClassOrInterfaceDeclaration classDeclaration, ConstructorDeclaration constructorDeclaration) { Optional parent = classDeclaration.getExtendedTypes().getFirst(); String parentName = ""; if(parent.isPresent()) { @@ -70,31 +80,42 @@ private static void addSuperTempConstructor(ClassOrInterfaceDeclaration classDec } } - private static void generateConstructor(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLConstructor idlConstructor) { + public static ConstructorDeclaration getOrCreateConstructorDeclaration(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLConstructor idlConstructor) { ConstructorDeclaration constructorDeclaration = containsConstructor(classOrInterfaceDeclaration, idlConstructor); if(constructorDeclaration == null) { constructorDeclaration = classOrInterfaceDeclaration.addConstructor(Modifier.Keyword.PUBLIC); ArrayList parameters = idlConstructor.parameters; for(int i = 0; i < parameters.size(); i++) { IDLParameter parameter = parameters.get(i); - String paramType = parameter.type; + String paramType = parameter.getJavaType(); paramType = IDLHelper.convertEnumToInt(idlParser.idlReader, paramType); JParserHelper.addMissingImportType(jParser, unit, paramType); constructorDeclaration.addAndGetParameter(paramType, parameter.name); } } - - if(constructorDeclaration.getBody().isEmpty()) { - setupConstructor(idlParser, jParser, idlConstructor, classOrInterfaceDeclaration, constructorDeclaration); - } + return constructorDeclaration; } - private static void setupConstructor(IDLDefaultCodeParser idlParser, JParser jParser, IDLConstructor idlConstructor, ClassOrInterfaceDeclaration classDeclaration, ConstructorDeclaration constructorDeclaration) { + public static MethodDeclaration setupConstructor(IDLConstructor idlConstructor, ClassOrInterfaceDeclaration classDeclaration, ConstructorDeclaration constructorDeclaration) { NodeList parameters = constructorDeclaration.getParameters(); Type type = StaticJavaParser.parseType(classDeclaration.getNameAsString()); - boolean isStatic = true; - MethodDeclaration nativeMethod = IDLMethodParser.generateNativeMethod(false, "create", parameters, type, isStatic); + + String additionalName = ""; + + // Constructor needs to have type in the name because there are some cases that multiple + // parameters with different type will skip creating this native method if they are equal. + // Since the parameters object is converter to long. It's impossible to override multiple methods + // with the same pointers type. + // TODO maybe add parameter type in all native method names. + for(int i = 0; i < parameters.size(); i++) { + Parameter parameter = parameters.get(i); + String typeName = parameter.getType().toString(); + additionalName += "_" + typeName; + } + + String methodName = "create" + additionalName; + MethodDeclaration nativeMethod = IDLMethodParser.generateNativeMethod(methodName, parameters, type, isStatic); if(!JParserHelper.containsMethod(classDeclaration, nativeMethod)) { //Add native method if it does not exist @@ -103,27 +124,31 @@ private static void setupConstructor(IDLDefaultCodeParser idlParser, JParser jPa MethodCallExpr caller = IDLMethodParser.createCaller(nativeMethod); BlockStmt blockStmt = constructorDeclaration.getBody(); + IDLMethodParser.NativeMethodData paramData = new IDLMethodParser.NativeMethodData(); + paramData.isStatic = isStatic; + IDLMethodParser.setupCallerParam(paramData, caller, parameters, idlConstructor.parameters); - IDLMethodParser.setupCallerParam(isStatic, false, caller, parameters); + String isMemoryOwned = String.valueOf(!idlConstructor.idlClass.classHeader.isNoDelete); Statement statement1 = StaticJavaParser.parseStatement("long addr = " + caller + ";"); - Statement statement2 = StaticJavaParser.parseStatement("initNative(addr, true);"); + Statement statement2 = StaticJavaParser.parseStatement("getNativeData().reset(addr, " + isMemoryOwned + ");"); blockStmt.addStatement(statement1); blockStmt.addStatement(statement2); - idlParser.onIDLConstructorGenerated(jParser, idlConstructor, classDeclaration, constructorDeclaration, nativeMethod); + return nativeMethod; } + return null; } - private static ConstructorDeclaration containsConstructor(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLConstructor idlConstructor) { + public static ConstructorDeclaration containsConstructor(ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLConstructor idlConstructor) { ArrayList parameters = idlConstructor.parameters; String[] paramTypes = new String[parameters.size()]; for(int i = 0; i < parameters.size(); i++) { IDLParameter parameter = parameters.get(i); - String paramType = parameter.type; + String paramType = parameter.getJavaType(); paramTypes[i] = paramType; } Optional constructorDeclarationOptional = classOrInterfaceDeclaration.getConstructorByParameterTypes(paramTypes); return constructorDeclarationOptional.orElse(null); } -} +} \ No newline at end of file diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDeConstructorParser.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDeConstructorParser.java index 3abb3141..24b3e209 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDeConstructorParser.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDeConstructorParser.java @@ -8,6 +8,7 @@ import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.type.PrimitiveType; import com.github.javaparser.ast.type.Type; import com.github.xpenatan.jparser.core.JParser; import com.github.xpenatan.jparser.core.JParserHelper; @@ -20,6 +21,12 @@ public class IDLDeConstructorParser { public static void generateDeConstructor(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLClass idlClass) { if(!idlClass.classHeader.isNoDelete) { + MethodDeclaration disposeMethod = classOrInterfaceDeclaration.addMethod("dispose", Modifier.Keyword.PUBLIC); + disposeMethod.getBody().get().addStatement(new MethodCallExpr("super.dispose")); + MethodDeclaration isDisposeMethod = classOrInterfaceDeclaration.addMethod("isDisposed", Modifier.Keyword.PUBLIC); + isDisposeMethod.setType(PrimitiveType.booleanType()); + isDisposeMethod.getBody().get().addStatement(new MethodCallExpr("return super.isDisposed")); + List methodsBySignature = classOrInterfaceDeclaration.getMethodsBySignature(DELETE_NATIVE); int size = methodsBySignature.size(); @@ -40,12 +47,12 @@ else if(size == 0) { if(deleteMethod != null) { NodeList parameters = deleteMethod.getParameters(); Type type = deleteMethod.getType(); - MethodDeclaration nativeMethod = IDLMethodParser.generateNativeMethod(false, DELETE_NATIVE, parameters, type, false); + MethodDeclaration nativeMethod = IDLMethodParser.generateNativeMethod(DELETE_NATIVE, parameters, type, false); if(!JParserHelper.containsMethod(classOrInterfaceDeclaration, nativeMethod)) { classOrInterfaceDeclaration.getMembers().add(nativeMethod); MethodCallExpr caller = IDLMethodParser.createCaller(nativeMethod); - caller.addArgument(IDLDefaultCodeParser.CPOINTER_METHOD); + caller.addArgument("(long)" + IDLDefaultCodeParser.CPOINTER_METHOD); BlockStmt blockStmt = deleteMethod.getBody().get(); blockStmt.addStatement(caller); idlParser.onIDLDeConstructorGenerated(jParser, idlClass, classOrInterfaceDeclaration, nativeMethod); diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDefaultCodeParser.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDefaultCodeParser.java index 5b1e7d5f..7efab6be 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDefaultCodeParser.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLDefaultCodeParser.java @@ -12,6 +12,7 @@ import com.github.javaparser.ast.stmt.BlockStmt; import com.github.javaparser.ast.stmt.ReturnStmt; import com.github.javaparser.ast.type.Type; +import com.github.javaparser.utils.Pair; import com.github.xpenatan.jparser.core.JParser; import com.github.xpenatan.jparser.core.JParserHelper; import com.github.xpenatan.jparser.core.codeparser.CodeParserItem; @@ -36,7 +37,8 @@ public class IDLDefaultCodeParser extends IDLClassGeneratorParser { protected boolean enableAttributeParsing = true; - protected static final String CPOINTER_METHOD = "getCPointer()"; + protected static final String CPOINTER_METHOD = "getNativeData().getCPointer()"; + protected static final String CPOINTER_ARRAY_METHOD = "getPointer()"; public IDLDefaultCodeParser(String headerCMD, IDLReader idlReader, String cppDir) { super("", headerCMD, idlReader, cppDir); @@ -80,6 +82,7 @@ public void onParseClassStart(JParser jParser, CompilationUnit unit, ClassOrInte if(headerCommands != null) { if(headerCommands.contains(IDLDefaultCodeParser.CMD_IDL_SKIP)) { //If skip is found then remove the method + idlClass.idlSkip = true; return; } } @@ -103,6 +106,13 @@ public void onParseClassStart(JParser jParser, CompilationUnit unit, ClassOrInte IDLAttributeParser.generateAttribute(this, jParser, unit, classOrInterfaceDeclaration, idlClass, idlAttribute); } } + + if(generateClass) { + if(idlClass.callbackImpl != null) { + IDLCallbackParser.generateCallback(this, jParser, unit, classOrInterfaceDeclaration, idlClass); + } + + } } else { if(generateClass) { @@ -120,7 +130,7 @@ public static void setDefaultReturnValues(JParser jParser, CompilationUnit unit, BlockStmt blockStmt = idlMethodDeclaration.getBody().get(); ReturnStmt returnStmt = new ReturnStmt(); if(returnType.isPrimitiveType()) { - if(JParserHelper.isLong(returnType) || JParserHelper.isInt(returnType) || JParserHelper.isFloat(returnType) || JParserHelper.isDouble(returnType)) { + if(JParserHelper.isLong(returnType) || JParserHelper.isInt(returnType) || JParserHelper.isFloat(returnType) || JParserHelper.isDouble(returnType) || JParserHelper.isShort(returnType)) { NameExpr returnNameExpr = new NameExpr(); returnNameExpr.setName("0"); returnStmt.setExpression(returnNameExpr); @@ -156,6 +166,9 @@ public void onIDLAttributeGenerated(JParser jParser, IDLAttribute idlAttribute, public void onIDLEnumMethodGenerated(JParser jParser, IDLEnum idlEnum, ClassOrInterfaceDeclaration classDeclaration, String enumStr, FieldDeclaration fieldDeclaration, MethodDeclaration nativeMethodDeclaration) { } + public void onIDLCallbackGenerated(JParser jParser, IDLClass idlClass, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration callbackDeclaration, ArrayList>> methods) { + } + public String getIDLMethodName(String name) { return name; } diff --git a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLMethodParser.java b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLMethodParser.java index 92841520..9bf83e26 100644 --- a/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLMethodParser.java +++ b/jParser/idl/src/main/java/com/github/xpenatan/jparser/idl/parser/IDLMethodParser.java @@ -36,21 +36,30 @@ public class IDLMethodParser { + public static final String NATIVE_METHOD = "internal_native_"; + static final String GET_OBJECT_TEMPLATE = "{\n" + " long pointer = [METHOD];\n" + " if(pointer == 0) return null;\n" + " if([TYPE]_TEMP_GEN_[NUM] == null) [TYPE]_TEMP_GEN_[NUM] = new [TYPE]((byte)1, (char)1);\n" + - " [TYPE]_TEMP_GEN_[NUM].setCPointer(pointer);\n" + + " [TYPE]_TEMP_GEN_[NUM].getNativeData().reset(pointer, false);\n" + " return [TYPE]_TEMP_GEN_[NUM];\n" + "}"; - static final String GET_TEMP_OBJECT_TEMPLATE = + static final String GET_NEW_OBJECT_TEMPLATE = "{\n" + - " [METHOD];\n" + - " return [TYPE]_TEMP_GEN_[NUM];\n" + + " long pointer = [METHOD];\n" + + " if(pointer == 0) return null;\n" + + " [TYPE] [TYPE]_NEW = new [TYPE]((byte)1, (char)1);\n" + + " [TYPE]_NEW.getNativeData().reset(pointer, [MEM_OWNED]);\n" + + " return [TYPE]_NEW;\n" + "}"; + static final String CALLBACK_PARAM_TEMPLATE = + "if([TYPE]_TEMP_GEN_[NUM] == null) [TYPE]_TEMP_GEN_[NUM] = new [TYPE]((byte)1, (char)1);\n" + + "[TYPE]_TEMP_GEN_[NUM].getNativeData().reset([PARAM], false);\n"; + static final String OPERATOR_OBJECT_TEMPLATE = "{\n" + " [METHOD];\n" + @@ -62,25 +71,36 @@ public class IDLMethodParser { static final String TEMPLATE_TAG_METHOD = "[METHOD]"; + static final String TEMPLATE_TAG_PARAM = "[PARAM]"; + static final String TEMPLATE_TAG_TYPE = "[TYPE]"; static final String TEMPLATE_TAG_NUM = "[NUM]"; + static final String TEMPLATE_TAG_MEM_OWNED = "[MEM_OWNED]"; + public static void generateMethod(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classOrInterfaceDeclaration, IDLClass idlClass, IDLMethod idlMethod) { + MethodDeclaration methodDeclaration = generateAndAddMethodOnly(idlParser, jParser, unit, classOrInterfaceDeclaration, idlMethod); + if(methodDeclaration != null && idlParser.generateClass) { + setupMethod(idlParser, jParser, idlMethod, classOrInterfaceDeclaration, methodDeclaration); + } + } + + public static MethodDeclaration generateAndAddMethodOnly(IDLDefaultCodeParser idlParser, JParser jParser, CompilationUnit unit, ClassOrInterfaceDeclaration classDeclaration, IDLMethod idlMethod) { if(idlMethod.skip) { - return; + return null; } String methodName = idlMethod.name; Type returnType = null; - MethodDeclaration containsMethod = containsMethod(idlParser, classOrInterfaceDeclaration, idlMethod); + MethodDeclaration containsMethod = containsMethod(idlParser, classDeclaration, idlMethod); if(containsMethod != null) { if(canGenerateMethod(containsMethod)) { returnType = containsMethod.getType(); } else { - return; + return null; } } @@ -89,11 +109,11 @@ public static void generateMethod(IDLDefaultCodeParser idlParser, JParser jParse String updatedMethodName = idlParser.getIDLMethodName(fixedMethodName); ArrayList parameters = idlMethod.parameters; - MethodDeclaration methodDeclaration = classOrInterfaceDeclaration.addMethod(updatedMethodName, Modifier.Keyword.PUBLIC); + MethodDeclaration methodDeclaration = classDeclaration.addMethod(updatedMethodName, Modifier.Keyword.PUBLIC); methodDeclaration.setStatic(idlMethod.isStaticMethod); for(int i = 0; i < parameters.size(); i++) { IDLParameter idlParameter = parameters.get(i); - String paramType = idlParameter.type; + String paramType = idlParameter.getJavaType(); String paramName = idlParameter.name; paramType = IDLHelper.convertEnumToInt(idlParser.idlReader, paramType); Parameter parameter = methodDeclaration.addAndGetParameter(paramType, paramName); @@ -102,15 +122,12 @@ public static void generateMethod(IDLDefaultCodeParser idlParser, JParser jParse } if(returnType == null) { - String returnTypeStr = IDLHelper.convertEnumToInt(idlParser.idlReader, idlMethod.returnType); + String returnTypeStr = IDLHelper.convertEnumToInt(idlParser.idlReader, idlMethod.getJavaReturnType()); returnType = StaticJavaParser.parseType(returnTypeStr); } methodDeclaration.setType(returnType); IDLDefaultCodeParser.setDefaultReturnValues(jParser, unit, returnType, methodDeclaration); - - if(idlParser.generateClass) { - setupMethod(idlParser, jParser, idlMethod, classOrInterfaceDeclaration, methodDeclaration); - } + return methodDeclaration; } public static boolean canGenerateMethod(MethodDeclaration containsMethod) { @@ -149,14 +166,25 @@ public static boolean canGenerateMethod(MethodDeclaration containsMethod) { } private static void setupMethod(IDLDefaultCodeParser idlParser, JParser jParser, IDLMethod idlMethod, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration) { - MethodDeclaration nativeMethodDeclaration = IDLMethodParser.prepareNativeMethod(idlMethod.isStaticMethod, idlMethod.isReturnValue, classDeclaration, methodDeclaration, idlMethod.name, idlMethod.operator); + NativeMethodData methodData = new NativeMethodData(); + methodData.isStatic = idlMethod.isStaticMethod; + methodData.isReturnValue = idlMethod.isReturnValue; + methodData.isReturnNewObject = idlMethod.isReturnNewObject; + methodData.isReturnMemoryOwned = idlMethod.isReturnMemoryOwned; + if(idlMethod.returnClassType != null && idlMethod.returnClassType.isClass()) { + IDLClass aClass = idlMethod.returnClassType.asClass(); + methodData.isNoDelete = aClass.classHeader.isNoDelete; + } + MethodDeclaration nativeMethodDeclaration = IDLMethodParser.prepareNativeMethod(methodData, classDeclaration, methodDeclaration, idlMethod.name, idlMethod.operator, idlMethod.parameters); if(nativeMethodDeclaration != null) { idlParser.onIDLMethodGenerated(jParser, idlMethod, classDeclaration, methodDeclaration, nativeMethodDeclaration); } } - public static MethodDeclaration prepareNativeMethod(boolean isStatic, boolean isReturnValue, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, String methodName, String operator) { - MethodDeclaration nativeMethodDeclaration = generateNativeMethod(isReturnValue, methodDeclaration, methodName); + public static MethodDeclaration prepareNativeMethod(NativeMethodData paramData, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, String methodName, String operator, ArrayList idlParameters) { + NodeList methodParameters = methodDeclaration.getParameters(); + Type methodReturnType = methodDeclaration.getType(); + MethodDeclaration nativeMethodDeclaration = generateNativeMethod(methodName, methodParameters, methodReturnType, methodDeclaration.isStatic()); if(!JParserHelper.containsMethod(classDeclaration, nativeMethodDeclaration)) { //Add native method if it does not exist classDeclaration.getMembers().add(nativeMethodDeclaration); @@ -164,24 +192,22 @@ public static MethodDeclaration prepareNativeMethod(boolean isStatic, boolean is MethodCallExpr caller = createCaller(nativeMethodDeclaration); - Type methodReturnType = methodDeclaration.getType(); - if(methodReturnType.isVoidType()) { // void types just call the method. - IDLMethodParser.setupCallerParam(isStatic, false, caller, methodDeclaration); + IDLMethodParser.setupCallerParam(paramData, caller, methodDeclaration.getParameters(), idlParameters); BlockStmt blockStmt = methodDeclaration.getBody().get(); blockStmt.addStatement(caller); } else if(methodReturnType.isClassOrInterfaceType()) { // Class object needs to generate some additional code. // Needs to obtain the pointer and return a temp object. - BlockStmt blockStmt = IDLMethodParser.generateTempObjects(isReturnValue, classDeclaration, methodDeclaration, nativeMethodDeclaration, caller, operator); + BlockStmt blockStmt = IDLMethodParser.generateTempObjects(paramData, classDeclaration, methodDeclaration, caller, operator, idlParameters); methodDeclaration.setBody(blockStmt); } else { // Should be a primitive return type. ReturnStmt returnStmt = IDLMethodParser.getReturnStmt(methodDeclaration); - IDLMethodParser.setupCallerParam(isStatic, false, caller, methodDeclaration); + IDLMethodParser.setupCallerParam(paramData, caller, methodDeclaration.getParameters(), idlParameters); returnStmt.setExpression(caller); } return nativeMethodDeclaration; @@ -196,31 +222,34 @@ public static MethodCallExpr createCaller(MethodDeclaration nativeMethodDeclarat return caller; } - public static void setupCallerParam(boolean isStatic, boolean isReturnValue, MethodCallExpr caller, MethodDeclaration methodDeclaration) { - NodeList methodParameters = methodDeclaration.getParameters(); - setupCallerParam(isStatic, isReturnValue, caller, methodParameters); - } - - public static void setupCallerParam(boolean isStatic, boolean isReturnValue, MethodCallExpr caller, NodeList methodParameters) { - if(!isStatic) { - caller.addArgument(IDLDefaultCodeParser.CPOINTER_METHOD); + public static void setupCallerParam(NativeMethodData paramData, MethodCallExpr caller, NodeList methodParameters, ArrayList idlParameters) { + if(!paramData.isStatic) { + caller.addArgument("(long)" + IDLDefaultCodeParser.CPOINTER_METHOD); } - for(int i = 0; i < methodParameters.size(); i++) { Parameter parameter = methodParameters.get(i); + IDLParameter idlParameter = null; + if(idlParameters != null) { + idlParameter = idlParameters.get(i); + } Type type = parameter.getType(); SimpleName name = parameter.getName(); String variableName = name.getIdentifier(); String paramName = parameter.getNameAsString(); if(type.isClassOrInterfaceType()) { - if(IDLHelper.getCArray(type.asClassOrInterfaceType().getNameAsString()) != null) { - String methodCall = paramName + ".getPointer()"; - paramName = "(" + variableName + " != null ? " + methodCall + " : 0)"; + boolean isArray = true; + if(idlParameter != null) { + //TODO create IDLParameter when is comming from attribute + isArray = idlParameter.isArray; + } + if(isArray && IDLHelper.getCArray(type.asClassOrInterfaceType().getNameAsString()) != null) { + String methodCall = paramName + "." + IDLDefaultCodeParser.CPOINTER_ARRAY_METHOD; + paramName = "(long)(" + variableName + " != null ? " + methodCall + " : 0)"; } else if(!IDLHelper.isString(type.asClassOrInterfaceType())) { //All methods must contain a base class to get its pointer - String methodCall = paramName + ".getCPointer()"; - paramName = "(" + variableName + " != null ? " + methodCall + " : 0)"; + String methodCall = paramName + "." + IDLDefaultCodeParser.CPOINTER_METHOD; + paramName = "(long)(" + variableName + " != null ? " + methodCall + " : 0)"; } } else if(type.isArrayType()) { @@ -231,26 +260,26 @@ else if(type.isArrayType()) { } } - public static BlockStmt generateTempObjects(boolean isReturnValue, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, MethodDeclaration nativeMethodDeclaration, MethodCallExpr caller, String operator) { + private static BlockStmt generateTempObjects(NativeMethodData paramData, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration methodDeclaration, MethodCallExpr caller, String operator, ArrayList idlParameters) { Type methodReturnType = methodDeclaration.getType(); String className = classDeclaration.getNameAsString(); String returnTypeName = methodReturnType.toString(); String newBody = null; boolean isStatic = methodDeclaration.isStatic(); - boolean isRetSameAsClass = false; + boolean isReturnMemOwned = paramData.isReturnMemoryOwned; + if(paramData.isNoDelete) { + // When NoDelete it means that the library is responsible to delete it. + isReturnMemOwned = false; + } - if(!operator.isEmpty() && className.equals(returnTypeName)) { + if(!operator.isEmpty() && className.equals(returnTypeName) && !paramData.isReturnValue) { // is pointer or ref // if its operator and return type is same as class name don't create temp object isRetSameAsClass = true; } - String fieldName = ""; - if(!isRetSameAsClass) { - fieldName = generateFieldName(classDeclaration, returnTypeName, isStatic); - } - IDLMethodParser.setupCallerParam(isStatic, isReturnValue, caller, methodDeclaration); + IDLMethodParser.setupCallerParam(paramData, caller, methodDeclaration.getParameters(), idlParameters); String methodCaller = caller.toString(); @@ -259,10 +288,19 @@ public static BlockStmt generateTempObjects(boolean isReturnValue, ClassOrInterf .replace(TEMPLATE_TAG_METHOD, methodCaller); } else { - newBody = GET_OBJECT_TEMPLATE - .replace(TEMPLATE_TAG_METHOD, methodCaller) - .replace(TEMPLATE_TEMP_FIELD, fieldName) - .replace(TEMPLATE_TAG_TYPE, returnTypeName); + if(paramData.isReturnNewObject) { + newBody = GET_NEW_OBJECT_TEMPLATE + .replace(TEMPLATE_TAG_METHOD, methodCaller) + .replace(TEMPLATE_TAG_MEM_OWNED, String.valueOf(isReturnMemOwned)) + .replace(TEMPLATE_TAG_TYPE, returnTypeName); + } + else { + String fieldName = generateFieldName(classDeclaration, returnTypeName, isStatic);; + newBody = GET_OBJECT_TEMPLATE + .replace(TEMPLATE_TAG_METHOD, methodCaller) + .replace(TEMPLATE_TEMP_FIELD, fieldName) + .replace(TEMPLATE_TAG_TYPE, returnTypeName); + } } BlockStmt body = null; @@ -278,7 +316,7 @@ public static BlockStmt generateTempObjects(boolean isReturnValue, ClassOrInterf return body; } - private static String generateFieldName(ClassOrInterfaceDeclaration classDeclaration, String fieldType, boolean isStatic) { + public static String generateFieldName(ClassOrInterfaceDeclaration classDeclaration, String fieldType, boolean isStatic) { // Will return a temp object. // Java variable will be created by checking its class, name and number. // if the temp object already exist it will increment variable number and create it. @@ -331,19 +369,12 @@ private static String getFieldName(String type, int number, boolean isStatic) { } } - private static MethodDeclaration generateNativeMethod(boolean isReturnValue, MethodDeclaration methodDeclaration, String methodName) { - NodeList methodParameters = methodDeclaration.getParameters(); - Type methodReturnType = methodDeclaration.getType(); - boolean isStatic = methodDeclaration.isStatic(); - return generateNativeMethod(isReturnValue, methodName, methodParameters, methodReturnType, isStatic); - } - - public static MethodDeclaration generateNativeMethod(boolean isReturnValue, String methodName, NodeList methodParameters, Type methodReturnType, boolean isStatic) { + public static MethodDeclaration generateNativeMethod(String methodName, NodeList methodParameters, Type methodReturnType, boolean isStatic) { boolean isClassOrInterfaceType = methodReturnType.isClassOrInterfaceType(); // Clone some generated idl method settings MethodDeclaration nativeMethod = new MethodDeclaration(); - nativeMethod.setName(methodName + "NATIVE"); + nativeMethod.setName(NATIVE_METHOD + methodName); nativeMethod.setModifiers(Modifier.createModifierList(Modifier.Keyword.PRIVATE, Modifier.Keyword.STATIC, Modifier.Keyword.NATIVE)); nativeMethod.removeBody(); @@ -395,7 +426,7 @@ private static MethodDeclaration containsMethod(IDLDefaultCodeParser idlParser, for(int i = 0; i < parameters.size(); i++) { IDLParameter parameter = parameters.get(i); - String paramType = parameter.type; + String paramType = parameter.getJavaType(); paramType = IDLHelper.convertEnumToInt(idlParser.idlReader, paramType); paramTypes[i] = paramType; } @@ -430,4 +461,11 @@ private static MethodDeclaration containsMethod(IDLDefaultCodeParser idlParser, return null; } + public static class NativeMethodData { + public boolean isStatic; + public boolean isReturnValue; + public boolean isReturnNewObject; + public boolean isReturnMemoryOwned; + public boolean isNoDelete; + } } diff --git a/jParser/idl/src/test/java/com/github/xpenatan/jparser/idl/IDLReaderTest.java b/jParser/idl/src/test/java/com/github/xpenatan/jparser/idl/IDLReaderTest.java index 95b98e68..17be7d6d 100644 --- a/jParser/idl/src/test/java/com/github/xpenatan/jparser/idl/IDLReaderTest.java +++ b/jParser/idl/src/test/java/com/github/xpenatan/jparser/idl/IDLReaderTest.java @@ -10,6 +10,16 @@ public class IDLReaderTest { public static void setUp() throws Exception { } + @Test + public void test_getTag() { + String tag1 = "[Const, Value] readonly attribute Vec3 mDirection;"; + String tag2= "[Value] attribute SoftBodySharedSettingsSkinWeight[] mWeights;"; + String test1 = IDLHelper.getTags(tag1); + String test2 = IDLHelper.getTags(tag2); + Assert.assertEquals("[Const, Value]", test1); + Assert.assertEquals("[Value]", test2); + } + @Test public void test_NoDeleteClassTest_not_null() { IDLReader idlReader = IDLReader.readIDL("src\\test\\resources\\idl\\Test.idl"); @@ -39,24 +49,24 @@ public void test_NoDeleteClassTest_attributes() { Assert.assertEquals("ReadOnlyInt", idlAttribute.name); Assert.assertTrue(idlClass.attributes.get(0).isStatic); Assert.assertTrue(idlClass.attributes.get(0).isReadOnly); - Assert.assertEquals("int", idlClass.attributes.get(0).type); + Assert.assertEquals("unsigned long", idlClass.attributes.get(0).idlType); Assert.assertTrue(idlClass.attributes.get(1).isConst); Assert.assertEquals("constNormalClass", idlClass.attributes.get(1).name); - Assert.assertEquals("NormalClassTest", idlClass.attributes.get(1).type); + Assert.assertEquals("NormalClassTest", idlClass.attributes.get(1).idlType); Assert.assertEquals("valueNormalClass", idlClass.attributes.get(2).name); Assert.assertTrue(idlClass.attributes.get(2).isValue); - Assert.assertEquals("NormalClassTest", idlClass.attributes.get(2).type); + Assert.assertEquals("NormalClassTest", idlClass.attributes.get(2).idlType); Assert.assertEquals("floatAttribute", idlClass.attributes.get(3).name); - Assert.assertEquals("float", idlClass.attributes.get(3).type); - Assert.assertEquals("NormalClassTest", idlClass.attributes.get(2).type); + Assert.assertEquals("float", idlClass.attributes.get(3).idlType); + Assert.assertEquals("NormalClassTest", idlClass.attributes.get(2).idlType); Assert.assertEquals("boolAttribute", idlClass.attributes.get(4).name); - Assert.assertEquals("boolean", idlClass.attributes.get(4).type); + Assert.assertEquals("boolean", idlClass.attributes.get(4).idlType); Assert.assertEquals("arrayBoolean", idlClass.attributes.get(6).name); - Assert.assertEquals("boolean[]", idlClass.attributes.get(6).type); + Assert.assertEquals("boolean[]", idlClass.attributes.get(6).idlType); Assert.assertEquals("arrayInt", idlClass.attributes.get(7).name); - Assert.assertEquals("int[]", idlClass.attributes.get(7).type); + Assert.assertEquals("unsigned long[]", idlClass.attributes.get(7).idlType); Assert.assertEquals("anyObject", idlClass.attributes.get(8).name); - Assert.assertEquals("any", idlClass.attributes.get(8).type); + Assert.assertEquals("any", idlClass.attributes.get(8).idlType); Assert.assertTrue(idlClass.attributes.get(8).isAny); } @@ -67,17 +77,17 @@ public void test_NoDeleteClassTest_methods() { IDLMethod idlMethod = idlClass.methods.get(1); Assert.assertEquals("getExtendClass", idlMethod.name); Assert.assertEquals("ExtendClassTest", idlMethod.returnType); - Assert.assertEquals("float", idlMethod.parameters.get(0).type); - Assert.assertEquals("int", idlMethod.parameters.get(1).type); - Assert.assertEquals("NormalClassTest", idlMethod.parameters.get(2).type); + Assert.assertEquals("float", idlMethod.parameters.get(0).idlType); + Assert.assertEquals("long", idlMethod.parameters.get(1).idlType); + Assert.assertEquals("NormalClassTest", idlMethod.parameters.get(2).idlType); Assert.assertEquals("normalClass", idlMethod.parameters.get(2).name); - Assert.assertEquals("IDLFloatArray", idlMethod.parameters.get(3).type); + Assert.assertEquals("float[]", idlMethod.parameters.get(3).idlType); Assert.assertTrue(idlMethod.parameters.get(3).isArray); Assert.assertEquals("vertices", idlMethod.parameters.get(3).name); Assert.assertTrue(idlMethod.parameters.get(2).isRef); Assert.assertTrue(idlMethod.parameters.get(2).isConst); IDLMethod flagsMethod = idlClass.getMethod("GetFlags"); - Assert.assertEquals("int", flagsMethod.returnType); + Assert.assertEquals("unsigned long", flagsMethod.returnType); IDLMethod copyNormalClassMethod = idlClass.getMethod("copyNormalClass"); Assert.assertTrue(copyNormalClassMethod.isReturnRef); Assert.assertEquals("=", copyNormalClassMethod.operator); diff --git a/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java b/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java index 0932a88f..574033b3 100644 --- a/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java +++ b/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java @@ -4,38 +4,27 @@ public class JParserLibraryLoader { - private final SharedLibraryLoader loader; + private static final SharedLibraryLoader loader = new SharedLibraryLoader(); - public JParserLibraryLoader() { - loader = new SharedLibraryLoader(); - } - - public JParserLibraryLoader(String nativesJar) { - loader = new SharedLibraryLoader(nativesJar); - } + private JParserLibraryLoader() {} - public void load(String libraryName) { - loadInternal(libraryName, null); - } - - public void load(String libraryName, JParserLibraryLoaderListener listener) { + public static void load(String libraryName, JParserLibraryLoaderListener listener) { loadInternal(libraryName, listener); } - public void loadInternal(String libraryName, JParserLibraryLoaderListener listener) { - if(listener != null) { - new Thread(() -> { - try { - loader.load(libraryName); - listener.onLoad(true); - } - catch(Exception e) { - listener.onLoad(false); - } - }).start(); - } - else { - loader.load(libraryName); + private static void loadInternal(String libraryName, JParserLibraryLoaderListener listener) { + if(listener == null) { + throw new RuntimeException("Should implement listener"); } + new Thread(() -> { + try { + loader.load(libraryName); + listener.onLoad(true, null); + } + catch(Exception e) { + e.printStackTrace(); + listener.onLoad(false, e); + } + }).start(); } } diff --git a/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoaderListener.java b/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoaderListener.java index fc48f4b7..378cfa7d 100644 --- a/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoaderListener.java +++ b/jParser/loader/loader-core/src/main/java/com/github/xpenatan/jparser/loader/JParserLibraryLoaderListener.java @@ -1,5 +1,5 @@ package com.github.xpenatan.jparser.loader; public interface JParserLibraryLoaderListener { - void onLoad(boolean isSuccess); + void onLoad(boolean isSuccess, Exception e); } \ No newline at end of file diff --git a/jParser/loader/loader-teavm/build.gradle.kts b/jParser/loader/loader-teavm/build.gradle.kts index ef864dc9..6c7c5734 100644 --- a/jParser/loader/loader-teavm/build.gradle.kts +++ b/jParser/loader/loader-teavm/build.gradle.kts @@ -5,8 +5,8 @@ plugins { val moduleName = "loader-teavm" dependencies { - api("com.badlogicgames.gdx:gdx-jnigen-loader:${LibExt.jniGenVersion}") implementation(project(":jParser:loader:loader-core")) + implementation("org.teavm:teavm-jso:${LibExt.teaVMVersion}") implementation("com.github.xpenatan.gdx-teavm:asset-loader:${LibExt.gdxTeaVMVersion}") } diff --git a/jParser/loader/loader-teavm/src/main/java/emu/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java b/jParser/loader/loader-teavm/src/main/java/emu/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java index ca566f78..2f999ec1 100644 --- a/jParser/loader/loader-teavm/src/main/java/emu/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java +++ b/jParser/loader/loader-teavm/src/main/java/emu/com/github/xpenatan/jparser/loader/JParserLibraryLoader.java @@ -1,49 +1,77 @@ package emu.com.github.xpenatan.jparser.loader; +import com.github.xpenatan.gdx.backends.teavm.assetloader.AssetInstance; import com.github.xpenatan.gdx.backends.teavm.assetloader.AssetLoader; import com.github.xpenatan.gdx.backends.teavm.assetloader.AssetLoaderListener; import com.github.xpenatan.jparser.loader.JParserLibraryLoaderListener; import java.util.HashSet; +import javax.script.ScriptException; +import org.teavm.jso.JSBody; +import org.teavm.jso.JSFunctor; public class JParserLibraryLoader { private static HashSet loadedLibraries = new HashSet<>(); - public JParserLibraryLoader() { - } - - public void load(String libraryName) { - loadInternal(libraryName, null); - } + private JParserLibraryLoader() {} - public void load(String libraryName, JParserLibraryLoaderListener listener) { + public static void load(String libraryName, JParserLibraryLoaderListener listener) { loadInternal(libraryName, listener); } - public void loadInternal(String libraryName, JParserLibraryLoaderListener listener) { - if(!libraryName.endsWith(".js")) { - libraryName = libraryName + ".js"; + private static void loadInternal(final String libraryName, JParserLibraryLoaderListener listener) { + if(listener == null) { + throw new RuntimeException("Should implement listener"); } if(loadedLibraries.contains(libraryName)) { return; } - loadedLibraries.add(libraryName); - AssetLoader.AssetLoad instance = AssetLoader.getInstance(); - if(listener != null) { - instance.loadScript(true, libraryName, new AssetLoaderListener<>(){ - @Override - public void onSuccess(String url, String result) { - listener.onLoad(true); - } - @Override - public void onFailure(String url) { - listener.onLoad(false); - } - }); - } - else { - instance.loadScript(false, libraryName, null); - } + + // Try to load wasm first + loadWasm(libraryName, listener); } + + private static void loadWasm(final String libraryName, JParserLibraryLoaderListener listener) { + AssetLoader instance = AssetInstance.getLoaderInstance(); + instance.loadScript(libraryName + ".wasm.js", new AssetLoaderListener<>() { + @Override + public void onSuccess(String url, String result) { + // Wasm requires to setup wasm first + String fullLibName = libraryName + "OnInit"; + setOnLoadInit(fullLibName, () -> { + loadedLibraries.add(libraryName); + listener.onLoad(true, null); + }); + } + @Override + public void onFailure(String url) { + // Fallback to javascript + loadJS(libraryName, listener); + } + }); + } + + private static void loadJS(final String libraryName, JParserLibraryLoaderListener listener) { + AssetLoader instance = AssetInstance.getLoaderInstance(); + instance.loadScript(libraryName + ".js", new AssetLoaderListener<>() { + @Override + public void onSuccess(String url, String result) { + loadedLibraries.add(libraryName); + listener.onLoad(true, null); + } + @Override + public void onFailure(String url) { + listener.onLoad(false, new ScriptException("Failed to load script: " + url)); + } + }); + } + + @JSFunctor + public interface OnInitFunction extends org.teavm.jso.JSObject { + void onInit(); + } + + @JSBody(params = { "libraryName", "onInitFunction" }, script = "window[libraryName] = onInitFunction;") + private static native void setOnLoadInit(String libraryName, OnInitFunction onInitFunction); } \ No newline at end of file diff --git a/jParser/teavm/src/main/java/com/github/xpenatan/jparser/teavm/TeaVMCodeParser.java b/jParser/teavm/src/main/java/com/github/xpenatan/jparser/teavm/TeaVMCodeParser.java index a38989e7..01249919 100644 --- a/jParser/teavm/src/main/java/com/github/xpenatan/jparser/teavm/TeaVMCodeParser.java +++ b/jParser/teavm/src/main/java/com/github/xpenatan/jparser/teavm/TeaVMCodeParser.java @@ -3,6 +3,7 @@ import com.github.javaparser.StaticJavaParser; import com.github.javaparser.ast.CompilationUnit; import com.github.javaparser.ast.ImportDeclaration; +import com.github.javaparser.ast.Modifier; import com.github.javaparser.ast.Node; import com.github.javaparser.ast.NodeList; import com.github.javaparser.ast.PackageDeclaration; @@ -12,6 +13,7 @@ import com.github.javaparser.ast.body.MethodDeclaration; import com.github.javaparser.ast.body.Parameter; import com.github.javaparser.ast.body.VariableDeclarator; +import com.github.javaparser.ast.expr.ArrayInitializerExpr; import com.github.javaparser.ast.expr.CastExpr; import com.github.javaparser.ast.expr.ConditionalExpr; import com.github.javaparser.ast.expr.EnclosedExpr; @@ -19,10 +21,20 @@ import com.github.javaparser.ast.expr.MethodCallExpr; import com.github.javaparser.ast.expr.Name; import com.github.javaparser.ast.expr.NormalAnnotationExpr; +import com.github.javaparser.ast.expr.ObjectCreationExpr; import com.github.javaparser.ast.expr.SimpleName; +import com.github.javaparser.ast.expr.StringLiteralExpr; +import com.github.javaparser.ast.expr.VariableDeclarationExpr; +import com.github.javaparser.ast.stmt.BlockStmt; +import com.github.javaparser.ast.stmt.ExpressionStmt; import com.github.javaparser.ast.type.ArrayType; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.Type; +import com.github.javaparser.resolution.types.ResolvedArrayType; +import com.github.javaparser.resolution.types.ResolvedPrimitiveType; +import com.github.javaparser.resolution.types.ResolvedReferenceType; +import com.github.javaparser.resolution.types.ResolvedType; +import com.github.javaparser.utils.Pair; import com.github.xpenatan.jparser.core.JParser; import com.github.xpenatan.jparser.core.JParserHelper; import com.github.xpenatan.jparser.core.JParserItem; @@ -33,10 +45,11 @@ import com.github.xpenatan.jparser.idl.IDLFile; import com.github.xpenatan.jparser.idl.IDLMethod; import com.github.xpenatan.jparser.idl.IDLParameter; +import com.github.xpenatan.jparser.idl.IDLReader; import com.github.xpenatan.jparser.idl.parser.IDLAttributeOperation; import com.github.xpenatan.jparser.idl.parser.IDLDefaultCodeParser; -import com.github.xpenatan.jparser.idl.IDLReader; import com.github.xpenatan.jparser.idl.parser.IDLMethodOperation; +import com.github.xpenatan.jparser.idl.parser.IDLMethodParser; import java.io.File; import java.util.ArrayList; import java.util.List; @@ -108,45 +121,88 @@ public class TeaVMCodeParser extends IDLDefaultCodeParser { "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + "return jsObj.get_[ATTRIBUTE]();"; + protected static final String ATTRIBUTE_ARRAY_GET_PRIMITIVE_TEMPLATE = + "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + + "return jsObj.get_[ATTRIBUTE](index);"; + protected static final String ATTRIBUTE_GET_PRIMITIVE_STATIC_TEMPLATE = "return [MODULE].[TYPE].prototype.get_[ATTRIBUTE]()"; + protected static final String ATTRIBUTE_ARRAY_GET_PRIMITIVE_STATIC_TEMPLATE = + "return [MODULE].[TYPE].prototype.get_[ATTRIBUTE](index)"; + protected static final String ATTRIBUTE_GET_OBJECT_POINTER_STATIC_TEMPLATE = "var returnedJSObj = [MODULE].[TYPE].prototype.get_[ATTRIBUTE]();\n" + "if(!returnedJSObj.hasOwnProperty('ptr')) return 0; \n" + "return [MODULE].getPointer(returnedJSObj);"; + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_STATIC_TEMPLATE = + "var returnedJSObj = [MODULE].[TYPE].prototype.get_[ATTRIBUTE](index);\n" + + "if(!returnedJSObj.hasOwnProperty('ptr')) return 0; \n" + + "return [MODULE].getPointer(returnedJSObj);"; + protected static final String ATTRIBUTE_GET_OBJECT_POINTER_TEMPLATE = "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + "var returnedJSObj = jsObj.get_[ATTRIBUTE]();\n" + "if(!returnedJSObj.hasOwnProperty('ptr')) return 0; \n" + "return [MODULE].getPointer(returnedJSObj);"; + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_TEMPLATE = + "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + + "var returnedJSObj = jsObj.get_[ATTRIBUTE](index);\n" + + "if(!returnedJSObj.hasOwnProperty('ptr')) return 0; \n" + + "return [MODULE].getPointer(returnedJSObj);"; + protected static final String ATTRIBUTE_SET_OBJECT_POINTER_TEMPLATE = "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + "jsObj.set_[ATTRIBUTE]([ATTRIBUTE]_addr);"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_TEMPLATE = + "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + + "jsObj.set_[ATTRIBUTE](index, [ATTRIBUTE]_addr);"; + protected static final String ATTRIBUTE_SET_OBJECT_POINTER_STATIC_TEMPLATE = "[MODULE].[TYPE].prototype.set_[ATTRIBUTE]([ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_STATIC_TEMPLATE = + "[MODULE].[TYPE].prototype.set_[ATTRIBUTE](index, [ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_SET_OBJECT_VALUE_TEMPLATE = "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + "jsObj.set_[ATTRIBUTE]([ATTRIBUTE]_addr);"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_TEMPLATE = + "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + + "jsObj.set_[ATTRIBUTE](index, [ATTRIBUTE]_addr);"; + protected static final String ATTRIBUTE_SET_OBJECT_VALUE_STATIC_TEMPLATE = "[MODULE].[TYPE].prototype.set_[ATTRIBUTE]([ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_STATIC_TEMPLATE = + "[MODULE].[TYPE].prototype.set_[ATTRIBUTE](index, [ATTRIBUTE]_addr);\n"; + protected static final String ATTRIBUTE_SET_PRIMITIVE_TEMPLATE = "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + "jsObj.set_[ATTRIBUTE]([ATTRIBUTE]);"; + protected static final String ATTRIBUTE_ARRAY_SET_PRIMITIVE_TEMPLATE = + "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].[TYPE]);\n" + + "jsObj.set_[ATTRIBUTE](index, [ATTRIBUTE]);"; + protected static final String ATTRIBUTE_SET_PRIMITIVE_STATIC_TEMPLATE = "[MODULE].[TYPE].prototype.set_[ATTRIBUTE]([ATTRIBUTE]);\n"; + protected static final String ATTRIBUTE_ARRAY_SET_PRIMITIVE_STATIC_TEMPLATE = + "[MODULE].[TYPE].prototype.set_[ATTRIBUTE](index, [ATTRIBUTE]);\n"; + protected static final String ATTRIBUTE_GET_OBJECT_VALUE_STATIC_TEMPLATE = ATTRIBUTE_GET_OBJECT_POINTER_STATIC_TEMPLATE; + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_STATIC_TEMPLATE = ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_STATIC_TEMPLATE; + protected static final String ATTRIBUTE_GET_OBJECT_VALUE_TEMPLATE = ATTRIBUTE_GET_OBJECT_POINTER_TEMPLATE; + protected static final String ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_TEMPLATE = ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_TEMPLATE; + protected static final String ENUM_GET_INT_TEMPLATE = "\nreturn [MODULE].[ENUM];\n"; @@ -208,11 +264,11 @@ private void convertJavaPrimitiveArrayToJavaScriptReferenceArray(NodeList parameters, ArrayList 0) { param += ", "; } @@ -377,7 +440,6 @@ public void onIDLAttributeGenerated(JParser jParser, IDLAttribute idlAttribute, String returnTypeName = classDeclaration.getNameAsString(); String attributeName = idlAttribute.name; - String returnType = idlAttribute.type; String param = ""; NodeList parameters = nativeMethod.getParameters(); @@ -398,43 +460,83 @@ public void onIDLAttributeGenerated(JParser jParser, IDLAttribute idlAttribute, case SET_OBJECT_VALUE: content = ATTRIBUTE_SET_OBJECT_VALUE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case SET_ARRAY_OBJECT_VALUE: + content = ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case SET_OBJECT_VALUE_STATIC: content = ATTRIBUTE_SET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case SET_ARRAY_OBJECT_VALUE_STATIC: + content = ATTRIBUTE_ARRAY_SET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case GET_OBJECT_VALUE: content = ATTRIBUTE_GET_OBJECT_VALUE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) .replace(TEMPLATE_TAG_TYPE, returnTypeName) .replace(TEMPLATE_TAG_MODULE, module); break; + case GET_ARRAY_OBJECT_VALUE: + content = ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_TYPE, returnTypeName) + .replace(TEMPLATE_TAG_MODULE, module); + break; case GET_OBJECT_VALUE_STATIC: content = ATTRIBUTE_GET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) .replace(TEMPLATE_TAG_TYPE, returnTypeName) .replace(TEMPLATE_TAG_MODULE, module); break; + case GET_ARRAY_OBJECT_VALUE_STATIC: + content = ATTRIBUTE_ARRAY_GET_OBJECT_VALUE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName) + .replace(TEMPLATE_TAG_TYPE, returnTypeName) + .replace(TEMPLATE_TAG_MODULE, module); + break; case SET_OBJECT_POINTER: content = ATTRIBUTE_SET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case SET_ARRAY_OBJECT_POINTER: + content = ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case SET_OBJECT_POINTER_STATIC: content = ATTRIBUTE_SET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case SET_ARRAY_OBJECT_POINTER_STATIC: + content = ATTRIBUTE_ARRAY_SET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case GET_OBJECT_POINTER: content = ATTRIBUTE_GET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case GET_ARRAY_OBJECT_POINTER: + content = ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case GET_OBJECT_POINTER_STATIC: content = ATTRIBUTE_GET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case GET_ARRAY_OBJECT_POINTER_STATIC: + content = ATTRIBUTE_ARRAY_GET_OBJECT_POINTER_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case SET_PRIMITIVE: content = ATTRIBUTE_SET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case SET_ARRAY_PRIMITIVE: + content = ATTRIBUTE_ARRAY_SET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case SET_PRIMITIVE_STATIC: content = ATTRIBUTE_SET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case SET_ARRAY_PRIMITIVE_STATIC: + content = ATTRIBUTE_ARRAY_SET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case GET_PRIMITIVE: content = ATTRIBUTE_GET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case GET_ARRAY_PRIMITIVE: + content = ATTRIBUTE_ARRAY_GET_PRIMITIVE_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; case GET_PRIMITIVE_STATIC: content = ATTRIBUTE_GET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); break; + case GET_ARRAY_PRIMITIVE_STATIC: + content = ATTRIBUTE_ARRAY_GET_PRIMITIVE_STATIC_TEMPLATE.replace(TEMPLATE_TAG_ATTRIBUTE, attributeName).replace(TEMPLATE_TAG_TYPE, returnTypeName).replace(TEMPLATE_TAG_MODULE, module); + break; } if(content != null) { @@ -490,6 +592,143 @@ public void onIDLEnumMethodGenerated(JParser jParser, IDLEnum idlEnum, ClassOrIn } } + @Override + public void onIDLCallbackGenerated(JParser jParser, IDLClass idlClass, ClassOrInterfaceDeclaration classDeclaration, MethodDeclaration callbackDeclaration, ArrayList>> methods) { + NodeList methodParameters = callbackDeclaration.getParameters(); + IDLClass idlCallbackClass = idlClass.callbackImpl; + String callbackClassName = idlCallbackClass.name; + Type methodReturnType = callbackDeclaration.getType(); + MethodDeclaration nativeMethodDeclaration = IDLMethodParser.generateNativeMethod(callbackDeclaration.getNameAsString(), methodParameters, methodReturnType, false); + if(!JParserHelper.containsMethod(classDeclaration, nativeMethodDeclaration)) { + NormalAnnotationExpr customAnnotation = new NormalAnnotationExpr(); + customAnnotation.setName("org.teavm.jso.JSBody"); + ArrayInitializerExpr paramsArray = new ArrayInitializerExpr(); + NodeList values = paramsArray.getValues(); + String script = "var " + callbackClassName + " = "+ module + ".wrapPointer(this_addr, " + module + "." + callbackClassName + ");"; + MethodCallExpr caller = IDLMethodParser.createCaller(nativeMethodDeclaration); + + caller.addArgument("getNativeData().getCPointer()"); + + values.add(new StringLiteralExpr("this_addr")); + for(int i = 0; i < methods.size(); i++) { + Pair> pair = methods.get(i); + IDLMethod idlMethod = pair.a; + String methodName = idlMethod.name; + values.add(new StringLiteralExpr(methodName)); + nativeMethodDeclaration.addParameter(methodName, methodName); + script += " " + callbackClassName + "." + methodName + " = " + methodName + ";"; + caller.addArgument(methodName); + } + + customAnnotation.addPair("params", paramsArray); + customAnnotation.addPair("script", new StringLiteralExpr(script)); + nativeMethodDeclaration.addAnnotation(customAnnotation); + classDeclaration.getMembers().add(nativeMethodDeclaration); + + BlockStmt callbackMethodBody = callbackDeclaration.getBody().get(); + + for(int i = 0; i < methods.size(); i++) { + Pair> pair = methods.get(i); + IDLMethod idlMethod = pair.a; + Pair methodPair = pair.b; + MethodDeclaration internalMethod = methodPair.a; + MethodDeclaration publicMethod = methodPair.b; + String internalMethodName = internalMethod.getNameAsString(); + String paramCode = ""; + String methodName = idlMethod.name; + + Type returnType = internalMethod.getType(); + String returnTypeStr = returnType.asString(); + + NodeList parameters = internalMethod.getParameters(); + createInterfaceClass(classDeclaration, methodName, returnTypeStr, parameters); + createInterfaceInstance(methodName, internalMethodName, returnTypeStr, parameters, callbackMethodBody); + } + callbackMethodBody.addStatement(caller); + } + } + + private void createInterfaceClass(ClassOrInterfaceDeclaration classDeclaration, String methodName, String returnTypeStr, NodeList parameters) { + ClassOrInterfaceDeclaration interfaceDecl = new ClassOrInterfaceDeclaration(); + interfaceDecl.setInterface(true); // Mark it as an interface + interfaceDecl.setName(methodName); + interfaceDecl.setPublic(true); // Optional, interfaces are public by default + interfaceDecl.addExtendedType("org.teavm.jso.JSObject"); + + NormalAnnotationExpr customAnnotation = new NormalAnnotationExpr(); + customAnnotation.setName("org.teavm.jso.JSFunctor"); + interfaceDecl.addAnnotation(customAnnotation); + + MethodDeclaration method = interfaceDecl.addMethod(methodName); + method.removeBody(); + method.setType(returnTypeStr); + for(int i1 = 0; i1 < parameters.size(); i1++) { + Parameter parameter = parameters.get(i1); + Type type = parameter.getType(); + String typeStr = type.asString(); + String paramName = parameter.getNameAsString(); + if(typeStr.equals("String") || JParserHelper.isLong(type)) { + typeStr = "int"; + } + method.addParameter(typeStr, paramName); + } + classDeclaration.addMember(interfaceDecl); + } + + private void createInterfaceInstance(String methodName, String internalMethodName, String returnTypeStr, NodeList parameters, BlockStmt callbackMethodBody) { + ObjectCreationExpr anonymousClass = new ObjectCreationExpr(); + anonymousClass.setType(new ClassOrInterfaceType().setName(methodName)); + + ClassOrInterfaceDeclaration anonymousBody = new ClassOrInterfaceDeclaration(); + anonymousBody.setInterface(false); // This is a class, not an interface + + // Implement onEvent method + MethodDeclaration implMethod1 = anonymousBody.addMethod(methodName, Modifier.Keyword.PUBLIC); + implMethod1.setType(returnTypeStr); + String params = ""; + int paramSize = parameters.size(); + for(int i1 = 0; i1 < paramSize; i1++) { + Parameter parameter = parameters.get(i1); + Type type = parameter.getType(); + String typeStr = type.asString(); + String paramNameOriginal = parameter.getNameAsString(); + String paramName = paramNameOriginal; + + if(typeStr.equals("String")) { + // Edge case where String need to be converted + paramName = "IDLBase.getJSString(" + paramName + ")"; + typeStr = "int"; + } + if(JParserHelper.isLong(type)) { + typeStr = "int"; + } + params += paramName; + if(i1 < paramSize-1) { + params += ", "; + } + implMethod1.addParameter(typeStr, paramNameOriginal); + } + BlockStmt body1 = new BlockStmt(); + String methodCall = internalMethodName + "(" + params + ");"; + String returnCode = ""; + if(!returnTypeStr.equals("void")) { + returnCode = "return "; + } + body1.addStatement(returnCode + methodCall); + implMethod1.setBody(body1); + + anonymousClass.setAnonymousClassBody(anonymousBody.getMembers()); + + VariableDeclarationExpr varDecl = new VariableDeclarationExpr( + new VariableDeclarator( + new ClassOrInterfaceType().setName(methodName), + methodName, + anonymousClass + ) + ); + callbackMethodBody.addStatement(new ExpressionStmt(varDecl)); + } + @Override public void onParserComplete(JParser jParser, ArrayList parserItems) { super.onParserComplete(jParser, parserItems); @@ -526,6 +765,7 @@ public void onParserComplete(JParser jParser, ArrayList parserItems boolean skipUnit = false; if(!JParser.CREATE_IDL_HELPER) { + //TODO implement better class renaming // Hack to skip the generated lib and use the main one ArrayList baseIDLClasses = getBaseIDLClasses(); for(String baseIDLClass : baseIDLClasses) { @@ -576,8 +816,6 @@ public void onParserComplete(JParser jParser, ArrayList parserItems ClassOrInterfaceDeclaration classDeclaration = classDeclarations.get(i1); convertNativeMethodLongType(classDeclaration); } - - List all = unit.findAll(MethodCallExpr.class); } } @@ -595,6 +833,7 @@ private void convertNativeMethodLongType(ClassOrInterfaceDeclaration classDeclar for(int i = 0; i < constructorDeclarations.size(); i++) { ConstructorDeclaration constructorDeclaration = constructorDeclarations.get(i); List methodCallerExprList = constructorDeclaration.findAll(MethodCallExpr.class); + NodeList constructorParameters = constructorDeclaration.getParameters(); updateLongToInt(classDeclaration, methodCallerExprList); } @@ -623,9 +862,19 @@ private void updateLongToInt(ClassOrInterfaceDeclaration classDeclaration, List< } for(int argI = 0; argI < arguments.size(); argI++) { Expression arg = arguments.get(argI); + boolean isLong = false; // used in public native methods + try { + ResolvedType resolvedType = arg.calculateResolvedType(); + if(resolvedType.isPrimitive()) { + ResolvedPrimitiveType primitive = resolvedType.asPrimitive(); + isLong = primitive.describe().equals("long"); + } + } + catch(Throwable t) { + } Parameter param = parameters.get(argI); Type type = param.getType(); - if(JParserHelper.isLong(type)) { + if(JParserHelper.isLong(type) || isLong) { Optional parentNode = arg.getParentNode(); if(parentNode.isPresent()) { Node node = parentNode.get(); @@ -655,13 +904,55 @@ private void updateLongToInt(ClassOrInterfaceDeclaration classDeclaration, List< } } - public MethodDeclaration getNativeMethod(ClassOrInterfaceDeclaration classDeclaration, MethodCallExpr methodCallExpr) { + private MethodDeclaration getNativeMethod(ClassOrInterfaceDeclaration classDeclaration, MethodCallExpr methodCallExpr) { String nativeMethodName = methodCallExpr.getNameAsString(); NodeList arguments = methodCallExpr.getArguments(); - List methodsByName = getNativeMethodsByName(classDeclaration, nativeMethodName, arguments.size(), null); + ArrayList paramTypes = new ArrayList<>(); + if(arguments.size() > 0) { + for(int i = 0; i < arguments.size(); i++) { + Expression expression = arguments.get(i); + if(expression.isMethodCallExpr() || expression.isEnclosedExpr()) { + paramTypes.add("long"); + continue; + } + else if(expression.isLambdaExpr()) { + continue; + } + ResolvedType resolvedType = null; + try { + resolvedType = expression.calculateResolvedType(); + } + catch(Throwable t) { +// t.printStackTrace(); + continue; + } + String type = null; + if(resolvedType.isPrimitive()) { + type = resolvedType.asPrimitive().describe(); + } + else if(resolvedType.isReferenceType()) { + ResolvedReferenceType referenceType1 = resolvedType.asReferenceType(); + String[] split = referenceType1.describe().split("\\."); + type = split[split.length-1]; + } + else if(resolvedType.isArray()) { + ResolvedArrayType arrayType = resolvedType.asArrayType(); + type = arrayType.describe(); + } + paramTypes.add(type); + } + } + String[] paramT = new String[paramTypes.size()]; + paramTypes.toArray(paramT); + List methodsByName = getNativeMethodsByName(classDeclaration, nativeMethodName, arguments.size(), paramT); int size = methodsByName.size(); if(size == 0) { - return null; + // The current state is not possible to get all paramT correctly. + // If method list is 0 and without passing type is 1 then use this method. + methodsByName = getNativeMethodsByName(classDeclaration, nativeMethodName, arguments.size(), null); + if(methodsByName.size() != 1) { + return null; + } } if(methodsByName.size() == 1) { MethodDeclaration methodDeclaration = methodsByName.get(0); diff --git a/settings.gradle.kts b/settings.gradle.kts index 25cee29a..c8810e7b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -25,7 +25,6 @@ include(":example:app:desktop") include(":example:app:teavm") include(":example:app:android") - //includeBuild("E:\\Dev\\Projects\\java\\gdx-teavm") { // dependencySubstitution { // substitute(module("com.github.xpenatan.gdx-teavm:backend-teavm")).using(project(":backends:backend-teavm"))