Add function parser
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8274f8f..ac5dbfb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,7 @@
Core
REQUIRED)
-add_executable(REFAL main.cpp Token.cpp Token.h Matcher.cpp Matcher.h VarContext.cpp VarContext.h Parser.cpp Parser.h AstNode.cpp AstNode.h Evaluator.cpp Evaluator.h)
+add_executable(REFAL main.cpp Token.cpp Token.h Matcher.cpp Matcher.h VarContext.cpp VarContext.h Parser.cpp Parser.h AstNode.cpp AstNode.h Evaluator.cpp Evaluator.h Function.cpp Function.h)
target_link_libraries(REFAL
Qt::Core
)
diff --git a/Function.cpp b/Function.cpp
new file mode 100644
index 0000000..6974fa6
--- /dev/null
+++ b/Function.cpp
@@ -0,0 +1,84 @@
+#include "Function.h"
+
+template <typename T>
+QString join(QList<T> list, QString sep)
+{
+ QStringList strings;
+
+ for (const T &item : list)
+ {
+ strings.append(static_cast<QString>(item));
+ }
+
+ return strings.join(sep);
+}
+
+Sentence::Sentence(QList<Token> pattern, QList<AstNode> result)
+{
+ _pattern = pattern;
+ _result = result;
+}
+
+QList<Token> Sentence::pattern() const
+{
+ return _pattern;
+}
+
+QList<AstNode> Sentence::result() const
+{
+ return _result;
+}
+
+Sentence::operator QString() const
+{
+ return join(_pattern, " ") + " = " + join(_result, " ") + ";";
+}
+
+Function::Function(QString name)
+ : Function(name, {})
+{
+}
+
+Function::Function(QString name, QList<Sentence> sentences)
+{
+ _name = name;
+ _sentences = sentences;
+}
+
+void Function::addSentence(Sentence sentence)
+{
+ _sentences.append(sentence);
+}
+
+
+QString Function::name() const
+{
+ return _name;
+}
+
+QList<Sentence> Function::sentences() const
+{
+ return _sentences;
+}
+
+Function::operator QString() const
+{
+ QString buffer = name() + " { ";
+ int leftPadding = buffer.length();
+
+ QString spaces;
+ for (int i = 0; i < leftPadding; i++)
+ spaces += " ";
+
+ for (int i = 0; i < _sentences.length(); i++)
+ {
+ if (i)
+ buffer += "\n" + spaces;
+
+ buffer += static_cast<QString>(_sentences[i]);
+ }
+
+ buffer += " }";
+
+ return buffer;
+}
diff --git a/Function.h b/Function.h
new file mode 100644
index 0000000..cb3ba1c
--- /dev/null
+++ b/Function.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "Token.h"
+#include "AstNode.h"
+
+class Sentence {
+public:
+ Sentence() = default;
+ Sentence(QList<Token> pattern, QList<AstNode> result);
+
+ QList<Token> pattern() const;
+ QList<AstNode> result() const;
+
+ operator QString() const;
+
+protected:
+ QList<Token> _pattern;
+ QList<AstNode> _result;
+};
+
+class Function {
+public:
+ Function() = default;
+ explicit Function(QString name);
+ Function(QString name, QList<Sentence> sentences);
+
+ void addSentence(Sentence sentence);
+
+ QString name() const;
+ QList<Sentence> sentences() const;
+
+ operator QString() const;
+
+private:
+ QString _name;
+ QList<Sentence> _sentences;
+};
diff --git a/Parser.cpp b/Parser.cpp
index 9233fbd..fd07c79 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -213,3 +213,70 @@
parseSymbol(node) ||
parseParens(node);
}
+
+bool Parser::parseSentence(Sentence *sentence)
+{
+ int pos = _pos;
+
+ QList<Token> pattern = parseMany<Token>();
+
+ skip();
+
+ if (get() != '=')
+ {
+ _pos = pos;
+ return false;
+ }
+
+ QList<AstNode> result = parseMany<AstNode>();
+
+ skip();
+
+ if (get() != ';')
+ {
+ _pos = pos;
+ return false;
+ }
+
+ *sentence = Sentence(pattern, result);
+ return true;
+}
+
+bool Parser::parseFunctionDefinition(Function *function)
+{
+ int pos = _pos;
+
+ Token identifier;
+ if (!parseIdentifier(&identifier))
+ {
+ _pos = pos;
+ return false;
+ }
+
+ QString name = identifier.name();
+ Function func(name);
+
+ skip();
+
+ if (get() != '{')
+ {
+ _pos = pos;
+ return false;
+ }
+
+ Sentence sentence;
+ while (parseSentence(&sentence))
+ {
+ func.addSentence(sentence);
+ skip();
+ }
+
+ if (get() != '}')
+ {
+ _pos = pos;
+ return false;
+ }
+
+ *function = func;
+ return true;
+}
diff --git a/Parser.h b/Parser.h
index fb56701..1426989 100644
--- a/Parser.h
+++ b/Parser.h
@@ -4,6 +4,7 @@
#include "Token.h"
#include "AstNode.h"
+#include "Function.h"
class Parser
{
@@ -39,6 +40,9 @@
template <typename T>
bool parseOne(T *node);
+ bool parseSentence(Sentence *sentence);
+ bool parseFunctionDefinition(Function *function);
+
private:
int _pos = 0;
QString _input;
diff --git a/main.cpp b/main.cpp
index 8ef1fb4..25c4504 100644
--- a/main.cpp
+++ b/main.cpp
@@ -42,6 +42,25 @@
qDebug() << "\033[36mParse\033[0m" << string << result;
}
+void testParseFunc(QString string)
+{
+ Parser parser{string};
+
+ Function func;
+
+ if (!parser.parseFunctionDefinition(&func))
+ {
+ g_numFailed++;
+ qDebug() << "\n\033[31mTEST FAILS:\033[0m";
+ qDebug() << string;
+ }
+ else
+ {
+ qDebug() << "\033[36mFunction\033[0m";
+ qDebug().noquote() << func;
+ }
+}
+
int testResults()
{
if (g_numFailed == 0)
@@ -109,6 +128,14 @@
testParseAst("(<Prout hi>)");
testParseAst("<If T Then (<Prout hi>) Else (<Prout sorry>)>");
testParseAst("(s.a) e.Middle s.a");
+ testParseAst("Hello; Goodbye");
+ testParseAst("Key = Value");
+}
+
+void testAllFunctionDefs()
+{
+ testParseFunc("Test { = HI; }");
+ testParseFunc("Palindrome { = T; s.A = T; s.A s.A = T; s.A e.Middle s.A = <Palindrome e.Middle>; } ");
}
int main(int argc, char *argv[])
@@ -118,6 +145,8 @@
testAllMatches();
qDebug() << "";
testAllParses();
+ qDebug() << "";
+ testAllFunctionDefs();
qDebug() << "";
return testResults();