- Tag matching was being performed using the regex \b<tag>\b, which makes
  taskwarrior dependent on regex lib bugs for basic functionality.  This is
  now modified to use pseudo-operators _hastag_ and _notag_.
This commit is contained in:
Paul Beckingham 2012-02-19 17:20:11 -05:00
parent 78e5891cd3
commit 09431caf1c
5 changed files with 72 additions and 54 deletions

View file

@ -74,30 +74,34 @@ static struct
char associativity;
} operators[] =
{
// Operator Precedence Type Symbol Associativity
{ "and", 5, 'b', 0, 'l' }, // Conjunction
{ "xor", 4, 'b', 0, 'l' }, // Disjunction
// Operator Precedence Type Symbol Associativity
{ "and", 5, 'b', 0, 'l' }, // Conjunction
{ "xor", 4, 'b', 0, 'l' }, // Disjunction
{ "or", 3, 'b', 0, 'l' }, // Disjunction
{ "<=", 10, 'b', 1, 'l' }, // Less than or equal
{ ">=", 10, 'b', 1, 'l' }, // Greater than or equal
{ "!~", 9, 'b', 1, 'l' }, // Regex non-match
{ "!=", 9, 'b', 1, 'l' }, // Inequal
{ "or", 3, 'b', 0, 'l' }, // Disjunction
{ "<=", 10, 'b', 1, 'l' }, // Less than or equal
{ ">=", 10, 'b', 1, 'l' }, // Greater than or equal
{ "!~", 9, 'b', 1, 'l' }, // Regex non-match
{ "!=", 9, 'b', 1, 'l' }, // Inequal
{ "=", 9, 'b', 1, 'l' }, // Equal
// { "^", 16, 'b', 1, 'r' }, // Exponent
{ ">", 10, 'b', 1, 'l' }, // Greater than
{ "~", 9, 'b', 1, 'l' }, // Regex match
{ "!", 15, 'u', 1, 'r' }, // Not
// { "-", 15, 'u', 1, 'r' }, // Unary minus
{ "*", 13, 'b', 1, 'l' }, // Multiplication
{ "/", 13, 'b', 1, 'l' }, // Division
// { "%", 13, 'b', 1, 'l' }, // Modulus
{ "+", 12, 'b', 1, 'l' }, // Addition
{ "-", 12, 'b', 1, 'l' }, // Subtraction
{ "<", 10, 'b', 1, 'l' }, // Less than
{ "(", 0, 'b', 1, 'l' }, // Precedence start
{ ")", 0, 'b', 1, 'l' }, // Precedence end
{ "=", 9, 'b', 1, 'l' }, // Equal
// { "^", 16, 'b', 1, 'r' }, // Exponent
{ ">", 10, 'b', 1, 'l' }, // Greater than
{ "~", 9, 'b', 1, 'l' }, // Regex match
{ "!", 15, 'u', 1, 'r' }, // Not
{ "_hastag_", 9, 'b', 0, 'l'}, // +tag [Pseudo-op]
{ "_notag_", 9, 'b', 0, 'l'}, // -tag [Pseudo-op]
// { "-", 15, 'u', 1, 'r' }, // Unary minus
{ "*", 13, 'b', 1, 'l' }, // Multiplication
{ "/", 13, 'b', 1, 'l' }, // Division
// { "%", 13, 'b', 1, 'l' }, // Modulus
{ "+", 12, 'b', 1, 'l' }, // Addition
{ "-", 12, 'b', 1, 'l' }, // Subtraction
{ "<", 10, 'b', 1, 'l' }, // Less than
{ "(", 0, 'b', 1, 'l' }, // Precedence start
{ ")", 0, 'b', 1, 'l' }, // Precedence end
};
#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0]))
@ -1047,24 +1051,16 @@ const A3 A3::expand (const A3& input) const
throw format (STRING_A3_UNKNOWN_ATTMOD, mod);
}
// [+-]value --> tags ~/!~ value
// [+-]value --> tags _hastag_/_notag_ value
else if (arg->_category == Arg::cat_tag)
{
char type;
std::string value;
extract_tag (arg->_raw, type, value);
expanded.push_back (Arg ("tags", Arg::type_string, Arg::cat_dom));
expanded.push_back (Arg (type == '+' ? "~" : "!~", Arg::cat_op));
#ifdef DARWIN
expanded.push_back (Arg ("tags", Arg::type_string, Arg::cat_dom_));
expanded.push_back (Arg (type == '+' ? "_hastag_" : "_notag_", Arg::cat_op));
expanded.push_back (Arg (value, Arg::type_string, Arg::cat_literal));
#else
#ifdef SOLARIS
expanded.push_back (Arg ("\\<" + value + "\\>", Arg::type_string, Arg::cat_rx));
#else
expanded.push_back (Arg ("\\b" + value + "\\b", Arg::type_string, Arg::cat_rx));
#endif
#endif
}
// word --> description ~ word
@ -2053,23 +2049,24 @@ void A3::dump (const std::string& label)
color_map[Arg::cat_program] = Color ("bold blue on blue");
color_map[Arg::cat_command] = Color ("bold cyan on cyan");
color_map[Arg::cat_rc] = Color ("bold red on red");
color_map[Arg::cat_override] = Color ("bold red on red");
color_map[Arg::cat_override] = color_map[Arg::cat_rc];
color_map[Arg::cat_terminator] = Color ("bold yellow on yellow");
color_map[Arg::cat_literal] = Color ("white on gray4");
// Filter colors.
color_map[Arg::cat_attr] = Color ("bold red on gray4");
color_map[Arg::cat_attmod] = Color ("bold red on gray4");
color_map[Arg::cat_attmod] = color_map[Arg::cat_attr];
color_map[Arg::cat_pattern] = Color ("cyan on gray4");
color_map[Arg::cat_subst] = Color ("bold cyan on gray4");
color_map[Arg::cat_op] = Color ("green on gray4");
color_map[Arg::type_string] = Color ("bold yellow on gray4");
color_map[Arg::cat_rx] = Color ("bold yellow on gray4");
color_map[Arg::type_date] = Color ("bold yellow on gray4");
color_map[Arg::cat_rx] = color_map[Arg::type_string];
color_map[Arg::type_date] = color_map[Arg::type_string];
color_map[Arg::cat_dom] = Color ("bold white on gray4");
color_map[Arg::cat_dom_] = color_map[Arg::cat_dom];
color_map[Arg::type_duration] = Color ("magenta on gray4");
color_map[Arg::cat_id] = Color ("white on gray4");
color_map[Arg::cat_uuid] = Color ("white on gray4");
color_map[Arg::cat_uuid] = color_map[Arg::cat_id];
// Default.
color_map[Arg::cat_none] = Color ("black on white");

