Skip to content

Commit

Permalink
Support backtracking in patterns to fix string errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
Moderocky committed Apr 28, 2022
1 parent 9681314 commit 1ddd866
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 31 deletions.
30 changes: 29 additions & 1 deletion src/main/java/org/byteskript/skript/compiler/Pattern.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.byteskript.skript.api.Library;

import java.util.*;
import java.util.regex.MatchResult;
import java.util.regex.Matcher;

public class Pattern { // todo remove regex go indexOf impl
Expand Down Expand Up @@ -61,7 +62,7 @@ protected void handle(final String string) {
current = builder;
} else {
input = true;
builder.append("(\\(.+\\)|.+?)");
builder.append("(\\(.+\\)|.+)");
current = new StringBuilder();
}
}
Expand Down Expand Up @@ -170,6 +171,7 @@ public String[] get(java.util.regex.Pattern pattern) {

public static final class Match {
public final int matchedPattern;
public final Variant[] variants;
private final Matcher matcher;
private final Object meta;
private final Type[] expected;
Expand All @@ -193,6 +195,28 @@ public Match(Matcher matcher, int matchedPattern, Object meta, Type... expected)
list.add(matcher.group(i).trim());
}
this.groups = list.toArray(new String[0]);
final List<Variant> variants = new ArrayList<>();
final Matcher second = matcher.pattern().matcher(matcher.group());
while (second.find()) {
final List<String> strings = new ArrayList<>();
for (int i = 1; i <= second.groupCount(); i++) strings.add(second.group(i).trim());
final String[] groups = strings.toArray(new String[0]);
variants.add(new Variant(second, expected, groups));
}
this.variants = variants.toArray(new Variant[0]);
}

public Match(Matcher matcher, Variant[] variants, int matchedPattern, Object meta, Type... expected) {
this.matcher = matcher;
this.meta = meta;
this.expected = expected;
this.matchedPattern = matchedPattern;
this.variants = variants;
final List<String> list = new ArrayList<>();
for (int i = 1; i <= matcher.groupCount(); i++) {
list.add(matcher.group(i).trim());
}
this.groups = list.toArray(new String[0]);
}

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

public record Variant(MatchResult result, Type[] expected, String[] groups) {

}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public ElementTree assembleStatement(final String statement, final FileContext c
for (int i = 0; i < types.length; i++) {
final String input = inputs[i];
final Type type = types[i];
final ElementTree sub = assembleExpression(input.trim(), type, context, details);
final ElementTree sub = this.assembleExpression(input.trim(), type, context, details);
if (sub == null) {
context.currentEffect = null;
continue outer;
Expand Down Expand Up @@ -261,25 +261,28 @@ public ElementTree assembleExpression(String expression, final Type expected, fi
final Pattern.Match match = handler.match(expression, context);
if (match == null) continue;
if (!match.equals(expression)) continue;
final Type[] types = match.expected();
final String[] inputs = match.groups();
if (inputs.length < types.length) continue;
context.setState(handler.getSubState()); // anticipate inner-effect state change
details.expressionMatched = handler;
inner:
for (int i = 0; i < types.length; i++) {
final String input = inputs[i];
final Type type = types[i];
final ElementTree sub = this.assembleExpression(input.trim(), type, context, details);
if (sub == null) continue outer;
elements.add(sub);
}
current = new ElementTree(handler, match, elements.toArray(new ElementTree[0]));
if (handler instanceof InnerModifyExpression) {
assert current.nested().length == 1;
current = current.nested()[0];
variants:
for (final Pattern.Match.Variant variant : match.variants) {
final Type[] types = variant.expected();
final String[] inputs = variant.groups();
if (inputs.length < types.length) continue;
context.setState(handler.getSubState()); // anticipate inner-effect state change
details.expressionMatched = handler;
inner:
for (int i = 0; i < types.length; i++) {
final String input = inputs[i];
final Type type = types[i];
final ElementTree sub = this.assembleExpression(input.trim(), type, context, details);
if (sub == null) continue variants;
elements.add(sub);
}
current = new ElementTree(handler, match, elements.toArray(new ElementTree[0]));
if (handler instanceof InnerModifyExpression) {
assert current.nested().length == 1;
current = current.nested()[0];
}
break outer;
}
break;
}
return current;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@ public int getLine() {

@Override
public void printStackTrace(PrintStream stream) {
if (System.getProperty("debug_mode") != null) super.printStackTrace(stream);
if (details == null) super.printStackTrace(stream);
else printStackTrace(new OutputWriter(stream, null));
}

@Override
public void printStackTrace(PrintWriter stream) {
if (System.getProperty("debug_mode") != null) super.printStackTrace(stream);
if (details == null) super.printStackTrace(stream);
else printStackTrace(new OutputWriter(null, stream));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import mx.kenzie.foundation.Type;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.syntax.RelationalExpression;
import org.byteskript.skript.compiler.CommonTypes;
import org.byteskript.skript.compiler.Context;
import org.byteskript.skript.compiler.Pattern;
Expand All @@ -32,7 +31,7 @@
"""
}
)
public class ExprAdd extends RelationalExpression {
public class ExprAdd extends SymbolJoiner {

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

@Override
char joiner() {
return '+';
}

@Override
public Pattern.Match match(String thing, Context context) {
if (!thing.contains("+")) return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import mx.kenzie.foundation.Type;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.syntax.RelationalExpression;
import org.byteskript.skript.compiler.CommonTypes;
import org.byteskript.skript.compiler.Context;
import org.byteskript.skript.compiler.Pattern;
Expand All @@ -29,10 +28,10 @@
"""
}
)
public class ExprMultiply extends RelationalExpression {
public class ExprMultiply extends SymbolJoiner {

public ExprMultiply() {
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Object% ?(\\\\*) ?%Number%");
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Object% ?(\\\\*) ?%Number%");
try {
handlers.put(StandardHandlers.FIND, OperatorHandler.class.getMethod("multiply", Object.class, Object.class));
handlers.put(StandardHandlers.GET, OperatorHandler.class.getMethod("multiply", Object.class, Object.class));
Expand All @@ -46,9 +45,14 @@ public Type getReturnType() {
return CommonTypes.OBJECT;
}

@Override
char joiner() {
return '*';
}

@Override
public Pattern.Match match(String thing, Context context) {
if (!thing.contains("*") && !thing.contains("×")) return null;
if (!thing.contains("*")) return null;
return super.match(thing, context);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

import mx.kenzie.foundation.Type;
import org.byteskript.skript.api.note.Documentation;
import org.byteskript.skript.api.syntax.RelationalExpression;
import org.byteskript.skript.compiler.CommonTypes;
import org.byteskript.skript.compiler.Context;
import org.byteskript.skript.compiler.Pattern;
Expand All @@ -28,7 +27,7 @@
"""
}
)
public class ExprSubtract extends RelationalExpression {
public class ExprSubtract extends SymbolJoiner {

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

@Override
char joiner() {
return '-';
}

@Override
public Pattern.Match match(String thing, Context context) {
if (!thing.contains("-")) return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2022 ByteSkript org (Moderocky)
* View the full licence information and permissions:
* https://github.com/Moderocky/ByteSkript/blob/master/LICENSE
*/

package org.byteskript.skript.lang.syntax.maths;

import mx.kenzie.foundation.Type;
import org.byteskript.skript.api.LanguageElement;
import org.byteskript.skript.api.Library;
import org.byteskript.skript.api.syntax.RelationalExpression;
import org.byteskript.skript.compiler.CommonTypes;
import org.byteskript.skript.compiler.Context;
import org.byteskript.skript.compiler.Pattern;

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

abstract class SymbolJoiner extends RelationalExpression {

public SymbolJoiner(Library provider, LanguageElement type, String... patterns) {
super(provider, type, patterns);
}

@Override
public Pattern.Match match(String thing, Context context) {
final char joiner = this.joiner();
if (!thing.contains("" + joiner)) return null;
final Pattern.Match.Variant[] variants = this.createVariants(thing);
return new Pattern.Match(Pattern.fakeMatcher(thing), variants, 0, thing, CommonTypes.OBJECT, CommonTypes.OBJECT);
}

abstract char joiner();

protected Pattern.Match.Variant[] createVariants(String thing) {
final int[] joins = this.joinIndices(thing);
final List<Pattern.Match.Variant> variants = new ArrayList<>();
for (int join : joins) {
if (join == 0 || join == thing.length() - 1) continue;
final String first = thing.substring(0, join).trim(), second = thing.substring(join + 1).trim();
variants.add(new Pattern.Match.Variant(null,
new Type[]{CommonTypes.OBJECT, CommonTypes.OBJECT},
new String[]{first, second}));
}
return variants.toArray(new Pattern.Match.Variant[0]);
}

protected int[] joinIndices(String thing) {
final char joiner = this.joiner();
final List<Integer> list = new ArrayList<>();
int index = thing.indexOf(thing);
while (index >= 0) {
list.add(index);
index = thing.indexOf(joiner, index + 1);
}
final Integer[] integers = list.toArray(new Integer[0]);
final int[] ints = new int[integers.length];
for (int i = 0; i < ints.length; i++) ints[i] = integers[i];
return ints;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ public boolean reversible() {
};
}

Object union(A first, B second) throws Throwable;

default Object union2(B first, A second) throws Throwable {
return this.union(second, first);
}

Object union(A first, B second) throws Throwable;

default boolean reversible() {
return true;
}
Expand Down
1 change: 0 additions & 1 deletion src/test/java/org/byteskript/skript/test/CreatePages.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

package org.byteskript.skript.test;

import mx.kenzie.autodoc.AutoDocs;
import mx.kenzie.autodoc.DocBuilder;

import java.io.File;
Expand Down
6 changes: 6 additions & 0 deletions src/test/java/org/byteskript/skript/test/SyntaxTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ public class SyntaxTest extends SkriptTest {
= new Skript();
// = new Skript(new DebugSkriptCompiler(Stream.controller(System.out)));

public static void main(String[] args) throws Throwable { // test only
System.setProperty("debug_mode", "true");
final PostCompileClass cls = skript.compileScript(MainTest.class.getClassLoader()
.getResourceAsStream("tests/bracket.bsk"), "skript.bracket");
}

@Test
public void all() throws Throwable {
final URI uri = SyntaxTest.class.getClassLoader().getResource("tests").toURI();
Expand Down
1 change: 1 addition & 0 deletions src/test/resources/tests/maths.bsk
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function basic:
assert {e} is 2: "Square root (syntax) failed."
assert "hello " + "there" is "hello there": "String joining failed."
assert "Hello " + "<there!" is "Hello <there!": "String joining failed."
assert "hello + " + "there" is "hello + there": "String joining failed."

function test:
trigger:
Expand Down

0 comments on commit 1ddd866

Please sign in to comment.