Skip to content

Commit 1ddd866

Browse files
committed
Support backtracking in patterns to fix string errors.
1 parent 9681314 commit 1ddd866

File tree

11 files changed

+145
-31
lines changed

11 files changed

+145
-31
lines changed

src/main/java/org/byteskript/skript/compiler/Pattern.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.byteskript.skript.api.Library;
1111

1212
import java.util.*;
13+
import java.util.regex.MatchResult;
1314
import java.util.regex.Matcher;
1415

1516
public class Pattern { // todo remove regex go indexOf impl
@@ -61,7 +62,7 @@ protected void handle(final String string) {
6162
current = builder;
6263
} else {
6364
input = true;
64-
builder.append("(\\(.+\\)|.+?)");
65+
builder.append("(\\(.+\\)|.+)");
6566
current = new StringBuilder();
6667
}
6768
}
@@ -170,6 +171,7 @@ public String[] get(java.util.regex.Pattern pattern) {
170171

171172
public static final class Match {
172173
public final int matchedPattern;
174+
public final Variant[] variants;
173175
private final Matcher matcher;
174176
private final Object meta;
175177
private final Type[] expected;
@@ -193,6 +195,28 @@ public Match(Matcher matcher, int matchedPattern, Object meta, Type... expected)
193195
list.add(matcher.group(i).trim());
194196
}
195197
this.groups = list.toArray(new String[0]);
198+
final List<Variant> variants = new ArrayList<>();
199+
final Matcher second = matcher.pattern().matcher(matcher.group());
200+
while (second.find()) {
201+
final List<String> strings = new ArrayList<>();
202+
for (int i = 1; i <= second.groupCount(); i++) strings.add(second.group(i).trim());
203+
final String[] groups = strings.toArray(new String[0]);
204+
variants.add(new Variant(second, expected, groups));
205+
}
206+
this.variants = variants.toArray(new Variant[0]);
207+
}
208+
209+
public Match(Matcher matcher, Variant[] variants, int matchedPattern, Object meta, Type... expected) {
210+
this.matcher = matcher;
211+
this.meta = meta;
212+
this.expected = expected;
213+
this.matchedPattern = matchedPattern;
214+
this.variants = variants;
215+
final List<String> list = new ArrayList<>();
216+
for (int i = 1; i <= matcher.groupCount(); i++) {
217+
list.add(matcher.group(i).trim());
218+
}
219+
this.groups = list.toArray(new String[0]);
196220
}
197221

198222
public String[] groups() {
@@ -216,6 +240,10 @@ public boolean equals(String string) {
216240
return matcher.group().equals(string);
217241
}
218242

243+
public record Variant(MatchResult result, Type[] expected, String[] groups) {
244+
245+
}
246+
219247
}
220248

221249
}

