Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/main/java/ch/njol/skript/lang/EventRestrictedSyntax.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package ch.njol.skript.lang;

import ch.njol.skript.Skript;
import ch.njol.util.Kleenean;
import ch.njol.util.StringUtils;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

/**
* A syntax element that restricts the events it can be used in.
Expand All @@ -23,4 +29,25 @@ public interface EventRestrictedSyntax {
*/
Class<? extends Event>[] supportedEvents();

/**
* Creates a readable list of the user-facing names of the given event classes.
* @param supportedEvents The classes of the events to list.
* @return A string containing the names of the events as a list: {@code "the on death event, the on explosion event, or the on player join event"}.
*/
static @NotNull String supportedEventsNames(Class<? extends Event>[] supportedEvents) {
List<String> names = new ArrayList<>();

for (SkriptEventInfo<?> eventInfo : Skript.getEvents()) {
for (Class<? extends Event> eventClass : supportedEvents) {
for (Class<? extends Event> event : eventInfo.events) {
if (event.isAssignableFrom(eventClass)) {
names.add("the %s event".formatted(eventInfo.getName().toLowerCase()));
}
}
}
}

return StringUtils.join(names, ", ", " or ");
}

}
203 changes: 203 additions & 0 deletions src/main/java/ch/njol/skript/lang/ParsingConstraints.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package ch.njol.skript.lang;

import ch.njol.skript.lang.parser.ParserInstance;
import ch.njol.util.coll.iterator.CheckedIterator;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.lang.converter.Converters;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class ParsingConstraints {

private enum ExceptionMode {
UNUSED,
EXCLUDE,
INCLUDE
}

private Set<Class<?>> exceptions = Set.of();
private ExceptionMode exceptionMode;

private boolean allowFunctionCalls;

private boolean allowNonLiterals;
private boolean allowLiterals;

private Class<?> @Nullable [] validReturnTypes;

@Contract("-> new")
public static @NotNull ParsingConstraints empty() {
return new ParsingConstraints()
.allowFunctionCalls(false)
.include()
.allowLiterals(false)
.allowNonLiterals(false);
}

@Contract(" -> new")
public static @NotNull ParsingConstraints all() {
return new ParsingConstraints();
}

private ParsingConstraints() {
exceptionMode = ExceptionMode.UNUSED;
allowFunctionCalls = true;
allowNonLiterals = true;
allowLiterals = true;
validReturnTypes = new Class[]{Object.class};
}

public <T extends SyntaxElement> @NotNull Iterator<? extends SyntaxElementInfo<T>> constrainIterator(Iterator<? extends SyntaxElementInfo<T>> uncheckedIterator) {
return new CheckedIterator<>(uncheckedIterator, info -> {
assert info != null;
Class<?> elementClass = info.getElementClass();
if (elementClass == null) {
return false;
}

// check literals
if (!allowsLiterals() && Literal.class.isAssignableFrom(elementClass)) {
return false;
}
// check non-literals
// TODO: allow simplification
if (!allowsNonLiterals() && !Literal.class.isAssignableFrom(elementClass)) {
return false;
}

// check exceptions
if (exceptionMode == ExceptionMode.INCLUDE && !exceptions.contains(elementClass)) {
return false;
} else if (exceptionMode == ExceptionMode.EXCLUDE && exceptions.contains(elementClass)) {
return false;
}

// check return types
if (info instanceof ExpressionInfo<?, ?> expressionInfo) {
if (validReturnTypes == null || expressionInfo.returnType == Object.class)
return true;

for (Class<?> returnType : validReturnTypes) {
if (Converters.converterExists(expressionInfo.returnType, returnType))
return true;
}
return false;
}
return true;
});
}

public ParsingConstraints include(Class<?>... exceptions) {
if (exceptionMode != ExceptionMode.INCLUDE) {
this.exceptions = new HashSet<>();
}
this.exceptions.addAll(Set.of(exceptions));
exceptionMode = ExceptionMode.INCLUDE;
return this;
}

public ParsingConstraints exclude(Class<?>... exceptions) {
if (exceptionMode != ExceptionMode.EXCLUDE) {
this.exceptions = new HashSet<>();
}
this.exceptions.addAll(Set.of(exceptions));
exceptionMode = ExceptionMode.EXCLUDE;
return this;
}

public ParsingConstraints clearExceptions() {
exceptions = Set.of();
exceptionMode = ExceptionMode.UNUSED;
return this;
}

public boolean allowsFunctionCalls() { return allowFunctionCalls; }

public ParsingConstraints allowFunctionCalls(boolean allow) {
allowFunctionCalls = allow;
return this;
}

public Class<?>[] getValidReturnTypes() {
return validReturnTypes;
}

public ParsingConstraints constrainReturnTypes(Class<?>... validReturnTypes) {
if (validReturnTypes == null || validReturnTypes.length == 0) {
this.validReturnTypes = null;
} else {
this.validReturnTypes = validReturnTypes;
}
return this;
}

public boolean allowsNonLiterals() { return allowNonLiterals; }

public ParsingConstraints allowNonLiterals(boolean allow) {
allowNonLiterals = allow;
return this;
}

public boolean allowsLiterals() { return allowLiterals; }

public ParsingConstraints allowLiterals(boolean allow) {
allowLiterals = allow;
return this;
}

@ApiStatus.Internal
public int asParseFlags() {
int flags = 0;
if (allowNonLiterals) {
flags |= SkriptParser.PARSE_EXPRESSIONS;
}
if (allowLiterals) {
flags |= SkriptParser.PARSE_LITERALS;
}
return flags;
}

@ApiStatus.Internal
public void applyParseFlags(int flags) {
allowNonLiterals = (flags & SkriptParser.PARSE_EXPRESSIONS) != 0;
allowLiterals = (flags & SkriptParser.PARSE_LITERALS) != 0;
}

public ParsingConstraints copy() {
ParsingConstraints copy = new ParsingConstraints();
copy.exceptions = new HashSet<>(exceptions);
copy.exceptionMode = exceptionMode;
copy.validReturnTypes = validReturnTypes;
copy.allowFunctionCalls = allowFunctionCalls;
copy.allowNonLiterals = allowNonLiterals;
copy.allowLiterals = allowLiterals;
return copy;
}

static {
ParserInstance.registerData(ConstraintData.class, ConstraintData::new);
}

public static class ConstraintData extends ParserInstance.Data {
private ParsingConstraints parsingConstraints = ParsingConstraints.all();

public ConstraintData(ParserInstance parserInstance) {
super(parserInstance);
}

public ParsingConstraints getConstraints() {
return parsingConstraints;
}

public void setConstraints(ParsingConstraints parsingConstraints) {
this.parsingConstraints = parsingConstraints;
}

}

}
Loading
Loading