Skip to content

Commit 1d9a559

Browse files
committed
Skript configuration files and syntax.
1 parent 5d21b19 commit 1d9a559

File tree

14 files changed

+732
-4
lines changed

14 files changed

+732
-4
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright (c) 2022 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.api;
8+
9+
/**
10+
* Something that can be deleted, and should be compiled as normal to handle the effect.
11+
*/
12+
public interface Deletable {
13+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import mx.kenzie.foundation.Type;
1010
import org.byteskript.skript.api.Event;
1111
import org.byteskript.skript.api.Referent;
12+
import org.byteskript.skript.runtime.config.ConfigMap;
1213
import org.byteskript.skript.runtime.type.AtomicVariable;
1314
import org.byteskript.skript.runtime.type.Executable;
1415

@@ -42,6 +43,7 @@ public class CommonTypes {
4243

4344
public static final Type LIST = new Type(List.class);
4445
public static final Type MAP = new Type(Map.class);
46+
public static final Type CONFIG = new Type(ConfigMap.class);
4547
public static final Type REFERENT = new Type(Referent.class);
4648
public static final Type RUNNABLE = new Type(Runnable.class);
4749
public static final Type SUPPLIER = new Type(Supplier.class);

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ protected String stripLine(final String old, AtomicBoolean comment) {
121121
}
122122
}
123123
return line.replaceAll(regex, ""); // trim trailing whitespace
124-
125124
}
126125