View file

@ -178,6 +178,7 @@ const std::string Arg::category_name (Arg::category c)
case Arg::cat_pattern: return "pattern";
case Arg::cat_tag: return "tag";
case Arg::cat_dom: return "dom";
case Arg::cat_dom_: return "[dom]";
case Arg::cat_op: return "op";
case Arg::cat_literal: return "literal";
}

View file

@ -36,7 +36,7 @@
class Arg
{
public:
enum category {cat_none=1, cat_terminator, cat_program, cat_command, cat_rc, cat_override, cat_attr, cat_attmod, cat_id, cat_uuid, cat_subst, cat_pattern, cat_rx, cat_tag, cat_dom, cat_op, cat_literal};
enum category {cat_none=1, cat_terminator, cat_program, cat_command, cat_rc, cat_override, cat_attr, cat_attmod, cat_id, cat_uuid, cat_subst, cat_pattern, cat_rx, cat_tag, cat_dom_, cat_dom, cat_op, cat_literal};
enum type {type_none=20, type_pseudo, type_bool, type_string, type_date, type_duration, type_number};
Arg ();

View file

@ -135,21 +135,23 @@ void E9::eval (const Task& task, std::vector <Arg>& value_stack)
Arg left = value_stack.back ();
value_stack.pop_back ();
if (arg->_raw == "and") operator_and (result, left, right);
else if (arg->_raw == "or") operator_or (result, left, right);
else if (arg->_raw == "xor") operator_xor (result, left, right);
else if (arg->_raw == "<") operator_lt (result, left, right);
else if (arg->_raw == "<=") operator_lte (result, left, right);
else if (arg->_raw == ">=") operator_gte (result, left, right);
else if (arg->_raw == ">") operator_gt (result, left, right);
else if (arg->_raw == "!=") operator_inequal (result, left, right, case_sensitive);
else if (arg->_raw == "=") operator_equal (result, left, right, case_sensitive);
else if (arg->_raw == "~") operator_match (result, left, right, case_sensitive, task);
else if (arg->_raw == "!~") operator_nomatch (result, left, right, case_sensitive, task);
else if (arg->_raw == "*") operator_multiply (result, left, right);
else if (arg->_raw == "/") operator_divide (result, left, right);
else if (arg->_raw == "+") operator_add (result, left, right);
else if (arg->_raw == "-") operator_subtract (result, left, right);
if (arg->_raw == "and") operator_and (result, left, right);
else if (arg->_raw == "or") operator_or (result, left, right);
else if (arg->_raw == "xor") operator_xor (result, left, right);
else if (arg->_raw == "<") operator_lt (result, left, right);
else if (arg->_raw == "<=") operator_lte (result, left, right);
else if (arg->_raw == ">=") operator_gte (result, left, right);
else if (arg->_raw == ">") operator_gt (result, left, right);
else if (arg->_raw == "!=") operator_inequal (result, left, right, case_sensitive);
else if (arg->_raw == "=") operator_equal (result, left, right, case_sensitive);
else if (arg->_raw == "~") operator_match (result, left, right, case_sensitive, task);
else if (arg->_raw == "!~") operator_nomatch (result, left, right, case_sensitive, task);
else if (arg->_raw == "*") operator_multiply (result, left, right);
else if (arg->_raw == "/") operator_divide (result, left, right);
else if (arg->_raw == "+") operator_add (result, left, right);
else if (arg->_raw == "-") operator_subtract (result, left, right);
else if (arg->_raw == "_hastag_") operator_hastag (result, right, false, task);
else if (arg->_raw == "_notag_") operator_hastag (result, right, true, task);
else
throw format (STRING_E9_UNSUPPORTED, arg->_raw);
}
@ -628,6 +630,23 @@ void E9::operator_subtract (Arg& result, Arg& left, Arg& right)
// std::cout << "# " << left << " <operator_subtract> " << right << " --> " << result << "\n";
}
////////////////////////////////////////////////////////////////////////////////
void E9::operator_hastag (
Arg& result,
Arg& right,
bool invert,
const Task& task)
{
result._type = Arg::type_bool;
if (task.hasTag (right._raw))
result._value = invert ? "false" : "true";
else
result._value = invert ? "true" : "false";
std::cout << "# tags" << (invert ? " <operator_notag> " : " <operator_hastag> ") << right << " --> " << result << "\n";
}
////////////////////////////////////////////////////////////////////////////////
const Arg E9::coerce (const Arg& input, const Arg::type type)
{

View file

@ -67,6 +67,7 @@ private:
void operator_divide (Arg&, Arg&, Arg&);
void operator_add (Arg&, Arg&, Arg&);
void operator_subtract (Arg&, Arg&, Arg&);
void operator_hastag (Arg&, Arg&, bool, const Task&);
const Arg coerce (const Arg&, const Arg::type);
bool get_bool (const Arg&);