-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathSubUtil.java
More file actions
150 lines (136 loc) · 5.21 KB
/
SubUtil.java
File metadata and controls
150 lines (136 loc) · 5.21 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
package org.perlonjava.runtime.perlmodule;
import org.perlonjava.runtime.runtimetypes.*;
import static org.perlonjava.runtime.runtimetypes.RuntimeScalarType.*;
/**
* Sub::Util module implementation for PerlOnJava.
* Provides utility functions for working with subroutines.
*/
public class SubUtil extends PerlModuleBase {
/**
* Constructor for SubUtil.
*/
public SubUtil() {
super("Sub::Util");
}
/**
* Static initializer to set up the Sub::Util module.
*/
public static void initialize() {
SubUtil subUtil = new SubUtil();
subUtil.initializeExporter();
// Set $VERSION so CPAN.pm can detect our bundled version
GlobalVariable.getGlobalVariable("Sub::Util::VERSION").set(new RuntimeScalar("1.70"));
subUtil.defineExport("EXPORT_OK", "prototype", "set_prototype", "subname", "set_subname");
try {
subUtil.registerMethod("prototype", "$");
subUtil.registerMethod("set_prototype", null); // No prototype to allow @_ passing
subUtil.registerMethod("subname", "$");
subUtil.registerMethod("set_subname", null); // No prototype to allow @_ passing
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing Sub::Util method: " + e.getMessage());
}
}
/**
* Returns the prototype of a subroutine.
*
* @param args The arguments: a CODE reference
* @param ctx The context
* @return The prototype string or undef
*/
public static RuntimeList prototype(RuntimeArray args, int ctx) {
if (args.size() != 1) {
throw new IllegalStateException("Bad number of arguments for prototype()");
}
RuntimeScalar codeRef = args.get(0);
if (codeRef.type != CODE) {
return new RuntimeScalar().getList(); // undef for non-CODE
}
RuntimeCode code = (RuntimeCode) codeRef.value;
String proto = code.prototype;
if (proto == null) {
return new RuntimeScalar().getList(); // undef
}
return new RuntimeScalar(proto).getList();
}
/**
* Sets the prototype of a subroutine.
*
* @param args The arguments: prototype string, CODE reference
* @param ctx The context
* @return The CODE reference
*/
public static RuntimeList set_prototype(RuntimeArray args, int ctx) {
if (args.size() != 2) {
throw new IllegalStateException("Bad number of arguments for set_prototype()");
}
RuntimeScalar protoScalar = args.get(0);
RuntimeScalar codeRef = args.get(1);
if (codeRef.type != CODE) {
throw new IllegalArgumentException("set_prototype requires a CODE reference");
}
RuntimeCode code = (RuntimeCode) codeRef.value;
if (protoScalar.type == UNDEF) {
code.prototype = null;
} else {
code.prototype = protoScalar.toString();
}
return codeRef.getList();
}
/**
* Returns the name of a subroutine.
*
* @param args The arguments: a CODE reference
* @param ctx The context
* @return The name of the subroutine
*/
public static RuntimeList subname(RuntimeArray args, int ctx) {
if (args.size() != 1) {
throw new IllegalStateException("Bad number of arguments for subname()");
}
RuntimeScalar codeRef = args.get(0);
if (codeRef.type != CODE) {
return new RuntimeScalar().getList(); // undef for non-CODE
}
RuntimeCode code = (RuntimeCode) codeRef.value;
String pkg = code.packageName;
String sub = code.subName;
if (sub == null || sub.isEmpty()) {
return new RuntimeScalar("__ANON__").getList();
}
if (pkg != null && !pkg.isEmpty()) {
return new RuntimeScalar(pkg + "::" + sub).getList();
}
return new RuntimeScalar(sub).getList();
}
/**
* Sets the name of a subroutine.
*
* @param args The arguments: name string, CODE reference
* @param ctx The context
* @return The CODE reference
*/
public static RuntimeList set_subname(RuntimeArray args, int ctx) {
if (args.size() != 2) {
throw new IllegalStateException("Bad number of arguments for set_subname()");
}
RuntimeScalar nameScalar = args.get(0);
RuntimeScalar codeRef = args.get(1);
if (codeRef.type != CODE) {
throw new IllegalArgumentException("set_subname requires a CODE reference");
}
RuntimeCode code = (RuntimeCode) codeRef.value;
String fullName = nameScalar.toString();
// Parse package::subname format
int lastColon = fullName.lastIndexOf("::");
if (lastColon >= 0) {
code.packageName = fullName.substring(0, lastColon);
code.subName = fullName.substring(lastColon + 2);
} else {
code.subName = fullName;
}
// Mark the CV as explicitly renamed so B::svref_2object()->GV->NAME
// honors the assigned name even when no matching stash entry exists.
code.explicitlyRenamed = true;
return codeRef.getList();
}
}