Add detailed parse errors
diff --git a/Parser.cpp b/Parser.cpp
index 145972f..9b8f264 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -2,6 +2,41 @@
#include <QDebug>
+ParseResult::ParseResult(bool okay)
+ : ParseResult((int)okay)
+{}
+
+ParseResult::ParseResult(int status, ParsePos pos)
+ : ParseResult(status, "", pos)
+{}
+
+ParseResult::ParseResult(int status, QString message, ParsePos pos)
+{
+ _status = status;
+ _message = message;
+ _pos = pos;
+}
+
+ParseResult::operator bool() const
+{
+ return _status == COMPLETE;
+}
+
+ParsePos ParseResult::pos() const
+{
+ return _pos;
+}
+
+QString ParseResult::message() const
+{
+ return _message;
+}
+
+int ParseResult::status() const
+{
+ return _status;
+}
+
Parser::Parser(QString input)
{
_input = input;
@@ -17,7 +52,19 @@
QChar Parser::get()
{
- return _input[_pos++];
+ QChar c = _input[_pos++];
+
+ if (c == '\n')
+ {
+ _line++;
+ _offset = 0;
+ }
+ else
+ {
+ _offset++;
+ }
+
+ return c;
}
bool Parser::atEnd()
@@ -31,8 +78,20 @@
get();
}
+ParsePos Parser::save() const
+{
+ return ParsePos{_line, _pos, _offset};
+}
+
+void Parser::reset(ParsePos pos)
+{
+ _line = pos.line;
+ _pos = pos.pos;
+ _offset = pos.lineOffset;
+}
+
template <typename T>
-bool Parser::parseSymbol(T *node)
+ParseResult Parser::parseSymbol(T *node)
{
skip();
@@ -46,7 +105,7 @@
}
template <typename T>
-bool Parser::parseIdentifier(T *node)
+ParseResult Parser::parseIdentifier(T *node)
{
skip();
@@ -67,7 +126,7 @@
}
template <typename T>
-bool Parser::parseNumber(T *node)
+ParseResult Parser::parseNumber(T *node)
{
skip();
@@ -86,11 +145,11 @@
}
template <typename T>
-bool Parser::parseVariable(T *node)
+ParseResult Parser::parseVariable(T *node)
{
skip();
- int pos = _pos;
+ ParsePos pos = save();
if (peek() == 's' || peek() == 'e' || peek() == 't')
{
@@ -112,47 +171,68 @@
*node = T(type, QString(nameNode.symbol()));
return true;
}
+ else
+ {
+ ParseResult ret(ParseResult::INCOMPLETE,
+ "Expected identifier or symbol after . in variable",
+ pos);
+
+ reset(pos);
+
+ return ret;
+ }
}
}
- _pos = pos;
+ reset(pos);
return false;
}
template <typename T>
-QList<T> Parser::parseMany()
+ParseResult Parser::parseMany(QList<T> *list)
{
- QList<T > nodes;
+ QList<T> nodes;
T next;
+ ParseResult ret;
- while (parseOne(&next))
+ while ((ret = parseOne(&next)))
{
+ // qDebug() << "parseMany one" << next;
nodes.append(next);
}
- return nodes;
+ *list = nodes;
+
+ if (ret.status() == ParseResult::INCOMPLETE)
+ return ret;
+ else
+ return true;
}
template <typename T>
-bool Parser::parseParens(T *node)
+ParseResult Parser::parseParens(T *node)
{
skip();
- int pos = _pos;
+ ParsePos pos = save();
if (peek() != '(')
return false;
get();
- QList<T> many = parseMany<T>();
+ QList<T> many;
+ ParseResult ret = parseMany(&many);
+
*node = T(many);
skip();
if (peek() != ')')
{
- _pos = pos;
- return false;
+ ret = ParseResult(ParseResult::INCOMPLETE, "Expected ) in parenthesized list", save());
+ reset(pos);
+
+ return ret;
}
get();
@@ -160,11 +240,12 @@
return true;
}
-bool Parser::parseFunction(AstNode *node)
+ParseResult Parser::parseFunction(AstNode *node)
{
skip();
- int pos = _pos;
+ ParsePos pos = save();
+ ParseResult ret;
if (peek() != '<')
return false;
@@ -172,20 +253,29 @@
get();
AstNode head;
- if (!parseIdentifier(&head))
+ if (!(ret = parseIdentifier(&head)))
{
- _pos = pos;
- return false;
+ reset(pos);
+ return ret;
}
- QList<AstNode> body = parseMany<AstNode>();
+ QList<AstNode> body;
+ ret = parseMany(&body);
+
+ if (!ret)
+ {
+ reset(pos);
+ return ret;
+ }
+
*node = AstNode(head.name(), body);
skip();
if (peek() != '>')
{
- _pos = pos;
- return false;
+ ret = ParseResult(ParseResult::INCOMPLETE, "Expected >", save());
+ reset(pos);
+ return ret;
}
get();
@@ -194,7 +284,7 @@
}
template <>
-bool Parser::parseOne<Token>(Token *node)
+ParseResult Parser::parseOne<Token>(Token *node)
{
return parseVariable(node) ||
parseNumber(node) ||
@@ -204,7 +294,7 @@
}
template <>
-bool Parser::parseOne<AstNode>(AstNode *node)
+ParseResult Parser::parseOne<AstNode>(AstNode *node)
{
return parseFunction(node) ||
parseVariable(node) ||
@@ -214,43 +304,74 @@
parseParens(node);
}
-bool Parser::parseSentence(Sentence *sentence)
+ParseResult Parser::parseSentence(Sentence *sentence)
{
- int pos = _pos;
+ ParsePos pos = save();
- QList<Token> pattern = parseMany<Token>();
+ qDebug() << "Parsing sentence" << peek();
+
+ if (peek() == '}')
+ {
+ return false;
+ }
+
+ QList<Token> pattern;
+ ParseResult ret = parseMany(&pattern);
+
+ if (!ret)
+ {
+ qDebug() << "Many failed" << ret.message();
+ reset(pos);
+ return ret;
+ }
skip();
+ qDebug() << "will we get an =?" << peek();
+
if (get() != '=')
{
- _pos = pos;
- return false;
+ ret = ParseResult(ParseResult::INCOMPLETE, "Expected = in sentence", save());
+ reset(pos);
+ return ret;
}
- QList<AstNode> result = parseMany<AstNode>();
+ QList<AstNode> result;
+ ret = parseMany(&result);
+
+ if (!ret)
+ {
+ qDebug() << "sentence parseMany returned" << ret.message();
+ reset(pos);
+ return ret;
+ }
skip();
- if (get() != ';')
+ qDebug() << "end of sentence" << peek();
+
+ if (peek() != '}' && get() != ';')
{
- _pos = pos;
- return false;
+ ret = ParseResult(ParseResult::INCOMPLETE, "Expected ; or } after sentence", save());
+ reset(pos);
+ return ret;
}
*sentence = Sentence(pattern, result);
+
return true;
}
-bool Parser::parseFunctionDefinition(Function *function)
+ParseResult Parser::parseFunctionDefinition(Function *function)
{
- int pos = _pos;
+ ParsePos pos = save();
+ ParseResult ret;
Token identifier;
- if (!parseIdentifier(&identifier))
+ if (!(ret = parseIdentifier(&identifier)))
{
- _pos = pos;
- return false;
+ reset(pos);
+ return ret;
}
QString name = identifier.name();
@@ -260,23 +381,33 @@
if (get() != '{')
{
- _pos = pos;
- return false;
+ reset(pos);
+ return false;
}
Sentence sentence;
- while (parseSentence(&sentence))
+ while ((ret = parseSentence(&sentence)))
{
func.addSentence(sentence);
skip();
}
+ if (ret.status() == ParseResult::INCOMPLETE)
+ {
+ qDebug() << "Function incomplete";
+ reset(pos);
+ return ret;
+ }
+
if (get() != '}')
{
- _pos = pos;
- return false;
+ ret = ParseResult(ParseResult::INCOMPLETE, "Expected } at end of function");
+ reset(pos);
+ return ret;
}
+ qDebug() << "Function parsing succeeded";
+
*function = func;
return true;
}