blob: c7cc7d7e23080c44132391a8da874993306132ce [file] [log] [blame]
#pragma once
#include <QList>
#include <QChar>
template <typename T>
class TokenBase
{
public:
TokenBase();
TokenBase(const T &other);
TokenBase(QString integer, int base);
explicit TokenBase(QChar symbol);
explicit TokenBase(QString identifier);
explicit TokenBase(QList<T> parenthesized);
TokenBase(char varType, const QString name);
static T fromInteger(int integer);
bool operator==(const T &other) const;
bool operator!=(const T &other) const;
bool isSym() const;
bool isIdent() const;
bool isParen() const;
bool isVar() const;
bool isInteger() const;
QList<T> parenContent();
char varType() const;
const QString &name() const;
QChar symbol() const;
int integer() const;
operator QString() const;
enum
{
SYM,
IDENT,
PAREN,
VAR,
INTEGER,
TOKEN_TYPE_LAST,
};
static QString typeToString(int type);
int type() const;
protected:
int _type = 0;
int _intVal = 0;
QString _stringVal = "";
QList<T> _listVal;
QChar _charVal = QChar(0);
};
template <typename T>
TokenBase<T>::TokenBase(const T &other)
{
_type = other._type;
_stringVal = other._stringVal;
_listVal = other._listVal;
_charVal = other._charVal;
}
template <typename T>
TokenBase<T>::TokenBase(QChar symbol)
{
_type = SYM;
_charVal = symbol;
}
template <typename T>
TokenBase<T>::TokenBase(QString identifier)
{
_type = IDENT;
_stringVal = identifier;
}
template <typename T>
TokenBase<T>::TokenBase(QList<T> parenthesized)
{
_type = PAREN;
_listVal = std::move(parenthesized);
}
template <typename T>
TokenBase<T>::TokenBase(QString integer, int base)
{
_type = INTEGER;
_intVal = integer.toInt(nullptr, base);
}
template <typename T>
T TokenBase<T>::fromInteger(int integer)
{
T tok;
tok._type = INTEGER;
tok._intVal = integer;
return tok;
}
template <typename T>
TokenBase<T>::TokenBase(char varType, const QString name)
{
_type = VAR;
_charVal = varType;
_stringVal = name;
}
template <typename T>
bool TokenBase<T>::isSym() const
{
return _type == SYM;
}
template <typename T>
bool TokenBase<T>::isIdent() const
{
return _type == IDENT;
}
template <typename T>
bool TokenBase<T>::isParen() const
{
return _type == PAREN;
}
template <typename T>
bool TokenBase<T>::isVar() const
{
return _type == VAR;
}
template <typename T>
bool TokenBase<T>::isInteger() const
{
return _type == INTEGER;
}
template <typename T>
TokenBase<T>::TokenBase() : TokenBase("Null")
{
}
template <typename T>
bool TokenBase<T>::operator==(const T &other) const
{
// Why is this needed? Beats me.
if (isInteger() && other.isInteger())
return _intVal == other._intVal;
return _type == other._type &&
_stringVal == other._stringVal &&
_charVal == other._charVal &&
_listVal == other._listVal &&
_intVal == other._intVal;
}
template <typename T>
QList<T> TokenBase<T>::parenContent()
{
if (isParen())
{
return _listVal;
}
else
{
return {};
}
}
template <typename T>
int TokenBase<T>::integer() const
{
return _intVal;
}
template <typename T>
char TokenBase<T>::varType() const
{
return _charVal.toLatin1();
}
template <typename T>
const QString &TokenBase<T>::name() const
{
return _stringVal;
}
template <typename T>
bool TokenBase<T>::operator!=(const T &other) const
{
return !(this->operator==(other));
}
template <typename T>
TokenBase<T>::operator QString() const
{
if (isIdent())
return _stringVal;
if (isSym())
return _charVal;
if (isVar())
return QString(_charVal) + "." + _stringVal;
if (isInteger())
return QString::number(_intVal, 10);
if (isParen())
{
QStringList parts;
for (const T &tok : _listVal)
{
parts.append(static_cast<QString>(tok));
}
return "(" + parts.join(" ") + ")";
}
return "Null";
}
template <typename T>
int TokenBase<T>::type() const
{
return _type;
}
template <typename T>
QString TokenBase<T>::typeToString(int type)
{
static const QString typeNames[] = {"SYMBOL", "IDENT", "PAREN", "VAR", "INTEGER"};
return typeNames[type];
}
template <typename T>
QChar TokenBase<T>::symbol() const
{
return _charVal;
}
class Token : public TokenBase<Token>
{
public:
using TokenBase<Token>::TokenBase;
};
using LTok = QList<Token>;