Skip to content

Commit

Permalink
Skript configuration files and syntax.
Browse files Browse the repository at this point in the history
  • Loading branch information
Moderocky committed Feb 5, 2022
1 parent 5d21b19 commit 1d9a559
Show file tree
Hide file tree
Showing 14 changed files with 732 additions and 4 deletions.
13 changes: 13 additions & 0 deletions src/main/java/org/byteskript/skript/api/Deletable.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright (c) 2022 ByteSkript org (Moderocky)
* View the full licence information and permissions:
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
*/

package org.byteskript.skript.api;

/**
* Something that can be deleted, and should be compiled as normal to handle the effect.
*/
public interface Deletable {
}
2 changes: 2 additions & 0 deletions src/main/java/org/byteskript/skript/compiler/CommonTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import mx.kenzie.foundation.Type;
import org.byteskript.skript.api.Event;
import org.byteskript.skript.api.Referent;
import org.byteskript.skript.runtime.config.ConfigMap;
import org.byteskript.skript.runtime.type.AtomicVariable;
import org.byteskript.skript.runtime.type.Executable;

Expand Down Expand Up @@ -42,6 +43,7 @@ public class CommonTypes {

public static final Type LIST = new Type(List.class);
public static final Type MAP = new Type(Map.class);
public static final Type CONFIG = new Type(ConfigMap.class);
public static final Type REFERENT = new Type(Referent.class);
public static final Type RUNNABLE = new Type(Runnable.class);
public static final Type SUPPLIER = new Type(Supplier.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ protected String stripLine(final String old, AtomicBoolean comment) {
}
}
return line.replaceAll(regex, ""); // trim trailing whitespace

}

