Skip to content

Commit 338cd05

Browse files
committed
Better error handling, messages and hints.
1 parent 9e19573 commit 338cd05

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+341
-98
lines changed

pom.xml

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

77
<groupId>org.byteskript</groupId>
88
<artifactId>byteskript</artifactId>
9-
<version>1.0.2</version>
9+
<version>1.0.3</version>
1010
<name>ByteSkript</name>
1111

1212
<properties>

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,13 @@ public abstract class Context {
2020
protected final List<Library> libraries = new ArrayList<>();
2121
protected final List<Unit> units = new ArrayList<>();
2222
protected final List<SectionMeta> sections = new ArrayList<>();
23+
protected ErrorDetails error;
2324
protected State state;
2425

26+
public ErrorDetails getError() {
27+
return error;
28+
}
29+
2530
public String getStoredVariableName() {
2631
return storedVariableName;
2732
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ public Match match(final String thing, final Context context, final Object meta)
147147
int found = 0;
148148
for (java.util.regex.Pattern pattern : patternMap.keySet()) {
149149
final Matcher matcher = pattern.matcher(thing);
150-
if (matcher.find()) return new Match(matcher, found, meta != null ? meta : found, convert(context, patternMap.get(pattern)));
150+
if (matcher.find())
151+
return new Match(matcher, found, meta != null ? meta : found, convert(context, patternMap.get(pattern)));
151152
found++;
152153
}
153154
return null;

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

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.byteskript.skript.api.SyntaxElement;
1414
import org.byteskript.skript.api.syntax.InnerModifyExpression;
1515
import org.byteskript.skript.api.syntax.Section;
16+
import org.byteskript.skript.compiler.structure.ErrorDetails;
1617
import org.byteskript.skript.compiler.structure.ProgrammaticSplitTree;
1718
import org.byteskript.skript.compiler.structure.SectionMeta;
1819
import org.byteskript.skript.error.ScriptCompileError;
@@ -26,7 +27,6 @@
2627
import java.util.regex.Matcher;
2728

2829
public class SimpleSkriptCompiler extends SkriptCompiler implements SkriptParser {
29-
3030
final List<Library> libraries = new ArrayList<>();
3131

3232
public SimpleSkriptCompiler(Library... libraries) {
@@ -102,10 +102,10 @@ public PostCompileClass[] compile(String file, Type path) {
102102
}
103103
try {
104104
this.compileLine(line, context);
105-
} catch (ScriptCompileError ex) {
105+
} catch (ScriptParseError | ScriptCompileError ex) {
106106
throw ex;
107107
} catch (Throwable ex) {
108-
throw new ScriptCompileError(context.lineNumber, "Error during compilation:", ex);
108+
throw new ScriptCompileError(context.lineNumber, "Unknown error during compilation:", ex);
109109
}
110110
}
111111
for (int i = 0; i < context.units.size(); i++) {
@@ -178,11 +178,16 @@ protected void compileLine(final String line, final FileContext context) {
178178

179179
protected ElementTree parseStatement(final String statement, final FileContext context, boolean storeSection) {
180180
final ElementTree effect;
181+
final ErrorDetails details = new ErrorDetails();
182+
context.error = details;
183+
details.file = context.getType().internalName() + ".bsk";
181184
try {
182-
effect = assembleStatement(statement, context);
185+
effect = assembleStatement(statement, context, details);
183186
context.line = effect;
184-
} catch (ScriptParseError error) {
185-
throw new ScriptParseError(context.lineNumber(), "Error while parsing statement '" + statement + "'", error);
187+
} catch (Throwable ex) {
188+
if (ex instanceof ScriptParseError)
189+
throw new ScriptParseError(context.lineNumber, details, "Error while parsing statement '" + statement + "'", ex);
190+
throw new ScriptCompileError(context.lineNumber, "An unknown error occurred while compiling:\n" + statement, ex);
186191
}
187192
if (effect == null)
188193
throw new ScriptParseError(context.lineNumber(), "No syntax match found for line '" + statement + "'");
@@ -240,8 +245,9 @@ public ElementTree parseLine(final String line, final FileContext context) {
240245
} else return this.parseStatement(statement, context, false);
241246
}
242247

243-
public ElementTree assembleStatement(final String statement, final FileContext context) {
248+
public ElementTree assembleStatement(final String statement, final FileContext context, final ErrorDetails details) {
244249
final List<ElementTree> elements = new ArrayList<>();
250+
details.line = statement;
245251
ElementTree current = null;
246252
outer:
247253
for (SyntaxElement handler : context.getHandlers()) {
@@ -253,11 +259,12 @@ public ElementTree assembleStatement(final String statement, final FileContext c
253259
if (inputs.length < types.length) continue;
254260
context.setState(handler.getSubState()); // move state change to syntax
255261
context.currentEffect = handler;
262+
details.lineMatched = handler;
256263
inner:
257264
for (int i = 0; i < types.length; i++) {
258265
final String input = inputs[i];
259266
final Type type = types[i];
260-
final ElementTree sub = assembleExpression(input.trim(), type, context);
267+
final ElementTree sub = assembleExpression(input.trim(), type, context, details);
261268
if (sub == null) {
262269
context.currentEffect = null;
263270
continue outer;
@@ -272,9 +279,10 @@ public ElementTree assembleStatement(final String statement, final FileContext c
272279
return current;
273280
}
274281

275-
public ElementTree assembleExpression(String expression, final Type expected, final FileContext context) {
282+
public ElementTree assembleExpression(String expression, final Type expected, final FileContext context, final ErrorDetails details) {
276283
final List<ElementTree> elements = new ArrayList<>();
277284
ElementTree current = null;
285+
details.expression = expression;
278286
outer:
279287
for (SyntaxElement handler : context.getHandlers()) {
280288
if (!handler.allowAsInputFor(expected)) continue;
@@ -284,11 +292,12 @@ public ElementTree assembleExpression(String expression, final Type expected, fi
284292
final Type[] types = match.expected();
285293
final String[] inputs = match.groups();
286294
if (inputs.length < types.length) continue;
295+
details.expressionMatched = handler;
287296
inner:
288297
for (int i = 0; i < types.length; i++) {
289298
final String input = inputs[i];
290299
final Type type = types[i];
291-
final ElementTree sub = assembleExpression(input.trim(), type, context);
300+
final ElementTree sub = assembleExpression(input.trim(), type, context, details);
292301
if (sub == null) continue outer;
293302
elements.add(sub);
294303
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
package org.byteskript.skript.compiler;
88

99
import mx.kenzie.foundation.Type;
10+
import org.byteskript.skript.compiler.structure.ErrorDetails;
1011

1112
public interface SkriptParser {
1213

1314
ElementTree parseLine(final String line, final FileContext context);
1415

15-
ElementTree assembleStatement(final String statement, final FileContext context);
16+
ElementTree assembleStatement(final String statement, final FileContext context, final ErrorDetails details);
1617

17-
ElementTree assembleExpression(String expression, final Type expected, final FileContext context);
18+
ElementTree assembleExpression(String expression, final Type expected, final FileContext context, final ErrorDetails details);
1819

1920
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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.compiler.structure;
8+
9+
import org.byteskript.skript.api.SyntaxElement;
10+
11+
import java.util.HashMap;
12+
import java.util.Map;
13+
14+
public class ErrorDetails {
15+
16+
public String file;
17+
public String line;
18+
public SyntaxElement lineMatched;
19+
public String expression;
20+
public SyntaxElement expressionMatched;
21+
22+
public final Map<SyntaxElement, String> hints = new HashMap<>();
23+
24+
public void addHint(SyntaxElement source, String hint) {
25+
hints.put(source, hint);
26+
}
27+
28+
}

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

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

77
package org.byteskript.skript.error;
88

9-
public class ScriptAssertionError extends AssertionError {
9+
public class ScriptAssertionError extends AssertionError implements ScriptError {
1010
private final int line;
1111
private final Class<?> script;
1212

@@ -55,9 +55,9 @@ public String toString() {
5555
}
5656
}
5757
}
58-
59-
@Override
60-
public synchronized Throwable fillInStackTrace() {
61-
return this;
62-
}
58+
59+
// @Override
60+
// public synchronized Throwable fillInStackTrace() {
61+
// return this;
62+
// }
6363
}

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

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

77
package org.byteskript.skript.error;
88

9-
public class ScriptBootstrapError extends Error {
9+
public class ScriptBootstrapError extends Error implements ScriptError {
1010

1111
public ScriptBootstrapError() {
1212
super();

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

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

77
package org.byteskript.skript.error;
88

9-
public class ScriptCompileError extends Error {
9+
public class ScriptCompileError extends Error implements ScriptError {
1010

1111
private final boolean fill = true;
1212
private final int line;
@@ -45,7 +45,7 @@ public String toString() {
4545

4646
@Override
4747
public synchronized Throwable fillInStackTrace() {
48-
if (fill)
48+
if (fill && System.getProperty("debug_mode") != null)
4949
return super.fillInStackTrace();
5050
return this;
5151
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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.error;
8+
9+
import java.io.PrintStream;
10+
import java.io.PrintWriter;
11+
12+
public interface ScriptError {
13+
14+
String BLACK_BACKGROUND = "\033[40m";
15+
String ANSI_RESET = "\u001B[0m";
16+
String ANSI_YELLOW = "\u001B[33m";
17+
String ANSI_RED = "\u001B[31m";
18+
String ANSI_PURPLE = "\u001B[35m";
19+
String ANSI_CYAN = "\u001B[36m";
20+
String ANSI_WHITE = "\u001B[37m";
21+
22+
23+
record OutputWriter(PrintStream stream, PrintWriter writer) implements Output {
24+
25+
@Override
26+
public void println(String string) {
27+
if (stream != null) stream.println(string);
28+
else writer.println(string);
29+
}
30+
31+
}
32+
33+
interface Output {
34+
void println(String string);
35+
}
36+
37+
}

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

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

77
package org.byteskript.skript.error;
88

9-
public class ScriptLibraryError extends Error {
9+
public class ScriptLibraryError extends Error implements ScriptError {
1010

1111
public ScriptLibraryError() {
1212
super();

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

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

77
package org.byteskript.skript.error;
88

9-
public class ScriptLoadError extends Error {
9+
public class ScriptLoadError extends Error implements ScriptError {
1010

1111
public ScriptLoadError() {
1212
super();

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

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,17 @@
66

77
package org.byteskript.skript.error;
88

9-
public class ScriptParseError extends Error {
9+
import org.byteskript.skript.api.SyntaxElement;
10+
import org.byteskript.skript.compiler.structure.ErrorDetails;
11+
12+
import java.io.PrintStream;
13+
import java.io.PrintWriter;
14+
import java.util.Map;
15+
16+
public class ScriptParseError extends Error implements ScriptError {
1017

1118
private final int line;
19+
private ErrorDetails details;
1220

1321
public ScriptParseError(int line) {
1422
super();
@@ -25,6 +33,12 @@ public ScriptParseError(int line, String message, Throwable cause) {
2533
this.line = line;
2634
}
2735

36+
public ScriptParseError(int line, ErrorDetails details, String message, Throwable cause) {
37+
super(message, cause);
38+
this.line = line;
39+
this.details = details;
40+
}
41+
2842
public ScriptParseError(int line, Throwable cause) {
2943
super(cause);
3044
this.line = line;
@@ -34,11 +48,44 @@ protected ScriptParseError(int line, String message, Throwable cause, boolean en
3448
super(message, cause, enableSuppression, writableStackTrace);
3549
this.line = line;
3650
}
37-
38-
// @Override
39-
// public Throwable fillInStackTrace() {
40-
// // no need for stack trace
41-
// return this;
42-
// }
43-
51+
52+
@Override
53+
public synchronized Throwable fillInStackTrace() {
54+
if (System.getProperty("debug_mode") != null)
55+
return super.fillInStackTrace();
56+
return this;
57+
}
58+
59+
@Override
60+
public void printStackTrace(PrintWriter stream) {
61+
if (details == null) super.printStackTrace(stream);
62+
printStackTrace(new OutputWriter(null, stream));
63+
}
64+
65+
@Override
66+
public void printStackTrace(PrintStream stream) {
67+
if (details == null) super.printStackTrace(stream);
68+
printStackTrace(new OutputWriter(stream, null));
69+
}
70+
71+
public void printStackTrace(OutputWriter stream) {
72+
stream.println(ANSI_RESET + "A parsing error has occurred in:");
73+
stream.println("\tline " + ANSI_CYAN + line + ANSI_RESET + " of '" + BLACK_BACKGROUND + ANSI_YELLOW + details.file + ANSI_RESET + "'");
74+
if (details.expression != null) {
75+
stream.println(ANSI_RESET + "No match was found for expression:\n\t'" + BLACK_BACKGROUND + ANSI_YELLOW + details.expression + ANSI_RESET + "'");
76+
stream.println(ANSI_RESET + "In the line/effect:\n\t'" + BLACK_BACKGROUND + ANSI_YELLOW + details.line + ANSI_RESET + "'");
77+
stream.println(ANSI_RESET + "This effect was matched to:\n\t'" + BLACK_BACKGROUND + ANSI_YELLOW + details.lineMatched.name() + ANSI_RESET + "'");
78+
} else if (details.line != null) {
79+
stream.println(ANSI_RESET + "No match was found for line:\n\t'" + BLACK_BACKGROUND + ANSI_YELLOW + details.line + ANSI_RESET + "'");
80+
}
81+
if (details.hints.isEmpty()) return;
82+
stream.println(ANSI_RESET + "Below are some hints from partial matches.");
83+
for (Map.Entry<SyntaxElement, String> entry : details.hints.entrySet()) {
84+
final SyntaxElement element = entry.getKey();
85+
final String hint = entry.getValue();
86+
stream.println(ANSI_RESET + "If you were trying to use '" + BLACK_BACKGROUND + ANSI_CYAN + element.name() + ANSI_RESET + "':");
87+
stream.println(ANSI_RESET + "\t" + hint);
88+
}
89+
}
90+
4491
}

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

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

77
package org.byteskript.skript.error;
88

9-
public class ScriptRuntimeError extends Error {
9+
public class ScriptRuntimeError extends Error implements ScriptError {
1010

1111
public ScriptRuntimeError() {
1212
super();

src/main/java/org/byteskript/skript/lang/syntax/entry/ReturnType.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import mx.kenzie.foundation.compiler.State;
1111
import org.byteskript.skript.api.syntax.SimpleEntry;
1212
import org.byteskript.skript.compiler.*;
13-
import org.byteskript.skript.error.ScriptCompileError;
1413
import org.byteskript.skript.lang.element.StandardElements;
1514

1615
public class ReturnType extends SimpleEntry {
@@ -39,8 +38,10 @@ public Pattern.Match match(String thing, Context context) {
3938
final Pattern.Match match = super.match(thing, context);
4039
if (match == null) return null;
4140
final String name = match.groups()[0].trim();
42-
if (name.contains("\""))
43-
throw new ScriptCompileError(context.lineNumber(), "Types should not be written inside quotation marks.");
41+
if (name.contains("\"")) {
42+
context.getError().addHint(this, "Types should not be written inside quotation marks.");
43+
return null;
44+
}
4445
return new Pattern.Match(Pattern.fakeMatcher(thing), name);
4546
}
4647

0 commit comments

Comments
 (0)