ledger/src/predicate.cc
2009-02-22 17:55:01 -04:00

198 lines
5.1 KiB
C++

/*
* Copyright (c) 2003-2009, John Wiegley. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of New Artisans LLC nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "predicate.h"
namespace ledger {
string args_to_predicate_expr(value_t::sequence_t::const_iterator begin,
value_t::sequence_t::const_iterator end)
{
std::ostringstream expr;
bool append_or = false;
bool only_parenthesis;
while (begin != end) {
string arg = (*begin).as_string();
string prefix;
bool parse_argument = true;
bool only_closed_parenthesis = false;;
if (arg == "not" || arg == "NOT") {
if (append_or)
prefix = " | ! ";
else
prefix = " ! ";
parse_argument = false;
append_or = false;
}
else if (arg == "and" || arg == "AND") {
prefix = " & ";
parse_argument = false;
append_or = false;
}
else if (arg == "or" || arg == "OR") {
prefix = " | ";
parse_argument = false;
append_or = false;
}
else if (append_or) {
if (! only_parenthesis)
prefix = " | ";
}
else {
append_or = true;
}
value_t::sequence_t::const_iterator next = begin;
if (++next != end) {
if (arg == "desc" || arg == "DESC" ||
arg == "payee" || arg == "PAYEE") {
arg = string("@") + (*++begin).as_string();
}
else if (arg == "code" || arg == "CODE") {
arg = string("#") + (*++begin).as_string();
}
else if (arg == "note" || arg == "NOTE") {
arg = string("&") + (*++begin).as_string();
}
else if (arg == "tag" || arg == "TAG" ||
arg == "meta" || arg == "META" ||
arg == "data" || arg == "DATA") {
arg = string("%") + (*++begin).as_string();
}
else if (arg == "expr" || arg == "EXPR") {
arg = string("=") + (*++begin).as_string();
}
}
if (parse_argument) {
bool in_prefix = true;
bool found_specifier = false;
bool no_final_slash = false;
only_parenthesis = true;
std::ostringstream buf;
string parens;
for (const char * c = arg.c_str(); *c != '\0'; c++) {
bool consumed = false;
if (*c != '(' && *c != ')')
only_parenthesis = false;
if (in_prefix) {
switch (*c) {
case ')':
if (only_parenthesis)
only_closed_parenthesis = true;
// fall through...
case '(':
parens += c;
consumed = true;
break;
case '@':
buf << "(payee =~ /";
found_specifier = true;
consumed = true;
break;
case '#':
buf << "(code =~ /";
found_specifier = true;
consumed = true;
break;
case '=':
buf << "(";
found_specifier = true;
no_final_slash = true;
consumed = true;
break;
case '&':
buf << "(note =~ /";
found_specifier = true;
consumed = true;
break;
case '%': {
bool found_metadata = false;
for (const char *q = c; *q != '\0'; q++)
if (*q == '=') {
buf << "has_tag(/"
<< string(c + 1, q - c - 1) << "/, /";
found_metadata = true;
c = q;
break;
}
if (! found_metadata) {
buf << "has_tag(/";
}
found_specifier = true;
consumed = true;
break;
}
default:
if (! found_specifier) {
buf << parens << "(account =~ /";
parens.clear();
found_specifier = true;
}
in_prefix = false;
break;
}
}
if (! consumed)
buf << *c;
}
if (! prefix.empty() &&
! (only_parenthesis && only_closed_parenthesis))
expr << prefix;
expr << parens << buf.str();
if (found_specifier) {
if (! no_final_slash)
expr << "/";
expr << ")";
}
} else {
expr << prefix;
}
begin++;
}
return std::string("(") + expr.str() + ")";
}
} // namespace ledger