Skip to content

Commit

Permalink
Merge branch 'dev/patch' into fix-turkish-lang
Browse files Browse the repository at this point in the history
  • Loading branch information
sovdeeth authored Nov 23, 2024
2 parents a2f32ea + 9111b87 commit f6a5065
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 28 deletions.
47 changes: 37 additions & 10 deletions src/main/java/ch/njol/skript/classes/data/DefaultOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,26 +32,53 @@ public class DefaultOperations {
static {
// Number - Number
Arithmetics.registerOperation(Operator.ADDITION, Number.class, (left, right) -> {
if (Utils.isInteger(left, right))
return left.longValue() + right.longValue();
if (Utils.isInteger(left, right)) {
long result = left.longValue() + right.longValue();
// catches overflow, from Math.addExact(long, long)
if (((left.longValue() ^ result) & (right.longValue() ^ result)) >= 0)
return result;
}
return left.doubleValue() + right.doubleValue();
});
Arithmetics.registerOperation(Operator.SUBTRACTION, Number.class, (left, right) -> {
if (Utils.isInteger(left, right))
return left.longValue() - right.longValue();
if (Utils.isInteger(left, right)) {
long result = left.longValue() - right.longValue();
// catches overflow, from Math.addExact(long, long)
if (((left.longValue() ^ result) & (right.longValue() ^ result)) >= 0)
return result;
}
return left.doubleValue() - right.doubleValue();
});
Arithmetics.registerOperation(Operator.MULTIPLICATION, Number.class, (left, right) -> {
if (Utils.isInteger(left, right))
return left.longValue() * right.longValue();
return left.doubleValue() * right.doubleValue();
if (!Utils.isInteger(left, right))
return left.doubleValue() * right.doubleValue();

// catch overflow, from Math.multiplyExact(long, long)
long longLeft = left.longValue();
long longRight = right.longValue();
long ax = Math.abs(longLeft);
long ay = Math.abs(longRight);

long result = left.longValue() * right.longValue();

if (((ax | ay) >>> 31 != 0)) {
// Some bits greater than 2^31 that might cause overflow
// Check the result using the divide operator
// and check for the special case of Long.MIN_VALUE * -1
if (((longRight != 0) && (result / longRight != longLeft)) ||
(longLeft == Long.MIN_VALUE && longRight == -1)) {
return left.doubleValue() * right.doubleValue();
}
}
return result;
});
Arithmetics.registerOperation(Operator.DIVISION, Number.class, (left, right) -> left.doubleValue() / right.doubleValue());
Arithmetics.registerOperation(Operator.EXPONENTIATION, Number.class, (left, right) -> Math.pow(left.doubleValue(), right.doubleValue()));
Arithmetics.registerDifference(Number.class, (left, right) -> {
if (Utils.isInteger(left, right))
return Math.abs(left.longValue() - right.longValue());
return Math.abs(left.doubleValue() - right.doubleValue());
double result = Math.abs(left.doubleValue() - right.doubleValue());
if (Utils.isInteger(left, right) && result < Long.MAX_VALUE && result > Long.MIN_VALUE)
return (long) result;
return result;
});
Arithmetics.registerDefaultValue(Number.class, () -> 0L);

Expand Down
67 changes: 49 additions & 18 deletions src/main/java/ch/njol/skript/expressions/ExprJoinSplit.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
package ch.njol.skript.expressions;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import ch.njol.skript.SkriptConfig;
import ch.njol.skript.lang.Literal;
import org.bukkit.event.Event;
import org.jetbrains.annotations.Nullable;

Expand All @@ -36,14 +38,11 @@
import ch.njol.util.Kleenean;
import ch.njol.util.StringUtils;

/**
* @author Peter Güttinger
*/
@Name("Join & Split")
@Description("Joins several texts with a common delimiter (e.g. \", \"), or splits a text into multiple texts at a given delimiter.")
@Examples({
"message \"Online players: %join all players with \"\" | \"\"%\" # %all players% would use the default \"x, y, and z\"",
"set {_s::*} to the string argument split at \",\""
"message \"Online players: %join all players' names with \"\" | \"\"%\" # %all players% would use the default \"x, y, and z\"",
"set {_s::*} to the string argument split at \",\""
})
@Since("2.1, 2.5.2 (regex support), 2.7 (case sensitivity)")
public class ExprJoinSplit extends SimpleExpression<String> {
Expand All @@ -61,33 +60,47 @@ public class ExprJoinSplit extends SimpleExpression<String> {
private boolean regex;
private boolean caseSensitivity;

@SuppressWarnings("null")
private Expression<String> strings;
@Nullable
private Expression<String> delimiter;
private @Nullable Expression<String> delimiter;

private @Nullable Pattern pattern;

@Override
@SuppressWarnings({"unchecked", "null"})
public boolean init(Expression<?>[] exprs, int matchedPattern, Kleenean isDelayed, ParseResult parseResult) {
join = matchedPattern == 0;
regex = matchedPattern >= 3;
caseSensitivity = SkriptConfig.caseSensitive.value() || parseResult.hasTag("case");
//noinspection unchecked
strings = (Expression<String>) exprs[0];
//noinspection unchecked
delimiter = (Expression<String>) exprs[1];
if (!join && delimiter instanceof Literal) {
String stringPattern = ((Literal<String>) delimiter).getSingle();
try {
this.pattern = compilePattern(stringPattern);
} catch (PatternSyntaxException e) {
Skript.error("'" + stringPattern + "' is not a valid regular expression");
return false;
}
}
return true;
}

@Override
@Nullable
protected String[] get(Event event) {
protected String @Nullable [] get(Event event) {
String[] strings = this.strings.getArray(event);
String delimiter = this.delimiter != null ? this.delimiter.getSingle(event) : "";
if (strings.length == 0 || delimiter == null)
return new String[0];
if (join) {
if (join)
return new String[] {StringUtils.join(strings, delimiter)};
} else {
return strings[0].split(regex ? delimiter : (caseSensitivity ? "" : "(?i)") + Pattern.quote(delimiter), -1);
try {
Pattern pattern = this.pattern;
if (pattern == null)
pattern = compilePattern(delimiter);
return pattern.split(strings[0], -1);
} catch (PatternSyntaxException e) {
return new String[0];
}
}

Expand All @@ -103,10 +116,28 @@ public Class<? extends String> getReturnType() {

@Override
public String toString(@Nullable Event event, boolean debug) {
if (join)
return "join " + strings.toString(event, debug) + (delimiter != null ? " with " + delimiter.toString(event, debug) : "");
return (regex ? "regex " : "") + "split " + strings.toString(event, debug) + (delimiter != null ? " at " + delimiter.toString(event, debug) : "")
+ (regex ? "" : "(case sensitive: " + caseSensitivity + ")");
StringBuilder builder = new StringBuilder();
if (join) {
builder.append("join ").append(strings.toString(event, debug));
if (delimiter != null)
builder.append(" with ").append(delimiter.toString(event, debug));
return builder.toString();
}

assert delimiter != null;
if (regex)
builder.append("regex ");
builder.append("split ")
.append(strings.toString(event, debug))
.append(" at ")
.append(delimiter.toString(event, debug));
if (!regex)
builder.append(" (case sensitive: ").append(caseSensitivity).append(")");
return builder.toString();
}

private Pattern compilePattern(String delimiter) {
return Pattern.compile(regex ? delimiter : (caseSensitivity ? "" : "(?i)") + Pattern.quote(delimiter));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
test "regex exceptions not handled":
parse:
set {_split::*} to regex split "test" at "\b{_name}\b"
assert last parse logs is "'\b{_name}\b' is not a valid regular expression" with "regex split did not error with invalid regex literal"

set {_pattern} to "\b{_name}\b"
set {_split::*} to regex split "test" at {_pattern}
assert {_split::*} is not set with "regex split returned a value with invalid regex expression"

assert regex split "apple,banana;cherry" at "[,;]" is "apple", "banana" and "cherry" with "regex split did not split correctly with literal"
set {_pattern} to "[,;]"
assert regex split "apple,banana;cherry" at {_pattern} is "apple", "banana" and "cherry" with "regex split did not split correctly with expression"
34 changes: 34 additions & 0 deletions src/test/skript/tests/regressions/7209-long overflow.sk
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
test "long overflow, addition":
set {_double-const} to 9000000000000000000.0
set {_long-const} to 9000000000000000000

loop 100 times:
set {_double} to {_double} + {_double-const}
set {_long} to {_long} + {_long-const}
assert {_double} is {_long} with "long value did not overflow to a double"

assert {_long} is 9000000000000000000 * 100.0 with "wrong final value"

test "long underflow, subtraction":
set {_double-const} to 9000000000000000000.0
set {_long-const} to 9000000000000000000

loop 100 times:
set {_double} to {_double} - {_double-const}
set {_long} to {_long} - {_long-const}
assert {_double} is {_long} with "long value did not overflow to a double"

assert {_long} is 9000000000000000000 * -100.0 with "wrong final value"

test "long overflow, multiplication":
set {_double} to 10.0
set {_long} to 10

loop 100 times:
set {_double} to {_double} * 10
set {_long} to {_long} * 10
assert {_double} is {_long} with "long value did not overflow to a double"

# the 6 is due to floating point error
assert {_long} is 100000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000 with "wrong final value"

0 comments on commit f6a5065

Please sign in to comment.