Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch sections (experimental feature). #6572

Draft
wants to merge 39 commits into
base: dev/feature
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
a52c7d5
First pass at supporting SimpleNode for Structures
APickledWalrus Apr 11, 2024
2d92a20
Experimental features - the 'using' structure.
Moderocky Apr 11, 2024
dac0fac
Oops :grimacing:
Moderocky Apr 11, 2024
ebbea3c
Improve documentation and test coverage.
Moderocky Apr 11, 2024
8ed6bf5
Add shane's extra special one-line creation & registration (50% off t…
Moderocky Apr 11, 2024
213b007
Deprecate Structure#getEntryContainer
APickledWalrus Apr 11, 2024
11829da
Update src/main/java/ch/njol/skript/conditions/CondIsUsing.java
Moderocky Apr 12, 2024
44d071c
Apply suggestions from code review
Moderocky Apr 12, 2024
d1389b9
Add Ayham's changes (bye bye nice final modifiers :cry:)
Moderocky Apr 12, 2024
aad6901
Merge branch 'dev/feature' into experiments
Moderocky Apr 12, 2024
9755f84
Merge branch 'dev/feature' into feature/simple-structures
Moderocky Apr 12, 2024
6aec06e
Add a test-only syntax contingent on a feature flag.
Moderocky Apr 12, 2024
705f6a6
Merge branch 'experiments' of https://github.com/Moderocky/Skript int…
Moderocky Apr 12, 2024
f14b074
The basics of annotations.
Moderocky Apr 12, 2024
1777746
Fix formatting.
Moderocky Apr 13, 2024
883cf81
Merge branch 'annotations' into switch-section
Moderocky Apr 13, 2024
144f455
Address reviews
APickledWalrus Apr 13, 2024
b1d5fe3
Add switch sections.
Moderocky Apr 13, 2024
0b1c5f5
Add tentative support for modes.
Moderocky Apr 14, 2024
c86f9d2
Add test for strict switching mode.
Moderocky Apr 14, 2024
421db8a
Add 'if' pattern for cases.
Moderocky Apr 14, 2024
4684bab
Add better annotation presence tests.
Moderocky Apr 14, 2024
0856ef0
Merge branch 'annotations' into switch-section
Moderocky Apr 14, 2024
a1cf07a
Make annotations properly scoped for section headers.
Moderocky Apr 14, 2024
831f3e7
Merge branch 'annotations' into switch-section
Moderocky Apr 14, 2024
ecdad01
Add tests for multiple cases.
Moderocky Apr 14, 2024
8fcf97e
Add tests for multiple (strict) switch inputs.
Moderocky Apr 14, 2024
2195580
Add case memory for fall-through.
Moderocky Apr 14, 2024
ef0c14d
Support fall-through cases.
Moderocky Apr 14, 2024
15572d3
Add a test for mixing modes.
Moderocky Apr 14, 2024
98c1e73
Scope annotations properly in section loadCode.
Moderocky Apr 14, 2024
2a8f03a
Add examples, description and check alternative pattern.
Moderocky Apr 15, 2024
5dcd17d
Remove 'check' pattern from cases and add docs.
Moderocky Apr 15, 2024
abd50f0
Make outer switch getter public for ExprIt to find.
Moderocky Apr 15, 2024
9c83169
Add docs and type safety for `this|it`.
Moderocky Apr 15, 2024
e8809d4
Evade type hints in test case.
Moderocky Apr 15, 2024
8b59347
Merge remote-tracking branch 'APickledWalrus/feature/simple-structure…
Moderocky Apr 15, 2024
1cb2c8b
Add root-level annotations for structures.
Moderocky Apr 15, 2024
df36243
Merge branch 'annotations' into switch-section
Moderocky Apr 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
80 changes: 51 additions & 29 deletions src/main/java/ch/njol/skript/ScriptLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.BlockingQueue;
Expand Down Expand Up @@ -490,17 +492,17 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O

ScriptInfo scriptInfo = new ScriptInfo();

List<NonNullPair<Script, List<Structure>>> scripts = new ArrayList<>();
List<LoadingScriptInfo> scripts = new ArrayList<>();

