Улучшена обработка ошибок, восстановление

This commit is contained in:
Victor 2016-02-14 21:03:28 +02:00
parent 5269d02a66
commit b2f7cc52ed
4 changed files with 105 additions and 2 deletions

View File

@ -70,10 +70,15 @@ public final class Main {
}
}
final Statement program = new Parser(tokens).parse();
final Parser parser = new Parser(tokens);
final Statement program = parser.parse();
if (showAst) {
System.out.println(program.toString());
}
if (parser.getParseErrors().hasErrors()) {
System.out.println(parser.getParseErrors());
return;
}
program.accept(new FunctionAdder());
// program.accept(new VariablePrinter());
program.accept(new AssignValidator());

View File

@ -0,0 +1,25 @@
package com.annimon.ownlang.parser;
public final class ParseError {
private final int line;
private final Exception exception;
public ParseError(int line, Exception exception) {
this.line = line;
this.exception = exception;
}
public int getLine() {
return line;
}
public Exception getException() {
return exception;
}
@Override
public String toString() {
return "ParseError on line " + line + ": " + exception.getMessage();
}
}

View File

@ -0,0 +1,40 @@
package com.annimon.ownlang.parser;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public final class ParseErrors implements Iterable<ParseError> {
private final List<ParseError> errors;
public ParseErrors() {
errors = new ArrayList<>();
}
public void clear() {
errors.clear();
}
public void add(Exception ex, int line) {
errors.add(new ParseError(line, ex));
}
public boolean hasErrors() {
return !errors.isEmpty();
}
@Override
public Iterator<ParseError> iterator() {
return errors.iterator();
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
for (ParseError error : errors) {
result.append(error).append(System.lineSeparator());
}
return result.toString();
}
}

View File

@ -38,22 +38,55 @@ public final class Parser {
private final List<Token> tokens;
private final int size;
private final ParseErrors parseErrors;
private int pos;
public Parser(List<Token> tokens) {
this.tokens = tokens;
size = tokens.size();
parseErrors = new ParseErrors();
}
public ParseErrors getParseErrors() {
return parseErrors;
}
public Statement parse() {
parseErrors.clear();
final BlockStatement result = new BlockStatement();
while (!match(TokenType.EOF)) {
result.add(statement());
try {
result.add(statement());
} catch (Exception ex) {
parseErrors.add(ex, getErrorLine());
recover();
}
}
return result;
}
private int getErrorLine() {
if (size == 0) return 0;
if (pos >= size) return tokens.get(size - 1).getRow();
return tokens.get(pos).getRow();
}
private void recover() {
int preRecoverPosition = pos;
for (int i = preRecoverPosition; i < size; i++) {
pos = i;
try {
statement();
// successfully parsed,
pos = i; // restore position
return;
} catch (Exception ex) {
// fail
}
}
}
private Statement block() {
final BlockStatement block = new BlockStatement();
consume(TokenType.LBRACE);