mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Add list literals to filters (#2103)
This commit is contained in:
parent
a27757e440
commit
a9590ae292
|
@ -259,6 +259,10 @@ ExpressionPtr FilterParser::parseValue()
|
|||
{
|
||||
return this->parseParentheses();
|
||||
}
|
||||
else if (type == TokenType::LIST_START)
|
||||
{
|
||||
return this->parseList();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->tokenizer_.next();
|
||||
|
@ -275,6 +279,48 @@ ExpressionPtr FilterParser::parseValue()
|
|||
return std::make_unique<ValueExpression>(0, TokenType::INT);
|
||||
}
|
||||
|
||||
ExpressionPtr FilterParser::parseList()
|
||||
{
|
||||
// Don't call .next() before calling this method
|
||||
assert(this->tokenizer_.nextTokenType() == TokenType::LIST_START);
|
||||
this->tokenizer_.next();
|
||||
|
||||
ExpressionList list;
|
||||
bool first = true;
|
||||
|
||||
while (this->tokenizer_.hasNext())
|
||||
{
|
||||
if (this->tokenizer_.nextTokenType() == TokenType::LIST_END)
|
||||
{
|
||||
this->tokenizer_.next();
|
||||
return std::make_unique<ListExpression>(std::move(list));
|
||||
}
|
||||
else if (this->tokenizer_.nextTokenType() == TokenType::COMMA && !first)
|
||||
{
|
||||
this->tokenizer_.next();
|
||||
list.push_back(this->parseValue());
|
||||
first = false;
|
||||
}
|
||||
else if (first)
|
||||
{
|
||||
list.push_back(this->parseValue());
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto message =
|
||||
this->tokenizer_.hasNext()
|
||||
? QString("Missing closing list braces: got %1")
|
||||
.arg(this->tokenizer_.preview())
|
||||
: "Missing closing list braces at end of statement";
|
||||
this->errorLog(message);
|
||||
return std::make_unique<ListExpression>(ExpressionList());
|
||||
}
|
||||
|
||||
void FilterParser::errorLog(const QString &text, bool expand)
|
||||
{
|
||||
this->valid_ = false;
|
||||
|
|
|
@ -26,6 +26,7 @@ private:
|
|||
ExpressionPtr parseParentheses();
|
||||
ExpressionPtr parseCondition();
|
||||
ExpressionPtr parseValue();
|
||||
ExpressionPtr parseList();
|
||||
|
||||
void errorLog(const QString &text, bool expand = false);
|
||||
|
||||
|
|
|
@ -103,6 +103,12 @@ TokenType Tokenizer::tokenize(const QString &text)
|
|||
return TokenType::LP;
|
||||
else if (text == ")")
|
||||
return TokenType::RP;
|
||||
else if (text == "{")
|
||||
return TokenType::LIST_START;
|
||||
else if (text == "}")
|
||||
return TokenType::LIST_END;
|
||||
else if (text == ",")
|
||||
return TokenType::COMMA;
|
||||
else if (text == "+")
|
||||
return TokenType::PLUS;
|
||||
else if (text == "-")
|
||||
|
|
|
@ -26,7 +26,8 @@ static const QRegularExpression tokenRegex(
|
|||
QString("\\\"((\\\\\")|[^\\\"])*\\\"|") + // String literal
|
||||
QString("[\\w\\.]+|") + // Identifier or reserved keyword
|
||||
QString("(<=?|>=?|!=?|==|\\|\\||&&|\\+|-|\\*|\\/|%)+|") + // Operator
|
||||
QString("[\\(\\)]") // Parentheses
|
||||
QString("[\\(\\)]|") + // Parentheses
|
||||
QString("[{},]") // List
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
|
|
|
@ -35,6 +35,12 @@ QString tokenTypeToInfoString(TokenType type)
|
|||
return "<left parenthesis>";
|
||||
case RP:
|
||||
return "<right parenthesis>";
|
||||
case LIST_START:
|
||||
return "<list start>";
|
||||
case LIST_END:
|
||||
return "<list end>";
|
||||
case COMMA:
|
||||
return "<comma>";
|
||||
case PLUS:
|
||||
return "<plus>";
|
||||
case MINUS:
|
||||
|
@ -117,6 +123,62 @@ QString ValueExpression::filterString() const
|
|||
}
|
||||
}
|
||||
|
||||
// ListExpression
|
||||
|
||||
ListExpression::ListExpression(ExpressionList list)
|
||||
: list_(std::move(list)){};
|
||||
|
||||
QVariant ListExpression::execute(const ContextMap &context) const
|
||||
{
|
||||
QList<QVariant> results;
|
||||
bool allStrings = true;
|
||||
for (const auto &exp : this->list_)
|
||||
{
|
||||
auto res = exp->execute(context);
|
||||
if (allStrings && res.type() != QVariant::Type::String)
|
||||
{
|
||||
allStrings = false;
|
||||
}
|
||||
results.append(res);
|
||||
}
|
||||
|
||||
// if everything is a string return a QStringList for case-insensitive comparison
|
||||
if (allStrings)
|
||||
{
|
||||
QStringList strings;
|
||||
strings.reserve(results.size());
|
||||
for (const auto &val : results)
|
||||
{
|
||||
strings << val.toString();
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
else
|
||||
{
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
QString ListExpression::debug() const
|
||||
{
|
||||
QStringList debugs;
|
||||
for (const auto &exp : this->list_)
|
||||
{
|
||||
debugs.append(exp->debug());
|
||||
}
|
||||
return QString("{%1}").arg(debugs.join(", "));
|
||||
}
|
||||
|
||||
QString ListExpression::filterString() const
|
||||
{
|
||||
QStringList strings;
|
||||
for (const auto &exp : this->list_)
|
||||
{
|
||||
strings.append(QString("(%1)").arg(exp->filterString()));
|
||||
}
|
||||
return QString("{%1}").arg(strings.join(", "));
|
||||
}
|
||||
|
||||
// BinaryOperation
|
||||
|
||||
BinaryOperation::BinaryOperation(TokenType op, ExpressionPtr left,
|
||||
|
@ -212,6 +274,11 @@ QVariant BinaryOperation::execute(const ContextMap &context) const
|
|||
return left.toMap().contains(right.toString());
|
||||
}
|
||||
|
||||
if (left.type() == QVariant::Type::List)
|
||||
{
|
||||
return left.toList().contains(right);
|
||||
}
|
||||
|
||||
if (left.canConvert(QMetaType::QString) &&
|
||||
right.canConvert(QMetaType::QString))
|
||||
{
|
||||
|
@ -230,6 +297,11 @@ QVariant BinaryOperation::execute(const ContextMap &context) const
|
|||
Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
if (left.type() == QVariant::Type::List)
|
||||
{
|
||||
return left.toList().startsWith(right);
|
||||
}
|
||||
|
||||
if (left.canConvert(QMetaType::QString) &&
|
||||
right.canConvert(QMetaType::QString))
|
||||
{
|
||||
|
@ -249,6 +321,11 @@ QVariant BinaryOperation::execute(const ContextMap &context) const
|
|||
Qt::CaseInsensitive);
|
||||
}
|
||||
|
||||
if (left.type() == QVariant::Type::List)
|
||||
{
|
||||
return left.toList().endsWith(right);
|
||||
}
|
||||
|
||||
if (left.canConvert(QMetaType::QString) &&
|
||||
right.canConvert(QMetaType::QString))
|
||||
{
|
||||
|
|
|
@ -14,19 +14,22 @@ enum TokenType {
|
|||
OR = 2,
|
||||
LP = 3,
|
||||
RP = 4,
|
||||
CONTROL_END = 9,
|
||||
LIST_START = 5,
|
||||
LIST_END = 6,
|
||||
COMMA = 7,
|
||||
CONTROL_END = 19,
|
||||
|
||||
// binary operator
|
||||
BINARY_START = 10,
|
||||
EQ = 11,
|
||||
NEQ = 12,
|
||||
LT = 13,
|
||||
GT = 14,
|
||||
LTE = 15,
|
||||
GTE = 16,
|
||||
CONTAINS = 17,
|
||||
STARTS_WITH = 18,
|
||||
ENDS_WITH = 19,
|
||||
BINARY_START = 20,
|
||||
EQ = 21,
|
||||
NEQ = 22,
|
||||
LT = 23,
|
||||
GT = 24,
|
||||
LTE = 25,
|
||||
GTE = 26,
|
||||
CONTAINS = 27,
|
||||
STARTS_WITH = 28,
|
||||
ENDS_WITH = 29,
|
||||
BINARY_END = 49,
|
||||
|
||||
// unary operator
|
||||
|
@ -93,6 +96,21 @@ private:
|
|||
TokenType type_;
|
||||
};
|
||||
|
||||
using ExpressionList = std::vector<std::unique_ptr<Expression>>;
|
||||
|
||||
class ListExpression : public Expression
|
||||
{
|
||||
public:
|
||||
ListExpression(ExpressionList list);
|
||||
|
||||
QVariant execute(const ContextMap &context) const override;
|
||||
QString debug() const override;
|
||||
QString filterString() const override;
|
||||
|
||||
private:
|
||||
ExpressionList list_;
|
||||
};
|
||||
|
||||
class BinaryOperation : public Expression
|
||||
{
|
||||
public:
|
||||
|
|
Loading…
Reference in a new issue