Skip to content

Commit 5a532d4

Browse files
committed
Tweak thread safety and test dependency bleeding.
1 parent 8753f1b commit 5a532d4

File tree

5 files changed

+134
-6
lines changed

5 files changed

+134
-6
lines changed

src/main/java/org/byteskript/skript/api/SyntaxElement.java

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,51 @@
2525

2626
import static mx.kenzie.foundation.WriteInstruction.*;
2727

28+
/**
29+
* A syntax element.
30+
* This instance controls the matching and compiling for a specific element.
31+
* The library it comes from controls where it can be matched.
32+
*/
2833
public interface SyntaxElement {
2934

35+
/**
36+
* Attempts to match this element to a source string.
37+
* The context can be accessed, but should not be modified here.
38+
* If the source does not match this element, return `null`.
39+
* If the source does match this element, return a match object with the match data in.
40+
* <p>
41+
* Complex patterns are advised to override this and attempt faster
42+
* checks with {@link String#contains(CharSequence)} before running the super matcher.
43+
* This will circumvent a complex regex having to be checked every time.
44+
*
45+
* @param thing the source
46+
* @param context the context of this source
47+
* @return the match result
48+
*/
3049
default Pattern.Match match(String thing, Context context) {
31-
return getPattern().match(thing, context);
50+
return this.getPattern().match(thing, context);
3251
}
3352

53+
/**
54+
* The pattern metadata object.
55+
*
56+
* @return the pattern
57+
*/
3458
Pattern getPattern();
3559

60+
/**
61+
* The library that provides this syntax element.
62+
*
63+
* @return the provider
64+
*/
3665
Library getProvider();
3766

67+
/**
68+
* For basic syntax, this can return a method that will be used as a handle.
69+
*
70+
* @param type the handler mode
71+
* @return the method handle
72+
*/
3873
Method getHandler(HandlerType type);
3974

4075
void setHandler(HandlerType type, Method method);
@@ -60,14 +95,35 @@ default boolean allowAsInputFor(Type type) {
6095

6196
boolean hasHandler(HandlerType type);
6297

98+
/**
99+
* The return type of this element, used for type tracking during compilation.
100+
*
101+
* @return the return type
102+
*/
63103
default Type getReturnType() {
64104
return CommonTypes.VOID;
65105
}
66106

107+
/**
108+
* This is called during the first compiler pass, Out->In, L->R.
109+
* Simple elements will not need this, but lookahead or re-ordering operations can be run here.
110+
*
111+
* @param context the compiler context
112+
* @param match the match used
113+
* @throws Throwable to avoid unnecessary try/catch blocks
114+
*/
67115
default void preCompile(Context context, Pattern.Match match) throws Throwable {
68116
// Very few elements require a lookahead.
69117
}
70118

119+
/**
120+
* This is called during the second compiler pass, In->Out, L->R.
121+
* Non-trivial syntax may need to override this to provide special behaviour.
122+
*
123+
* @param context the compiler context
124+
* @param match the match used
125+
* @throws Throwable to avoid unnecessary try/catch blocks
126+
*/
71127
void compile(Context context, Pattern.Match match) throws Throwable;
72128

73129
default boolean allowedIn(State state, Context context) {
@@ -86,6 +142,15 @@ default void addSkipInstruction(Context context, Consumer<Context> consumer) {
86142
context.addSkipInstruction(consumer);
87143
}
88144

145+
/**
146+
* This writes a smart method call for the syntax, obeying rewrite rules.
147+
* This can perform inlining, extraction and basic rewrites.
148+
* This also has access to the bridge compiler.
149+
*
150+
* @param builder the method builder to use
151+
* @param method the target method
152+
* @param context the compiler context
153+
*/
89154
default void writeCall(final MethodBuilder builder, final Method method, final Context context) {
90155
final ForceInline inline = method.getAnnotation(ForceInline.class);
91156
final ForceExtract extract = method.getAnnotation(ForceExtract.class);
@@ -133,6 +198,9 @@ default void writeCall(final MethodBuilder builder, final Method method, final C
133198
}
134199
}
135200

201+
/**
202+
* A wrapped version of {@link Class#getMethod(String, Class[])} to avoid catching exceptions.
203+
*/
136204
default Method findMethod(Class<?> owner, String name, Class<?>... parameters) {
137205
try {
138206
return owner.getMethod(name, parameters);
@@ -168,7 +236,7 @@ default String name() {
168236

169237
default String description() {
170238
final Documentation documentation = this.getClass().getAnnotation(Documentation.class);
171-
if (documentation == null) return "None.";
239+
if (documentation == null) return "No description.";
172240
return documentation.description();
173241
}
174242

@@ -179,9 +247,7 @@ default String[] examples() {
179247
}
180248

181249
class Handlers extends HashMap<HandlerType, Method> {
182-
183-
public static final Handlers EMPTY = new Handlers();
184-
250+
185251
}
186252

187253
}

src/main/java/org/byteskript/skript/api/syntax/Element.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
import java.lang.reflect.Method;
1616
import java.util.Arrays;
1717

18+
/**
19+
* The basic syntax element class, which all existing syntax uses.
20+
*/
1821
public abstract class Element implements SyntaxElement {
1922

2023
protected final Library provider;

src/main/java/org/byteskript/skript/runtime/Script.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public Class<? extends CompiledScript> mainClass() {
8989
}
9090

9191
void verify() {
92-
this.forceLoad(mainClass());
92+
this.forceLoad(this.mainClass());
9393
for (final Map.Entry<String, Member> entry : functions.entrySet()) {
9494
final Member value = entry.getValue();
9595
final String name = entry.getKey();

src/main/java/org/byteskript/skript/runtime/internal/Member.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
import java.util.Collection;
2020
import java.util.concurrent.Future;
2121

22+
/**
23+
* A handle for a function, event, etc. inside a script.
24+
* Keeping strong references to this is not advised, since it will prevent safe unloading.
25+
* The member can be triggered safely from this.
26+
*/
2227
public class Member {
2328

2429
protected final Script script;
@@ -123,10 +128,46 @@ public static MethodAccessor<Object> findFunction(Object owner, String name, Num
123128
return Mirror.of(owner).useProvider(Skript.findLoader()).method(name, parameters);
124129
}
125130

131+
/**
132+
* Gets the script instance that provided this member.
133+
*
134+
* @return the owning script
135+
*/
126136
public Script getScript() {
127137
return script;
128138
}
129139

140+
/**
141+
* Triggers this member in a new script thread.
142+
* This will be run in the runtime from which the member was originally loaded.
143+
*
144+
* @param arguments the (function) arguments to pass
145+
* @return a future governing this process
146+
*/
147+
public Future<?> run(Object... arguments) {
148+
final ScriptRunner runner = new ScriptRunner() {
149+
@Override
150+
public void start() {
151+
invoker.invoke(arguments);
152+
}
153+
154+
@Override
155+
public Class<? extends CompiledScript> owner() {
156+
return script.mainClass();
157+
}
158+
};
159+
return script.skriptInstance().runScript(runner);
160+
}
161+
162+
/**
163+
* Triggers this member in a new script thread.
164+
* This allows running in a different script runtime.
165+
* This is potentially unsafe - alternative class versions can bleed between runtimes.
166+
*
167+
* @param skript the Skript runtime
168+
* @param arguments the (function) arguments to pass
169+
* @return a future governing this process
170+
*/
130171
public Future<?> run(Skript skript, Object... arguments) {
131172
final ScriptRunner runner = new ScriptRunner() {
132173
@Override
@@ -142,6 +183,10 @@ public Class<? extends CompiledScript> owner() {
142183
return skript.runScript(runner);
143184
}
144185

186+
/**
187+
* Triggers this member's verifier with a set of `null` parameters.
188+
* Rather than returning a boolean result, this will throw an error if the verifier fails.
189+
*/
145190
public void verify() {
146191
if (verifier == null) return;
147192
verifier.invoke(new Object[parameters]);

src/test/java/org/byteskript/skript/test/ThreadingTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
public class ThreadingTest extends SkriptTest {
1717

1818
private static final Skript skript = new Skript();
19+
private static final Skript skript2 = new Skript();
1920
private static Script script;
21+
private static Script script2;
2022

2123
@BeforeClass
2224
public static void start() throws Throwable {
2325
final PostCompileClass cls = skript.compileScript(ProvidedFunctionsTest.class.getClassLoader()
2426
.getResourceAsStream("flow.bsk"), "skript.flow");
2527
script = skript.loadScript(cls);
28+
script2 = skript2.loadScript(cls);
2629
}
2730

2831
@Test
@@ -32,4 +35,15 @@ public void sleep_test() throws Throwable {
3235
function.run(skript).get();
3336
}
3437

38+
@Test
39+
public void multipleProcess() throws Throwable {
40+
final Member function = script.getFunction("sleep_flow");
41+
final Member function2 = script2.getFunction("sleep_flow");
42+
function.run(skript).get();
43+
function.run(skript2).get();
44+
function2.run(skript2).get();
45+
assert script.mainClass() != script2.mainClass();
46+
assert script.skriptInstance() != script2.skriptInstance();
47+
}
48+
3549
}

0 commit comments

Comments
 (0)