Skip to content

Commit

Permalink
Add support for String literals (SkriptLang#6718)
Browse files Browse the repository at this point in the history
  • Loading branch information
Moderocky authored Jul 1, 2024
1 parent b226c8b commit 0348a71
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 22 deletions.
81 changes: 81 additions & 0 deletions src/main/java/ch/njol/skript/lang/LiteralString.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
package ch.njol.skript.lang;

import ch.njol.skript.lang.util.ConvertedLiteral;
import ch.njol.skript.util.Utils;
import ch.njol.util.coll.CollectionUtils;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;
import org.skriptlang.skript.lang.converter.Converters;

import java.util.Optional;

public class LiteralString extends VariableString implements Literal<String> {

/**
* Creates a new VariableString which does not contain variables.
*
* @param input Content for string.
*/
protected LiteralString(String input) {
super(input);
}

@Override
public String[] getArray() {
return new String[]{original};
}

@Override
public String getSingle() {
return original;
}

@Override
public String[] getAll() {
return new String[]{original};
}

@Override
public Optional<String> getOptionalSingle(Event event) {
return Optional.of(original);
}

@Override
@SuppressWarnings("unchecked")
public <R> @Nullable Literal<? extends R> getConvertedExpression(Class<R>... to) {
if (CollectionUtils.containsSuperclass(to, String.class))
return (Literal<? extends R>) this;
Class<R> superType = (Class<R>) Utils.getSuperType(to);
R[] parsedData = Converters.convert(this.getArray(), to, superType);
if (parsedData.length != 1)
return null;
return new ConvertedLiteral<>(this, parsedData, superType);
}

/**
* Use {@link #toString(Event)} to get the actual string. This method is for debugging.
*/
@Override
public String toString(@Nullable Event event, boolean debug) {
return '"' + original + '"';
}

}
10 changes: 10 additions & 0 deletions src/main/java/ch/njol/skript/lang/SkriptParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,16 @@ private Expression<?> parseSingleExpr(boolean allowUnparsedLiteral, @Nullable Lo
return new SimpleLiteral<>(parsedObject, false, new UnparsedLiteral(expr));
}
}
if (expr.startsWith("\"") && expr.endsWith("\"") && expr.length() > 1) {
for (ClassInfo<?> aClass : exprInfo.classes) {
if (!aClass.getC().isAssignableFrom(String.class))
continue;
VariableString string = VariableString.newInstance(expr.substring(1, expr.length() - 1));
if (string instanceof LiteralString)
return string;
break;
}
}
log.printError();
return null;
} finally {
Expand Down
42 changes: 20 additions & 22 deletions src/main/java/ch/njol/skript/lang/VariableString.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package ch.njol.skript.lang;

import ch.njol.skript.Skript;
import ch.njol.skript.SkriptConfig;
import ch.njol.skript.classes.Changer.ChangeMode;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.expressions.ExprColoured;
Expand All @@ -43,9 +42,8 @@
import ch.njol.util.coll.iterator.SingleItemIterator;
import com.google.common.collect.Lists;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NotNull;
import org.skriptlang.skript.lang.script.Script;

Expand All @@ -62,13 +60,13 @@ public class VariableString implements Expression<String> {

@Nullable
private final Script script;
private final String orig;
protected final String original;

@Nullable
private final Object[] strings;

@Nullable
private Object[] stringsUnformatted;
private final Object @Nullable [] strings;


private Object @Nullable [] stringsUnformatted;
private final boolean isSimple;

@Nullable
Expand All @@ -83,15 +81,15 @@ public class VariableString implements Expression<String> {

/**
* Creates a new VariableString which does not contain variables.
*
*
* @param input Content for string.
*/
private VariableString(String input) {
protected VariableString(String input) {
this.isSimple = true;
this.simpleUnformatted = input.replace("%%", "%"); // This doesn't contain variables, so this wasn't done in newInstance!
this.simple = Utils.replaceChatStyles(simpleUnformatted);

this.orig = simple;
this.original = simple;
this.strings = null;
this.mode = StringMode.MESSAGE;

Expand All @@ -103,13 +101,13 @@ private VariableString(String input) {

/**
* Creates a new VariableString which contains variables.
*
*
* @param original Original string (unparsed).
* @param strings Objects, some of them are variables.
* @param mode String mode.
*/
private VariableString(String original, Object[] strings, StringMode mode) {
this.orig = original;
this.original = original;
this.strings = new Object[strings.length];
this.stringsUnformatted = new Object[strings.length];

Expand Down Expand Up @@ -151,7 +149,7 @@ public static VariableString newInstance(String input) {
/**
* Creates an instance of VariableString by parsing given string.
* Prints errors and returns null if it is somehow invalid.
*
*
* @param original Unquoted string to parse.
* @return A new VariableString instance.
*/
Expand Down Expand Up @@ -251,7 +249,7 @@ public static VariableString newInstance(String original, StringMode mode) {

// Check if this isn't actually variable string, and return
if (strings.size() == 1 && strings.get(0) instanceof String)
return new VariableString(original);
return new LiteralString(original);

if (strings.size() == 1 && strings.get(0) instanceof Expression &&
((Expression<?>) strings.get(0)).getReturnType() == String.class &&
Expand Down Expand Up @@ -285,7 +283,7 @@ public static String quote(String string) {
/**
* Tests whether a string is correctly quoted, i.e. only has doubled double quotes in it.
* Singular double quotes are only allowed between percentage signs.
*
*
* @param string The string to test
* @param withQuotes Whether the string must be surrounded by double quotes or not
* @return Whether the string is quoted correctly
Expand Down Expand Up @@ -316,7 +314,7 @@ public static boolean isQuotedCorrectly(String string, boolean withQuotes) {

/**
* Removes quoted quotes from a string.
*
*
* @param string The string to remove quotes from
* @param surroundingQuotes Whether the string has quotes at the start & end that should be removed
* @return The string with double quotes replaced with single ones and optionally with removed surrounding quotes.
Expand All @@ -330,7 +328,7 @@ public static String unquote(String string, boolean surroundingQuotes) {

/**
* Copied from {@code SkriptParser#nextBracket(String, char, char, int, boolean)}, but removed escaping & returns -1 on error.
*
*
* @param string The string to search in
* @param start Index after the opening bracket
* @return The next closing curly bracket
Expand Down Expand Up @@ -485,7 +483,7 @@ public List<MessageComponent> getMessageComponentsUnsafe(Event event) {

/**
* Parses all expressions in the string and returns it in chat JSON format.
*
*
* @param event Event to pass to the expressions.
* @return The input string with all expressions replaced.
*/
Expand Down Expand Up @@ -513,7 +511,7 @@ public String toString() {
/**
* Parses all expressions in the string and returns it.
* If this is a simple string, the event may be null.
*
*
* @param event Event to pass to the expressions.
* @return The input string with all expressions replaced.
*/
Expand Down Expand Up @@ -573,7 +571,7 @@ public String toString(@Nullable Event event, boolean debug) {

/**
* Builds all possible default variable type hints based on the super type of the expression.
*
*
* @return List<String> of all possible super class code names.
*/
@NotNull
Expand Down Expand Up @@ -629,7 +627,7 @@ public VariableString setMode(StringMode mode) {
if (this.mode == mode || isSimple)
return this;
try (BlockingLogHandler ignored = new BlockingLogHandler().start()) {
VariableString variableString = newInstance(orig, mode);
VariableString variableString = newInstance(original, mode);
if (variableString == null) {
assert false : this + "; " + mode;
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* This file is part of Skript.
*
* Skript is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Skript is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Skript. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright Peter Güttinger, SkriptLang team and contributors
*/
package ch.njol.skript.test.runner;

import ch.njol.skript.Skript;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.NoDoc;
import ch.njol.skript.lang.*;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.util.SimpleExpression;
import ch.njol.util.Kleenean;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

@Name("Test String Literal")
@Description("Accepts only a string literal. Used for testing correct parsing & literal treatment. Returns the value.")
@NoDoc
public class ExprTestStringLiteral extends SimpleExpression<String> {

static {
if (TestMode.ENABLED)
Skript.registerExpression(ExprTestStringLiteral.class, String.class, ExpressionType.SIMPLE, "test string literal %*string%");
}

private Expression<String> literal;

@Override
@SuppressWarnings("unchecked")
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
this.literal = (Expression<String>) expressions[0];
return literal instanceof LiteralString;
}

@Override
protected @Nullable String[] get(Event event) {
return literal.getArray(event);
}

@Override
public Class<? extends String> getReturnType() {
return String.class;
}

@Override
public boolean isSingle() {
return true;
}

@Override
public String toString(@Nullable Event event, boolean debug) {
return "test string literal " + literal.toString(event, debug);
}

}
20 changes: 20 additions & 0 deletions src/test/skript/tests/misc/string literals.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
test "string literals":
set {_c} to (test string literal "blob blob blob")
assert {_c} is "blob blob blob" with "string literal value wrong"
assert test string literal "blob blob blob" is "blob blob blob" with "string literal value wrong"

test "string literals (parsing)":

parse:
set {_test} to test string literal "hello there this is a long string blah blah blah"
assert last parse logs is not set with "skript should be able to understand literal: %last parse logs%"

parse:
set {_test} to test string literal "hello %% percent"
assert last parse logs is not set with "percents shouldn't invalidate literal: %last parse logs%"

parse:
set {_test} to test string literal "hello %now%"
assert last parse logs is set with "the non-literal should not have been accepted"

assert (test string literal "hello") is "hello" with "string literal value wrong"

0 comments on commit 0348a71

Please sign in to comment.