Add REPL
diff --git a/.gitignore b/.gitignore
index e37d10e..2892543 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 *.user
 build
 .cache
+compile_commands.json
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ac5dbfb..b0be929 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,19 +1,17 @@
-cmake_minimum_required(VERSION 3.20)
+cmake_minimum_required(VERSION 3.15)
 project(REFAL)
 
 set(CMAKE_CXX_STANDARD 14)
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_AUTORCC ON)
 set(CMAKE_AUTOUIC ON)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
 
+find_package(Qt5 COMPONENTS Core REQUIRED)
 
-find_package(Qt5 COMPONENTS
-        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 Function.cpp Function.h Repl.cpp
+  Repl.h PPrint.cpp PPrint.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
-        )
-
-add_compile_options("-fsanitize=address")
+target_link_libraries(REFAL Qt::Core readline)
diff --git a/Evaluator.cpp b/Evaluator.cpp
index e4e5d6f..fd46805 100644
--- a/Evaluator.cpp
+++ b/Evaluator.cpp
@@ -13,6 +13,7 @@
 RuntimeResult::RuntimeResult(QString message)
 {
 	_errorMessage = message;
+	_success = false;
 }
 
 bool RuntimeResult::success() const
diff --git a/Matcher.cpp b/Matcher.cpp
index 460253a..1b65158 100644
--- a/Matcher.cpp
+++ b/Matcher.cpp
@@ -104,20 +104,23 @@
                 return match(data, pattern, context);
 
             case 'e':
-                // Now this is tricky
-                // TODO: Optimize this to check if there is an obvious length that this expression has to be
-                for (int matchSyms = 1; matchSyms <= data.length(); matchSyms++)
+                // Now this is tricky TODO: Optimize this to check if
+                // there is an obvious length that this expression has
+                // to be
+                for (int matchSyms = 0; matchSyms <= data.length(); matchSyms++)
                 {
                     QList<Token> slice = listSlice(data, 0, matchSyms);
                     VarContext newContext = context;
                     newContext.add(ph.varType(), ph.name(), slice);
 
-                    MatchResult tryMatch = match(listSlice(data, matchSyms, data.length()), pattern, newContext);
+                    MatchResult tryMatch = match(
+						listSlice(data, matchSyms, data.length()),
+						pattern, newContext);
+
                     if (tryMatch.success)
                     {
                         return tryMatch;
                     }
-                    // else matchSyms ++
                 }
                 // If this worked we would have returned already
                 return MatchResult{false, context};
@@ -129,7 +132,7 @@
         }
     }
 
-    qDebug() << "FALLING THROUGH, THIS SHOULD NOT HAPPEN";
+    qFatal("FALLING THROUGH, THIS SHOULD NOT HAPPEN");
     // Fallthrough
     return MatchResult{false, context};
 }