@Override
Expand All @@ -146,7 +145,7 @@ protected ElementTree parseStatement(final String statement, final FileContext c
context.error = details;
details.file = context.getType().internalName() + ".bsk";
try {
effect = assembleStatement(statement, context, details);
effect = this.assembleStatement(statement, context, details);
context.line = effect;
} catch (ScriptParseError ex) {
if (ex.getDetails() == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
import org.byteskript.skript.error.ScriptRuntimeError;
import org.byteskript.skript.lang.element.StandardElements;
import org.byteskript.skript.lang.syntax.comparison.*;
import org.byteskript.skript.lang.syntax.config.ConfigCreator;
import org.byteskript.skript.lang.syntax.config.ConfigFile;
import org.byteskript.skript.lang.syntax.config.KeyInConfig;
import org.byteskript.skript.lang.syntax.config.SaveConfigEffect;
import org.byteskript.skript.lang.syntax.control.AddEffect;
import org.byteskript.skript.lang.syntax.control.DeleteEffect;
import org.byteskript.skript.lang.syntax.control.RemoveEffect;
Expand Down Expand Up @@ -162,6 +166,7 @@ private SkriptLangSpec() {
new AddEffect(),
new DeleteEffect(),
new RemoveEffect(),
new SaveConfigEffect(),
new AssertWithErrorEffect(),
new AssertEffect(),
new ExitEffect(),
Expand Down Expand Up @@ -255,6 +260,9 @@ private SkriptLangSpec() {
new WeeksExpression(),
new MonthsExpression(),
new YearsExpression(),
new ConfigFile(),
new ConfigCreator(),
new KeyInConfig(),
new MapCreator(),
new ListCreator(),
new IndexOfList(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2021 ByteSkript org (Moderocky)
* View the full licence information and permissions:
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
*/

package org.byteskript.skript.lang.syntax.config;

import mx.kenzie.foundation.Type;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.note.ForceInline;
import org.byteskript.skript.api.syntax.SimpleExpression;
import org.byteskript.skript.compiler.CommonTypes;
import org.byteskript.skript.compiler.SkriptLangSpec;
import org.byteskript.skript.lang.element.StandardElements;
import org.byteskript.skript.lang.handler.StandardHandlers;
import org.byteskript.skript.runtime.config.ConfigMap;

@Documentation(
name = "New Config",
description = """
A new key/value config.
This functions like a map and can be written to a file.
""",
examples = {
"""
set {config} to a new config
set "blob" in {map} to 55.3
"""
}
)
public class ConfigCreator extends SimpleExpression {

public ConfigCreator() {
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[a] new config[uration]");
handlers.put(StandardHandlers.GET, findMethod(this.getClass(), "create"));
}

@ForceInline
public static ConfigMap create() {
return new ConfigMap();
}

@Override
public Type getReturnType() {
return CommonTypes.CONFIG;
}

}
126 changes: 126 additions & 0 deletions src/main/java/org/byteskript/skript/lang/syntax/config/ConfigFile.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2021 ByteSkript org (Moderocky)
* View the full licence information and permissions:
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
*/

package org.byteskript.skript.lang.syntax.config;

import mx.kenzie.foundation.MethodBuilder;
import mx.kenzie.foundation.Type;
import mx.kenzie.foundation.WriteInstruction;
import org.byteskript.skript.api.Deletable;
import org.byteskript.skript.api.Referent;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.syntax.Section;
import org.byteskript.skript.compiler.CommonTypes;
import org.byteskript.skript.compiler.Context;
import org.byteskript.skript.compiler.Pattern;
import org.byteskript.skript.compiler.SkriptLangSpec;
import org.byteskript.skript.compiler.structure.BasicTree;
import org.byteskript.skript.compiler.structure.PreVariable;
import org.byteskript.skript.compiler.structure.SectionMeta;
import org.byteskript.skript.lang.element.StandardElements;
import org.byteskript.skript.lang.handler.StandardHandlers;
import org.byteskript.skript.runtime.config.ConfigMap;

import java.lang.reflect.Method;

@Documentation(
name = "Config File",
description = """
Obtains data from a `.csk` config file.
If used as a section header, this will automatically save the config
to its file after the section exits.
""",
examples = {
"""
set {config} to resources/myconf.csk
add "hello: " + {var} to {config}
set "hello" from {config} to "there"
save config {config}
""",
"""
set {config} to folder/config.csk:
add "key: value" to {config}
"""
}
)
public class ConfigFile extends Section implements Referent, Deletable {

public ConfigFile() {
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "path/to/file.csk");
this.handlers.put(StandardHandlers.DELETE, this.findMethod(ConfigMap.class, "delete"));
}

@Override
public Pattern.Match match(String thing, Context context) {
if (!thing.endsWith(".csk")) return null;
if (thing.contains(" ")) {
context.getError().addHint(this, "Config file paths should not contain spaces.");
return null;
}
return new Pattern.Match(Pattern.fakeMatcher(thing), thing);
}

@Override
public Type getReturnType() {
return CommonTypes.CONFIG;
}

@Override
public void compile(Context context, Pattern.Match match) throws Throwable {
final String path = match.<String>meta().trim();
final MethodBuilder method = context.getMethod();
method.writeCode(WriteInstruction.push(path));
final Method target = ConfigMap.class.getMethod("create", String.class);
method.writeCode(WriteInstruction.invoke(target));
if (!context.isSectionHeader()) return;
final PreVariable variable = new PreVariable(null);
variable.internal = true;
context.forceUnspecVariable(variable);
final int slot = context.slotOf(variable);
method.writeCode(WriteInstruction.storeObject(slot));
method.writeCode(WriteInstruction.loadObject(slot)); // make available to whatever eats this
final ConfigTree tree = new ConfigTree(context.getSection(1));
context.createTree(tree);
tree.variable = variable;
}

@Override
public void onSectionExit(Context context, SectionMeta meta) {
final ConfigTree tree = context.findTree(ConfigTree.class);
final MethodBuilder method = context.getMethod();
if (tree == null) return;
final int slot = context.slotOf(tree.variable);
method.writeCode(WriteInstruction.loadObject(slot));
final Method target = this.findMethod(ConfigMap.class, "save");
method.writeCode(WriteInstruction.invoke(target));
}

@Override
public void compileInline(Context context, Pattern.Match match) throws Throwable {
this.compile(context, match);
}

@Override
public boolean allowAsInputFor(Type type) {
return CommonTypes.OBJECT.equals(type) || CommonTypes.REFERENT.equals(type) || CommonTypes.CONFIG.equals(type) || super.allowAsInputFor(type);
}

@Override
public Type getHolderType() {
return CommonTypes.CONFIG;
}

static class ConfigTree extends BasicTree {

protected PreVariable variable;

public ConfigTree(SectionMeta owner) {
super(owner);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2021 ByteSkript org (Moderocky)
* View the full licence information and permissions:
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
*/

package org.byteskript.skript.lang.syntax.config;

import mx.kenzie.foundation.MethodBuilder;
import mx.kenzie.foundation.Type;
import org.byteskript.skript.api.Referent;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.syntax.RelationalExpression;
import org.byteskript.skript.compiler.CommonTypes;
import org.byteskript.skript.compiler.Context;
import org.byteskript.skript.compiler.Pattern;
import org.byteskript.skript.compiler.SkriptLangSpec;
import org.byteskript.skript.lang.element.StandardElements;
import org.byteskript.skript.lang.handler.StandardHandlers;
import org.byteskript.skript.runtime.config.ConfigMap;

import java.lang.reflect.Method;

@Documentation(
name = "Key in Map",
description = """
Accesses this key in the provided map.
This can use the set/get/delete handlers.
""",
examples = {
"""
set {var} to "hello" in map {map}
set ("name" in map {map}) to "Bob"
"""
}
)
public class KeyInConfig extends RelationalExpression implements Referent {

public KeyInConfig() {
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%String% from [config] %Config%");
try {
handlers.put(StandardHandlers.GET, ConfigMap.class.getMethod("getMapValue", Object.class, Object.class));
handlers.put(StandardHandlers.SET, ConfigMap.class.getMethod("setMapValue", Object.class, Object.class, Object.class));
handlers.put(StandardHandlers.DELETE, ConfigMap.class.getMethod("deleteMapValue", Object.class, Object.class));
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}

@Override
public Pattern.Match match(String thing, Context context) {
if (!thing.contains(" from ")) return null;
return super.match(thing, context);
}

@Override
public void compile(Context context, Pattern.Match match) throws Throwable {
final MethodBuilder method = context.getMethod();
assert method != null;
final Method target = handlers.get(context.getHandlerMode());
assert target != null;
this.writeCall(method, target, context);
}

@Override
public Type getHolderType() {
return CommonTypes.CONFIG;
}

@Override
public boolean allowAsInputFor(Type type) {
return super.allowAsInputFor(type) || CommonTypes.REFERENT.equals(type);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2021 ByteSkript org (Moderocky)
* View the full licence information and permissions:
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
*/

package org.byteskript.skript.lang.syntax.config;

import mx.kenzie.foundation.MethodBuilder;
import mx.kenzie.foundation.WriteInstruction;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.syntax.Effect;
import org.byteskript.skript.compiler.*;
import org.byteskript.skript.lang.element.StandardElements;
import org.byteskript.skript.runtime.config.ConfigMap;

@Documentation(
name = "Save Config",
description = """
Saves the given config object.
""",
examples = {
"""
set {conf} to my/config.csk
save config {conf}
"""
}
)
public class SaveConfigEffect extends Effect {

public SaveConfigEffect() {
super(SkriptLangSpec.LIBRARY, StandardElements.EFFECT, "save config %Object%");
}

@Override
public void preCompile(Context context, Pattern.Match match) throws Throwable {
final MethodBuilder method = context.getMethod();
method.writeCode(WriteInstruction.getField(System.class.getField("out")));
super.preCompile(context, match);
}

@Override
public void compile(Context context, Pattern.Match match) throws Throwable {
final MethodBuilder method = context.getMethod();
method.writeCode(WriteInstruction.cast(CommonTypes.CONFIG));
method.writeCode(WriteInstruction.invokeVirtual(ConfigMap.class.getMethod("save")));
context.setState(CompileState.CODE_BODY);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package org.byteskript.skript.lang.syntax.control;

import mx.kenzie.foundation.MethodBuilder;
import org.byteskript.skript.api.Deletable;
import org.byteskript.skript.api.HandlerType;
import org.byteskript.skript.api.Referent;
import org.byteskript.skript.api.note.Documentation;
Expand Down Expand Up @@ -58,7 +59,8 @@ public void preCompile(Context context, Pattern.Match match) throws Throwable {
if (target == null)
throw new ScriptParseError(context.lineNumber(), "Syntax '" + inputs[0].current()
.name() + "' cannot be deleted.");
inputs[0].compile = false;

if (!(inputs[0].current() instanceof Deletable)) inputs[0].compile = false;
super.preCompile(context, match);
}

Expand Down
Loading

0 comments on commit 1d9a559

Please sign in to comment.