Skip to content

Commit 0ec2972

Browse files
committed
Script loading distribution.
1 parent 137ca31 commit 0ec2972

File tree

13 files changed

+357
-31
lines changed

13 files changed

+357
-31
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>org.byteskript</groupId>
88
<artifactId>byteskript</artifactId>
9-
<version>1.0.8</version>
9+
<version>1.0.9</version>
1010
<name>ByteSkript</name>
1111

1212
<properties>

src/main/java/org/byteskript/skript/app/ScriptLoader.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,17 @@
66

77
package org.byteskript.skript.app;
88

9-
import org.byteskript.skript.runtime.Script;
109
import org.byteskript.skript.runtime.Skript;
1110

1211
import java.io.IOException;
13-
import java.util.ArrayList;
14-
import java.util.Collection;
15-
import java.util.List;
1612

1713
public final class ScriptLoader extends SkriptApp {
1814
private static final Skript SKRIPT = new Skript();
1915

20-
static final List<Script> SCRIPTS = new ArrayList<>();
21-
2216
public static void main(String... args) throws IOException {
2317
registerLibraries(SKRIPT);
24-
final Collection<Script> scripts = SKRIPT.compileLoadScripts(SOURCE);
18+
SKRIPT.compileLoadScripts(SOURCE);
2519
new SimpleThrottleController(SKRIPT).run();
26-
SCRIPTS.addAll(scripts);
2720
}
2821

2922
}

src/main/java/org/byteskript/skript/compiler/SkriptLangSpec.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
import org.byteskript.skript.lang.syntax.map.KeyInMap;
5353
import org.byteskript.skript.lang.syntax.map.MapCreator;
5454
import org.byteskript.skript.lang.syntax.maths.*;
55+
import org.byteskript.skript.lang.syntax.script.CurrentScriptExpression;
56+
import org.byteskript.skript.lang.syntax.script.LoadScriptEffect;
57+
import org.byteskript.skript.lang.syntax.script.UnloadScriptEffect;
5558
import org.byteskript.skript.lang.syntax.timing.*;
5659
import org.byteskript.skript.lang.syntax.type.*;
5760
import org.byteskript.skript.lang.syntax.type.property.FinalEntry;
@@ -169,7 +172,9 @@ private SkriptLangSpec() {
169172
new BreakIfEffect(),
170173
new BreakEffect(),
171174
new TryEffect(),
172-
new ClearList()
175+
new ClearList(),
176+
new LoadScriptEffect(),
177+
new UnloadScriptEffect()
173178
);
174179
registerSyntax(CompileState.STATEMENT,
175180
new NoneLiteral(),

src/main/java/org/byteskript/skript/lang/syntax/generic/CurrentScriptExpression.java renamed to src/main/java/org/byteskript/skript/lang/syntax/script/CurrentScriptExpression.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
/*
2-
* Copyright (c) 2021 ByteSkript org (Moderocky)
2+
* Copyright (c) 2021-2022 ByteSkript org (Moderocky)
33
* View the full licence information and permissions:
44
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
55
*/
66

7-
package org.byteskript.skript.lang.syntax.generic;
7+
package org.byteskript.skript.lang.syntax.script;
88

99
import mx.kenzie.foundation.MethodBuilder;
1010
import mx.kenzie.foundation.Type;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2021 ByteSkript org (Moderocky)
3+
* View the full licence information and permissions:
4+
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
5+
*/
6+
7+
package org.byteskript.skript.lang.syntax.script;
8+
9+
import org.byteskript.skript.api.note.Documentation;
10+
import org.byteskript.skript.api.note.ForceExtract;
11+
import org.byteskript.skript.api.syntax.Effect;
12+
import org.byteskript.skript.compiler.SkriptLangSpec;
13+
import org.byteskript.skript.lang.element.StandardElements;
14+
import org.byteskript.skript.lang.handler.StandardHandlers;
15+
import org.byteskript.skript.runtime.Skript;
16+
17+
import java.io.ByteArrayInputStream;
18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.nio.charset.StandardCharsets;
21+
22+
@Documentation(
23+
name = "Load Script",
24+
description = """
25+
Loads a script from the given file or string source code.
26+
""",
27+
examples = {
28+
"""
29+
load script {file} as "skript/myscript"
30+
load script {code} as "skript/myscript"
31+
"""
32+
} // todo
33+
)
34+
public class LoadScriptEffect extends Effect {
35+
36+
public LoadScriptEffect() {
37+
super(SkriptLangSpec.LIBRARY, StandardElements.EFFECT, "load script %Object% as %String%");
38+
handlers.put(StandardHandlers.RUN, findMethod(this.getClass(), "loadScript", Object.class, String.class));
39+
}
40+
41+
@ForceExtract
42+
public static void loadScript(Object object, String name) throws IOException {
43+
if (object instanceof File file)
44+
Skript.currentInstance().compileLoad(file, name);
45+
else if (object instanceof String string)
46+
Skript.currentInstance()
47+
.compileLoad(new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)), name);
48+
}
49+
50+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright (c) 2021 ByteSkript org (Moderocky)
3+
* View the full licence information and permissions:
4+
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
5+
*/
6+
7+
package org.byteskript.skript.lang.syntax.script;
8+
9+
import org.byteskript.skript.api.note.Documentation;
10+
import org.byteskript.skript.api.note.ForceExtract;
11+
import org.byteskript.skript.api.syntax.Effect;
12+
import org.byteskript.skript.compiler.SkriptLangSpec;
13+
import org.byteskript.skript.lang.element.StandardElements;
14+
import org.byteskript.skript.lang.handler.StandardHandlers;
15+
import org.byteskript.skript.runtime.Script;
16+
import org.byteskript.skript.runtime.Skript;
17+
18+
import java.io.IOException;
19+
20+
@Documentation(
21+
name = "Unload Script",
22+
description = """
23+
Unloads a script by its class name.
24+
If you store the script or any of its functions it will not unload.
25+
This is a **very** destructive operation - misusing it can cause serious errors.
26+
""",
27+
examples = {
28+
"""
29+
unload script skript/myscript
30+
"""
31+
} // todo
32+
)
33+
public class UnloadScriptEffect extends Effect {
34+
35+
public UnloadScriptEffect() {
36+
super(SkriptLangSpec.LIBRARY, StandardElements.EFFECT, "unload script %Object%");
37+
handlers.put(StandardHandlers.RUN, findMethod(this.getClass(), "unloadScript", Object.class));
38+
}
39+
40+
@ForceExtract
41+
public static void unloadScript(Object object) throws IOException {
42+
if (object instanceof Class main)
43+
Skript.currentInstance().unloadScript(main);
44+
else if (object instanceof Script script)
45+
Skript.currentInstance().unloadScript(script);
46+
else if (object instanceof String name)
47+
Skript.currentInstance().unloadScript(Skript.LOADER.findClass(name.replace('/', '.')));
48+
}
49+
50+
}

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