diff --git a/PPrint.cpp b/PPrint.cpp
new file mode 100644
index 0000000..a072a1b
--- /dev/null
+++ b/PPrint.cpp
@@ -0,0 +1 @@
+#include "PPrint.h"
diff --git a/PPrint.h b/PPrint.h
new file mode 100644
index 0000000..3a00379
--- /dev/null
+++ b/PPrint.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <QString>
+#include <QList>
+
+#include "Token.h"
+#include "AstNode.h"
+
+template <typename T>
+QString pprint(T val);
+
+template <>
+QString pprint<Token>(Token val);
+
+template <>
+QString pprint<AstNode>(AstNode val);
+
+template <typename T>
+QString pprint(QList<T> val)
+{
+	QStringList out;
+
+	for (const T &v : val)
+		out.append(static_cast<QString>(v));
+
+	return out.join(" ");
+}
+
+template <typename T>
+QString pprint(T val)
+{
+	return static_cast<QString>(val);
+}
diff --git a/Repl.cpp b/Repl.cpp
new file mode 100644
index 0000000..415602f
--- /dev/null
+++ b/Repl.cpp
@@ -0,0 +1,129 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <QDebug>
+
+#include "Repl.h"
+#include "Parser.h"
+#include "PPrint.h"
+
+// JANK! librl isn't namespaced!
+namespace ReadLine
+{
+#include <readline/readline.h>
+#include <readline/history.h>
+}
+
+
+Repl::Repl()
+{
+}
+
+char *Repl::prompt()
+{
+	static char p[] = "\033[36mREFAL >\033[0m ";
+	return p;
+}
+
+QString Repl::readLine()
+{
+	char *line = ReadLine::readline(prompt());
+
+	if (!line)
+	{
+		_running = false;
+		return "";
+	}
+
+	ReadLine::add_history(line);
+
+	QString string = QString::fromUtf8(line);
+
+	free(line);
+
+	return string;
+}
+
+void Repl::start()
+{
+	while (_running)
+	{
+		QString line = readLine();
+
+		line = line.trimmed();
+
+		QList<AstNode> expr;
+
+		if (trySpecialCase(line))
+		{}
+		else if (tryEvaluate(line, &expr))
+		{
+			bool okay = true;
+			QList<Token> out;
+
+			for (const AstNode &node : expr)
+			{
+				RuntimeResult res = _eval.evaluate(node, VarContext());
+
+				if (res.success())
+				{
+					out.append(res.result());
+				}
+				else
+				{
+					qDebug() << "Failed to evaluate" << node;
+					qDebug() << res.message();
+					okay = false;
+					break;
+				}
+			}
+
+			if (okay)
+			{
+				qDebug() << pprint(out);
+			}
+		}
+		else
+		{
+			qDebug() << "What?";
+		}
+	}
+}
+
+bool Repl::trySpecialCase(QString line)
+{
+	if (line.startsWith("."))
+	{
+		if (line == ".q" || line == ".quit")
+		{
+			_running = false;
+		}
+		else
+		{
+			qDebug().noquote() << "Unknown special command, try .help";
+		}
+
+		return true;
+	}
+
+	return false;
+}
+
+bool Repl::tryEvaluate(QString line, QList<AstNode> *expr)
+{
+	Parser parser(line);
+	Function func;
+
+	if (parser.parseFunctionDefinition(&func))
+	{
+		_eval.addFunction(func);
+		*expr = {};
+
+		return true;
+	}
+
+	*expr = parser.parseMany<AstNode>();
+	parser.skip();
+
+	return parser.atEnd();
+}
diff --git a/Repl.h b/Repl.h
new file mode 100644
index 0000000..a4939d3
--- /dev/null
+++ b/Repl.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include <QString>
+#include <QList>
+
+#include "Evaluator.h"
+#include "AstNode.h"
+
+class Repl
+{
+public:
+	Repl();
+
+	void start();
+	char *prompt();
+
+protected:
+	QString readLine();
+	bool trySpecialCase(QString line);
+	bool tryEvaluate(QString line, QList<AstNode> *expr);
+
+	Evaluator _eval;
+
+	bool _running = true;
+};
diff --git a/main.cpp b/main.cpp
index 2d40231..765e380 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,4 +1,5 @@
 #include <QCoreApplication>
+#include <QCommandLineParser>
 #include <QDebug>
 
 #include "Matcher.h"
@@ -7,6 +8,7 @@
 #include "Parser.h"
 #include "Evaluator.h"
 #include "VarContext.h"
+#include "Repl.h"
 
 int g_numFailed = 0;
 
@@ -201,7 +203,7 @@
 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>; e.Ignored = F; } ");
+    testParseFunc("Palindrome { = T; s.A = T; s.A e.Middle s.A = <Palindrome e.Middle>; e.Ignored = F; } ");
 }
 
 void testAllEvals()
@@ -212,15 +214,36 @@
 int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
+	QCoreApplication::setApplicationName("REFAL");
+	QCoreApplication::setApplicationVersion("1.0-a1");
 
-    testAllMatches();
-    qDebug() << "";
-    testAllParses();
-    qDebug() << "";
-    testAllFunctionDefs();
-	qDebug() << "";
-	testAllEvals();
+	QCommandLineParser cli;
+	cli.setApplicationDescription("REFAL interpreter");
+	cli.addHelpOption();
+	cli.addVersionOption();
 
-    qDebug() << "";
-    return testResults();
+	QCommandLineOption testOption(QStringList{"t", "test"}, "Run test suite");
+	cli.addOption(testOption);
+
+	cli.process(a);
+
+	if (cli.isSet(testOption))
+	{
+		testAllMatches();
+		qDebug() << "";
+		testAllParses();
+		qDebug() << "";
+		testAllFunctionDefs();
+		qDebug() << "";
+		testAllEvals();
+
+		qDebug() << "";
+
+		return testResults();
+	}
+	else
+	{
+		Repl repl;
+		repl.start();
+	}
 }
diff --git a/notes.txt b/notes.txt
index f9d7a80..fe6f185 100644
--- a/notes.txt
+++ b/notes.txt
@@ -1,4 +1,12 @@
-export QT_LOGGING_RULES="*.debug=true"
+SETUP
+
+	If you don't get console output from REFAL run:
+	export QT_LOGGING_RULES="*.debug=true"
+
+
+DEPENDENCIES
+
+	Install libedit-dev and libqt5core5a
 
 
 OPTIMIZATION POSSIBILITIES:
@@ -14,4 +22,3 @@
 
 	- Pattern matching and delegation (which sentence of a function do we choose to evaluate)
 	- Expression evaluation (how do we expand an AstNode stream into a Token stream)
-	
\ No newline at end of file