src/main/java/org/byteskript/skript/compiler/SimpleSkriptCompiler.java

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public ElementTree assembleStatement(final String statement, final FileContext c
232232
for (int i = 0; i < types.length; i++) {
233233
final String input = inputs[i];
234234
final Type type = types[i];
235-
final ElementTree sub = assembleExpression(input.trim(), type, context, details);
235+
final ElementTree sub = this.assembleExpression(input.trim(), type, context, details);
236236
if (sub == null) {
237237
context.currentEffect = null;
238238
continue outer;
@@ -261,25 +261,28 @@ public ElementTree assembleExpression(String expression, final Type expected, fi
261261
final Pattern.Match match = handler.match(expression, context);
262262
if (match == null) continue;
263263
if (!match.equals(expression)) continue;
264-
final Type[] types = match.expected();
265-
final String[] inputs = match.groups();
266-
if (inputs.length < types.length) continue;
267-
context.setState(handler.getSubState()); // anticipate inner-effect state change
268-
details.expressionMatched = handler;
269-
inner:
270-
for (int i = 0; i < types.length; i++) {
271-
final String input = inputs[i];
272-
final Type type = types[i];
273-
final ElementTree sub = this.assembleExpression(input.trim(), type, context, details);
274-
if (sub == null) continue outer;
275-
elements.add(sub);
276-
}
277-
current = new ElementTree(handler, match, elements.toArray(new ElementTree[0]));
278-
if (handler instanceof InnerModifyExpression) {
279-
assert current.nested().length == 1;
280-
current = current.nested()[0];
264+
variants:
265+
for (final Pattern.Match.Variant variant : match.variants) {
266+
final Type[] types = variant.expected();
267+
final String[] inputs = variant.groups();
268+
if (inputs.length < types.length) continue;
269+
context.setState(handler.getSubState()); // anticipate inner-effect state change
270+
details.expressionMatched = handler;
271+
inner:
272+
for (int i = 0; i < types.length; i++) {
273+
final String input = inputs[i];
274+
final Type type = types[i];
275+
final ElementTree sub = this.assembleExpression(input.trim(), type, context, details);
276+
if (sub == null) continue variants;
277+
elements.add(sub);
278+
}
279+
current = new ElementTree(handler, match, elements.toArray(new ElementTree[0]));
280+
if (handler instanceof InnerModifyExpression) {
281+
assert current.nested().length == 1;
282+
current = current.nested()[0];
283+
}
284+
break outer;
281285
}
282-
break;
283286
}
284287
return current;
285288
}

src/main/java/org/byteskript/skript/error/ScriptParseError.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,14 @@ public int getLine() {
6161

6262
@Override
6363
public void printStackTrace(PrintStream stream) {
64+
if (System.getProperty("debug_mode") != null) super.printStackTrace(stream);
6465
if (details == null) super.printStackTrace(stream);
6566
else printStackTrace(new OutputWriter(stream, null));
6667
}
6768

6869
@Override
6970
public void printStackTrace(PrintWriter stream) {
71+
if (System.getProperty("debug_mode") != null) super.printStackTrace(stream);
7072
if (details == null) super.printStackTrace(stream);
7173
else printStackTrace(new OutputWriter(null, stream));
7274
}

src/main/java/org/byteskript/skript/lang/syntax/maths/ExprAdd.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import mx.kenzie.foundation.Type;
1010
import org.byteskript.skript.api.note.Documentation;
11-
import org.byteskript.skript.api.syntax.RelationalExpression;
1211
import org.byteskript.skript.compiler.CommonTypes;
1312
import org.byteskript.skript.compiler.Context;
1413
import org.byteskript.skript.compiler.Pattern;
@@ -32,7 +31,7 @@
3231
"""
3332
}
3433
)
35-
public class ExprAdd extends RelationalExpression {
34+
public class ExprAdd extends SymbolJoiner {
3635

3736
public ExprAdd() {
3837
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Object% ?\\\\+ ?%Object%");
@@ -49,6 +48,11 @@ public Type getReturnType() {
4948
return CommonTypes.OBJECT;
5049
}
5150

51+
@Override
52+
char joiner() {
53+
return '+';
54+
}
55+
5256
@Override
5357
public Pattern.Match match(String thing, Context context) {
5458
if (!thing.contains("+")) return null;

src/main/java/org/byteskript/skript/lang/syntax/maths/ExprMultiply.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import mx.kenzie.foundation.Type;
1010
import org.byteskript.skript.api.note.Documentation;
11-
import org.byteskript.skript.api.syntax.RelationalExpression;
1211
import org.byteskript.skript.compiler.CommonTypes;
1312
import org.byteskript.skript.compiler.Context;
1413
import org.byteskript.skript.compiler.Pattern;
@@ -29,10 +28,10 @@
2928
"""
3029
}
3130
)
32-
public class ExprMultiply extends RelationalExpression {
31+
public class ExprMultiply extends SymbolJoiner {
3332

3433
public ExprMultiply() {
35-
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Object% ?(\\\\*) ?%Number%");
34+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Object% ?(\\\\*) ?%Number%");
3635
try {
3736
handlers.put(StandardHandlers.FIND, OperatorHandler.class.getMethod("multiply", Object.class, Object.class));
3837
handlers.put(StandardHandlers.GET, OperatorHandler.class.getMethod("multiply", Object.class, Object.class));
@@ -46,9 +45,14 @@ public Type getReturnType() {
4645
return CommonTypes.OBJECT;
4746
}
4847

48+
@Override
49+
char joiner() {
50+
return '*';
51+
}
52+
4953
@Override
5054
public Pattern.Match match(String thing, Context context) {
51-
if (!thing.contains("*") && !thing.contains("×")) return null;
55+
if (!thing.contains("*")) return null;
5256
return super.match(thing, context);
5357
}
5458

src/main/java/org/byteskript/skript/lang/syntax/maths/ExprSubtract.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import mx.kenzie.foundation.Type;
1010
import org.byteskript.skript.api.note.Documentation;
11-
import org.byteskript.skript.api.syntax.RelationalExpression;
1211
import org.byteskript.skript.compiler.CommonTypes;
1312
import org.byteskript.skript.compiler.Context;
1413
import org.byteskript.skript.compiler.Pattern;
@@ -28,7 +27,7 @@
2827
"""
2928
}
3029
)
31-
public class ExprSubtract extends RelationalExpression {
30+
public class ExprSubtract extends SymbolJoiner {
3231

3332
public ExprSubtract() {
3433
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Object% ?- ?%Object%");
@@ -45,6 +44,11 @@ public Type getReturnType() {
4544
return CommonTypes.OBJECT;
4645
}
4746

47+
@Override
48+
char joiner() {
49+
return '-';
50+
}
51+
4852
@Override
4953
public Pattern.Match match(String thing, Context context) {
5054
if (!thing.contains("-")) return null;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright (c) 2022 ByteSkript org (Moderocky)
3+
* View the full licence information and permissions:
4+
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
5+
*/
6+
7+
package org.byteskript.skript.lang.syntax.maths;
8+
9+
import mx.kenzie.foundation.Type;
10+
import org.byteskript.skript.api.LanguageElement;
11+
import org.byteskript.skript.api.Library;
12+
import org.byteskript.skript.api.syntax.RelationalExpression;
13+
import org.byteskript.skript.compiler.CommonTypes;
14+
import org.byteskript.skript.compiler.Context;
15+
import org.byteskript.skript.compiler.Pattern;
16+
17+
import java.util.ArrayList;
18+
import java.util.List;
19+
20+
abstract class SymbolJoiner extends RelationalExpression {
21+
22+
public SymbolJoiner(Library provider, LanguageElement type, String... patterns) {
23+
super(provider, type, patterns);
24+
}
25+
26+
@Override
27+
public Pattern.Match match(String thing, Context context) {
28+
final char joiner = this.joiner();
29+
if (!thing.contains("" + joiner)) return null;
30+
final Pattern.Match.Variant[] variants = this.createVariants(thing);
31+
return new Pattern.Match(Pattern.fakeMatcher(thing), variants, 0, thing, CommonTypes.OBJECT, CommonTypes.OBJECT);
32+
}
33+
34+
abstract char joiner();
35+
36+
protected Pattern.Match.Variant[] createVariants(String thing) {
37+
final int[] joins = this.joinIndices(thing);
38+
final List<Pattern.Match.Variant> variants = new ArrayList<>();
39+
for (int join : joins) {
40+
if (join == 0 || join == thing.length() - 1) continue;
41+
final String first = thing.substring(0, join).trim(), second = thing.substring(join + 1).trim();
42+
variants.add(new Pattern.Match.Variant(null,
43+
new Type[]{CommonTypes.OBJECT, CommonTypes.OBJECT},
44+
new String[]{first, second}));
45+
}
46+
return variants.toArray(new Pattern.Match.Variant[0]);
47+
}
48+
49+
protected int[] joinIndices(String thing) {
50+
final char joiner = this.joiner();
51+
final List<Integer> list = new ArrayList<>();
52+
int index = thing.indexOf(thing);
53+
while (index >= 0) {
54+
list.add(index);
55+
index = thing.indexOf(joiner, index + 1);
56+
}
57+
final Integer[] integers = list.toArray(new Integer[0]);
58+
final int[] ints = new int[integers.length];
59+
for (int i = 0; i < ints.length; i++) ints[i] = integers[i];
60+
return ints;
61+
}
62+
63+
}

src/main/java/org/byteskript/skript/runtime/type/OperatorFunction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ public boolean reversible() {
2929
};
3030
}
3131

32+
Object union(A first, B second) throws Throwable;
33+
3234
default Object union2(B first, A second) throws Throwable {
3335
return this.union(second, first);
3436
}
3537

36-
Object union(A first, B second) throws Throwable;
37-
3838
default boolean reversible() {
3939
return true;
4040
}

src/test/java/org/byteskript/skript/test/CreatePages.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
package org.byteskript.skript.test;
88

9-
import mx.kenzie.autodoc.AutoDocs;
109
import mx.kenzie.autodoc.DocBuilder;
1110

1211
import java.io.File;

src/test/java/org/byteskript/skript/test/SyntaxTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ public class SyntaxTest extends SkriptTest {
2929
= new Skript();
3030
// = new Skript(new DebugSkriptCompiler(Stream.controller(System.out)));
3131

32+
public static void main(String[] args) throws Throwable { // test only
33+
System.setProperty("debug_mode", "true");
34+
final PostCompileClass cls = skript.compileScript(MainTest.class.getClassLoader()
35+
.getResourceAsStream("tests/bracket.bsk"), "skript.bracket");
36+
}
37+
3238
@Test
3339
public void all() throws Throwable {
3440
final URI uri = SyntaxTest.class.getClassLoader().getResource("tests").toURI();

src/test/resources/tests/maths.bsk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ function basic:
2222
assert {e} is 2: "Square root (syntax) failed."
2323
assert "hello " + "there" is "hello there": "String joining failed."
2424
assert "Hello " + "<there!" is "Hello <there!": "String joining failed."
25+
assert "hello + " + "there" is "hello + there": "String joining failed."
2526

2627
function test:
2728
trigger:

0 commit comments

Comments
 (0)