127126
@Override
@@ -146,7 +145,7 @@ protected ElementTree parseStatement(final String statement, final FileContext c
146145
context.error = details;
147146
details.file = context.getType().internalName() + ".bsk";
148147
try {
149-
effect = assembleStatement(statement, context, details);
148+
effect = this.assembleStatement(statement, context, details);
150149
context.line = effect;
151150
} catch (ScriptParseError ex) {
152151
if (ex.getDetails() == null)

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
import org.byteskript.skript.error.ScriptRuntimeError;
2121
import org.byteskript.skript.lang.element.StandardElements;
2222
import org.byteskript.skript.lang.syntax.comparison.*;
23+
import org.byteskript.skript.lang.syntax.config.ConfigCreator;
24+
import org.byteskript.skript.lang.syntax.config.ConfigFile;
25+
import org.byteskript.skript.lang.syntax.config.KeyInConfig;
26+
import org.byteskript.skript.lang.syntax.config.SaveConfigEffect;
2327
import org.byteskript.skript.lang.syntax.control.AddEffect;
2428
import org.byteskript.skript.lang.syntax.control.DeleteEffect;
2529
import org.byteskript.skript.lang.syntax.control.RemoveEffect;
@@ -162,6 +166,7 @@ private SkriptLangSpec() {
162166
new AddEffect(),
163167
new DeleteEffect(),
164168
new RemoveEffect(),
169+
new SaveConfigEffect(),
165170
new AssertWithErrorEffect(),
166171
new AssertEffect(),
167172
new ExitEffect(),
@@ -255,6 +260,9 @@ private SkriptLangSpec() {
255260
new WeeksExpression(),
256261
new MonthsExpression(),
257262
new YearsExpression(),
263+
new ConfigFile(),
264+
new ConfigCreator(),
265+
new KeyInConfig(),
258266
new MapCreator(),
259267
new ListCreator(),
260268
new IndexOfList(),
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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.config;
8+
9+
import mx.kenzie.foundation.Type;
10+
import org.byteskript.skript.api.note.Documentation;
11+
import org.byteskript.skript.api.note.ForceInline;
12+
import org.byteskript.skript.api.syntax.SimpleExpression;
13+
import org.byteskript.skript.compiler.CommonTypes;
14+
import org.byteskript.skript.compiler.SkriptLangSpec;
15+
import org.byteskript.skript.lang.element.StandardElements;
16+
import org.byteskript.skript.lang.handler.StandardHandlers;
17+
import org.byteskript.skript.runtime.config.ConfigMap;
18+
19+
@Documentation(
20+
name = "New Config",
21+
description = """
22+
A new key/value config.
23+
This functions like a map and can be written to a file.
24+
""",
25+
examples = {
26+
"""
27+
set {config} to a new config
28+
set "blob" in {map} to 55.3
29+
"""
30+
}
31+
)
32+
public class ConfigCreator extends SimpleExpression {
33+
34+
public ConfigCreator() {
35+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[a] new config[uration]");
36+
handlers.put(StandardHandlers.GET, findMethod(this.getClass(), "create"));
37+
}
38+
39+
@ForceInline
40+
public static ConfigMap create() {
41+
return new ConfigMap();
42+
}
43+
44+
@Override
45+
public Type getReturnType() {
46+
return CommonTypes.CONFIG;
47+
}
48+
49+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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.config;
8+
9+
import mx.kenzie.foundation.MethodBuilder;
10+
import mx.kenzie.foundation.Type;
11+
import mx.kenzie.foundation.WriteInstruction;
12+
import org.byteskript.skript.api.Deletable;
13+
import org.byteskript.skript.api.Referent;
14+
import org.byteskript.skript.api.note.Documentation;
15+
import org.byteskript.skript.api.syntax.Section;
16+
import org.byteskript.skript.compiler.CommonTypes;
17+
import org.byteskript.skript.compiler.Context;
18+
import org.byteskript.skript.compiler.Pattern;
19+
import org.byteskript.skript.compiler.SkriptLangSpec;
20+
import org.byteskript.skript.compiler.structure.BasicTree;
21+
import org.byteskript.skript.compiler.structure.PreVariable;
22+
import org.byteskript.skript.compiler.structure.SectionMeta;
23+
import org.byteskript.skript.lang.element.StandardElements;
24+
import org.byteskript.skript.lang.handler.StandardHandlers;
25+
import org.byteskript.skript.runtime.config.ConfigMap;
26+
27+
import java.lang.reflect.Method;
28+
29+
@Documentation(
30+
name = "Config File",
31+
description = """
32+
Obtains data from a `.csk` config file.
33+
34+
If used as a section header, this will automatically save the config
35+
to its file after the section exits.
36+
""",
37+
examples = {
38+
"""
39+
set {config} to resources/myconf.csk
40+
add "hello: " + {var} to {config}
41+
set "hello" from {config} to "there"
42+
save config {config}
43+
""",
44+
"""
45+
set {config} to folder/config.csk:
46+
add "key: value" to {config}
47+
"""
48+
}
49+
)
50+
public class ConfigFile extends Section implements Referent, Deletable {
51+
52+
public ConfigFile() {
53+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "path/to/file.csk");
54+
this.handlers.put(StandardHandlers.DELETE, this.findMethod(ConfigMap.class, "delete"));
55+
}
56+
57+
@Override
58+
public Pattern.Match match(String thing, Context context) {
59+
if (!thing.endsWith(".csk")) return null;
60+
if (thing.contains(" ")) {
61+
context.getError().addHint(this, "Config file paths should not contain spaces.");
62+
return null;
63+
}
64+
return new Pattern.Match(Pattern.fakeMatcher(thing), thing);
65+
}
66+
67+
@Override
68+
public Type getReturnType() {
69+
return CommonTypes.CONFIG;
70+
}
71+
72+
@Override
73+
public void compile(Context context, Pattern.Match match) throws Throwable {
74+
final String path = match.<String>meta().trim();
75+
final MethodBuilder method = context.getMethod();
76+
method.writeCode(WriteInstruction.push(path));
77+
final Method target = ConfigMap.class.getMethod("create", String.class);
78+
method.writeCode(WriteInstruction.invoke(target));
79+
if (!context.isSectionHeader()) return;
80+
final PreVariable variable = new PreVariable(null);
81+
variable.internal = true;
82+
context.forceUnspecVariable(variable);
83+
final int slot = context.slotOf(variable);
84+
method.writeCode(WriteInstruction.storeObject(slot));
85+
method.writeCode(WriteInstruction.loadObject(slot)); // make available to whatever eats this
86+
final ConfigTree tree = new ConfigTree(context.getSection(1));
87+
context.createTree(tree);
88+
tree.variable = variable;
89+
}
90+
91+
@Override
92+
public void onSectionExit(Context context, SectionMeta meta) {
93+
final ConfigTree tree = context.findTree(ConfigTree.class);
94+
final MethodBuilder method = context.getMethod();
95+
if (tree == null) return;
96+
final int slot = context.slotOf(tree.variable);
97+
method.writeCode(WriteInstruction.loadObject(slot));
98+
final Method target = this.findMethod(ConfigMap.class, "save");
99+
method.writeCode(WriteInstruction.invoke(target));
100+
}
101+
102+
@Override
103+
public void compileInline(Context context, Pattern.Match match) throws Throwable {
104+
this.compile(context, match);
105+
}
106+
107+
@Override
108+
public boolean allowAsInputFor(Type type) {
109+
return CommonTypes.OBJECT.equals(type) || CommonTypes.REFERENT.equals(type) || CommonTypes.CONFIG.equals(type) || super.allowAsInputFor(type);
110+
}
111+
112+
@Override
113+
public Type getHolderType() {
114+
return CommonTypes.CONFIG;
115+
}
116+
117+
static class ConfigTree extends BasicTree {
118+
119+
protected PreVariable variable;
120+
121+
public ConfigTree(SectionMeta owner) {
122+
super(owner);
123+
}
124+
}
125+
126+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
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.config;
8+
9+
import mx.kenzie.foundation.MethodBuilder;
10+
import mx.kenzie.foundation.Type;
11+
import org.byteskript.skript.api.Referent;
12+
import org.byteskript.skript.api.note.Documentation;
13+
import org.byteskript.skript.api.syntax.RelationalExpression;
14+
import org.byteskript.skript.compiler.CommonTypes;
15+
import org.byteskript.skript.compiler.Context;
16+
import org.byteskript.skript.compiler.Pattern;
17+
import org.byteskript.skript.compiler.SkriptLangSpec;
18+
import org.byteskript.skript.lang.element.StandardElements;
19+
import org.byteskript.skript.lang.handler.StandardHandlers;
20+
import org.byteskript.skript.runtime.config.ConfigMap;
21+
22+
import java.lang.reflect.Method;
23+
24+
@Documentation(
25+
name = "Key in Map",
26+
description = """
27+
Accesses this key in the provided map.
28+
This can use the set/get/delete handlers.
29+
""",
30+
examples = {
31+
"""
32+
set {var} to "hello" in map {map}
33+
set ("name" in map {map}) to "Bob"
34+
"""
35+
}
36+
)
37+
public class KeyInConfig extends RelationalExpression implements Referent {
38+
39+
public KeyInConfig() {
40+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%String% from [config] %Config%");
41+
try {
42+
handlers.put(StandardHandlers.GET, ConfigMap.class.getMethod("getMapValue", Object.class, Object.class));
43+
handlers.put(StandardHandlers.SET, ConfigMap.class.getMethod("setMapValue", Object.class, Object.class, Object.class));
44+
handlers.put(StandardHandlers.DELETE, ConfigMap.class.getMethod("deleteMapValue", Object.class, Object.class));
45+
} catch (NoSuchMethodException e) {
46+
e.printStackTrace();
47+
}
48+
}
49+
50+
@Override
51+
public Pattern.Match match(String thing, Context context) {
52+
if (!thing.contains(" from ")) return null;
53+
return super.match(thing, context);
54+
}
55+
56+
@Override
57+
public void compile(Context context, Pattern.Match match) throws Throwable {
58+
final MethodBuilder method = context.getMethod();
59+
assert method != null;
60+
final Method target = handlers.get(context.getHandlerMode());
61+
assert target != null;
62+
this.writeCall(method, target, context);
63+
}
64+
65+
@Override
66+
public Type getHolderType() {
67+
return CommonTypes.CONFIG;
68+
}
69+
70+
@Override
71+
public boolean allowAsInputFor(Type type) {
72+
return super.allowAsInputFor(type) || CommonTypes.REFERENT.equals(type);
73+
}
74+
75+
76+
}
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.config;
8+
9+
import mx.kenzie.foundation.MethodBuilder;
10+
import mx.kenzie.foundation.WriteInstruction;
11+
import org.byteskript.skript.api.note.Documentation;
12+
import org.byteskript.skript.api.syntax.Effect;
13+
import org.byteskript.skript.compiler.*;
14+
import org.byteskript.skript.lang.element.StandardElements;
15+
import org.byteskript.skript.runtime.config.ConfigMap;
16+
17+
@Documentation(
18+
name = "Save Config",
19+
description = """
20+
Saves the given config object.
21+
""",
22+
examples = {
23+
"""
24+
set {conf} to my/config.csk
25+
save config {conf}
26+
"""
27+
}
28+
)
29+
public class SaveConfigEffect extends Effect {
30+
31+
public SaveConfigEffect() {
32+
super(SkriptLangSpec.LIBRARY, StandardElements.EFFECT, "save config %Object%");
33+
}
34+
35+
@Override
36+
public void preCompile(Context context, Pattern.Match match) throws Throwable {
37+
final MethodBuilder method = context.getMethod();
38+
method.writeCode(WriteInstruction.getField(System.class.getField("out")));
39+
super.preCompile(context, match);
40+
}
41+
42+
@Override
43+
public void compile(Context context, Pattern.Match match) throws Throwable {
44+
final MethodBuilder method = context.getMethod();
45+
method.writeCode(WriteInstruction.cast(CommonTypes.CONFIG));
46+
method.writeCode(WriteInstruction.invokeVirtual(ConfigMap.class.getMethod("save")));
47+
context.setState(CompileState.CODE_BODY);
48+
}
49+
50+
}

src/main/java/org/byteskript/skript/lang/syntax/control/DeleteEffect.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package org.byteskript.skript.lang.syntax.control;
88

99
import mx.kenzie.foundation.MethodBuilder;
10+
import org.byteskript.skript.api.Deletable;
1011
import org.byteskript.skript.api.HandlerType;
1112
import org.byteskript.skript.api.Referent;
1213
import org.byteskript.skript.api.note.Documentation;
@@ -58,7 +59,8 @@ public void preCompile(Context context, Pattern.Match match) throws Throwable {
5859
if (target == null)
5960
throw new ScriptParseError(context.lineNumber(), "Syntax '" + inputs[0].current()
6061
.name() + "' cannot be deleted.");
61-
inputs[0].compile = false;
62+
63+
if (!(inputs[0].current() instanceof Deletable)) inputs[0].compile = false;
6264
super.preCompile(context, match);
6365
}
6466

0 commit comments

Comments
 (0)