Skip to content

Commit b80829f

Browse files
committed
Monitor section.
1 parent e83f0f2 commit b80829f

File tree

10 files changed

+231
-5
lines changed

10 files changed

+231
-5
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.28</version>
9+
<version>1.0.29</version>
1010
<name>ByteSkript</name>
1111
<description>A compiled JVM implementation of the Skript language.</description>
1212

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,15 @@ private SkriptLangSpec() {
125125
);
126126
registerConverter(String.class, Integer.class, Integer::valueOf);
127127
registerConverter(String.class, Double.class, Double::valueOf);
128+
registerConverter(String.class, Float.class, Float::valueOf);
128129
registerConverter(String.class, Long.class, Long::valueOf);
129130
registerConverter(String.class, Number.class, Double::valueOf);
131+
registerConverter(String.class, Boolean.class, Boolean::valueOf);
130132
registerConverter(String.class, Error.class, Error::new);
131133
registerConverter(String.class, File.class, File::new);
132134
registerConverter(String.class, Class.class, Skript::findAnyClass);
135+
registerConverter(Object[].class, DataList.class, DataList::of);
136+
registerConverter(Collection.class, Object[].class, Collection::toArray);
133137
registerConverter(File.class, OutputStream.class, FileOutputStream::new);
134138
registerConverter(File.class, InputStream.class, FileInputStream::new);
135139
registerConverter(Object.class, String.class, Object::toString);
@@ -165,6 +169,7 @@ private SkriptLangSpec() {
165169
new WakeEffect(),
166170
new WaitEffect(),
167171
new ReturnEffect(),
172+
new MonitorSection(),
168173
new WhileSection(),
169174
new TrySection(),
170175
new CatchSection(),
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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.compiler.structure;
8+
9+
import mx.kenzie.foundation.MethodBuilder;
10+
import mx.kenzie.foundation.WriteInstruction;
11+
import org.byteskript.skript.api.SyntaxElement;
12+
import org.byteskript.skript.compiler.Context;
13+
import org.byteskript.skript.error.ScriptCompileError;
14+
import org.objectweb.asm.Label;
15+
16+
public class MonitorTree extends ProgrammaticSplitTree {
17+
18+
private final SectionMeta owner;
19+
private final MultiLabel end;
20+
public int slot;
21+
protected boolean closed;
22+
private boolean open;
23+
private Label top;
24+
25+
public MonitorTree(SectionMeta owner) {
26+
this.owner = owner;
27+
this.end = new MultiLabel();
28+
}
29+
30+
@Override
31+
public SectionMeta owner() {
32+
return owner;
33+
}
34+
35+
@Override
36+
public MultiLabel getEnd() {
37+
return end;
38+
}
39+
40+
@Override
41+
public void start(Context context) {
42+
this.closed = false;
43+
final PreVariable variable = new PreVariable(null);
44+
context.forceUnspecVariable(variable);
45+
this.slot = context.slotOf(variable);
46+
final MethodBuilder method = context.getMethod();
47+
method.writeCode(WriteInstruction.duplicate());
48+
method.writeCode(WriteInstruction.storeObject(slot));
49+
method.writeCode((writer, visitor) -> visitor.visitInsn(194));
50+
}
51+
52+
@Override
53+
public void branch(Context context) {
54+
55+
}
56+
57+
@Override
58+
public void close(Context context) {
59+
this.closed = true;
60+
final MethodBuilder method = context.getMethod();
61+
if (method == null) throw new ScriptCompileError(context.lineNumber(), "Monitor block left unclosed.");
62+
final Label label = end.use();
63+
method.writeCode(WriteInstruction.label(label));
64+
method.writeCode(WriteInstruction.loadObject(slot));
65+
method.writeCode((writer, visitor) -> visitor.visitInsn(195));
66+
context.removeTree(this);
67+
}
68+
69+
@Override
70+
public boolean permit(SyntaxElement element) {
71+
return true;
72+
}
73+
74+
@Override
75+
public boolean isOpen() {
76+
return !closed;
77+
}
78+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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.flow.execute;
8+
9+
import mx.kenzie.foundation.compiler.State;
10+
import org.byteskript.skript.api.note.Documentation;
11+
import org.byteskript.skript.api.syntax.Section;
12+
import org.byteskript.skript.compiler.CompileState;
13+
import org.byteskript.skript.compiler.Context;
14+
import org.byteskript.skript.compiler.Pattern;
15+
import org.byteskript.skript.compiler.SkriptLangSpec;
16+
import org.byteskript.skript.compiler.structure.MonitorTree;
17+
import org.byteskript.skript.compiler.structure.ProgrammaticSplitTree;
18+
import org.byteskript.skript.compiler.structure.SectionMeta;
19+
import org.byteskript.skript.lang.element.StandardElements;
20+
21+
@Documentation(
22+
name = "Monitor Section",
23+
description = """
24+
Locks an object so only this process may use it during the block.
25+
Additionally waits for other locks on the same object to close before starting.
26+
""",
27+
examples = {
28+
"""
29+
monitor {list}:
30+
add 10 to {list}
31+
"""
32+
}
33+
)
34+
public class MonitorSection extends Section {
35+
36+
public MonitorSection() {
37+
super(SkriptLangSpec.LIBRARY, StandardElements.SECTION, "monitor %Object%");
38+
}
39+
40+
@Override
41+
public Pattern.Match match(String thing, Context context) {
42+
if (!thing.startsWith("monitor ")) return null;
43+
return super.match(thing, context);
44+
}
45+
46+
@Override
47+
public void compile(Context context, Pattern.Match match) throws Throwable {
48+
final MonitorTree tree = new MonitorTree(context.getSection(1));
49+
this.compileTogether(context, tree);
50+
}
51+
52+
public void compileTogether(Context context, MonitorTree tree) throws Throwable {
53+
context.createTree(tree);
54+
tree.start(context);
55+
context.setState(CompileState.CODE_BODY);
56+
}
57+
58+
@Override
59+
public boolean allowedIn(State state, Context context) {
60+
return super.allowedIn(state, context)
61+
&& context.getSection() != null
62+
&& context.getMethod() != null;
63+
}
64+
65+
@Override
66+
public boolean isDelay() {
67+
return true;
68+
}
69+
70+
@Override
71+
public void onSectionExit(Context context, SectionMeta meta) {
72+
final ProgrammaticSplitTree current;
73+
if (context.getTree(context.getSection()) instanceof MonitorTree found) current = found;
74+
else current = context.getCurrentTree();
75+
if (current instanceof MonitorTree tree) tree.close(context);
76+
}
77+
78+
@Override
79+
public void compileInline(Context context, Pattern.Match match) throws Throwable {
80+
final MonitorTree tree = new MonitorTree(context.getSection());
81+
this.compileTogether(context, tree);
82+
tree.close(context);
83+
}
84+
85+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ private void forceLoad(Class<?> cls) {
145145
}
146146
}
147147

148+
boolean ownsClass(Class<?> cls) {
149+
for (final Class<?> type : classes) if (type == cls) return true;
150+
return false;
151+
}
152+
148153
@Description("""
149154
The simple name of the main class for this script.
150155
This will be something in the format `script`.

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,13 @@ private SkriptMirror createLoader() {
796796
return new SkriptMirror(loader);
797797
}
798798

799+
public Script getScript(final Class<?> part) {
800+
for (final Script script : this.scripts) {
801+
if (script.ownsClass(part)) return script;
802+
}
803+
return null;
804+
}
805+
799806
@Description("""
800807
Loads all compiled classes from the given root file as scripts.
801808
This is not a safe operation - not all compiled classes are suitable to be loaded in this way.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ public static String pathOf(File file) {
6969
return file.getPath();
7070
}
7171

72-
@Expression("%File% is [a ]folder")
72+
@Expression("%File% is [a] folder")
7373
public static Boolean isFolder(File file) {
7474
return file.isDirectory();
7575
}
7676

77-
@Expression("%File% is [a ]file")
77+
@Expression("%File% is [a] file")
7878
public static Boolean isFile(File file) {
7979
return file.isFile();
8080
}
@@ -93,7 +93,7 @@ public static void setContents(File file, String contents)
9393
}
9494
}
9595

96-
@Expression("[a ]new file at %String%")
96+
@Expression("[a] new file at %String%")
9797
public static File create(String path)
9898
throws Throwable {
9999
final File file = new File(path);
@@ -104,7 +104,7 @@ public static File create(String path)
104104
return file;
105105
}
106106

107-
@Expression("[the ]file at %String%")
107+
@Expression("[the] file at %String%")
108108
public static File get(String path)
109109
throws Throwable {
110110
return new File(path);

src/main/java/org/byteskript/skript/runtime/type/DataList.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.io.Serializable;
1313
import java.util.ArrayList;
14+
import java.util.Arrays;
1415
import java.util.Collection;
1516

1617
@Description("""
@@ -33,4 +34,8 @@ public static Integer getSize(Collection target) {
3334
return target.size();
3435
}
3536

37+
public static DataList of(Object... objects) {
38+
return new DataList(Arrays.asList(objects));
39+
}
40+
3641
}

src/main/java/unsafe.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import mx.kenzie.mirror.MethodAccessor;
2+
import org.byteskript.skript.api.Event;
23
import org.byteskript.skript.runtime.Skript;
34
import org.byteskript.skript.runtime.UnsafeAccessor;
45
import org.byteskript.skript.runtime.type.DataList;
@@ -46,4 +47,22 @@ public static void unregister_converter(Class<Object> from, Class<Object> to) {
4647
skript.unregisterConverter(from, to);
4748
}
4849

50+
public static void call_event(Event event, Class<?> script) {
51+
final Skript skript = get_runtime();
52+
if (script == null) skript.runEvent(event);
53+
else skript.runEvent(event, skript.getScript(script));
54+
}
55+
56+
public static void sleep(Object object) throws InterruptedException {
57+
synchronized (object) {
58+
object.wait();
59+
}
60+
}
61+
62+
public static void wake(Object object) throws InterruptedException {
63+
synchronized (object) {
64+
object.notify();
65+
}
66+
}
67+
4968
}

src/test/resources/tests/monitor.bsk

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
function test:
3+
trigger:
4+
set {lock} to a new object
5+
monitor {lock}
6+
set {thread} to the current process
7+
set {lock} to a new object
8+
set {@thing} to false
9+
set {var} to a new runnable:
10+
monitor {lock}
11+
assert {@thing} is null
12+
set {@thing} to true
13+
wake {thread}
14+
monitor {lock}:
15+
assert {@thing} is false
16+
run {var} in the background
17+
delete {@thing}
18+
assert {@thing} is null
19+
sleep
20+
assert {@thing} is true
21+
delete {@thing}
22+
return true

0 commit comments

Comments
 (0)