-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathPerlModuleBase.java
More file actions
164 lines (141 loc) · 6.26 KB
/
PerlModuleBase.java
File metadata and controls
164 lines (141 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package org.perlonjava.runtime.perlmodule;
import org.perlonjava.runtime.operators.ModuleOperators;
import org.perlonjava.runtime.runtimetypes.*;
import java.lang.invoke.MethodHandle;
import java.net.URL;
/**
* Abstract base class for Perl modules in the Java environment.
* This class provides functionalities to initialize Perl modules,
* register methods, and define exports.
*/
public abstract class PerlModuleBase {
// The name of the Perl module
protected String moduleName;
/**
* Constructor for PerlModuleBase.
*
* @param moduleName The name of the Perl module.
*/
public PerlModuleBase(String moduleName) {
this.moduleName = moduleName;
initializeModule();
}
public PerlModuleBase(String moduleName, boolean setInc) {
this.moduleName = moduleName;
if (setInc) {
initializeModule();
}
}
/**
* Initializes the Perl module by setting the %INC hash to indicate
* that the module is loaded.
* If a .pm stub file exists in the JAR, use the jar:PERL5LIB path format
* so that code opening %INC entries can find a real file.
*/
private void initializeModule() {
String pmFileName = moduleName.replace("::", "/") + ".pm";
String incValue;
// Check if there's a .pm file in the bundled lib (JAR)
String resourcePath = "/lib/" + pmFileName;
URL resource = PerlModuleBase.class.getResource(resourcePath);
if (resource != null) {
// Use jar:PERL5LIB path format - this can be opened by the runtime
incValue = GlobalContext.JAR_PERLLIB + "/" + pmFileName;
} else {
// No .pm stub file - use simple name (backwards compatible)
incValue = moduleName + ".pm";
}
// Set %INC to indicate the module is loaded
GlobalVariable.getGlobalHash("main::INC").put(pmFileName, new RuntimeScalar(incValue));
}
/**
* Registers a method in the Perl module with a different name than the Java method.
*
* @param perlMethodName The name of the method in Perl.
* @param javaMethodName The name of the method in Java.
* @param signature The signature of the method.
* @throws NoSuchMethodException If the method does not exist.
*/
protected void registerMethod(String perlMethodName, String javaMethodName, String signature) throws NoSuchMethodException {
try {
// Retrieve the method from the current class using the Java method name
MethodHandle methodHandle = RuntimeCode.lookup.findStatic(this.getClass(), javaMethodName, RuntimeCode.methodType);
RuntimeCode code = new RuntimeCode(methodHandle, this, signature);
code.isStatic = true;
code.packageName = moduleName;
code.subName = perlMethodName;
String fullMethodName = NameNormalizer.normalizeVariableName(perlMethodName, moduleName);
// Set the method as a global code reference in the Perl namespace using the Perl method name
GlobalVariable.getGlobalCodeRef(fullMethodName).set(new RuntimeScalar(code));
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
/**
* Registers a method in the Perl module.
*
* @param methodName The name of the method to register.
* @param signature The signature of the method.
* @throws NoSuchMethodException If the method does not exist.
*/
protected void registerMethod(String methodName, String signature) throws NoSuchMethodException {
registerMethod(methodName, methodName, signature);
}
/**
* Defines symbols to be exported by the Perl module.
*
* @param exportType The type of export (e.g., EXPORT, EXPORT_OK).
* @param symbols The symbols to be exported.
*/
protected void defineExport(String exportType, String... symbols) {
// Retrieve the global array for the specified export type
RuntimeArray exportArray = GlobalVariable.getGlobalArray(moduleName + "::" + exportType);
// Add each symbol to the export array
for (String symbol : symbols) {
RuntimeArray.push(exportArray, new RuntimeScalar(symbol));
}
}
/**
* Defines a tag bundle of exportable symbols for the Perl module.
*
* @param tagName The name of the export tag (without the ':' prefix)
* @param symbols The symbols to be included in this tag bundle
*/
protected void defineExportTag(String tagName, String... symbols) {
// Get the EXPORT_TAGS hash
RuntimeHash exportTags = GlobalVariable.getGlobalHash(moduleName + "::EXPORT_TAGS");
// Create new array for the tag symbols
RuntimeArray tagArray = new RuntimeArray();
for (String symbol : symbols) {
RuntimeArray.push(tagArray, new RuntimeScalar(symbol));
}
// Add the tag array to EXPORT_TAGS hash
exportTags.put(tagName, tagArray.createReference());
}
/**
* Requires a Perl module and adds it to this module's @ISA.
* This allows the current module to inherit methods from the parent module.
* The parent module is loaded via require if not already loaded.
*
* @param parentModule The name of the parent module (e.g., "Exporter", "DynaLoader")
*/
protected void inheritFrom(String parentModule) {
// Convert module name to file path (e.g., "Exporter" -> "Exporter.pm", "Foo::Bar" -> "Foo/Bar.pm")
String modulePath = parentModule.replace("::", "/") + ".pm";
// Require the module if not already loaded
RuntimeHash inc = GlobalVariable.getGlobalHash("main::INC");
if (!inc.exists(new RuntimeScalar(modulePath)).getBoolean()) {
ModuleOperators.require(new RuntimeScalar(modulePath));
}
// Add to @ISA
RuntimeArray isa = GlobalVariable.getGlobalArray(moduleName + "::ISA");
RuntimeArray.push(isa, new RuntimeScalar(parentModule));
}
/**
* Initializes the exporter by inheriting from the Exporter module.
* This makes the module inherit Exporter's import() method from pure Perl.
*/
protected void initializeExporter() {
inheritFrom("Exporter");
}
}