From b2f7cc52ed996fe8150f5d1b7c246ccc08e61524 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 14 Feb 2016 21:03:28 +0200 Subject: [PATCH] =?UTF-8?q?=D0=A3=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B0?= =?UTF-8?q?=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BE=D0=BA,=20=D0=B2=D0=BE=D1=81?= =?UTF-8?q?=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/annimon/ownlang/Main.java | 7 +++- .../annimon/ownlang/parser/ParseError.java | 25 ++++++++++++ .../annimon/ownlang/parser/ParseErrors.java | 40 +++++++++++++++++++ src/com/annimon/ownlang/parser/Parser.java | 35 +++++++++++++++- 4 files changed, 105 insertions(+), 2 deletions(-) create mode 100644 src/com/annimon/ownlang/parser/ParseError.java create mode 100644 src/com/annimon/ownlang/parser/ParseErrors.java diff --git a/src/com/annimon/ownlang/Main.java b/src/com/annimon/ownlang/Main.java index 913687e..390341d 100644 --- a/src/com/annimon/ownlang/Main.java +++ b/src/com/annimon/ownlang/Main.java @@ -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()); diff --git a/src/com/annimon/ownlang/parser/ParseError.java b/src/com/annimon/ownlang/parser/ParseError.java new file mode 100644 index 0000000..7506552 --- /dev/null +++ b/src/com/annimon/ownlang/parser/ParseError.java @@ -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(); + } +} diff --git a/src/com/annimon/ownlang/parser/ParseErrors.java b/src/com/annimon/ownlang/parser/ParseErrors.java new file mode 100644 index 0000000..345bb2d --- /dev/null +++ b/src/com/annimon/ownlang/parser/ParseErrors.java @@ -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 { + + private final List 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 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(); + } +} diff --git a/src/com/annimon/ownlang/parser/Parser.java b/src/com/annimon/ownlang/parser/Parser.java index ae8cdbe..47d2245 100644 --- a/src/com/annimon/ownlang/parser/Parser.java +++ b/src/com/annimon/ownlang/parser/Parser.java @@ -38,22 +38,55 @@ public final class Parser { private final List tokens; private final int size; + private final ParseErrors parseErrors; private int pos; public Parser(List 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);