List<CompletableFuture<Void>> scriptInfoFutures = new ArrayList<>();
for (Config config : configs) {
if (config == null)
throw new NullPointerException();

CompletableFuture<Void> future = makeFuture(() -> {
NonNullPair<Script, List<Structure>> pair = loadScript(config);
scripts.add(pair);
scriptInfo.add(new ScriptInfo(1, pair.getSecond().size()));
LoadingScriptInfo info = loadScript(config);
scripts.add(info);
scriptInfo.add(new ScriptInfo(1, info.structures.size()));
return null;
}, openCloseable);

Expand All @@ -518,31 +520,32 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O

// build sorted list
// this nest of pairs is terrible, but we need to keep the reference to the modifiable structures list
List<NonNullPair<NonNullPair<Script, List<Structure>>, Structure>> pairs = scripts.stream()
.flatMap(pair -> { // Flatten each entry down to a stream of Script-Structure pairs
return pair.getSecond().stream()
.map(structure -> new NonNullPair<>(pair, structure));
List<NonNullPair<LoadingScriptInfo, Structure>> pairs = scripts.stream()
.flatMap(info -> { // Flatten each entry down to a stream of Script-Structure pairs
return info.structures.stream()
.map(structure -> new NonNullPair<>(info, structure));
})
.sorted(Comparator.comparing(pair -> pair.getSecond().getPriority()))
.collect(Collectors.toCollection(ArrayList::new));

// pre-loading
pairs.removeIf(pair -> {
LoadingScriptInfo loadingInfo = pair.getFirst();
Structure structure = pair.getSecond();

parser.setActive(pair.getFirst().getFirst());
parser.setActive(loadingInfo.script);
parser.setCurrentStructure(structure);
parser.setNode(structure.getEntryContainer().getSource());
parser.setNode(loadingInfo.nodeMap.get(structure));

try {
if (!structure.preLoad()) {
pair.getFirst().getSecond().remove(structure);
loadingInfo.structures.remove(structure);
return true;
}
} catch (Exception e) {
//noinspection ThrowableNotThrown
Skript.exception(e, "An error occurred while trying to preLoad a Structure.");
pair.getFirst().getSecond().remove(structure);
loadingInfo.structures.remove(structure);
return true;
}
return false;
Expand All @@ -556,21 +559,22 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O

// loading
pairs.removeIf(pair -> {
LoadingScriptInfo loadingInfo = pair.getFirst();
Structure structure = pair.getSecond();

parser.setActive(pair.getFirst().getFirst());
parser.setActive(loadingInfo.script);
parser.setCurrentStructure(structure);
parser.setNode(structure.getEntryContainer().getSource());
parser.setNode(loadingInfo.nodeMap.get(structure));

try {
if (!structure.load()) {
pair.getFirst().getSecond().remove(structure);
loadingInfo.structures.remove(structure);
return true;
}
} catch (Exception e) {
//noinspection ThrowableNotThrown
Skript.exception(e, "An error occurred while trying to load a Structure.");
pair.getFirst().getSecond().remove(structure);
loadingInfo.structures.remove(structure);
return true;
}
return false;
Expand All @@ -579,21 +583,22 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O

// post-loading
pairs.removeIf(pair -> {
LoadingScriptInfo loadingInfo = pair.getFirst();
Structure structure = pair.getSecond();

parser.setActive(pair.getFirst().getFirst());
parser.setActive(loadingInfo.script);
parser.setCurrentStructure(structure);
parser.setNode(structure.getEntryContainer().getSource());
parser.setNode(loadingInfo.nodeMap.get(structure));

try {
if (!structure.postLoad()) {
pair.getFirst().getSecond().remove(structure);
loadingInfo.structures.remove(structure);
return true;
}
} catch (Exception e) {
//noinspection ThrowableNotThrown
Skript.exception(e, "An error occurred while trying to postLoad a Structure.");
pair.getFirst().getSecond().remove(structure);
loadingInfo.structures.remove(structure);
return true;
}
return false;
Expand All @@ -612,17 +617,34 @@ private static CompletableFuture<ScriptInfo> loadScripts(List<Config> configs, O
});
}

private static class LoadingScriptInfo {

public final Script script;

public final List<Structure> structures;

public final Map<Structure, Node> nodeMap;

public LoadingScriptInfo(Script script, List<Structure> structures, Map<Structure, Node> nodeMap) {
this.script = script;
this.structures = structures;
this.nodeMap = nodeMap;
}

}

/**
* Creates a script and loads the provided config into it.
* @param config The config to load into a script.
* @return A pair containing the script that was loaded and a modifiable version of the structures list.
*/
// Whenever you call this method, make sure to also call PreScriptLoadEvent
private static NonNullPair<Script, List<Structure>> loadScript(Config config) {
private static LoadingScriptInfo loadScript(Config config) {
if (config.getFile() == null)
throw new IllegalArgumentException("A config must have a file to be loaded.");

ParserInstance parser = getParser();
Map<Structure, Node> nodeMap = new HashMap<>();
List<Structure> structures = new ArrayList<>();
Script script = new Script(config, structures);
parser.setActive(script);
Expand All @@ -632,31 +654,31 @@ private static NonNullPair<Script, List<Structure>> loadScript(Config config) {
SkriptConfig.configs.add(config);

try (CountingLogHandler ignored = new CountingLogHandler(SkriptLogger.SEVERE).start()) {
for (Node cnode : config.getMainNode()) {
if (!(cnode instanceof SectionNode)) {
Skript.error("invalid line - all code has to be put into triggers");
for (Node node : config.getMainNode()) {
if (!(node instanceof SimpleNode) && !(node instanceof SectionNode)) {
// unlikely to occur, but just in case
Skript.error("could not interpret line as a structure");
continue;
}

SectionNode node = ((SectionNode) cnode);
String line = node.getKey();
if (line == null)
continue;
line = replaceOptions(line); // replace options here before validation

if (!SkriptParser.validateLine(line))
continue;

if (Skript.logVeryHigh() && !Skript.debug())
Skript.info("loading trigger '" + line + "'");

line = replaceOptions(line);

Structure structure = Structure.parse(line, node, "Can't understand this structure: " + line);

if (structure == null)
continue;

structures.add(structure);
nodeMap.put(structure, node);
}

if (Skript.logHigh()) {
Expand Down Expand Up @@ -694,8 +716,8 @@ private static NonNullPair<Script, List<Structure>> loadScript(Config config) {
Skript.exception(e);
}
}
return new NonNullPair<>(script, structures);

return new LoadingScriptInfo(script, structures, nodeMap);
}

/*
Expand Down
33 changes: 29 additions & 4 deletions src/main/java/ch/njol/skript/Skript.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
import ch.njol.util.Kleenean;
import ch.njol.util.NullableChecker;
import ch.njol.util.StringUtils;
import ch.njol.util.coll.CollectionUtils;
import ch.njol.util.coll.iterator.CheckedIterator;
import ch.njol.util.coll.iterator.EnumerationIterable;
import com.google.common.collect.Lists;
Expand All @@ -108,6 +107,7 @@
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.eclipse.jdt.annotation.Nullable;
import org.jetbrains.annotations.UnknownNullability;
import org.junit.After;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
Expand All @@ -116,6 +116,9 @@
import org.skriptlang.skript.lang.converter.Converter;
import org.skriptlang.skript.lang.converter.Converters;
import org.skriptlang.skript.lang.entry.EntryValidator;
import org.skriptlang.skript.lang.experiment.ExperimentManager;
import org.skriptlang.skript.lang.experiment.Feature;
import org.skriptlang.skript.lang.script.Annotation;
import org.skriptlang.skript.lang.script.Script;
import org.skriptlang.skript.lang.structure.Structure;
import org.skriptlang.skript.lang.structure.StructureInfo;
Expand Down Expand Up @@ -230,6 +233,7 @@ public static void updateMinecraftVersion() {

@Nullable
private static Version version = null;
private static @UnknownNullability ExperimentManager experimentManager;

public static Version getVersion() {
final Version v = version;
Expand Down Expand Up @@ -362,6 +366,13 @@ public static void disableHookRegistration(Class<? extends Hook<?>>... hooks) {
*/
private File scriptsFolder;

/**
* @return The manager for experimental, optional features.
*/
public static ExperimentManager experiments() {
return experimentManager;
}

/**
* @return The folder containing all Scripts.
*/
Expand Down Expand Up @@ -392,6 +403,8 @@ public void onEnable() {
} catch (Exception e) {
Skript.exception(e, "Update checker could not be initialized.");
}
experimentManager = new ExperimentManager(this);
Feature.registerAll(getAddonInstance(), experimentManager);

if (!getDataFolder().isDirectory())
getDataFolder().mkdirs();
Expand Down Expand Up @@ -1197,6 +1210,7 @@ public void onDisable() {
if (disabled)
return;
disabled = true;
this.experimentManager = null;

if (!partDisabled) {
beforeDisable();
Expand Down Expand Up @@ -1515,6 +1529,13 @@ public static <E extends Structure> void registerStructure(Class<E> c, String...
structures.add(structureInfo);
}

public static <E extends Structure> void registerSimpleStructure(Class<E> c, String... patterns) {
checkAcceptRegistrations();
String originClassPath = Thread.currentThread().getStackTrace()[2].getClassName();
StructureInfo<E> structureInfo = new StructureInfo<>(patterns, c, originClassPath, true);
structures.add(structureInfo);
}

public static <E extends Structure> void registerStructure(Class<E> c, EntryValidator entryValidator, String... patterns) {
checkAcceptRegistrations();
String originClassPath = Thread.currentThread().getStackTrace()[2].getClassName();
Expand Down Expand Up @@ -1605,16 +1626,18 @@ public static void info(final String info) {
*/
@SuppressWarnings("null")
public static void warning(final String warning) {
SkriptLogger.log(Level.WARNING, warning);
if (!Annotation.isAnnotationPresent("suppress warnings"))
SkriptLogger.log(Level.WARNING, warning);
}

/**
* @see SkriptLogger#log(Level, String)
*/
@SuppressWarnings("null")
public static void error(final @Nullable String error) {
if (error != null)
SkriptLogger.log(Level.SEVERE, error);
if (error == null || Annotation.isAnnotationPresent("suppress errors"))
return;
SkriptLogger.log(Level.SEVERE, error);
}

/**
Expand All @@ -1625,6 +1648,8 @@ public static void error(final @Nullable String error) {
* @param quality
*/
public static void error(final String error, final ErrorQuality quality) {
if (Annotation.isAnnotationPresent("suppress errors"))
return;
SkriptLogger.log(new LogEntry(SkriptLogger.SEVERE, quality, error));
}

Expand Down