Files

432 lines
13 KiB
Plaintext

## vim: ft=makocpp
<%
api = java_api
nat = c_api.get_name
project_type = capi.get_name('gpr_project')
str_array_type = capi.get_name('string_array_ptr')
scn_var_type = capi.get_name('gpr_project_scenario_variable')
sig_base = "com/adacore/" + ctx.lib_name.lower + "/" + ctx.lib_name.camel
ptr_sig = sig_base + "$PointerWrapper"
%>
void add_error_to_diagnostics(
JNIEnv *env,
jstring error,
jobject diagnostics
) {
// Get the "add" method of the list
jclass clazz = (*env)->GetObjectClass(env, diagnostics);
jmethodID add_id = (*env)-> GetMethodID(
env,
clazz,
"add",
"(Ljava/lang/Object;)Z"
);
// Call the "add" method with the Java string to add it to the diagnostics
(*env)->CallVoidMethod(env, diagnostics, add_id, error);
}
// Unwrap a scenario variable in the given pointer
void ScenarioVariable_unwrap(
JNIEnv *env,
jobject scenario_variable,
${scn_var_type} *scenario_variables_native_ref
) {
// Get the Java class
jclass clazz = (*env)->GetObjectClass(env, scenario_variable);
% for field in ('name', 'value'):
// Get the field ids
jfieldID ${field}_field = (*env)->GetFieldID(
env,
clazz,
"${field}",
"Ljava/lang/String;"
);
// Get the field values
jstring ${field} = (jstring) (*env)->GetObjectField(
env,
scenario_variable,
${field}_field
);
// Get the native values
const char *${field}_native = (*env)->GetStringUTFChars(
env,
${field},
NULL
);
int ${field}_native_length = (*env)->GetStringUTFLength(
env,
${field}
);
// Allocate the buffer in the result structure
scenario_variables_native_ref->${field} = calloc(${field}_native_length, sizeof(char));
for(int i = 0; i < ${field}_native_length; i++) {
scenario_variables_native_ref->${field}[i] = ${field}_native[i];
}
// Release the source chararcter pointer
(*env)->ReleaseStringUTFChars(env, ${field}, ${field}_native);
% endfor
}
// Release the given native scenario variable
void ScenarioVariable_release(
${scn_var_type} scenario_variable_native
) {
free(scenario_variable_native.name);
free(scenario_variable_native.value);
}
// Load a gpr project
${api.jni_func_sig("gpr_project_load", "jobject")}(
JNIEnv *env,
jclass jni_lib,
jstring project_file,
jobjectArray scenario_variables,
jstring target,
jstring runtime,
jobject diagnostics
) {
// Create the scenario variable array
${scn_var_type} *scenario_variables_native = NULL;
int scenario_variables_length = 0;
if(scenario_variables != NULL) {
// Get the scenario variable length
scenario_variables_length = (*env)->GetArrayLength(env, scenario_variables);
if(scenario_variables_length > 0) {
// Allocate the scenario variable array
int size = scenario_variables_length + 1;
scenario_variables_native = (${scn_var_type}*) calloc(
(size_t) size,
(size_t) sizeof(${scn_var_type})
);
// Unwrap all scenario variables in the native array
for(int i = 0; i < scenario_variables_length; i++) {
jobject scenario_variable = (*env)->GetObjectArrayElement(
env,
scenario_variables,
(jsize) i
);
ScenarioVariable_unwrap(
env,
scenario_variable,
&scenario_variables_native[i]
);
}
}
}
// Translate the arguments to C values
const char *project_file_c = to_c_string(env, project_file);
const char *target_c = to_c_string(env, target);
const char *runtime_c = to_c_string(env, runtime);
// Call the native function to create the project
${project_type} res = NULL;
${str_array_type} errors = NULL;
${nat("gpr_project_load")}(
project_file_c,
scenario_variables_native,
target_c,
runtime_c,
&res,
&errors
);
// Free the scenario variables
if(scenario_variables_native != NULL) {
for(int i = 0; i < scenario_variables_length; i++) {
ScenarioVariable_release(scenario_variables_native[i]);
}
free(scenario_variables_native);
}
// Free the translated strings
(*env)->ReleaseStringUTFChars(env, project_file, project_file_c);
(*env)->ReleaseStringUTFChars(env, target, target_c);
(*env)->ReleaseStringUTFChars(env, runtime, runtime_c);
// The `errors` pointer is not allocated if an exception was raised during
// project file loading.
if (errors != NULL) {
// Handle the errors
for(int i = 0 ; i < errors->length ; i++) {
const char *error = errors->c_ptr[i];
jstring j_error = (*env)->NewStringUTF(env, error);
add_error_to_diagnostics(env, j_error, diagnostics);
}
// Free the error array
${nat("free_string_array")}(errors);
}
// Return the pointer
return PointerWrapper_wrap(env, (void *) res);
}
// Free a gpr project
${api.jni_func_sig("gpr_project_free", "void")}(
JNIEnv *env,
jclass jni_lib,
jobject project
) {
// Do the native call
${nat("gpr_project_free")}((${project_type}) get_reference(env, project));
}
// Get the unit provider from a gpr project
${api.jni_func_sig("gpr_project_create_unit_provider", "jobject")}(
JNIEnv *env,
jclass jni_lib,
jobject project,
jstring subproject
) {
const char* subproject_c = NULL;
if (subproject != NULL) {
subproject_c = (*env)->GetStringUTFChars(env, subproject, NULL);
}
// Call the native function
${unit_provider_type} res = ${nat("gpr_project_create_unit_provider")}(
(${project_type}) get_reference(env, project),
subproject_c
);
// Free all temporarily allocated memory
if (subproject_c != NULL) {
(*env)->ReleaseStringUTFChars(env, subproject, subproject_c);
}
// Return the new unit provider
return UnitProvider_wrap(env, res);
}
// Get the list of the files of a project
${api.jni_func_sig("gpr_project_source_files", "jobjectArray")}(
JNIEnv *env,
jclass jni_lib,
jobject project,
jint mode,
jobjectArray subprojects
) {
jobjectArray result_java = NULL;
/* Convert the Java array of subprojects ("subprojects" argument) into the
required C array (subproject_count/subprojects_c). */
jsize subproject_count = 0;
const char** subprojects_c = NULL;
if (subprojects != NULL)
{
subproject_count = (*env)->GetArrayLength (env, subprojects);
subprojects_c = calloc (subproject_count, sizeof (char*));
}
for (int i = 0; i < subproject_count; ++i)
{
jstring subproject
= (jstring) (*env)->GetObjectArrayElement (env, subprojects, i);
subprojects_c[i] = (*env)->GetStringUTFChars (env, subproject, NULL);
}
/* Call the C API. In case of failure, return NULL and let the caller
propagate the native exception into the Java world. */
${str_array_type} result_c = ${nat("gpr_project_source_files")} (
(${project_type}) get_reference (env, project),
(int) mode,
subprojects_c,
subproject_count
);
if (${nat("get_last_exception")} () != NULL)
goto error;
/* Create the Java array result and initialize it. */
jclass clazz = (*env)->FindClass (env, "java/lang/String");
result_java
= (*env)->NewObjectArray (env, (jsize) result_c->length, clazz, NULL);
for (int i = 0 ; i < result_c->length ; i++)
{
jstring source_file
= to_j_string (env, result_c->c_ptr[i]);
(*env)->SetObjectArrayElement (env, result_java, (jsize) i,
(jobject) source_file);
}
/* Now that the Java result is ready, release the C result. */
${nat("free_string_array")} (result_c);
error:
/* Release subprojects_c. */
for (int i = 0; i < subproject_count; ++i)
{
jstring subproject
= (jstring) (*env)->GetObjectArrayElement(env, subprojects, i);
(*env)->ReleaseStringUTFChars (env, subproject, subprojects_c[i]);
}
free (subprojects_c);
return result_java;
}
${c_doc("libadalang.gpr_project_create_context", lang="java")}
${api.jni_func_sig("gpr_project_create_context", "jobject")}(
JNIEnv *env,
jclass jni_lib,
jobject project,
jstring subproject,
jobject event_handler,
jboolean with_trivia,
jint tab_stop
)
{
const char *subproject_c = NULL;
if (subproject != NULL)
subproject_c = (*env)->GetStringUTFChars (env, subproject, NULL);
${event_handler_type} event_handler_c = NULL;
if (event_handler != NULL)
event_handler_c = EventHandler_unwrap (env, event_handler);
/* Manually allocate a C-level analysis context so that we can initialize
it ourselves. */
${analysis_context_type} ctx_c = ${nat("allocate_analysis_context")} ();
/* Create the Java wrapper, so that we have one ready for event handler
callbacks triggered during context initialization. */
jobject ctx = AnalysisContext_wrap (env, ctx_c);
/* The wrapper created its own ownership share: release ours. */
${nat("context_decref")} (ctx_c);
/* TODO: attach extra wrappers to the analysis context wrapper so that
wrappers ("project" and "event_handler") live at least as long as the
analysis context. */
/* Finally, initialize the analysis context. Note that this step may raise
an exception: in that case, the analysis context is considered not
initialized: release it. */
${nat("gpr_project_initialize_context")} (
(${project_type}) get_reference (env, project),
ctx_c,
subproject_c,
event_handler_c,
(int) with_trivia,
(int) tab_stop
);
if (subproject_c != NULL)
(*env)->ReleaseStringUTFChars (env, subproject, subproject_c);
const ${exception_type} *exc_c = ${nat("get_last_exception")} ();
if (exc_c != NULL)
{
jthrowable exc = LangkitException_wrap (env, *exc_c);
${nat("context_decref")} (ctx_c);
(*env)->Throw (env, exc);
}
return ctx;
}
// Create an auto provider reference
${api.jni_func_sig("create_auto_provider", "jobject")}(
JNIEnv *env,
jclass jni_lib,
jobjectArray source_files,
jstring charset
) {
// Retrieve the number of files N
jsize source_file_count = (*env)->GetArrayLength(env, source_files);
// Allocate an array of N+1 element (the last one should be the null pointer),
// indicating the end of the C array.
const char** source_files_c = calloc(source_file_count + 1, sizeof(char*));
for (int i = 0; i < source_file_count; ++i) {
jstring source_file = (jstring) (*env)->GetObjectArrayElement(
env,
source_files,
i
);
source_files_c[i] = (*env)->GetStringUTFChars(env, source_file, NULL);
}
const char* charset_c = NULL;
if (charset != NULL) {
charset_c = (*env)->GetStringUTFChars(env, charset, NULL);
}
// Create the auto provider
${unit_provider_type} res = ${nat("create_auto_provider")}(
source_files_c, charset_c
);
// Free all temporarily allocated memory
if (charset_c != NULL) {
(*env)->ReleaseStringUTFChars(env, charset, charset_c);
}
for (int i = 0; i < source_file_count; ++i) {
jstring source_file = (jstring) (*env)->GetObjectArrayElement(
env,
source_files,
i
);
(*env)->ReleaseStringUTFChars(env, source_file, source_files_c[i]);
}
free(source_files_c);
// Return the new unit provider
return UnitProvider_wrap(env, res);
}
${api.jni_func_sig("set_config_pragmas_mapping", "void")}(
JNIEnv *env,
jclass jni_lib,
jobject context,
jobject global_pragmas,
jobjectArray local_pragmas
) {
ada_analysis_context context_c;
ada_analysis_unit global_pragmas_c;
ada_analysis_unit *local_pragmas_c;
int i, size;
context_c = AnalysisContext_unwrap (env, context);
global_pragmas_c
= (global_pragmas == NULL)
? NULL
: AnalysisUnit_unwrap (env, global_pragmas);
size = (*env)->GetArrayLength (env, local_pragmas);
local_pragmas_c = calloc (size, sizeof (ada_analysis_unit));
for (i = 0; i < size; ++i)
{
jobject unit_java
= (*env)->GetObjectArrayElement (env, local_pragmas, (jsize) i);
ada_analysis_unit unit_c;
unit_c
= (unit_java == NULL) ? NULL : AnalysisUnit_unwrap (env, unit_java);
local_pragmas_c[i] = unit_c;
}
${nat("set_config_pragmas_mapping")} (context_c, global_pragmas_c,
local_pragmas_c);
free (local_pragmas_c);
}