You've already forked libadalang
mirror of
https://github.com/AdaCore/libadalang.git
synced 2026-02-12 12:28:54 -08:00
The 'toCString' function has been removed from generated bindings. Now generated code should use functions provided by the Native Image C API library.
748 lines
24 KiB
Plaintext
748 lines
24 KiB
Plaintext
## vim: ft=makojava
|
|
|
|
<%
|
|
api = java_api
|
|
nat = c_api.get_name
|
|
%>
|
|
|
|
// ==========
|
|
// Define classes to handle project loading
|
|
// ==========
|
|
|
|
/**
|
|
* Exception to represent errors during project manipulation
|
|
*/
|
|
public static final class ProjectManagerException extends RuntimeException {
|
|
ProjectManagerException(
|
|
final String message
|
|
) {
|
|
super(message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enum to represent the source file mode for a GPR project
|
|
*/
|
|
public static enum SourceFileMode {
|
|
|
|
// ----- Enum values -----
|
|
|
|
DEFAULT(0),
|
|
ROOT_PROJECT(1),
|
|
WHOLE_PROJECT(2),
|
|
WHOLE_PROJECT_WITH_RUNTIME(3),
|
|
;
|
|
|
|
// ----- Class attributes -----
|
|
|
|
/** Singleton that represents the none source file mode */
|
|
public static final SourceFileMode NONE = DEFAULT;
|
|
|
|
/** The map from int to enum values */
|
|
private static final Map<Integer, SourceFileMode> map = new HashMap<>();
|
|
|
|
// ----- Instance attributes -----
|
|
|
|
/** The value of the instance */
|
|
private final int value;
|
|
|
|
// ----- Constructors -----
|
|
|
|
/**
|
|
* The private constructor
|
|
*/
|
|
private SourceFileMode(
|
|
final int value
|
|
) {
|
|
this.value = value;
|
|
}
|
|
|
|
static {
|
|
for(SourceFileMode elem : SourceFileMode.values()) {
|
|
map.put(elem.value, elem);
|
|
}
|
|
}
|
|
|
|
// ----- Enum methods -----
|
|
|
|
/**
|
|
* Get a source file mode from a native integer value.
|
|
*
|
|
* @param cValue The native value of the enum.
|
|
* @return The Java source file mode.
|
|
* @throws EnumException If the given native value doesn't correspond
|
|
* to an actual enum value.
|
|
*/
|
|
public static SourceFileMode fromC(
|
|
final int cValue
|
|
) throws EnumException {
|
|
if(!map.containsKey(cValue))
|
|
throw new EnumException(
|
|
"Cannot get SourceFileMode from " + cValue
|
|
);
|
|
return (SourceFileMode) map.get(cValue);
|
|
}
|
|
|
|
/**
|
|
* Get the native integer value of the enum instance.
|
|
*
|
|
* @return The native C value.
|
|
*/
|
|
public int toC() {
|
|
return this.value;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Enum to represent a given project loading option.
|
|
*/
|
|
public static enum ProjectOption {
|
|
|
|
// ----- Enum values -----
|
|
|
|
AP(0),
|
|
AUTOCONF(1),
|
|
CONFIG(2),
|
|
DB(3),
|
|
DB_MINUS(4),
|
|
IMPLICIT_WITH(5),
|
|
RESOLVE_LINKS(6),
|
|
NO_PROJECT(7),
|
|
P(8),
|
|
PRINT_GPR_REGISTRY(9),
|
|
RELOCATE_BUILD_TREE(10),
|
|
ROOT_DIR(11),
|
|
RTS(12),
|
|
SRC_SUBDIRS(13),
|
|
SUBDIRS(14),
|
|
TARGET(15),
|
|
X(16),
|
|
;
|
|
|
|
// ----- Class attributes -----
|
|
|
|
/** The map from int to enum values */
|
|
private static final Map<Integer, ProjectOption> map = new HashMap<>();
|
|
|
|
// ----- Instance attributes -----
|
|
|
|
/** The value of the instance */
|
|
private final int value;
|
|
|
|
// ----- Constructors -----
|
|
|
|
/**
|
|
* The private constructor
|
|
*/
|
|
private ProjectOption(
|
|
final int value
|
|
) {
|
|
this.value = value;
|
|
}
|
|
|
|
static {
|
|
for(ProjectOption elem : ProjectOption.values()) {
|
|
map.put(elem.value, elem);
|
|
}
|
|
}
|
|
|
|
// ----- Enum methods -----
|
|
|
|
/**
|
|
* Get a project option from a native integer value.
|
|
*
|
|
* @param cValue The native value of the enum.
|
|
* @return The corresponding Java enum value.
|
|
* @throws EnumException If the given native value doesn't correspond
|
|
* to an actual enum value.
|
|
*/
|
|
public static ProjectOption fromC(
|
|
final int cValue
|
|
) throws EnumException {
|
|
if(!map.containsKey(cValue))
|
|
throw new EnumException(
|
|
"Cannot get ProjectOption from " + cValue
|
|
);
|
|
return (ProjectOption) map.get(cValue);
|
|
}
|
|
|
|
/**
|
|
* Get the native integer value of the enum instance.
|
|
*
|
|
* @return The native C value.
|
|
*/
|
|
public int toC() {
|
|
return this.value;
|
|
}
|
|
}
|
|
|
|
${java_doc("libadalang.gpr_options", 4)}
|
|
public static final class ProjectOptions implements AutoCloseable {
|
|
|
|
// ----- Instance attributes -----
|
|
|
|
/**
|
|
* Reference to the native value.
|
|
*
|
|
* It is package visible so that binding code in the ProjectManager can
|
|
* convert ProjectOptions arguments down to the C value. */
|
|
final PointerWrapper reference;
|
|
|
|
// ----- Constructors -----
|
|
|
|
/**
|
|
* Create a new project loading options holder.
|
|
*
|
|
* @param reference The reference to the native options holder.
|
|
*/
|
|
private ProjectOptions(
|
|
final PointerWrapper reference
|
|
) {
|
|
this.reference = reference;
|
|
}
|
|
|
|
/**
|
|
* Create a new project loading options holder.
|
|
*/
|
|
public ProjectOptions() {
|
|
if(ImageInfo.inImageCode()) {
|
|
ProjectOptionsNative res =
|
|
NI_LIB.${nat("gpr_options_create")}();
|
|
this.reference = new PointerWrapper(res);
|
|
} else {
|
|
this.reference = JNI_LIB.${nat("gpr_options_create")}();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a switch to the given options.
|
|
*
|
|
* See the Ada API for `GPR2.Options.Add_Switch`.
|
|
*/
|
|
public void addSwitch(
|
|
ProjectOption switch_,
|
|
String param,
|
|
String index,
|
|
boolean overwrite
|
|
) {
|
|
if(ImageInfo.inImageCode()) {
|
|
try (
|
|
CCharPointerHolder paramNative =
|
|
param == null ?
|
|
null :
|
|
CTypeConversion.toCString(param);
|
|
CCharPointerHolder indexNative =
|
|
index == null ?
|
|
null :
|
|
CTypeConversion.toCString(index);
|
|
) {
|
|
NI_LIB.${nat("gpr_options_add_switch")}(
|
|
this.reference.ni(),
|
|
switch_.toC(),
|
|
(param == null ?
|
|
WordFactory.nullPointer() :
|
|
paramNative.get()),
|
|
(index == null ?
|
|
WordFactory.nullPointer() :
|
|
indexNative.get()),
|
|
overwrite ? 1 : 0
|
|
);
|
|
}
|
|
} else {
|
|
JNI_LIB.${nat("gpr_options_add_switch")}(
|
|
this,
|
|
switch_.toC(),
|
|
param,
|
|
index,
|
|
overwrite
|
|
);
|
|
}
|
|
|
|
try {
|
|
checkException();
|
|
} catch (LangkitException e) {
|
|
throw new ProjectManagerException(e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add a switch to the given options.
|
|
*
|
|
* See the Ada API for `GPR2.Options.Add_Switch`.
|
|
*/
|
|
public void addSwitch(
|
|
ProjectOption switch_,
|
|
String param,
|
|
String index
|
|
) {
|
|
this.addSwitch(switch_, param, index, false);
|
|
}
|
|
|
|
/**
|
|
* Add a switch to the given options.
|
|
*
|
|
* See the Ada API for `GPR2.Options.Add_Switch`.
|
|
*/
|
|
public void addSwitch(
|
|
ProjectOption switch_,
|
|
String param
|
|
) {
|
|
this.addSwitch(switch_, param, null, false);
|
|
}
|
|
|
|
/**
|
|
* Add a switch to the given options.
|
|
*
|
|
* See the Ada API for `GPR2.Options.Add_Switch`.
|
|
*/
|
|
public void addSwitch(
|
|
ProjectOption switch_
|
|
) {
|
|
this.addSwitch(switch_, null, null, false);
|
|
}
|
|
|
|
/** @see java.lang.AutoCloseable#close() */
|
|
@Override
|
|
public void close() {
|
|
if(ImageInfo.inImageCode()) {
|
|
NI_LIB.${nat("gpr_options_free")}(this.reference.ni());
|
|
} else {
|
|
JNI_LIB.${nat("gpr_options_free")}(this);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This class is used for the GPR project loading.
|
|
*/
|
|
public static final class ProjectManager implements AutoCloseable {
|
|
|
|
// ----- Class attributes -----
|
|
|
|
/** Singleton that represents the none project manager. */
|
|
public static final ProjectManager NONE =
|
|
new ProjectManager(PointerWrapper.nullPointer());
|
|
|
|
// ----- Instance attributes -----
|
|
|
|
/** Reference to the native value. */
|
|
private final PointerWrapper reference;
|
|
|
|
/**
|
|
* List of diagnostics emitted by the native API during the project
|
|
* opening.
|
|
*/
|
|
private final List<String> diagnostics;
|
|
|
|
// ----- Constructors -----
|
|
|
|
/**
|
|
* Create a new project manager from its native reference.
|
|
*
|
|
* @param reference The reference to the native project manager.
|
|
*/
|
|
ProjectManager(
|
|
final PointerWrapper reference
|
|
) {
|
|
this.reference = reference;
|
|
this.diagnostics = new ArrayList<>();
|
|
}
|
|
|
|
/**
|
|
* Create a new project manager.
|
|
*
|
|
* @param options The GPR loading options.
|
|
* @param adaOnly Restrict project loading to the Ada language.
|
|
*/
|
|
public ProjectManager(
|
|
final ProjectOptions options,
|
|
final boolean adaOnly
|
|
) {
|
|
if (options == null) {
|
|
throw new ProjectManagerException(
|
|
"non-null `options` argument required"
|
|
);
|
|
}
|
|
|
|
if(ImageInfo.inImageCode()) {
|
|
// Declare native values
|
|
final ProjectOptionsNative optionsPointer;
|
|
final Pointer errorsPointer;
|
|
|
|
// Prepare the result pointer
|
|
final Pointer projectPointer = StackValue.get(SizeOf.get(VoidPointer.class));
|
|
projectPointer.writeWord(0, WordFactory.nullPointer());
|
|
|
|
optionsPointer = options.reference.ni();
|
|
errorsPointer = StackValue.get(SizeOf.get(WordPointer.class));
|
|
errorsPointer.writeWord(0, WordFactory.nullPointer());
|
|
|
|
NI_LIB.${nat("gpr_project_load")}(
|
|
optionsPointer,
|
|
adaOnly ? 1 : 0,
|
|
projectPointer,
|
|
errorsPointer
|
|
);
|
|
|
|
// Check the langkit exception and cast it into a project manager error
|
|
try {
|
|
checkException();
|
|
} catch (LangkitException e) {
|
|
throw new ProjectManagerException(e.getMessage());
|
|
}
|
|
|
|
// Get the result of modified values
|
|
final ProjectManagerNative projectManagerNative = (ProjectManagerNative) projectPointer.readWord(0);
|
|
final StringArrayNative errorArrayNative = (StringArrayNative) errorsPointer.readWord(0);
|
|
|
|
// `errorsPointer` is not allocated if an exception was raised during project file loading
|
|
String[] errors = new String[0];
|
|
if (errorArrayNative.isNonNull()) {
|
|
// Translate the error native array into a Java array
|
|
errors = toJStringArray(errorArrayNative);
|
|
|
|
// Free the error array
|
|
NI_LIB.${nat("free_string_array")}(errorArrayNative);
|
|
}
|
|
|
|
// Check the langkit exception and cast it into a project manager error
|
|
try {
|
|
checkException();
|
|
} catch (LangkitException e) {
|
|
throw new ProjectManagerException(e.getMessage());
|
|
}
|
|
|
|
// Create the result project manager and add diagnostics if any
|
|
this.reference = new PointerWrapper(projectManagerNative);
|
|
this.diagnostics = List.of(errors);
|
|
} else {
|
|
// Call the native function from the stubs
|
|
final List<String> diagnostics = new ArrayList<>();
|
|
final PointerWrapper reference =
|
|
JNI_LIB.${nat("gpr_project_load")}(
|
|
options,
|
|
adaOnly,
|
|
diagnostics
|
|
);
|
|
|
|
// Check the langkit exceptions
|
|
try {
|
|
checkException();
|
|
} catch (LangkitException e) {
|
|
throw new ProjectManagerException(e.getMessage());
|
|
}
|
|
|
|
// Return the project manager
|
|
this.reference = reference;
|
|
this.diagnostics = diagnostics;
|
|
}
|
|
|
|
}
|
|
|
|
// ----- Graal C API methods -----
|
|
|
|
/**
|
|
* Wrap a native project manager in the Java class.
|
|
*
|
|
* @param pointer The pointer to the native project manager.
|
|
* @return The newly wrapped project manager.
|
|
*/
|
|
static ProjectManager wrap(
|
|
final Pointer pointer
|
|
) {
|
|
return wrap((ProjectManagerNative) pointer.readWord(0));
|
|
}
|
|
|
|
/**
|
|
* Wrap a native project manager in the Java class.
|
|
*
|
|
* @param projectManagerNative The native project manager to wrap.
|
|
* @return The newly wrapped project manager.
|
|
*/
|
|
static ProjectManager wrap(
|
|
final ProjectManagerNative projectManagerNative
|
|
) {
|
|
return new ProjectManager(new PointerWrapper(projectManagerNative));
|
|
}
|
|
|
|
/**
|
|
* Unwrap the project manager inside the given pointer.
|
|
*
|
|
* @param pointer The pointer to write in.
|
|
*/
|
|
public void unwrap(
|
|
final Pointer pointer
|
|
) {
|
|
pointer.writeWord(0, this.unwrap());
|
|
}
|
|
|
|
/**
|
|
* Get the native value of the project manager.
|
|
*
|
|
* @return The native project manager.
|
|
*/
|
|
public ProjectManagerNative unwrap() {
|
|
return (ProjectManagerNative) this.reference.ni();
|
|
}
|
|
|
|
// ----- Class methods -----
|
|
|
|
/**
|
|
* Translate a native string array structure into a Java string
|
|
* array.
|
|
*
|
|
* @param stringArrayNative The native string array structure.
|
|
* @return The Java string array.
|
|
*/
|
|
private static String[] toJStringArray(
|
|
final StringArrayNative stringArrayNative
|
|
) {
|
|
final String[] res = new String[stringArrayNative.get_length()];
|
|
final CCharPointerPointer nativeFilesPointer = stringArrayNative.get_c_ptr();
|
|
for(int i = 0 ; i < res.length ; i++) {
|
|
final CCharPointer nativeFile = nativeFilesPointer.read(i);
|
|
res[i] = toJString(nativeFile);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
// ----- Instance methods -----
|
|
|
|
public List<String> getDiagnostics() {
|
|
return this.diagnostics;
|
|
}
|
|
|
|
/**
|
|
* Create a unit provider for the given subproject.
|
|
*
|
|
* @param subproject The subproject for which to create a unit provider.
|
|
* @return The unit provider for the project manager.
|
|
*/
|
|
public UnitProvider getProvider(final String subproject) {
|
|
final UnitProvider result;
|
|
if(ImageInfo.inImageCode()) {
|
|
try (
|
|
CCharPointerHolder subprojectNative =
|
|
subproject == null ?
|
|
null :
|
|
CTypeConversion.toCString(subproject);
|
|
) {
|
|
UnitProviderNative unitProviderNative = NI_LIB.${nat('gpr_project_create_unit_provider')}(
|
|
this.reference.ni(),
|
|
(subproject == null ?
|
|
WordFactory.nullPointer() :
|
|
subprojectNative.get())
|
|
);
|
|
result = UnitProvider.wrap(unitProviderNative);
|
|
}
|
|
|
|
} else {
|
|
result = JNI_LIB.${nat("gpr_project_create_unit_provider")}(
|
|
this,
|
|
subproject
|
|
);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Create a unit provider for root project.
|
|
*/
|
|
public UnitProvider getProvider() {
|
|
return this.getProvider(null);
|
|
}
|
|
|
|
${java_doc("libadalang.gpr_project_create_context", 8)}
|
|
public AnalysisContext createContext(
|
|
String subproject,
|
|
EventHandler eventHandler,
|
|
boolean withTrivia,
|
|
int tabStop
|
|
) {
|
|
if(ImageInfo.inImageCode()) {
|
|
try (
|
|
CCharPointerHolder subproject_c =
|
|
subproject == null ?
|
|
null :
|
|
CTypeConversion.toCString(subproject);
|
|
) {
|
|
// Manually allocate a C-level analysis context so that we can
|
|
// initialize it ourselves.
|
|
final PointerWrapper context = new PointerWrapper(
|
|
NI_LIB.${nat("allocate_analysis_context")}()
|
|
);
|
|
|
|
// Create the Java wrapper, so that we have one ready for
|
|
// event handler callbacks triggered during context
|
|
// initialization.
|
|
AnalysisContext result =
|
|
AnalysisContext.fromReference(context, eventHandler, true);
|
|
|
|
// "result" has its own ownership share: release ours
|
|
NI_LIB.${nat("context_decref")}(context.ni());
|
|
|
|
// TODO: attach "this" to "result" so that the former lives at
|
|
// least as long as the former.
|
|
|
|
// 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.
|
|
NI_LIB.${nat("gpr_project_initialize_context")}(
|
|
this.reference.ni(),
|
|
context.ni(),
|
|
(subproject == null ?
|
|
WordFactory.nullPointer() :
|
|
subproject_c.get()),
|
|
(eventHandler == null ?
|
|
WordFactory.nullPointer() :
|
|
eventHandler.reference.ni()),
|
|
withTrivia ? 1 : 0,
|
|
tabStop
|
|
);
|
|
final LangkitExceptionNative exc_c =
|
|
NI_LIB.${nat("get_last_exception")}();
|
|
if (exc_c.isNonNull()) {
|
|
LangkitException exc = wrapException(exc_c);
|
|
NI_LIB.${nat("context_decref")}(context.ni());
|
|
throw exc;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
} else {
|
|
return JNI_LIB.${nat("gpr_project_create_context")}(
|
|
this,
|
|
subproject,
|
|
eventHandler,
|
|
withTrivia,
|
|
tabStop
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the files for the given subprojects in a string array.
|
|
*
|
|
* @param mode The file getting mode.
|
|
* @param subprojects The subprojects to consider.
|
|
* @return The array that contains the project files.
|
|
*/
|
|
public String[] getFiles(
|
|
final SourceFileMode mode,
|
|
final String[] subprojects
|
|
) {
|
|
// Verify if the project is null
|
|
if(this.reference.isNull())
|
|
return new String[0];
|
|
|
|
String[] result = null;
|
|
LangkitException exc;
|
|
|
|
if(ImageInfo.inImageCode()) {
|
|
try (
|
|
CCharPointerPointerHolder subprojectsNative =
|
|
subprojects == null ?
|
|
null :
|
|
CTypeConversion.toCStrings(subprojects);
|
|
) {
|
|
// Call the C API. Keep track of a potential native
|
|
// ²exception.
|
|
StringArrayNative sourceFileArray =
|
|
NI_LIB.${nat('gpr_project_source_files')}(
|
|
this.reference.ni(),
|
|
mode.toC(),
|
|
(subprojects == null ?
|
|
WordFactory.nullPointer() :
|
|
subprojectsNative.get()),
|
|
(subprojects == null ? 0 : subprojects.length)
|
|
);
|
|
exc = getLastException();
|
|
|
|
// If the call was successful, create the Java array result
|
|
// and initialize it, and free the C array result.
|
|
if(exc == null) {
|
|
result = toJStringArray(sourceFileArray);
|
|
NI_LIB.${nat("free_string_array")}(sourceFileArray);
|
|
}
|
|
}
|
|
} else {
|
|
result = JNI_LIB.${nat("gpr_project_source_files")}(
|
|
this,
|
|
mode.toC(),
|
|
subprojects
|
|
);
|
|
exc = getLastException();
|
|
}
|
|
|
|
// If we got an exception, turn it into a ProjectManagerException
|
|
// one.
|
|
if(exc != null) {
|
|
throw new ProjectManagerException(exc.getMessage());
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/**
|
|
* Get the files of the root project in a string array.
|
|
*
|
|
* @param mode The file getting mode.
|
|
* @return The array that contains the project files.
|
|
*/
|
|
public String[] getFiles(final SourceFileMode mode) {
|
|
return this.getFiles(mode, null);
|
|
}
|
|
|
|
/** @see java.lang.AutoCloseable#close() */
|
|
@Override
|
|
public void close() {
|
|
|
|
if(ImageInfo.inImageCode()) {
|
|
NI_LIB.${nat("gpr_project_free")}(this.reference.ni());
|
|
} else {
|
|
JNI_LIB.${nat("gpr_project_free")}(this);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
${java_doc("libadalang.create_auto_provider", 4)}
|
|
public static UnitProvider createAutoProvider(
|
|
final String[] sourceFiles,
|
|
final String charset
|
|
) {
|
|
if (ImageInfo.inImageCode()) {
|
|
try (
|
|
CCharPointerPointerHolder sourceFilesNative =
|
|
sourceFiles == null ?
|
|
null :
|
|
CTypeConversion.toCStrings(sourceFiles);
|
|
CCharPointerHolder charsetNative =
|
|
charset == null ?
|
|
null :
|
|
CTypeConversion.toCString(charset);
|
|
) {
|
|
final UnitProviderNative unitProviderNative =
|
|
NI_LIB.${nat('create_auto_provider')}(
|
|
(sourceFiles == null ?
|
|
WordFactory.nullPointer() :
|
|
sourceFilesNative.get()),
|
|
(charset == null ?
|
|
WordFactory.nullPointer() :
|
|
charsetNative.get())
|
|
);
|
|
return UnitProvider.wrap(unitProviderNative);
|
|
}
|
|
|
|
} else {
|
|
return JNI_LIB.${nat("create_auto_provider")}(
|
|
sourceFiles,
|
|
charset
|
|
);
|
|
}
|
|
}
|