diff options
| author | Ahmed El Khazari <ahmed.el.khazari@qt.io> | 2025-01-31 16:32:06 +0200 |
|---|---|---|
| committer | Ville Voutilainen <ville.voutilainen@qt.io> | 2025-04-15 05:56:54 +0000 |
| commit | 12faa98892213c0ce55e5a967905b6905ef56e70 (patch) | |
| tree | 6943498e6dd13bfb0cb8c002982534d6bb161432 | |
| parent | 7cca383a2e354b57467df2859b38dd6262557eef (diff) | |
Integrate predefined templates into Compiler module for improved usability
Ensure the templates folder exists for proxy file generation. The
compiler module relies on this folder to function correctly. Currently,
using Jenny in an example with templates requires manually maintaining a
templates folder alongside the example. This approach is error-prone,
requires frequent updates (especially when the compiler evolves or adds
support for new languages), and negatively impacts the user experience.
To address this, predefined templates are now bundled with the compiler
module.
Additionally, users can specify a custom templates folder via
configuration, as long as it follows the same naming convention.
Task-number: QTTA-271
Change-Id: I68326aa4dbd36c0a6f236b46dbdba1d89beeb3a7
Reviewed-by: Ville Voutilainen <ville.voutilainen@qt.io>
31 files changed, 762 insertions, 0 deletions
diff --git a/compiler/src/main/resources/jte/auto_generate_notice.kte b/compiler/src/main/resources/jte/auto_generate_notice.kte new file mode 100644 index 0000000..14654ba --- /dev/null +++ b/compiler/src/main/resources/jte/auto_generate_notice.kte @@ -0,0 +1,11 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +/** +* File generated by QtJenny +* +* DO NOT EDIT THIS FILE. +* +* For bug reports, please refer to Link To QtJenny bug report page: https://bugreports.qt.io/projects/QTTA +*/ diff --git a/compiler/src/main/resources/jte/class_init_postamble.kte b/compiler/src/main/resources/jte/class_init_postamble.kte new file mode 100644 index 0000000..8127086 --- /dev/null +++ b/compiler/src/main/resources/jte/class_init_postamble.kte @@ -0,0 +1,35 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param endNamespace: String +@param cppClassName: String +@param headerOnly: Boolean +@param threadSafe: Boolean + +!{val prefix = if (headerOnly) "/*static*/ inline" else "/*static*/"} +!{val lockGuard = if (threadSafe) "std::lock_guard<std::mutex> lg(state.sInitLock);" else ""} + + state.sInited = true; + } +@if(threadSafe) + +} +@endif +#undef JENNY_CHECK_NULL + return true; +} + +${prefix} void ${cppClassName}::releaseClazz(JNIEnv* env) { + auto& state = getClassInitState(); + if (state.sInited) { + ${lockGuard} + if (state.sInited) { + env->DeleteGlobalRef(state.sClazz); + state.sClazz = nullptr; + state.sInited = false; + } + } +} + +${endNamespace} diff --git a/compiler/src/main/resources/jte/class_init_preamble.kte b/compiler/src/main/resources/jte/class_init_preamble.kte new file mode 100644 index 0000000..d4b5e9d --- /dev/null +++ b/compiler/src/main/resources/jte/class_init_preamble.kte @@ -0,0 +1,53 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param headerFileName: String +@param startOfNamespace: String +@param cppClassName: String +@param errorLoggerFunction: String +@param headerOnly: Boolean +@param threadSafe: Boolean + +@if(!headerOnly) + #include "${headerFileName}" +@endif +@if(errorLoggerFunction.isNotEmpty()) + + void ${errorLoggerFunction}(JNIEnv* env, const char* error); + +@endif +${startOfNamespace} + +!{val prefix = if (headerOnly) "/*static*/ inline" else "/*static*/"} + +${prefix} bool ${cppClassName}::initClazz(JNIEnv* env) { +#define JENNY_CHECK_NULL(val) \ + do { \ + if ((val) == nullptr) { \ +@if(errorLoggerFunction.isNotEmpty()) + + ${errorLoggerFunction}(env, "can't init ${cppClassName}::" #val);\ +@else + + env->ExceptionDescribe();\ +@endif + + return false; \ + } \ + } while(false) \ + + + auto& state = getClassInitState(); + +@if(threadSafe) + if (!state.sInited) { + std::lock_guard<std::mutex> lg(state.sInitLock); +@endif + + if (!state.sInited) { + auto clazz = env->FindClass(FULL_CLASS_NAME); + JENNY_CHECK_NULL(clazz); + state.sClazz = reinterpret_cast<jclass>(env->NewGlobalRef(clazz)); + env->DeleteLocalRef(clazz); + JENNY_CHECK_NULL(state.sClazz); diff --git a/compiler/src/main/resources/jte/constants_ids_declarations.kte b/compiler/src/main/resources/jte/constants_ids_declarations.kte new file mode 100644 index 0000000..3601a3d --- /dev/null +++ b/compiler/src/main/resources/jte/constants_ids_declarations.kte @@ -0,0 +1,14 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.ParametersProvider + +@param constants:Collection<JennyVarElement> +@param parametersProvider:ParametersProvider + +@for(constant in constants) + + ${parametersProvider.getConstexprStatement(constant)} +@endfor diff --git a/compiler/src/main/resources/jte/constructors_definitions.kte b/compiler/src/main/resources/jte/constructors_definitions.kte new file mode 100644 index 0000000..d58349f --- /dev/null +++ b/compiler/src/main/resources/jte/constructors_definitions.kte @@ -0,0 +1,24 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.utils.print +@import io.github.landerlyoung.jenny.utils.JennyNameProvider + +@param constructors:Map<JennyExecutableElement, Int> +@param parametersProvider:ParametersProvider +@param simpleClassName:String +@param returnType:String +@param useJniHelper:Boolean + +@for((constructor,count) in constructors) + !{val jniParameters = parametersProvider.getJennyElementJniParams(element = constructor,useJniHelper=useJniHelper)} + !{val javaParameters = parametersProvider.getJavaMethodParameters(constructor)} + // construct: ${constructor.modifiers.print()} ${simpleClassName}(${javaParameters}) + static ${returnType} ${constructor.name}(${jniParameters}) { + @template.method_prologue(useJniHelper = useJniHelper,isStatic = true) + return env->NewObject(${JennyNameProvider.getClassState()}, ${JennyNameProvider.getClassState(JennyNameProvider.getConstructorName(count))}${parametersProvider.getJniMethodParamVal(constructor, useJniHelper)}); + } +@endfor diff --git a/compiler/src/main/resources/jte/constructors_ids_declarations.kte b/compiler/src/main/resources/jte/constructors_ids_declarations.kte new file mode 100644 index 0000000..d6b789d --- /dev/null +++ b/compiler/src/main/resources/jte/constructors_ids_declarations.kte @@ -0,0 +1,13 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement +@import io.github.landerlyoung.jenny.utils.JennyNameProvider + +@param constructors:Map<JennyExecutableElement, Int> + +@for((constructor,count) in constructors) + + jmethodID ${JennyNameProvider.getConstructorName(count)} = nullptr; +@endfor diff --git a/compiler/src/main/resources/jte/constructors_ids_initialisations.kte b/compiler/src/main/resources/jte/constructors_ids_initialisations.kte new file mode 100644 index 0000000..24d92e6 --- /dev/null +++ b/compiler/src/main/resources/jte/constructors_ids_initialisations.kte @@ -0,0 +1,16 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement +@import io.github.landerlyoung.jenny.utils.JennyNameProvider +@import io.github.landerlyoung.jenny.utils.Signature + +@param constructors:Map<JennyExecutableElement, Int> + +@for((constructor,count) in constructors) + !{val name = "state.${JennyNameProvider.getConstructorName(count)}"} + !{val signature = Signature.getBinaryJennyElementSignature(constructor)} + ${name} = env->GetMethodID(state.sClazz, "<init>", "${signature}"); + JENNY_CHECK_NULL(${name}); +@endfor diff --git a/compiler/src/main/resources/jte/field_getter.kte b/compiler/src/main/resources/jte/field_getter.kte new file mode 100644 index 0000000..1ea705a --- /dev/null +++ b/compiler/src/main/resources/jte/field_getter.kte @@ -0,0 +1,37 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.utils.JennyNameProvider +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.needWrapLocalRef +@import io.github.landerlyoung.jenny.utils.toJniCall +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.toCamelCase +@import io.github.landerlyoung.jenny.utils.print + +@param field: JennyVarElement +@param fieldId: String +@param parametersProvider: ParametersProvider +@param useJniHelper:Boolean +@param comment:String + +!{val isStatic = field.isStatic()} +!{val classOrObj = if (isStatic) JennyNameProvider.getClassState() else "thiz"} +!{val static = if (isStatic) "Static" else "" } +!{val staticMod = if (isStatic || !useJniHelper) "static " else ""} +!{val constMod = if (isStatic || !useJniHelper) "" else " const"} +!{val parameters = parametersProvider.makeParameter(field, useJniHelper)} +!{val jniReturnType = field.type.toJniReturnTypeString()} +!{val needCast = parametersProvider.returnTypeNeedCast(jniReturnType)} +!{val cast = if (needCast) "reinterpret_cast<${jniReturnType}>(" else ""} +!{val rField = "env->Get${static}${field.type.toJniCall()}Field(${classOrObj}, ${JennyNameProvider.getClassState(fieldId)})"} +!{val needWrap = (useJniHelper && field.type.needWrapLocalRef())} +!{val jniReturn = if (needWrap) "$jniReturnType(" else ""} + ${comment} + ${staticMod}${jniReturnType} get${field.name.toCamelCase()}(${parameters}) ${constMod}{ + @template.method_prologue(useJniHelper = useJniHelper,isStatic = isStatic) + return ${jniReturn}${cast}${rField}${if(needCast) ")" else ""}${if (needWrap) ")" else ""}; + } diff --git a/compiler/src/main/resources/jte/field_setter.kte b/compiler/src/main/resources/jte/field_setter.kte new file mode 100644 index 0000000..b56e30a --- /dev/null +++ b/compiler/src/main/resources/jte/field_setter.kte @@ -0,0 +1,36 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.utils.JennyNameProvider +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.needWrapLocalRef +@import io.github.landerlyoung.jenny.utils.toJniCall +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.toCamelCase +@import io.github.landerlyoung.jenny.utils.print + +@param field: JennyVarElement +@param fieldId: String +@param parametersProvider: ParametersProvider +@param useJniHelper:Boolean +@param comment:String + +!{val isStatic = field.isStatic()} +!{val classOrObj = if (isStatic) JennyNameProvider.getClassState() else "thiz"} +!{val static = if (isStatic) "Static" else "" } +!{val staticMod = if (isStatic || !useJniHelper) "static " else ""} +!{val constMod = if (isStatic || !useJniHelper) "" else " const"} +!{val jniReturnType = field.type.toJniReturnTypeString()} +!{val fieldJniType = if (useJniHelper && field.type.needWrapLocalRef()) "::jenny::LocalRef<$jniReturnType>" else jniReturnType} +!{val parameter = parametersProvider.makeParameter(field, useJniHelper)} +!{val preparameters = if(parameter.isEmpty()) parameter else "$parameter, "} +!{val parameters = preparameters + fieldJniType+ " ${field.name}"} +!{val passedParam = if (useJniHelper && field.type.needWrapLocalRef()) "${field.name}.get()" else field.name} + ${comment} + ${staticMod}void set${field.name.toCamelCase()}(${parameters}) ${constMod}{ + @template.method_prologue(useJniHelper = useJniHelper,isStatic = isStatic) + env->Set${static}${field.type.toJniCall()}Field(${classOrObj}, ${JennyNameProvider.getClassState(fieldId)}, ${passedParam}); + } diff --git a/compiler/src/main/resources/jte/fields_definitions.kte b/compiler/src/main/resources/jte/fields_definitions.kte new file mode 100644 index 0000000..103537d --- /dev/null +++ b/compiler/src/main/resources/jte/fields_definitions.kte @@ -0,0 +1,32 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.needWrapLocalRef +@import io.github.landerlyoung.jenny.utils.print +@import io.github.landerlyoung.jenny.utils.toJniCall +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.toCamelCase +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.element.model.type.JennyKind +@import io.github.landerlyoung.jenny.utils.JennyNameProvider + + +@param useJniHelper:Boolean +@param fields:Collection<JennyVarElement> +@param hasGetter:(JennyVarElement)->Boolean +@param hasSetter:(JennyVarElement)->Boolean +@param parametersProvider: ParametersProvider +@for((index, field) in fields.withIndex()) + !{val fieldId = JennyNameProvider.getElementName(field,index) } + !{val jniComment = "// field: ${field.modifiers.print()} ${field.type.typeName} ${field.name}"} + !{val comment = if(!useJniHelper)jniComment else " // for jni helper\n $jniComment"} + @if(hasGetter(field)) + @template.field_getter(field = field, fieldId = fieldId, parametersProvider = parametersProvider, useJniHelper = useJniHelper, comment = comment) + @endif + @if(hasSetter(field)) + @template.field_setter(field = field, fieldId = fieldId, parametersProvider = parametersProvider, useJniHelper = useJniHelper, comment = comment) + @endif +@endfor diff --git a/compiler/src/main/resources/jte/fields_ids_declarations.kte b/compiler/src/main/resources/jte/fields_ids_declarations.kte new file mode 100644 index 0000000..8de1976 --- /dev/null +++ b/compiler/src/main/resources/jte/fields_ids_declarations.kte @@ -0,0 +1,13 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.utils.JennyNameProvider +@import io.github.landerlyoung.jenny.element.field.JennyVarElement + +@param fields:Collection<JennyVarElement> + +@for((index, field) in fields.withIndex()) + + jfieldID ${JennyNameProvider.getElementName(field, index)} = nullptr; +@endfor diff --git a/compiler/src/main/resources/jte/fields_ids_initialisations.kte b/compiler/src/main/resources/jte/fields_ids_initialisations.kte new file mode 100644 index 0000000..25f408a --- /dev/null +++ b/compiler/src/main/resources/jte/fields_ids_initialisations.kte @@ -0,0 +1,20 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.utils.JennyNameProvider +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.Signature + +@param fields:Collection<JennyVarElement> + +@for((index, field) in fields.withIndex()) + !{val name = "state.${JennyNameProvider.getElementName(field, index)}"} + !{val static = if (field.isStatic()) "Static" else ""} + !{val fieldName = field.name} + !{val signature = Signature.getBinaryJennyElementSignature(field)} + ${name} = env->Get${static}FieldID(state.sClazz, "${fieldName}", "${signature}"); + JENNY_CHECK_NULL(${name}); + +@endfor diff --git a/compiler/src/main/resources/jte/header_final_postamble.kte b/compiler/src/main/resources/jte/header_final_postamble.kte new file mode 100644 index 0000000..12fa60b --- /dev/null +++ b/compiler/src/main/resources/jte/header_final_postamble.kte @@ -0,0 +1,7 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param includeGuard:String + +#endif // End of ${includeGuard} diff --git a/compiler/src/main/resources/jte/header_initfunctions.kte b/compiler/src/main/resources/jte/header_initfunctions.kte new file mode 100644 index 0000000..4d0b20b --- /dev/null +++ b/compiler/src/main/resources/jte/header_initfunctions.kte @@ -0,0 +1,14 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +public: + + static bool initClazz(JNIEnv* env); + + static void releaseClazz(JNIEnv* env); + + static void assertInited(JNIEnv* env) { + auto initClazzSuccess = initClazz(env); + assert(initClazzSuccess); + } diff --git a/compiler/src/main/resources/jte/header_initvars.kte b/compiler/src/main/resources/jte/header_initvars.kte new file mode 100644 index 0000000..56f3c0b --- /dev/null +++ b/compiler/src/main/resources/jte/header_initvars.kte @@ -0,0 +1,17 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param isThreadSafe:Boolean +private: + struct ClassInitState { + +@if (isThreadSafe) + // thread safe init + std::atomic_bool sInited {}; + std::mutex sInitLock {}; +@else + bool sInited = false; +@endif + jclass sClazz = nullptr; + diff --git a/compiler/src/main/resources/jte/header_postamble.kte b/compiler/src/main/resources/jte/header_postamble.kte new file mode 100644 index 0000000..1ee595e --- /dev/null +++ b/compiler/src/main/resources/jte/header_postamble.kte @@ -0,0 +1,15 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param endNamespace:String + + + }; // endof struct ClassInitState + + static inline ClassInitState& getClassInitState() { + static ClassInitState classInitState; + return classInitState; + } +}; +${endNamespace} diff --git a/compiler/src/main/resources/jte/header_preamble.kte b/compiler/src/main/resources/jte/header_preamble.kte new file mode 100644 index 0000000..7b86040 --- /dev/null +++ b/compiler/src/main/resources/jte/header_preamble.kte @@ -0,0 +1,32 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.model.JennyProxyConfiguration +@import io.github.landerlyoung.jenny.model.ClassInfo + +@param includeGuard:String +@param proxyConfiguration:JennyProxyConfiguration +@param startOfNamespace: String +@param cppClassName: String +@param slashClassName: String +#ifndef ${includeGuard} +#define ${includeGuard} + +#include <jni.h> +#include <assert.h> + +@if (proxyConfiguration.threadSafe) +#include <atomic> +#include <mutex> +@endif + +@if (proxyConfiguration.useJniHelper) +#include "jnihelper.h" +@endif + +${startOfNamespace} +class ${cppClassName} { + +public: + static constexpr auto FULL_CLASS_NAME = "${slashClassName}"; diff --git a/compiler/src/main/resources/jte/jni_helper.kte b/compiler/src/main/resources/jte/jni_helper.kte new file mode 100644 index 0000000..e85bdd7 --- /dev/null +++ b/compiler/src/main/resources/jte/jni_helper.kte @@ -0,0 +1,37 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param cppClassName:String + +// ====== jni helper ====== +private: + ::jenny::LocalRef<jobject> _local; + ::jenny::GlobalRef<jobject> _global; +public: + + // jni helper + ::jenny::LocalRef<jobject> getThis(bool owned = true) const { + if (_local) { + if (owned) { + return _local; + } else { + return ::jenny::LocalRef<jobject>(_local.get(), false); + } + } else { + return _global.toLocal(); + } + } + + // jni helper constructors + ${cppClassName}(jobject ref, bool owned = false): _local(ref, owned) { + assertInited(::jenny::Env().get()); + } + + ${cppClassName}(::jenny::LocalRef<jobject> ref): _local(std::move(ref)) { + assertInited(::jenny::Env().get()); + } + + ${cppClassName}(::jenny::GlobalRef<jobject> ref): _global(std::move(ref)) { + assertInited(::jenny::Env().get()); + } diff --git a/compiler/src/main/resources/jte/method_prologue.kte b/compiler/src/main/resources/jte/method_prologue.kte new file mode 100644 index 0000000..c0bea40 --- /dev/null +++ b/compiler/src/main/resources/jte/method_prologue.kte @@ -0,0 +1,18 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param useJniHelper:Boolean +@param isStatic:Boolean +@if (useJniHelper) + @if (isStatic) + ::jenny::Env env; + assertInited(env.get()); + @else + ::jenny::Env env; + ::jenny::LocalRef<jobject> jennyLocalRef = getThis(false); + jobject thiz = jennyLocalRef.get(); + @endif +@else + assertInited(env); +@endif diff --git a/compiler/src/main/resources/jte/methods_definitions.kte b/compiler/src/main/resources/jte/methods_definitions.kte new file mode 100644 index 0000000..f2d4aba --- /dev/null +++ b/compiler/src/main/resources/jte/methods_definitions.kte @@ -0,0 +1,50 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.needWrapLocalRef +@import io.github.landerlyoung.jenny.utils.print +@import io.github.landerlyoung.jenny.utils.toJniCall +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.element.model.type.JennyKind +@import io.github.landerlyoung.jenny.utils.JennyNameProvider + +@param useJniHelper:Boolean +@param methods:Map<JennyExecutableElement, Int> +@param parametersProvider:ParametersProvider + +@for((method,count) in methods) + !{val isStatic = method.isStatic()} + !{val jniReturnType = method.returnType.toJniReturnTypeString()} + !{val functionReturnType = if (useJniHelper && method.returnType.needWrapLocalRef()) "::jenny::LocalRef<$jniReturnType>" else jniReturnType} + !{val staticMod = if (isStatic || useJniHelper) "static " else ""} + !{val constMod = if (isStatic || useJniHelper) "" else "const "} + !{val classOrObj = if (isStatic) JennyNameProvider.getClassState() else "thiz"} + !{val static = if (isStatic) "Static" else ""} + !{val jniParam = parametersProvider.getJennyElementJniParams(element = method,useJniHelper=useJniHelper)} + !{val returnStatement = if (method.returnType.jennyKind != JennyKind.VOID) "return " else ""} + !{fun returnCast (isFront:Boolean):String { + return if (parametersProvider.returnTypeNeedCast(jniReturnType)) + if(isFront) "reinterpret_cast<${jniReturnType}>(" else ")" + else "" + } + } + !{fun returnWrap(isFront:Boolean):String { + return if (useJniHelper && method.returnType.needWrapLocalRef()) + if(isFront) "${functionReturnType}(" else ")" + else "" + } + } + @if(useJniHelper) + + // for jni helper + @endif + // method: ${method.modifiers.print()} ${method.returnType.typeName} ${method.name}(${parametersProvider.getJavaMethodParameters(method)}) + ${staticMod}${functionReturnType} ${method.resolvedName}(${jniParam}) ${constMod}{ + @template.method_prologue(useJniHelper = useJniHelper,isStatic = isStatic) + ${returnStatement}${returnWrap(true)}${returnCast(true)}env->Call${static}${method.returnType.toJniCall()}Method(${classOrObj}, ${JennyNameProvider.getClassState(JennyNameProvider.getElementName(method, count))}${parametersProvider.getJniMethodParamVal(method, useJniHelper)})${returnCast(false)}${returnWrap(false)}; + } +@endfor diff --git a/compiler/src/main/resources/jte/methods_ids_declarations.kte b/compiler/src/main/resources/jte/methods_ids_declarations.kte new file mode 100644 index 0000000..bf04abf --- /dev/null +++ b/compiler/src/main/resources/jte/methods_ids_declarations.kte @@ -0,0 +1,13 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.utils.JennyNameProvider +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement + +@param methods:Map<JennyExecutableElement, Int> + +@for((method,count) in methods) + + jmethodID ${JennyNameProvider.getElementName(method, count)} = nullptr; +@endfor diff --git a/compiler/src/main/resources/jte/methods_ids_initialisations.kte b/compiler/src/main/resources/jte/methods_ids_initialisations.kte new file mode 100644 index 0000000..183fc3f --- /dev/null +++ b/compiler/src/main/resources/jte/methods_ids_initialisations.kte @@ -0,0 +1,20 @@ +<%-- + Copyright (C) 2024 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement +@import io.github.landerlyoung.jenny.utils.JennyNameProvider +@import io.github.landerlyoung.jenny.utils.Signature +@import io.github.landerlyoung.jenny.utils.isStatic + +@param methods:Map<JennyExecutableElement, Int> + +@for((method,count) in methods) + !{val name = "state.${JennyNameProvider.getElementName(method, count)}"} + !{val static = if (method.isStatic()) "Static" else ""} + !{val methodName = method.name} + !{val signature = Signature.getBinaryJennyElementSignature(method)} + ${name} = env->Get${static}MethodID(state.sClazz, "${methodName}", "${signature}"); + JENNY_CHECK_NULL(${name}); + +@endfor diff --git a/compiler/src/main/resources/jte/qjni/qjni_class_init_postamble.kte b/compiler/src/main/resources/jte/qjni/qjni_class_init_postamble.kte new file mode 100644 index 0000000..b596819 --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_class_init_postamble.kte @@ -0,0 +1,7 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param endNamespace: String + +${endNamespace} diff --git a/compiler/src/main/resources/jte/qjni/qjni_class_init_preamble.kte b/compiler/src/main/resources/jte/qjni/qjni_class_init_preamble.kte new file mode 100644 index 0000000..e54462e --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_class_init_preamble.kte @@ -0,0 +1,34 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param headerFileName: String +@param errorLoggerFunction: String +@param startOfNamespace: String +@param cppClassName: String +@param headerOnly: Boolean + + +@if(!headerOnly) + #include "${headerFileName}" +@endif +@if(errorLoggerFunction.isNotEmpty()) +void ${errorLoggerFunction}(const char* error); +@else +#include <QDebug> +@endif +${startOfNamespace} + + +#define JENNY_CHECK_NULL(val) \ + do { \ + if ((val) == nullptr) { \ +@if(errorLoggerFunction.isNotEmpty()) + ${errorLoggerFunction}("Can't init ${cppClassName}::" #val);\ +@else + qWarning()<< #val "is null. Cannot access it"; \ +@endif + + return false; \ + } \ +} while(0) diff --git a/compiler/src/main/resources/jte/qjni/qjni_constructors_definitions.kte b/compiler/src/main/resources/jte/qjni/qjni_constructors_definitions.kte new file mode 100644 index 0000000..5f8cde1 --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_constructors_definitions.kte @@ -0,0 +1,25 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.utils.print +@import io.github.landerlyoung.jenny.utils.Signature + +@param constructors:Map<JennyExecutableElement, Int> +@param parametersProvider:ParametersProvider +@param simpleClassName:String +@param returnType:String +@param useJniHelper:Boolean + +@for((constructor,count) in constructors) + !{val jniParameters = parametersProvider.getJennyElementJniParams(element = constructor,useJniHelper=useJniHelper)} + !{val javaParameters = parametersProvider.getJavaMethodParameters(constructor)} + // construct: ${constructor.modifiers.print()} ${simpleClassName}(${javaParameters}) + static ${returnType} ${constructor.name}(${jniParameters}) { + ${returnType} ret; + ret.m_jniObject = QJniObject(FULL_CLASS_NAME, "${Signature.getBinaryJennyElementSignature(constructor)}"${parametersProvider.getJniMethodParamVal(constructor, useJniHelper)}); + return ret; + } +@endfor diff --git a/compiler/src/main/resources/jte/qjni/qjni_field_getter.kte b/compiler/src/main/resources/jte/qjni/qjni_field_getter.kte new file mode 100644 index 0000000..e55653c --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_field_getter.kte @@ -0,0 +1,29 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.toCamelCase + +@param field: JennyVarElement +@param parametersProvider: ParametersProvider +@param useJniHelper:Boolean +@param comment:String + +!{val isStatic = field.isStatic()} +!{val classParam = if (isStatic) "FULL_CLASS_NAME," else ""} +!{val classOrObj = if (isStatic) "QJniObject::" else "m_jniObject."} +!{val static = if (isStatic) "Static" else "" } +!{val staticMod = if (isStatic || !useJniHelper) "static " else ""} +!{val constMod = if (isStatic || !useJniHelper) "" else " const"} +!{val parameters = parametersProvider.makeParameter(field, useJniHelper)} +!{val jniReturnType = field.type.toJniReturnTypeString()} +!{val needCast = parametersProvider.returnTypeNeedCast(jniReturnType)} +!{val rField = "${classOrObj}get${static}Field<${jniReturnType}>(${classParam}\"${field.name}\")"} + ${comment} + ${staticMod}auto get${field.name.toCamelCase()}(${parameters}) ${constMod}{ + return ${rField}; + } diff --git a/compiler/src/main/resources/jte/qjni/qjni_field_setter.kte b/compiler/src/main/resources/jte/qjni/qjni_field_setter.kte new file mode 100644 index 0000000..f00bcb6 --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_field_setter.kte @@ -0,0 +1,30 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.needWrapLocalRef +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.toCamelCase + +@param field: JennyVarElement +@param parametersProvider: ParametersProvider +@param useJniHelper:Boolean +@param comment:String + +!{val isStatic = field.isStatic()} +!{val classParam = if (isStatic) "FULL_CLASS_NAME," else ""} +!{val classOrObj = if (isStatic) "QJniObject::" else "m_jniObject."} +!{val static = if (isStatic) "Static" else "" } +!{val staticMod = if (isStatic || !useJniHelper) "static " else ""} +!{val constMod = if (isStatic || !useJniHelper) "" else " const"} +!{val parameter = parametersProvider.makeParameter(field, useJniHelper)} +!{val preparameters = if(parameter.isEmpty()) parameter else "$parameter, "} +!{val parameters = preparameters + field.type.toJniReturnTypeString()+ " ${field.name}"} +!{val passedParam = if (useJniHelper && field.type.needWrapLocalRef()) "${field.name}.get()" else field.name} + ${comment} + ${staticMod}void set${field.name.toCamelCase()}(${parameters}) ${constMod}{ + ${classOrObj}set${static}Field(${classParam}"${field.name}", ${passedParam}); + } diff --git a/compiler/src/main/resources/jte/qjni/qjni_fields_definitions.kte b/compiler/src/main/resources/jte/qjni/qjni_fields_definitions.kte new file mode 100644 index 0000000..bff824f --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_fields_definitions.kte @@ -0,0 +1,29 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.field.JennyVarElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.needWrapLocalRef +@import io.github.landerlyoung.jenny.utils.print +@import io.github.landerlyoung.jenny.utils.toJniCall +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.toCamelCase +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.element.model.type.JennyKind + + +@param useJniHelper:Boolean +@param fields:Collection<JennyVarElement> +@param hasGetter:(JennyVarElement)->Boolean +@param hasSetter:(JennyVarElement)->Boolean +@param parametersProvider: ParametersProvider +@for( field in fields) + !{val jniComment = "// field: ${field.modifiers.print()} ${field.type.typeName} ${field.name}"} + @if(hasGetter(field)) + @template.qjni.qjni_field_getter(field = field, parametersProvider = parametersProvider, useJniHelper = useJniHelper, comment = jniComment) + @endif + @if(hasSetter(field)) + @template.qjni.qjni_field_setter(field = field, parametersProvider = parametersProvider, useJniHelper = useJniHelper, comment = jniComment) + @endif +@endfor diff --git a/compiler/src/main/resources/jte/qjni/qjni_header_postamble.kte b/compiler/src/main/resources/jte/qjni/qjni_header_postamble.kte new file mode 100644 index 0000000..99aa59f --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_header_postamble.kte @@ -0,0 +1,8 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@param endNamespace:String + +}; +${endNamespace} diff --git a/compiler/src/main/resources/jte/qjni/qjni_header_preamble.kte b/compiler/src/main/resources/jte/qjni/qjni_header_preamble.kte new file mode 100644 index 0000000..238b78b --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_header_preamble.kte @@ -0,0 +1,39 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.model.JennyProxyConfiguration +@import io.github.landerlyoung.jenny.model.ClassInfo + +@param includeGuard:String +@param startOfNamespace: String +@param cppClassName: String +@param slashClassName: String +#ifndef ${includeGuard} +#define ${includeGuard} + +#include <QJniObject> +#include <cmath> + +${startOfNamespace} +class ${cppClassName} { +private: + QJniObject m_jniObject; + static constexpr double NaN = NAN; +public: + static constexpr auto FULL_CLASS_NAME = "${slashClassName}"; + QJniObject getJniObject() const {return m_jniObject;} + const QJniObject* operator->() const {return &m_jniObject;} + template <class T> operator T() {return m_jniObject.object<T>();} + ${cppClassName}() {} + ${cppClassName}(const QJniObject& jniObject) { + m_jniObject = jniObject; + } + ${cppClassName}(jobject globalRef) { + m_jniObject = QJniObject(globalRef); + } + static ${cppClassName} fromLocalRef(jobject localRef) { + ${cppClassName} res; + res.m_jniObject = QJniObject::fromLocalRef(localRef); + return res; + } diff --git a/compiler/src/main/resources/jte/qjni/qjni_methods_definitions.kte b/compiler/src/main/resources/jte/qjni/qjni_methods_definitions.kte new file mode 100644 index 0000000..6f83bf9 --- /dev/null +++ b/compiler/src/main/resources/jte/qjni/qjni_methods_definitions.kte @@ -0,0 +1,34 @@ +<%-- + Copyright (C) 2025 The Qt Company Ltd. + SPDX-License-Identifier: Apache-2.0 +--%> +@import io.github.landerlyoung.jenny.element.method.JennyExecutableElement +@import io.github.landerlyoung.jenny.utils.toJniReturnTypeString +@import io.github.landerlyoung.jenny.utils.needWrapLocalRef +@import io.github.landerlyoung.jenny.utils.print +@import io.github.landerlyoung.jenny.utils.toJniCall +@import io.github.landerlyoung.jenny.utils.isStatic +@import io.github.landerlyoung.jenny.utils.ParametersProvider +@import io.github.landerlyoung.jenny.element.model.type.JennyKind +@import io.github.landerlyoung.jenny.utils.Signature + +@param useJniHelper:Boolean +@param methods:Map<JennyExecutableElement, Int> +@param parametersProvider:ParametersProvider + +@for((method,count) in methods) + !{val isStatic = method.isStatic()} + !{val jniReturnType = method.returnType.toJniReturnTypeString()} + !{val staticMod = if (isStatic || useJniHelper) "static " else ""} + !{val constMod = if (isStatic || useJniHelper) "" else "const "} + !{val classOrObj = if (isStatic) "QJniObject::" else "m_jniObject."} + !{val static = if (isStatic) "Static" else ""} + !{val classParam = if (isStatic) "FULL_CLASS_NAME," else ""} + !{val jniParam = parametersProvider.getJennyElementJniParams(element = method,useJniHelper=useJniHelper, isByPass = true)} + !{val returnStatement = if (method.returnType.jennyKind != JennyKind.VOID) "return " else ""} + !{val signature = Signature.getBinaryJennyElementSignature(method)} + // method: ${method.modifiers.print()} ${method.returnType.typeName} ${method.name}(${parametersProvider.getJavaMethodParameters(method)}) + ${staticMod}auto ${method.resolvedName}(${jniParam}) ${constMod}{ + ${returnStatement}${classOrObj}call${static}Method<${jniReturnType}>(${classParam}"${method.name}", "${signature}"${parametersProvider.getJniMethodParamVal(method, false)}); + } +@endfor |
