21 #include "filterexpression.h"
23 #include <QtCore/QRegularExpression>
25 #include "exception.h"
41 std::vector<ArgFilter> m_filters;
42 QStringList m_filterNames;
51 static const char FILTER_SEPARATOR =
'|';
52 static const char FILTER_ARGUMENT_SEPARATOR =
':';
54 static QRegularExpression getFilterRegexp()
57 QRegularExpression::escape(QChar::fromLatin1(FILTER_SEPARATOR)));
59 QRegularExpression::escape(QChar::fromLatin1(FILTER_ARGUMENT_SEPARATOR)));
61 const QLatin1String varChars(
62 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.");
63 const QLatin1String numChars(
"[-+\\.]?\\d[\\d\\.e]*");
64 const QString i18nOpen(QRegularExpression::escape(QStringLiteral(
"_(")));
65 const QLatin1String doubleQuoteStringLiteral(
66 "\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"");
67 const QLatin1String singleQuoteStringLiteral(
68 "\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'");
69 const QString i18nClose(QRegularExpression::escape(QStringLiteral(
")")));
70 const QString variable = QLatin1Char(
'[') + varChars + QStringLiteral(
"]+");
72 const QString localizedExpression
73 = QStringLiteral(
"(?:") + i18nOpen + doubleQuoteStringLiteral + i18nClose
74 + QLatin1Char(
'|') + i18nOpen + singleQuoteStringLiteral + i18nClose
75 + QLatin1Char(
'|') + i18nOpen + numChars + i18nClose + QLatin1Char(
'|')
76 + i18nOpen + variable + i18nClose + QLatin1Char(
')');
78 const QString constantString = QStringLiteral(
"(?:")
79 + doubleQuoteStringLiteral + QLatin1Char(
'|')
80 + singleQuoteStringLiteral + QLatin1Char(
')');
83 = QLatin1Char(
'^') + constantString + QLatin1Char(
'|') + QLatin1Char(
'^')
84 + localizedExpression + QLatin1Char(
'|') + QLatin1Char(
'^') + variable
85 + QLatin1Char(
'|') + numChars + QLatin1Char(
'|') + filterSep
86 + QStringLiteral(
"\\w+|") + argSep + QStringLiteral(
"(?:")
87 + constantString + QLatin1Char(
'|') + localizedExpression
88 + QLatin1Char(
'|') + variable + QLatin1Char(
'|') + numChars
89 + QLatin1Char(
'|') + filterSep + QStringLiteral(
"\\w+)");
91 return QRegularExpression(filterRawString);
106 static const auto sFilterRe = getFilterRegexp();
111 auto i = sFilterRe.globalMatch(vs);
112 while (i.hasNext()) {
113 auto match = i.next();
114 len = match.capturedLength();
115 pos = match.capturedStart();
116 subString = match.captured();
117 const auto ssSize = subString.size();
119 if (pos != lastPos) {
122 QStringLiteral(
"Could not parse some characters: \"%1\"")
123 .arg(vs.mid(lastPos, pos)));
126 if (subString.startsWith(QLatin1Char(FILTER_SEPARATOR))) {
127 subString = subString.right(ssSize - 1);
132 d->m_filterNames << subString;
133 d->m_filters.push_back({f,
Variable()});
135 }
else if (subString.startsWith(QLatin1Char(FILTER_ARGUMENT_SEPARATOR))) {
136 if (d->m_filters.empty()
137 || d->m_filters.at(d->m_filters.size() - 1).second.isValid()) {
138 const auto remainder = vs.right(vs.size() - lastPos);
141 QStringLiteral(
"Could not parse the remainder, %1 from %2")
142 .arg(remainder, varString));
144 subString = subString.right(ssSize - 1);
145 const auto lastFilter = d->m_filters.size();
146 if (subString.startsWith(QLatin1Char(FILTER_SEPARATOR)))
149 QStringLiteral(
"Missing argument to filter: %1")
150 .arg(d->m_filterNames[lastFilter - 1]));
152 d->m_filters[lastFilter - 1].second =
Variable(subString);
155 d->m_variable =
Variable(subString);
162 const auto remainder = vs.right(vs.size() - lastPos);
163 if (!remainder.isEmpty()) {
166 QStringLiteral(
"Could not parse the remainder, %1 from %2")
167 .arg(remainder, varString));
188 return d->m_variable.isValid();
196 return d->m_variable;
203 d_ptr->m_variable = other.d_ptr->m_variable;
204 d_ptr->m_filters = other.d_ptr->m_filters;
205 d_ptr->m_filterNames = other.d_ptr->m_filterNames;
212 auto var = d->m_variable.resolve(c);
214 for (
const auto &filterPair : d->m_filters) {
215 auto filter = filterPair.first;
216 filter->setStream(stream);
217 const auto argVar = filterPair.second;
218 auto arg = argVar.resolve(c);
222 if (arg.userType() == qMetaTypeId<Cutelee::SafeString>()) {
224 }
else if (arg.userType() == qMetaTypeId<QString>()) {
227 if (argVar.isConstant()) {
230 if (!argString.
get().isEmpty()) {
237 var = filter->doFilter(var, arg, c->autoEscape());
239 if (var.userType() == qMetaTypeId<Cutelee::SafeString>()
240 || var.userType() == qMetaTypeId<QString>()) {
241 if (filter->isSafe() && varString.isSafe()) {
243 }
else if (varString.needsEscape()) {
263 if (!var.canConvert<QVariantList>())
264 return QVariantList();
265 return var.value<QVariantList>();
273 QStringList FilterExpression::filters()
const
276 return d->m_filterNames;
The Context class holds the context to render a Template with.
An exception for use when implementing template tags.
A FilterExpression object represents a filter expression in a template.
QVariantList toList(Context *c) const
bool isTrue(Context *c) const
QVariant resolve(OutputStream *stream, Context *c) const
Variable variable() const
FilterExpression & operator=(const FilterExpression &other)
The OutputStream class is used to render templates to a QTextStream.
The Parser class processes a string template into a tree of nodes.
std::shared_ptr< Filter > getFilter(const QString &name) const
A QString wrapper class for containing whether a string is safe or needs to be escaped.
const NestedString & get() const
A container for static variables defined in Templates.
The Cutelee namespace holds all public Cutelee API.
Cutelee::SafeString getSafeString(const QVariant &input)
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Cutelee::SafeString markForEscaping(const Cutelee::SafeString &input)
bool variantIsTrue(const QVariant &variant)
Utility functions used throughout Cutelee.