2
* Embed a tag expression in a class with proper copy semantics
3
* Plus some filters based on tag expressions
5
* Copyright (C) 2003,2004,2005 Enrico Zini <enrico@debian.org>
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
#include <tagcoll/expression.h>
24
#include <tagcoll/tagexpr/TagexprParser.h>
30
class TagexprTrue : public ExpressionImpl
34
virtual ~TagexprTrue() {}
36
virtual std::string format() const { return "*"; }
38
virtual bool eval(const TagexprContext& context) const { return true; }
39
virtual bool eval(const std::set<std::string>& tags) const { return true; }
42
class TagexprTag : public ExpressionImpl
48
TagexprTag(const std::string& tag) : _tag(tag) {}
49
virtual ~TagexprTag() {}
51
virtual std::string format() const { return _tag; }
53
virtual bool eval(const TagexprContext& context) const
55
return context.eval(_tag);
57
virtual bool eval(const std::set<std::string>& tags) const
61
string match = _tag.substr(1);
62
for (std::set<string>::const_iterator i = tags.begin();
64
if (i->size() >= match.size() &&
65
i->substr(i->size() - match.size()) == match)
69
else if (_tag[_tag.size() - 1] == '*')
71
string match = _tag.substr(0, _tag.size() - 1);
72
for (std::set<string>::const_iterator i = tags.begin();
74
if (i->size() >= match.size() &&
75
i->substr(0, match.size()) == match)
80
return tags.find(_tag) != tags.end();
84
class TagexprNot : public ExpressionImpl
90
TagexprNot(const Expression& operand) : _op(operand) {}
92
virtual std::string format() const { return "!" + _op.format(); }
94
virtual bool eval(const TagexprContext& context) const
96
return ! _op(context);
98
virtual bool eval(const std::set<std::string>& tags) const
104
class TagexprAnd : public ExpressionImpl
111
TagexprAnd(const Expression& operand1, const Expression& operand2)
112
: _op1(operand1), _op2(operand2) {}
114
virtual std::string format() const
116
return "( " + _op1.format() + " && " + _op2.format() + " )";
119
virtual bool eval(const TagexprContext& context) const
121
return _op1(context) && _op2(context);
123
virtual bool eval(const std::set<std::string>& tags) const
125
return _op1(tags) && _op2(tags);
129
class TagexprOr : public ExpressionImpl
136
TagexprOr(const Expression& operand1, const Expression& operand2)
137
: _op1(operand1), _op2(operand2) {}
139
virtual std::string format() const
141
return "( " + _op1.format() + " || " + _op2.format() + " )";
144
virtual bool eval(const TagexprContext& context) const
146
return _op1(context) || _op2(context);
148
virtual bool eval(const std::set<std::string>& tags) const
150
return _op1(tags) || _op2(tags);
155
Expression::Expression(const std::string& expr) : m_impl(0)
157
Expression e = TagexprParser::instance()->parse(expr);
163
Expression::Expression() : m_impl(new TagexprTrue) { m_impl->ref(); }
165
Expression Expression::matchTag(const std::string& pattern)
167
return Expression(new TagexprTag(pattern));
170
Expression Expression::operator and (const Expression& e)
172
return Expression(new TagexprAnd(*this, e));
175
Expression Expression::operator or (const Expression& e)
177
return Expression(new TagexprOr(*this, e));
180
Expression Expression::operator not ()
182
return Expression(new TagexprNot(*this));
186
bool TagexprContext::eval(const std::string& tag) const
188
std::map<std::string, Expression>::const_iterator i = derivedTags.find(tag);
189
if (i == derivedTags.end())
190
return tags.find(tag) != tags.end();
191
else if (seen.find(tag) == seen.end())
194
bool res = i->second(*this);
199
// If we got here, we have a circular dependency between derived tags
200
// FIXME: find a better way to handle it: throw an exception, maybe?
206
// vim:set ts=4 sw=4: