Skip to content

Commit 996d77b

Browse files
committed
Merge branch 'pattern-compiling'
2 parents e8a855f + a66f498 commit 996d77b

File tree

7 files changed

+167
-20
lines changed

7 files changed

+167
-20
lines changed

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

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,15 @@ public static Matcher fakeMatcher(String thing) {
4545
}
4646

4747
protected void handle(final String string) {
48-
final StringBuilder builder = new StringBuilder().append("^");
48+
final StringBuilder builder = new StringBuilder();
4949
final List<String> types = new ArrayList<>();
50-
boolean escape = false;
51-
boolean input = false;
50+
final List<Integer> nest = new ArrayList<>();
51+
boolean escape = false,
52+
input = false,
53+
head = false;
54+
char last = 0;
5255
StringBuilder current = builder;
53-
for (char c : string.toCharArray()) {
56+
for (final char c : string.toCharArray()) {
5457
if (escape) {
5558
escape = false;
5659
builder.append(c);
@@ -59,6 +62,7 @@ protected void handle(final String string) {
5962
switch (c) {
6063
case ESCAPE -> escape = true;
6164
case INPUT -> {
65+
if (last == END_OPTIONAL) current.append(")?");
6266
if (input) {
6367
input = false;
6468
types.add(current.toString());
@@ -69,13 +73,37 @@ protected void handle(final String string) {
6973
current = new StringBuilder();
7074
}
7175
}
72-
case START_SWITCH, START_OPTIONAL -> current.append("(?:");
73-
case END_OPTIONAL -> current.append(")?");
74-
default -> current.append(c);
76+
case START_SWITCH -> {
77+
if (last == END_OPTIONAL) current.append(")?");
78+
current.append("(?:");
79+
}
80+
case START_OPTIONAL -> {
81+
if (last == END_OPTIONAL) current.append(")?");
82+
if (last == ' ' || last == 0) nest.add(0, 1);
83+
else nest.add(0, 0);
84+
current.append("(?:");
85+
}
86+
case END_OPTIONAL -> {
87+
if (last == END_OPTIONAL) current.append(")?");
88+
if (nest.remove(0) > 0) head = true;
89+
}
90+
case ' ' -> {
91+
if (last == END_OPTIONAL && head) {
92+
current.append(c);
93+
current.append(")?");
94+
} else if (last == END_OPTIONAL) current.append(")?");
95+
else current.append(c);
96+
}
97+
default -> {
98+
if (last == END_OPTIONAL) current.append(")?");
99+
current.append(c);
100+
head = false;
101+
}
75102
}
103+
last = c;
76104
}
77-
builder.append("$");
78-
final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(builder.toString());
105+
if (last == END_OPTIONAL) current.append(")?");
106+
final java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("^" + builder.toString().trim() + "$");
79107
this.patternMap.put(pattern, types.toArray(new String[0]));
80108
}
81109

@@ -125,18 +153,43 @@ protected Type[] convert(final Context context, final String... strings) {
125153
return types;
126154
}
127155

128-
public record Match(Matcher matcher, Object meta, Type... expected) {
156+
public static final class Match {
157+
private final Matcher matcher;
158+
private final Object meta;
159+
private final Type[] expected;
160+
private final String[] groups;
161+
162+
public Match(Matcher matcher, Object meta, Type... expected) {
163+
this.matcher = matcher;
164+
this.meta = meta;
165+
this.expected = expected;
166+
{
167+
final List<String> list = new ArrayList<>();
168+
for (int i = 1; i <= matcher.groupCount(); i++) {
169+
list.add(matcher.group(i).trim());
170+
}
171+
this.groups = list.toArray(new String[0]);
172+
}
173+
}
129174

130175
public Match(Matcher matcher, Type... expected) {
131176
this(matcher, null, expected);
132177
}
133178

134179
public String[] groups() {
135-
final List<String> list = new ArrayList<>();
136-
for (int i = 1; i <= matcher.groupCount(); i++) {
137-
list.add(matcher.group(i));
138-
}
139-
return list.toArray(new String[0]);
180+
return groups;
181+
}
182+
183+
public Matcher matcher() {
184+
return matcher;
185+
}
186+
187+
public Object meta() {
188+
return meta;
189+
}
190+
191+
public Type[] expected() {
192+
return expected;
140193
}
141194

142195
}

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.byteskript.skript.api.syntax.Section;
1616
import org.byteskript.skript.compiler.structure.ProgrammaticSplitTree;
1717
import org.byteskript.skript.compiler.structure.SectionMeta;
18+
import org.byteskript.skript.error.ScriptCompileError;
1819
import org.byteskript.skript.error.ScriptParseError;
1920

2021
import java.io.*;
@@ -99,7 +100,13 @@ public PostCompileClass[] compile(String file, Type path) {
99100
if (context.getMethod() != null) {
100101
context.getMethod().writeCode(WriteInstruction.lineNumber(context.lineNumber));
101102
}
102-
this.compileLine(line, context);
103+
try {
104+
this.compileLine(line, context);
105+
} catch (ScriptCompileError ex) {
106+
throw ex;
107+
} catch (Throwable ex) {
108+
throw new ScriptCompileError(context.lineNumber, "Error during compilation:", ex);
109+
}
103110
}
104111
for (int i = 0; i < context.units.size(); i++) {
105112
context.destroyUnit();

src/main/java/org/byteskript/skript/lang/syntax/generic/SystemInputExpression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
public class SystemInputExpression extends SimpleExpression {
2222

2323
public SystemInputExpression() {
24-
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[the ](system|console) input");
24+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[the] (system|console) input");
2525
}
2626

2727
@Override

src/main/java/org/byteskript/skript/lang/syntax/timing/MillisecondsExpression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
public class MillisecondsExpression extends SimpleExpression {
2222

2323
public MillisecondsExpression() {
24-
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Integer% m[illi[ ]]s[econd[s]]");
24+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "%Number% (ms|millis|milli[ ]second[s])");
2525
try {
2626
handlers.put(StandardHandlers.FIND, this.getClass().getMethod("find", Object.class));
2727
} catch (NoSuchMethodException e) {

src/main/java/org/byteskript/skript/lang/syntax/timing/ThreadExpression.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
public class ThreadExpression extends SimpleExpression {
2020

2121
public ThreadExpression() {
22-
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[the ][current ](process|thread)");
22+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[the] [current] (process|thread)");
2323
}
2424

2525
@Override

src/main/java/org/byteskript/skript/lang/syntax/type/TypeCreator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
public class TypeCreator extends SimpleExpression {
2121

2222
public TypeCreator() {
23-
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[a ]new %Type%");
23+
super(SkriptLangSpec.LIBRARY, StandardElements.EXPRESSION, "[a] new %Type%");
2424
handlers.put(StandardHandlers.GET, findMethod(TypeCreator.class, "create", Object.class));
2525
handlers.put(StandardHandlers.FIND, findMethod(TypeCreator.class, "create", Object.class));
2626
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2021 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.test;
8+
9+
import org.byteskript.skript.compiler.Pattern;
10+
import org.junit.Test;
11+
12+
public class PatternsTest {
13+
14+
@Test
15+
public void simpleOptional() {
16+
final Pattern pattern = new Pattern(new String[]{"[a] new thing"}, null);
17+
final java.util.regex.Pattern result = pattern.getCompiledPatterns()[0];
18+
assert result.pattern().equals("^(?:a )?new thing$");
19+
assert result.matcher("a new thing").matches();
20+
assert result.matcher("new thing").matches();
21+
}
22+
23+
@Test
24+
public void simpleChoice() {
25+
final Pattern pattern = new Pattern(new String[]{"the (new|old) thing"}, null);
26+
final java.util.regex.Pattern result = pattern.getCompiledPatterns()[0];
27+
assert result.pattern().equals("^the (?:new|old) thing$");
28+
assert result.matcher("the new thing").matches();
29+
assert result.matcher("the old thing").matches();
30+
}
31+
32+
@Test
33+
public void optionalAndChoice() {
34+
final Pattern pattern = new Pattern(new String[]{"[the] (new|old) thing"}, null);
35+
final java.util.regex.Pattern result = pattern.getCompiledPatterns()[0];
36+
assert result.pattern().equals("^(?:the )?(?:new|old) thing$");
37+
assert result.matcher("new thing").matches();
38+
assert result.matcher("old thing").matches();
39+
assert result.matcher("the new thing").matches();
40+
}
41+
42+
@Test
43+
public void optionalInChoice() {
44+
final Pattern pattern = new Pattern(new String[]{"([a ]new|old) thing"}, null);
45+
final java.util.regex.Pattern result = pattern.getCompiledPatterns()[0];
46+
assert result.pattern().equals("^(?:(?:a )?new|old) thing$");
47+
assert result.matcher("a new thing").matches();
48+
assert result.matcher("old thing").matches();
49+
assert result.matcher("new thing").matches();
50+
}
51+
52+
@Test
53+
public void choiceInOptional() {
54+
final Pattern pattern = new Pattern(new String[]{"[(new|old)] thing"}, null);
55+
final java.util.regex.Pattern result = pattern.getCompiledPatterns()[0];
56+
assert result.pattern().equals("^(?:(?:new|old) )?thing$");
57+
assert result.matcher("thing").matches();
58+
assert result.matcher("new thing").matches();
59+
assert result.matcher("old thing").matches();
60+
}
61+
62+
@Test
63+
public void strange() {
64+
final Pattern pattern = new Pattern(new String[]{"[the] [current] (process|thread)"}, null);
65+
final java.util.regex.Pattern result = pattern.getCompiledPatterns()[0];
66+
assert result.pattern().equals("^(?:the )?(?:current )?(?:process|thread)$");
67+
assert result.matcher("process").matches();
68+
assert result.matcher("thread").matches();
69+
assert result.matcher("the thread").matches();
70+
assert result.matcher("current thread").matches();
71+
assert result.matcher("the current thread").matches();
72+
}
73+
74+
@Test
75+
public void strangeNested() {
76+
final Pattern pattern = new Pattern(new String[]{"%Integer% (ms|millis|milli[ ]second[s])"}, null);
77+
final java.util.regex.Pattern result = pattern.getCompiledPatterns()[0];
78+
assert result.pattern().equals("^(.+) (?:ms|millis|milli(?: )?second(?:s)?)$");
79+
assert result.matcher("4 millis").matches();
80+
assert result.matcher("4 ms").matches();
81+
assert !result.matcher("5 mseconds").matches();
82+
assert result.matcher("5 milli seconds").matches();
83+
assert result.matcher("5 milliseconds").matches();
84+
}
85+
86+
87+
}

0 commit comments

Comments
 (0)