Initial commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1c85d0e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+cmake-build-*
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4fcd8af
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.20)
+project(REFAL)
+
+set(CMAKE_CXX_STANDARD 14)
+set(CMAKE_AUTOMOC ON)
+set(CMAKE_AUTORCC ON)
+set(CMAKE_AUTOUIC ON)
+
+
+find_package(Qt5 COMPONENTS
+        Core
+        REQUIRED)
+
+add_executable(REFAL main.cpp Token.cpp Token.h Matcher.cpp Matcher.h VarContext.cpp VarContext.h)
+target_link_libraries(REFAL
+        Qt::Core
+        )
+
diff --git a/Matcher.cpp b/Matcher.cpp
new file mode 100644
index 0000000..4fc901c
--- /dev/null
+++ b/Matcher.cpp
@@ -0,0 +1,29 @@
+#include "Matcher.h"
+
+MatchResult match(QList<Token> data, QList<Token> pattern, VarContext context) {
+    if (data.empty() && pattern.empty()) {
+        return MatchResult{true, context};
+    }
+
+    Token patternHead = pattern.first();
+    Token dataHead = data.first();
+    pattern.removeFirst();
+
+    if (patternHead.isSym() || patternHead.isIdent()) {
+        if (patternHead == pattern.first()) {
+            data.removeFirst();
+            return match(data, pattern, context);
+        } else {
+            return MatchResult{false, context};
+        }
+    } else if (patternHead.isParen() && dataHead.isParen()) {
+        data.removeFirst();
+        auto result = match(dataHead.parenContent(), patternHead.parenContent(), context);
+
+        if (result.success) {
+            return match(data, pattern, result.context);
+        } else {
+            return MatchResult{false, result.context};
+        }
+    }
+}
diff --git a/Matcher.h b/Matcher.h
new file mode 100644
index 0000000..81f4305
--- /dev/null
+++ b/Matcher.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "Token.h"
+#include "VarContext.h"
+
+struct MatchResult {
+    bool success;
+    VarContext context;
+};
+
+MatchResult match(QList<Token> data, QList<Token> pattern, VarContext context);
diff --git a/Token.cpp b/Token.cpp
new file mode 100644
index 0000000..7cb50e0
--- /dev/null
+++ b/Token.cpp
@@ -0,0 +1,65 @@
+#include "Token.h"
+
+Token::Token(const Token &other) {
+    *this = other;
+}
+
+Token::Token(QChar symbol) {
+    _type = SYM;
+    _charVal = symbol;
+}
+
+Token::Token(QString &&identifier) {
+    _type = IDENT;
+    _stringVal = identifier;
+}
+
+Token::Token(QList<Token> &&parenthesized) {
+    _type = PAREN;
+    _listVal = new QList<Token>(parenthesized);
+}
+
+Token::Token(char varType, const QString &&name) {
+    _type = VAR;
+    _charVal = varType;
+    _stringVal = name;
+}
+
+Token::~Token() {
+    // Стерать нулевые пойнтеры безопасно
+    delete _listVal;
+}
+
+bool Token::isSym() {
+    return _type == SYM;
+}
+
+bool Token::isIdent() {
+    return _type == IDENT;
+}
+
+bool Token::isParen() {
+    return _type == PAREN;
+}
+
+bool Token::isVar() {
+    return _type == VAR;
+}
+
+Token::Token() : Token("Null") {
+}
+
+bool Token::operator==(const Token &other) {
+    return _type == other._type
+           && _stringVal == other._stringVal
+           && _charVal == other._charVal
+           && (_listVal == nullptr || *_listVal == (*other._listVal));
+}
+
+QList<Token> Token::parenContent() {
+    if (isParen() && _listVal) {
+        return *_listVal;
+    } else {
+        return {};
+    }
+}
diff --git a/Token.h b/Token.h
new file mode 100644
index 0000000..bb46127
--- /dev/null
+++ b/Token.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <QList>
+#include <QChar>
+
+class Token {
+public:
+    Token();
+    Token(const Token &other);
+
+    explicit Token(QChar symbol);
+    explicit Token(QString &&identifier);
+    explicit Token(QList<Token> &&parenthesized);
+    Token(char varType, const QString &&name);
+
+    bool operator ==(const Token &other);
+
+    ~Token();
+
+    bool isSym();
+    bool isIdent();
+    bool isParen();
+    bool isVar();
+
+    QList<Token> parenContent();
+
+private:
+    enum Type {
+        SYM, IDENT, PAREN, VAR,
+    };
+
+    int _type = 0;
+    QString _stringVal = "";
+    QList<Token> *_listVal = nullptr;
+    QChar _charVal = 0;
+};
diff --git a/VarContext.cpp b/VarContext.cpp
new file mode 100644
index 0000000..bde30ef
--- /dev/null
+++ b/VarContext.cpp
@@ -0,0 +1,17 @@
+#include "VarContext.h"
+
+void VarContext::add(char t, const QString &&name, const Token &value) {
+    _vars.insert(name, Var{t, value});
+}
+
+char VarContext::exists(const QString &name) {
+    return _vars.contains(name);
+}
+
+Token VarContext::operator[](const QString &name) {
+    return _vars[name].value;
+}
+
+VarContext::VarContext(const VarContext &other) noexcept {
+    _vars = other._vars;
+}
diff --git a/VarContext.h b/VarContext.h
new file mode 100644
index 0000000..afa1b9a
--- /dev/null
+++ b/VarContext.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <QMap>
+#include "Token.h"
+
+class VarContext {
+public:
+    VarContext() = default;
+    VarContext(VarContext const &other)  noexcept;
+
+    void add(char t, const QString &&name, const Token &value);
+    char exists(const QString &name);
+    Token operator [](const QString &name);
+
+private:
+    struct Var {
+        Var() = default;
+
+        char t = 0;
+        Token value;
+    };
+
+    QMap<QString, Var> _vars;
+};
\ No newline at end of file
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..6c07880
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,8 @@
+#include <QCoreApplication>
+#include <QDebug>
+
+int main(int argc, char *argv[]) {
+    QCoreApplication a(argc, argv);
+    qDebug() << "Hello World";
+    return QCoreApplication::exec();
+}