Skip to content

Commit a52a50e

Browse files
committed
More work with functions
1 parent ae0542c commit a52a50e

File tree

6 files changed

+106
-76
lines changed

6 files changed

+106
-76
lines changed

src/main/java/ch/njol/skript/ScriptLoader.java

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ static ScriptInfo loadScripts() {
197197
try {
198198
Language.setUseLocal(false);
199199

200+
loadStructures(scriptsFolder);
200201
i = loadScripts(scriptsFolder);
201202

202203
synchronized (loadedScripts) {
@@ -213,7 +214,6 @@ static ScriptInfo loadScripts() {
213214
Skript.info(m_scripts_loaded.toString(i.files, i.triggers, i.commands, start.difference(new Date())));
214215

215216
SkriptEventHandler.registerBukkitEvents();
216-
Functions.postCheck(); // Check that all functions which are called exist.
217217

218218
return i;
219219
}
@@ -252,8 +252,6 @@ public final static ScriptInfo loadScripts(final File directory) {
252252
Language.setUseLocal(true);
253253
}
254254

255-
Functions.postCheck(); // Check that all functions which are called exist.
256-
257255
return i;
258256
}
259257

@@ -283,8 +281,6 @@ public final static ScriptInfo loadScripts(final File[] files) {
283281

284282
SkriptEventHandler.registerBukkitEvents();
285283

286-
Functions.postCheck(); // Check that all functions which are called exist.
287-
288284
return i;
289285
}
290286

@@ -576,10 +572,45 @@ public String run(final Matcher m) {
576572
}
577573

578574
/**
579-
* Parses elements of a script.
575+
* Loads the specified scripts.
576+
*
577+
* @param files
578+
*/
579+
public final static void loadStructures(final File[] files) {
580+
Arrays.sort(files);
581+
for (final File f : files) {
582+
assert f != null : Arrays.toString(files);
583+
loadStructure(f);
584+
}
585+
586+
587+
SkriptEventHandler.registerBukkitEvents();
588+
}
589+
590+
/**
591+
* Loads structures of all scripts in given directory.
592+
*
593+
* @param directory
594+
*/
595+
public final static void loadStructures(final File directory) {
596+
final File[] files = directory.listFiles(scriptFilter);
597+
Arrays.sort(files);
598+
for (final File f : files) {
599+
if (f.isDirectory()) {
600+
loadStructures(f);
601+
} else {
602+
loadStructure(f);
603+
}
604+
}
605+
}
606+
607+
/**
608+
* Loads structure of given script, currently only for functions. Must be called before
609+
* actually loading that script.
610+
* @param f Script
580611
*/
581612
@SuppressWarnings("unchecked")
582-
private final static void loadElements(final File f) {
613+
private final static void loadStructure(final File f) {
583614
try {
584615
final Config config = new Config(f, true, false, ":");
585616
if (SkriptConfig.keepConfigsLoaded.value())
@@ -616,7 +647,7 @@ private final static void loadElements(final File f) {
616647

617648
setCurrentEvent("function", FunctionEvent.class);
618649

619-
final Signature<?> func = Functions.loadSignature(node);
650+
final Signature<?> func = Functions.loadSignature(config.getFileName(), node);
620651
if (func != null) {
621652
numFunctions++;
622653
}
@@ -673,7 +704,8 @@ private final static ScriptInfo unloadScripts_(final File folder) {
673704
*/
674705
final static ScriptInfo unloadScript(final File script) {
675706
final ScriptInfo r = unloadScript_(script);
676-
Functions.validateFunctions();
707+
Functions.clearFunctions(script);
708+
//Functions.validateFunctions();
677709
return r;
678710
}
679711

src/main/java/ch/njol/skript/SkriptCommand.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,13 @@ public boolean onCommand(final @Nullable CommandSender sender, final @Nullable C
157157
}
158158
reloading(sender, "script", f.getName());
159159
ScriptLoader.unloadScript(f);
160+
ScriptLoader.loadStructures(new File[] {f});
160161
ScriptLoader.loadScripts(new File[] {f});
161162
reloaded(sender, r, "script", f.getName());
162163
} else {
163164
reloading(sender, "scripts in folder", f.getName());
164165
final int disabled = ScriptLoader.unloadScripts(f).files;
166+
ScriptLoader.loadStructures(f);
165167
final int enabled = ScriptLoader.loadScripts(f).files;
166168
if (Math.max(disabled, enabled) == 0)
167169
info(sender, "reload.empty folder", f.getName());
@@ -175,6 +177,7 @@ public boolean onCommand(final @Nullable CommandSender sender, final @Nullable C
175177
info(sender, "enable.all.enabling");
176178
final File[] files = toggleScripts(new File(Skript.getInstance().getDataFolder(), Skript.SCRIPTSFOLDER), true).toArray(new File[0]);
177179
assert files != null;
180+
ScriptLoader.loadStructures(files);
178181
ScriptLoader.loadScripts(files);
179182
if (r.numErrors() == 0) {
180183
info(sender, "enable.all.enabled");
@@ -202,6 +205,7 @@ public boolean onCommand(final @Nullable CommandSender sender, final @Nullable C
202205
}
203206

204207
info(sender, "enable.single.enabling", f.getName());
208+
ScriptLoader.loadStructures(new File[] {f});
205209
ScriptLoader.loadScripts(new File[] {f});
206210
if (r.numErrors() == 0) {
207211
info(sender, "enable.single.enabled", f.getName());
@@ -224,6 +228,8 @@ public boolean onCommand(final @Nullable CommandSender sender, final @Nullable C
224228
info(sender, "enable.folder.enabling", f.getName(), scripts.size());
225229
final File[] ss = scripts.toArray(new File[scripts.size()]);
226230
assert ss != null;
231+
232+
ScriptLoader.loadStructures(ss);
227233
final ScriptInfo i = ScriptLoader.loadScripts(ss);
228234
assert i.files == scripts.size();
229235
if (r.numErrors() == 0) {

src/main/java/ch/njol/skript/lang/SkriptParser.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -752,13 +752,9 @@ public final <T> FunctionReference<T> parseFunction(final @Nullable Class<? exte
752752
// }
753753
// @SuppressWarnings("null")
754754
final FunctionReference<T> e = new FunctionReference<T>(functionName, SkriptLogger.getNode(), ScriptLoader.currentScript != null ? ScriptLoader.currentScript.getFile() : null, types, params);//.toArray(new Expression[params.size()]));
755-
if (SkriptConfig.allowFunctionsBeforeDefs.value()) {
756-
Functions.addPostCheck(e); // Query function for post-checking
757-
} else {
758-
if (!e.validateFunction(true)) {
759-
log.printError();
760-
return null;
761-
}
755+
if (!e.validateFunction(true)) {
756+
log.printError();
757+
return null;
762758
}
763759
log.printLog();
764760
return e;

src/main/java/ch/njol/skript/lang/function/FunctionReference.java

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.eclipse.jdt.annotation.Nullable;
3030

3131
import ch.njol.skript.Skript;
32+
import ch.njol.skript.SkriptAPIException;
3233
import ch.njol.skript.classes.ClassInfo;
3334
import ch.njol.skript.config.Node;
3435
import ch.njol.skript.lang.Expression;
@@ -47,6 +48,8 @@ public class FunctionReference<T> {
4748

4849
@Nullable
4950
private Function<? extends T> function;
51+
@Nullable
52+
private Signature<? extends T> signature;
5053

5154
private boolean singleUberParam;
5255
private final Expression<?>[] parameters;
@@ -70,9 +73,10 @@ public FunctionReference(final String functionName, final @Nullable Node node, @
7073

7174
@SuppressWarnings("unchecked")
7275
public boolean validateFunction(final boolean first) {
76+
final Signature<?> sign = Functions.getSignature(functionName);
7377
final Function<?> newFunc = Functions.getFunction(functionName);
7478
SkriptLogger.setNode(node);
75-
if (newFunc == null) {
79+
if (sign == null) {
7680
if (first)
7781
Skript.error("The function '" + functionName + "' does not exist.");
7882
else
@@ -85,7 +89,7 @@ public boolean validateFunction(final boolean first) {
8589

8690
final Class<? extends T>[] returnTypes = this.returnTypes;
8791
if (returnTypes != null) {
88-
final ClassInfo<?> rt = newFunc.returnType;
92+
final ClassInfo<?> rt = sign.returnType;
8993
if (rt == null) {
9094
if (first)
9195
Skript.error("The function '" + functionName + "' doesn't return any value.");
@@ -96,31 +100,31 @@ public boolean validateFunction(final boolean first) {
96100
}
97101
if (!CollectionUtils.containsAnySuperclass(returnTypes, rt.getC())) {
98102
if (first)
99-
Skript.error("The returned value of the function '" + functionName + "', " + newFunc.returnType + ", is " + SkriptParser.notOfType(returnTypes) + ".");
103+
Skript.error("The returned value of the function '" + functionName + "', " + sign.returnType + ", is " + SkriptParser.notOfType(returnTypes) + ".");
100104
else
101105
Skript.error("The function '" + functionName + "' was redefined with a different, incompatible return type, but is still used in other script(s)."
102106
+ " These will continue to use the old version of the function until Skript restarts.");
103107
return false;
104108
}
105109
if (first) {
106-
single = newFunc.single;
107-
} else if (single && !newFunc.single) {
110+
single = sign.single;
111+
} else if (single && !sign.single) {
108112
Skript.error("The function '" + functionName + "' was redefined with a different, incompatible return type, but is still used in other script(s)."
109113
+ " These will continue to use the old version of the function until Skript restarts.");
110114
return false;
111115
}
112116
}
113117

114118
// check number of parameters only if the function does not have a single parameter that accepts multiple values
115-
singleUberParam = newFunc.getMaxParameters() == 1 && !newFunc.parameters[0].single;
119+
singleUberParam = sign.getMaxParameters() == 1 && !sign.parameters.get(0).single;
116120
if (!singleUberParam) {
117-
if (parameters.length > newFunc.getMaxParameters()) {
121+
if (parameters.length > sign.getMaxParameters()) {
118122
if (first) {
119-
if (newFunc.getMaxParameters() == 0)
123+
if (sign.getMaxParameters() == 0)
120124
Skript.error("The function '" + functionName + "' has no arguments, but " + parameters.length + " are given."
121125
+ " To call a function without parameters, just write the function name followed by '()', e.g. 'func()'.");
122126
else
123-
Skript.error("The function '" + functionName + "' has only " + newFunc.getMaxParameters() + " argument" + (newFunc.getMaxParameters() == 1 ? "" : "s") + ","
127+
Skript.error("The function '" + functionName + "' has only " + sign.getMaxParameters() + " argument" + (sign.getMaxParameters() == 1 ? "" : "s") + ","
124128
+ " but " + parameters.length + " are given."
125129
+ " If you want to use lists in function calls, you have to use additional parentheses, e.g. 'give(player, (iron ore and gold ore))'");
126130
} else {
@@ -130,17 +134,17 @@ public boolean validateFunction(final boolean first) {
130134
return false;
131135
}
132136
}
133-
if (parameters.length < newFunc.getMinParameters()) {
137+
if (parameters.length < sign.getMinParameters()) {
134138
if (first)
135-
Skript.error("The function '" + functionName + "' requires at least " + newFunc.getMinParameters() + " argument" + (newFunc.getMinParameters() == 1 ? "" : "s") + ","
139+
Skript.error("The function '" + functionName + "' requires at least " + sign.getMinParameters() + " argument" + (sign.getMinParameters() == 1 ? "" : "s") + ","
136140
+ " but only " + parameters.length + " " + (parameters.length == 1 ? "is" : "are") + " given.");
137141
else
138142
Skript.error("The function '" + functionName + "' was redefined with a different, incompatible amount of arguments, but is still used in other script(s)."
139143
+ " These will continue to use the old version of the function until Skript restarts.");
140144
return false;
141145
}
142146
for (int i = 0; i < parameters.length; i++) {
143-
final Parameter<?> p = newFunc.parameters[singleUberParam ? 0 : i];
147+
final Parameter<?> p = sign.parameters.get(singleUberParam ? 0 : i);
144148
final RetainingLogHandler log = SkriptLogger.startRetainingLog();
145149
try {
146150
final Expression<?> e = parameters[i].getConvertedExpression(p.type.getC());
@@ -160,16 +164,18 @@ public boolean validateFunction(final boolean first) {
160164
}
161165
}
162166

163-
function = (Function<? extends T>) newFunc;
167+
signature = (Signature<? extends T>) sign;
168+
function = (Function<? extends T>) newFunc; // Try this, in case it exists
164169
Functions.registerCaller(this);
165170

166171
return true;
167172
}
168173

174+
@SuppressWarnings("unchecked")
169175
@Nullable
170176
protected T[] execute(final Event e) {
171177
if (function == null)
172-
return null;
178+
function = (Function<? extends T>) Functions.getFunction(functionName);
173179

174180
final Object[][] params = new Object[singleUberParam ? 1 : parameters.length][];
175181
if (singleUberParam && parameters.length > 1) {
@@ -191,10 +197,12 @@ public boolean isSingle() {
191197

192198
@SuppressWarnings("unchecked")
193199
public Class<? extends T> getReturnType() {
194-
if (function == null)
195-
return (Class<? extends T>) Void.class; // No function = no return
196-
assert function != null;
197-
ClassInfo<? extends T> ret = function.getReturnType();
200+
if (signature == null) {
201+
throw new SkriptAPIException("Signature of function is null when return type is asked!");
202+
}
203+
assert signature != null;
204+
@SuppressWarnings("null") // Wait what, Eclipse? Already asserted this...
205+
ClassInfo<? extends T> ret = signature.returnType;
198206
return (Class<? extends T>) (ret == null ? Unknown.class : ret.getC());
199207
}
200208

src/main/java/ch/njol/skript/lang/function/Functions.java

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ public final static Function<?> loadFunction(final SectionNode node) {
109109
// return error("Invalid function definition. Please check for typos and that the function's name only contains letters and underscores. Refer to the documentation for more information.");
110110
final String name = "" + m.group(1);
111111
Signature<?> sign = signatures.get(name);
112-
final List<Parameter<?>> params = sign.getParameters();
113-
final ClassInfo<?> c = sign.getReturnType();
114-
final NonNullPair<String, Boolean> p = sign.getDbgInfo();
112+
final List<Parameter<?>> params = sign.parameters;
113+
final ClassInfo<?> c = sign.returnType;
114+
final NonNullPair<String, Boolean> p = sign.info;
115115

116116
if (Skript.debug() || node.debug())
117117
Skript.debug("function " + name + "(" + StringUtils.join(params, ", ") + ")" + (c != null && p != null ? " :: " + Utils.toEnglishPlural(c.getCodeName(), p.getSecond()) : "") + ":");
@@ -123,14 +123,14 @@ public final static Function<?> loadFunction(final SectionNode node) {
123123
}
124124

125125
@Nullable
126-
public static Signature<?> loadSignature(final SectionNode node) {
126+
public static Signature<?> loadSignature(String script, final SectionNode node) {
127127
SkriptLogger.setNode(node);
128128
final String definition = node.getKey();
129129
assert definition != null;
130130
final Matcher m = functionPattern.matcher(definition);
131131
if (!m.matches())
132-
error("Invalid function definition. Please check for typos and that the function's name only contains letters and underscores. Refer to the documentation for more information.");
133-
final String name = "" + m.group(1);
132+
return signError("Invalid function definition. Please check for typos and that the function's name only contains letters and underscores. Refer to the documentation for more information.");
133+
final String name = "" + m.group(1); // TODO check for name uniqueness (currently functions with same name silently override each other)
134134
final String args = m.group(2);
135135
final String returnType = m.group(3);
136136
final List<Parameter<?>> params = new ArrayList<Parameter<?>>();
@@ -181,7 +181,7 @@ public static Signature<?> loadSignature(final SectionNode node) {
181181
}
182182

183183
@SuppressWarnings("unchecked")
184-
Signature<?> sign = new Signature<Object>(name, params, (ClassInfo<Object>) c, p);
184+
Signature<?> sign = new Signature<Object>(script, name, params, (ClassInfo<Object>) c, p, p == null ? false : !p.getSecond());
185185
return sign;
186186
}
187187

@@ -225,6 +225,7 @@ public final static int clearFunctions(final File script) {
225225
final FunctionData d = iter.next();
226226
if (d.function instanceof ScriptFunction && script.equals(((ScriptFunction<?>) d.function).trigger.getScript())) {
227227
iter.remove();
228+
signatures.remove(d.function.name);
228229
r++;
229230
final Iterator<FunctionReference<?>> it = d.calls.iterator();
230231
while (it.hasNext()) {
@@ -257,6 +258,7 @@ public final static void clearFunctions() {
257258
else
258259
d.calls.clear();
259260
}
261+
signatures.clear();
260262
assert toValidate.isEmpty() : toValidate;
261263
toValidate.clear();
262264
}
@@ -266,23 +268,4 @@ public static Iterable<JavaFunction<?>> getJavaFunctions() {
266268
return javaFunctions.values();
267269
}
268270

269-
public final static void addPostCheck(FunctionReference<?> ref) {
270-
postCheckNeeded.add(ref);
271-
}
272-
273-
public final static void postCheck() {
274-
if (postCheckNeeded.isEmpty()) return;
275-
276-
final ParseLogHandler log = SkriptLogger.startParseLogHandler();
277-
for (final FunctionReference<?> ref : postCheckNeeded) {
278-
if (!ref.validateFunction(true)) {
279-
log.printError();
280-
}
281-
}
282-
log.printLog();
283-
284-
postCheckNeeded.clear();
285-
log.stop();
286-
}
287-
288271
}

0 commit comments

Comments
 (0)