Lines changed: 76 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@
1616
import org.byteskript.skript.compiler.SkriptCompiler;
1717
import org.byteskript.skript.error.ScriptCompileError;
1818
import org.byteskript.skript.error.ScriptLoadError;
19-
import org.byteskript.skript.runtime.internal.EventHandler;
20-
import org.byteskript.skript.runtime.internal.GlobalVariableMap;
21-
import org.byteskript.skript.runtime.internal.Instruction;
22-
import org.byteskript.skript.runtime.internal.ModifiableCompiler;
19+
import org.byteskript.skript.runtime.internal.*;
2320
import org.byteskript.skript.runtime.threading.*;
2421

2522
import java.io.*;
@@ -43,7 +40,9 @@ public final class Skript {
4340
final ModifiableCompiler compiler;
4441
final List<OperationController> processes;
4542
final Map<Class<? extends Event>, EventHandler> events;
46-
final SkriptMirror mirror = new SkriptMirror(Skript.class);
43+
final SkriptMirror mirror = new SkriptMirror(LOADER);
44+
final WeakList<ScriptClassLoader> loaders = new WeakList<>();
45+
final List<Script> scripts = new ArrayList<>(); // the only strong reference, be careful!
4746
static final GlobalVariableMap VARIABLES = new GlobalVariableMap();
4847

4948
public static class RuntimeClassLoader extends ClassLoader implements ClassProvider {
@@ -53,14 +52,32 @@ protected RuntimeClassLoader(ClassLoader parent) {
5352

5453
@Override
5554
public Class<?> loadClass(String name) throws ClassNotFoundException {
56-
return super.loadClass(name);
55+
try {
56+
return super.loadClass(name);
57+
} catch (ClassNotFoundException ex) {
58+
for (final ScriptClassLoader value : Skript.currentInstance().loaders.collectRemaining()) {
59+
if (value == null) continue;
60+
try {
61+
return value.loadClass0(name);
62+
} catch (ClassNotFoundException ignored) {
63+
}
64+
}
65+
throw ex;
66+
}
5767
}
5868

5969
@Override
6070
public Class<?> findClass(String name) {
6171
try {
6272
return super.findClass(name);
6373
} catch (ClassNotFoundException e) {
74+
for (final ScriptClassLoader value : Skript.currentInstance().loaders.collectRemaining()) {
75+
if (value == null) continue;
76+
try {
77+
return value.findClass0(name);
78+
} catch (ClassNotFoundException ignored) {
79+
}
80+
}
6481
return Skript.currentInstance().getClass(name);
6582
}
6683
}
@@ -80,9 +97,9 @@ public Class<?> loadClass(Class<?> aClass, String name, byte[] bytecode) {
8097
}
8198

8299
static class SkriptMirror extends Mirror<Object> {
83-
protected SkriptMirror(Object target) {
84-
super(target);
85-
useProvider(LOADER);
100+
protected SkriptMirror(ClassProvider provider) {
101+
super(Skript.class);
102+
useProvider(provider);
86103
}
87104

88105
@Override
@@ -91,6 +108,16 @@ public Class<?> loadClass(String name, byte[] bytecode) {
91108
}
92109
}
93110

111+
private Class<?> loadClass(String name, byte[] bytecode) {
112+
return this.createLoader().loadClass(name, bytecode);
113+
}
114+
115+
private SkriptMirror createLoader() {
116+
final ScriptClassLoader loader = new ScriptClassLoader();
117+
this.loaders.addActual(loader);
118+
return new SkriptMirror(loader);
119+
}
120+
94121
public Skript(ModifiableCompiler compiler) {
95122
this(new SkriptThreadProvider(), compiler, Thread.currentThread());
96123
}
@@ -337,6 +364,33 @@ public PostCompileClass compileScript(final InputStream stream, final String nam
337364
//endregion
338365

339366
//region Script Loading
367+
public void unloadScript(Class<?> main) {
368+
for (Script script : scripts.toArray(new Script[0])) {
369+
if (script.mainClass() == main) this.unloadScript(script);
370+
}
371+
}
372+
373+
public void unloadScript(Script script) {
374+
synchronized (events) {
375+
for (final EventHandler value : events.values()) {
376+
for (final ScriptRunner trigger : value.getTriggers().toArray(new ScriptRunner[0])) {
377+
if (trigger.owner() != script.mainClass()) continue;
378+
value.getTriggers().remove(trigger);
379+
UnsafeAccessor.graveyard(trigger);
380+
}
381+
}
382+
}
383+
scripts.remove(script);
384+
UnsafeAccessor.graveyard(script);
385+
}
386+
387+
@Deprecated
388+
public Script compileLoad(File file, String name) throws IOException {
389+
try (final InputStream stream = new FileInputStream(file)) {
390+
return compileLoad(stream, null);
391+
}
392+
}
393+
340394
@Deprecated
341395
public Script compileLoad(InputStream stream, String name) {
342396
return loadScript(compileScript(stream, name));
@@ -386,22 +440,26 @@ public Script assembleScript(final PostCompileClass... data) {
386440
if (data.length == 0) return null;
387441
final List<Class<?>> classes = new ArrayList<>();
388442
for (PostCompileClass datum : data) {
389-
final Class<?> part = mirror.loadClass(datum.name(), datum.code());
443+
final Class<?> part = this.createLoader().loadClass(datum.name(), datum.code());
390444
classes.add(part);
391445
}
392-
return new Script(false, this, null, classes.toArray(new Class[0]));
446+
return assembleScript(classes.toArray(new Class[0]));
393447
}
394448

395-
public Script assembleScript(final Class<?> loaded) {
396-
return new Script(false, this, null, loaded);
449+
public Script assembleScript(final Class<?>... loaded) {
450+
final Script script = new Script(false, this, null, loaded);
451+
this.scripts.add(script);
452+
return script;
397453
}
398454

399455
public Script loadScript(final Class<?> loaded) {
400-
return new Script(this, null, loaded);
456+
final Script script = new Script(this, null, loaded);
457+
this.scripts.add(script);
458+
return script;
401459
}
402460

403461
public Script loadScript(final PostCompileClass datum) {
404-
return new Script(this, null, mirror.loadClass(datum.name(), datum.code()));
462+
return loadScript(this.loadClass(datum.name(), datum.code()));
405463
}
406464

407465
public Collection<Script> loadScripts(final PostCompileClass[] data) {
@@ -413,7 +471,7 @@ public Collection<Script> loadScripts(final PostCompileClass[] data) {
413471
}
414472

415473
public Script loadScript(final byte[] bytecode, final String name) {
416-
return new Script(this, null, mirror.loadClass(name, bytecode));
474+
return loadScript(this.loadClass(name, bytecode));
417475
}
418476

419477
public Script loadScript(final byte[] bytecode) throws IOException {
@@ -422,7 +480,7 @@ public Script loadScript(final byte[] bytecode) throws IOException {
422480

423481
public Script loadScript(final InputStream stream, final String name)
424482
throws IOException {
425-
return new Script(this, null, mirror.loadClass(name, stream.readAllBytes()));
483+
return loadScript(this.loadClass(name, stream.readAllBytes()));
426484
}
427485

428486
public Script loadScript(final InputStream stream)
@@ -440,7 +498,7 @@ public Script loadScript(final File source)
440498
public Script loadScript(final File source, final String name)
441499
throws IOException {
442500
try (InputStream stream = new FileInputStream(source)) {
443-
return new Script(this, source, mirror.loadClass(name, stream.readAllBytes()));
501+
return loadScript(this.loadClass(name, stream.readAllBytes()));
444502
}
445503
}
446504
//endregion

0 commit comments

Comments
 (0)