mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Expressions
- Many operators implemented - DOM::get partially implemented
This commit is contained in:
parent
4fca40fc69
commit
c77c6f172f
6 changed files with 315 additions and 101 deletions
|
@ -37,6 +37,7 @@
|
||||||
#include <ViewText.h>
|
#include <ViewText.h>
|
||||||
#include <text.h>
|
#include <text.h>
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
|
#include <i18n.h>
|
||||||
#include <Arguments.h>
|
#include <Arguments.h>
|
||||||
|
|
||||||
extern Context context;
|
extern Context context;
|
||||||
|
@ -111,11 +112,11 @@ static struct
|
||||||
{ "!=", 9, 'b', 1, 'l' }, // Inequal
|
{ "!=", 9, 'b', 1, 'l' }, // Inequal
|
||||||
|
|
||||||
{ "=", 9, 'b', 1, 'l' }, // Equal
|
{ "=", 9, 'b', 1, 'l' }, // Equal
|
||||||
{ "^", 16, 'b', 1, 'r' }, // Exponent
|
// { "^", 16, 'b', 1, 'r' }, // Exponent
|
||||||
{ ">", 10, 'b', 1, 'l' }, // Greater than
|
{ ">", 10, 'b', 1, 'l' }, // Greater than
|
||||||
{ "~", 9, 'b', 1, 'l' }, // Regex match
|
{ "~", 9, 'b', 1, 'l' }, // Regex match
|
||||||
{ "!", 15, 'u', 1, 'r' }, // Not
|
{ "!", 15, 'u', 1, 'r' }, // Not
|
||||||
{ "-", 15, 'u', 1, 'r' }, // Unary minus
|
// { "-", 15, 'u', 1, 'r' }, // Unary minus
|
||||||
{ "*", 13, 'b', 1, 'l' }, // Multiplication
|
{ "*", 13, 'b', 1, 'l' }, // Multiplication
|
||||||
{ "/", 13, 'b', 1, 'l' }, // Division
|
{ "/", 13, 'b', 1, 'l' }, // Division
|
||||||
{ "%", 13, 'b', 1, 'l' }, // Modulus
|
{ "%", 13, 'b', 1, 'l' }, // Modulus
|
||||||
|
@ -149,8 +150,11 @@ void Arguments::capture (int argc, const char** argv)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < argc; ++i)
|
for (int i = 0; i < argc; ++i)
|
||||||
{
|
{
|
||||||
|
// The "i != 0" guarantees that argv[0] does not get split, because it may
|
||||||
|
// be an absolute path, and Expression::expand_tokens would make a dog's
|
||||||
|
// dinner out of it.
|
||||||
std::vector <std::string> parts;
|
std::vector <std::string> parts;
|
||||||
if (is_multipart (argv[i], parts))
|
if (is_multipart (argv[i], parts) && i != 0)
|
||||||
{
|
{
|
||||||
std::vector <std::string>::iterator part;
|
std::vector <std::string>::iterator part;
|
||||||
for (part = parts.begin (); part != parts.end (); ++part)
|
for (part = parts.begin (); part != parts.end (); ++part)
|
||||||
|
@ -270,22 +274,16 @@ void Arguments::categorize ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// rc:<file>
|
// rc:<file>
|
||||||
|
// Note: This doesn't break a sequence chain.
|
||||||
else if (arg->first.substr (0, 3) == "rc:")
|
else if (arg->first.substr (0, 3) == "rc:")
|
||||||
{
|
{
|
||||||
found_non_sequence = true;
|
|
||||||
if (found_sequence)
|
|
||||||
found_something_after_sequence = true;
|
|
||||||
|
|
||||||
arg->second = "rc";
|
arg->second = "rc";
|
||||||
}
|
}
|
||||||
|
|
||||||
// rc.<name>:<value>
|
// rc.<name>:<value>
|
||||||
|
// Note: This doesn't break a sequence chain.
|
||||||
else if (arg->first.substr (0, 3) == "rc.")
|
else if (arg->first.substr (0, 3) == "rc.")
|
||||||
{
|
{
|
||||||
found_non_sequence = true;
|
|
||||||
if (found_sequence)
|
|
||||||
found_something_after_sequence = true;
|
|
||||||
|
|
||||||
arg->second = "override";
|
arg->second = "override";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +445,7 @@ void Arguments::categorize ()
|
||||||
found_sequence)
|
found_sequence)
|
||||||
{
|
{
|
||||||
// TODO Invoke the info command.
|
// TODO Invoke the info command.
|
||||||
// std::cout << STRING_ASSUME_INFO << "\n";
|
std::cout << STRING_ASSUME_INFO << "\n";
|
||||||
// parseCmd.command = "info";
|
// parseCmd.command = "info";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -925,10 +923,28 @@ bool Arguments::is_attribute (const std::string& input, std::string& canonical)
|
||||||
// Guess at the full attribute name.
|
// Guess at the full attribute name.
|
||||||
std::vector <std::string> candidates;
|
std::vector <std::string> candidates;
|
||||||
for (unsigned i = 0; i < NUM_ATT_NAMES; ++i)
|
for (unsigned i = 0; i < NUM_ATT_NAMES; ++i)
|
||||||
|
{
|
||||||
|
// Short-circuit: exact matches cause immediate return.
|
||||||
|
if (attributeNames[i] == input)
|
||||||
|
{
|
||||||
|
canonical = input;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
candidates.push_back (attributeNames[i]);
|
candidates.push_back (attributeNames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < NUM_MODIFIABLE_ATT_NAMES; ++i)
|
for (unsigned i = 0; i < NUM_MODIFIABLE_ATT_NAMES; ++i)
|
||||||
|
{
|
||||||
|
// Short-circuit: exact matches cause immediate return.
|
||||||
|
if (modifiableAttributeNames[i] == input)
|
||||||
|
{
|
||||||
|
canonical = input;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
candidates.push_back (modifiableAttributeNames[i]);
|
candidates.push_back (modifiableAttributeNames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector <std::string> matches;
|
std::vector <std::string> matches;
|
||||||
autoComplete (input, candidates, matches);
|
autoComplete (input, candidates, matches);
|
||||||
|
@ -948,7 +964,13 @@ bool Arguments::is_modifier (const std::string& input)
|
||||||
// Guess at the full attribute name.
|
// Guess at the full attribute name.
|
||||||
std::vector <std::string> candidates;
|
std::vector <std::string> candidates;
|
||||||
for (unsigned i = 0; i < NUM_MODIFIER_NAMES; ++i)
|
for (unsigned i = 0; i < NUM_MODIFIER_NAMES; ++i)
|
||||||
|
{
|
||||||
|
// Short-circuit: exact matches cause immediate return.
|
||||||
|
if (modifierNames[i] == input)
|
||||||
|
return true;
|
||||||
|
|
||||||
candidates.push_back (modifierNames[i]);
|
candidates.push_back (modifierNames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector <std::string> matches;
|
std::vector <std::string> matches;
|
||||||
autoComplete (input, candidates, matches);
|
autoComplete (input, candidates, matches);
|
||||||
|
|
169
src/DOM.cpp
169
src/DOM.cpp
|
@ -63,26 +63,6 @@ DOM::~DOM ()
|
||||||
// context.width
|
// context.width
|
||||||
// context.height
|
// context.height
|
||||||
//
|
//
|
||||||
// <id>.<?>
|
|
||||||
// <id>.{entry,start,end,due,until,wait}
|
|
||||||
// <id>.{entry,start,end,due,until,wait}.year
|
|
||||||
// <id>.{entry,start,end,due,until,wait}.month
|
|
||||||
// <id>.{entry,start,end,due,until,wait}.day
|
|
||||||
// <id>.{entry,start,end,due,until,wait}.hour
|
|
||||||
// <id>.{entry,start,end,due,until,wait}.minute
|
|
||||||
// <id>.{entry,start,end,due,until,wait}.second
|
|
||||||
// <id>.description
|
|
||||||
// <id>.project
|
|
||||||
// <id>.priority
|
|
||||||
// <id>.parent
|
|
||||||
// <id>.status
|
|
||||||
// <id>.tags
|
|
||||||
// <id>.urgency
|
|
||||||
// <id>.recur
|
|
||||||
// <id>.depends
|
|
||||||
//
|
|
||||||
// <uuid>.<?>
|
|
||||||
//
|
|
||||||
// TODO report.<name>. <-- context.reports
|
// TODO report.<name>. <-- context.reports
|
||||||
// TODO stats.<name> <-- context.stats
|
// TODO stats.<name> <-- context.stats
|
||||||
//
|
//
|
||||||
|
@ -93,8 +73,6 @@ const std::string DOM::get (const std::string& name)
|
||||||
{
|
{
|
||||||
int len = name.length ();
|
int len = name.length ();
|
||||||
Nibbler n (name);
|
Nibbler n (name);
|
||||||
int id;
|
|
||||||
std::string uuid;
|
|
||||||
|
|
||||||
// Primitives
|
// Primitives
|
||||||
if (is_primitive (name))
|
if (is_primitive (name))
|
||||||
|
@ -137,30 +115,6 @@ const std::string DOM::get (const std::string& name)
|
||||||
throw format (STRING_DOM_UNREC, name);
|
throw format (STRING_DOM_UNREC, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// <id>.<name>
|
|
||||||
else if (n.getInt (id))
|
|
||||||
{
|
|
||||||
if (n.skip ('.'))
|
|
||||||
{
|
|
||||||
std::string ref;
|
|
||||||
n.getUntilEOS (ref);
|
|
||||||
|
|
||||||
if (ref == "description")
|
|
||||||
;
|
|
||||||
// TODO return task.get ("description");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO <uuid>.<name>
|
|
||||||
else if (n.getUUID (uuid))
|
|
||||||
{
|
|
||||||
std::string attr;
|
|
||||||
if (n.skip ('.') &&
|
|
||||||
n.getUntilEOS (attr))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO report.
|
// TODO report.
|
||||||
// TODO stats.<name>
|
// TODO stats.<name>
|
||||||
|
|
||||||
|
@ -205,6 +159,129 @@ const std::string DOM::get (const std::string& name)
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DOM Supported References:
|
||||||
|
//
|
||||||
|
// TODO <id>.{entry,start,end,due,until,wait}
|
||||||
|
// TODO <id>.description
|
||||||
|
// TODO <id>.project
|
||||||
|
// TODO <id>.priority
|
||||||
|
// TODO <id>.parent
|
||||||
|
// TODO <id>.status
|
||||||
|
// TODO <id>.tags
|
||||||
|
// TODO <id>.urgency
|
||||||
|
// TODO <id>.recur
|
||||||
|
// TODO <id>.depends
|
||||||
|
//
|
||||||
|
// TODO <uuid>.{entry,start,end,due,until,wait}
|
||||||
|
// TODO <uuid>.description
|
||||||
|
// TODO <uuid>.project
|
||||||
|
// TODO <uuid>.priority
|
||||||
|
// TODO <uuid>.parent
|
||||||
|
// TODO <uuid>.status
|
||||||
|
// TODO <uuid>.tags
|
||||||
|
// TODO <uuid>.urgency
|
||||||
|
// TODO <uuid>.recur
|
||||||
|
// TODO <uuid>.depends
|
||||||
|
//
|
||||||
|
// {entry,start,end,due,until,wait}
|
||||||
|
// description
|
||||||
|
// project
|
||||||
|
// priority
|
||||||
|
// parent
|
||||||
|
// status
|
||||||
|
// tags
|
||||||
|
// urgency
|
||||||
|
// recur
|
||||||
|
// depends
|
||||||
|
//
|
||||||
|
const std::string DOM::get (const std::string& name, Task& task)
|
||||||
|
{
|
||||||
|
Nibbler n (name);
|
||||||
|
int id;
|
||||||
|
std::string uuid;
|
||||||
|
|
||||||
|
// Primitives
|
||||||
|
if (is_primitive (name))
|
||||||
|
return name;
|
||||||
|
|
||||||
|
// <id>.<name>
|
||||||
|
else if (n.getInt (id))
|
||||||
|
{
|
||||||
|
if (n.skip ('.'))
|
||||||
|
{
|
||||||
|
// TODO Obtain task 'id' from TDB2.
|
||||||
|
|
||||||
|
std::string attr;
|
||||||
|
n.getUntilEOS (attr);
|
||||||
|
|
||||||
|
if (attr == "description") return task.get ("description");
|
||||||
|
else if (attr == "status") return task.get ("status");
|
||||||
|
else if (attr == "project") return task.get ("project");
|
||||||
|
else if (attr == "priority") return task.get ("priority");
|
||||||
|
else if (attr == "parent") return task.get ("parent");
|
||||||
|
else if (attr == "tags") return task.get ("tags");
|
||||||
|
else if (attr == "urgency") return format (task.urgency (), 4, 3);
|
||||||
|
else if (attr == "recur") return task.get ("recur");
|
||||||
|
else if (attr == "depends") return task.get ("depends");
|
||||||
|
else if (attr == "entry") return task.get ("entry");
|
||||||
|
else if (attr == "start") return task.get ("start");
|
||||||
|
else if (attr == "end") return task.get ("end");
|
||||||
|
else if (attr == "due") return task.get ("due");
|
||||||
|
else if (attr == "until") return task.get ("until");
|
||||||
|
else if (attr == "wait") return task.get ("wait");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <uuid>.<name>
|
||||||
|
else if (n.getUUID (uuid))
|
||||||
|
{
|
||||||
|
if (n.skip ('.'))
|
||||||
|
{
|
||||||
|
// TODO Obtain task 'uuid' from TDB2.
|
||||||
|
|
||||||
|
std::string attr;
|
||||||
|
n.getUntilEOS (attr);
|
||||||
|
|
||||||
|
if (attr == "description") return task.get ("description");
|
||||||
|
else if (attr == "status") return task.get ("status");
|
||||||
|
else if (attr == "project") return task.get ("project");
|
||||||
|
else if (attr == "priority") return task.get ("priority");
|
||||||
|
else if (attr == "parent") return task.get ("parent");
|
||||||
|
else if (attr == "tags") return task.get ("tags");
|
||||||
|
else if (attr == "urgency") return format (task.urgency (), 4, 3);
|
||||||
|
else if (attr == "recur") return task.get ("recur");
|
||||||
|
else if (attr == "depends") return task.get ("depends");
|
||||||
|
else if (attr == "entry") return task.get ("entry");
|
||||||
|
else if (attr == "start") return task.get ("start");
|
||||||
|
else if (attr == "end") return task.get ("end");
|
||||||
|
else if (attr == "due") return task.get ("due");
|
||||||
|
else if (attr == "until") return task.get ("until");
|
||||||
|
else if (attr == "wait") return task.get ("wait");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [<task>.] <name>
|
||||||
|
if (name == "description") return task.get ("description");
|
||||||
|
else if (name == "status") return task.get ("status");
|
||||||
|
else if (name == "project") return task.get ("project");
|
||||||
|
else if (name == "priority") return task.get ("priority");
|
||||||
|
else if (name == "parent") return task.get ("parent");
|
||||||
|
else if (name == "tags") return task.get ("tags");
|
||||||
|
else if (name == "urgency") return format (task.urgency (), 4, 3);
|
||||||
|
else if (name == "recur") return task.get ("recur");
|
||||||
|
else if (name == "depends") return task.get ("depends");
|
||||||
|
else if (name == "entry") return task.get ("entry");
|
||||||
|
else if (name == "start") return task.get ("start");
|
||||||
|
else if (name == "end") return task.get ("end");
|
||||||
|
else if (name == "due") return task.get ("due");
|
||||||
|
else if (name == "until") return task.get ("until");
|
||||||
|
else if (name == "wait") return task.get ("wait");
|
||||||
|
|
||||||
|
// Delegate to the context-free version of DOM::get.
|
||||||
|
return this->get (name);
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void DOM::set (const std::string& name, const std::string& value)
|
void DOM::set (const std::string& name, const std::string& value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#define L10N // Localization complete.
|
#define L10N // Localization complete.
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <Task.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
class DOM
|
class DOM
|
||||||
|
@ -38,6 +39,7 @@ public:
|
||||||
~DOM ();
|
~DOM ();
|
||||||
|
|
||||||
const std::string get (const std::string&);
|
const std::string get (const std::string&);
|
||||||
|
const std::string get (const std::string&, Task&);
|
||||||
void set (const std::string&, const std::string&);
|
void set (const std::string&, const std::string&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -46,12 +46,6 @@ Expression::Expression (Arguments& arguments)
|
||||||
{
|
{
|
||||||
_args.dump ("Expression::Expression");
|
_args.dump ("Expression::Expression");
|
||||||
|
|
||||||
bool new_style = is_new_style () && context.config.getBoolean ("expressions");
|
|
||||||
if (new_style)
|
|
||||||
context.debug ("Filter --> new");
|
|
||||||
else
|
|
||||||
context.debug ("Filter --> old");
|
|
||||||
|
|
||||||
expand_sequence ();
|
expand_sequence ();
|
||||||
implicit_and ();
|
implicit_and ();
|
||||||
expand_tag ();
|
expand_tag ();
|
||||||
|
@ -84,108 +78,231 @@ bool Expression::eval (Task& task)
|
||||||
{
|
{
|
||||||
if (arg->second == "op")
|
if (arg->second == "op")
|
||||||
{
|
{
|
||||||
// We already know it's an operator, but we need to know more. Or do we?
|
|
||||||
/*
|
|
||||||
char type;
|
|
||||||
int precedence;
|
|
||||||
char associativity;
|
|
||||||
Arguments::is_operator (arg->first, type, precedence, associativity);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO Need helpers that pop, and error out if necessary.
|
// TODO Need helpers that pop, and error out if necessary.
|
||||||
if (arg->first == "+")
|
if (arg->first == "and")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
Variant right (value_stack.back ());
|
Variant right (value_stack.back ());
|
||||||
value_stack.pop_back ();
|
value_stack.pop_back ();
|
||||||
Variant left (value_stack.back ());
|
Variant left (value_stack.back ());
|
||||||
value_stack.pop_back ();
|
value_stack.pop_back ();
|
||||||
|
|
||||||
context.debug ("eval left=" + left.format ());
|
left = left && right;
|
||||||
context.debug ("eval right=" + right.format ());
|
|
||||||
left = left + right;
|
|
||||||
context.debug ("eval + --> " + left.format ());
|
|
||||||
|
|
||||||
value_stack.push_back (left);
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "and")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (arg->first == "xor")
|
else if (arg->first == "xor")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = (left && !right) || (!left && right);
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "or")
|
else if (arg->first == "or")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left || right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "<=")
|
else if (arg->first == "<=")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left <= right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == ">=")
|
else if (arg->first == ">=")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left >= right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "!~")
|
else if (arg->first == "!~")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
|
if left == "description" then it really means description or annotations or project.
|
||||||
|
if left == "tags" then it just means tags.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "!=")
|
else if (arg->first == "!=")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left != right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "=")
|
else if (arg->first == "=")
|
||||||
{
|
{
|
||||||
}
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
else if (arg->first == "^")
|
Variant right (value_stack.back ());
|
||||||
{
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left == right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == ">")
|
else if (arg->first == ">")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left > right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "~")
|
else if (arg->first == "~")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
|
if left == "description" then it really means description or annotations or project.
|
||||||
|
if left == "tags" then it just means tags.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "!")
|
else if (arg->first == "!")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 1)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = ! left;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "*")
|
else if (arg->first == "*")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left * right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "/")
|
else if (arg->first == "/")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left / right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "%")
|
else if (arg->first == "%")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
// TODO Implement modulus.
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "+")
|
else if (arg->first == "+")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left + right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "-")
|
else if (arg->first == "-")
|
||||||
{
|
{
|
||||||
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
|
Variant right (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
|
left = left - right;
|
||||||
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (arg->first == "<")
|
else if (arg->first == "<")
|
||||||
{
|
{
|
||||||
}
|
if (value_stack.size () < 2)
|
||||||
|
throw std::string ("Error: Insufficient operands.");
|
||||||
|
|
||||||
else if (arg->first == "(")
|
Variant right (value_stack.back ());
|
||||||
{
|
value_stack.pop_back ();
|
||||||
}
|
Variant left (value_stack.back ());
|
||||||
|
value_stack.pop_back ();
|
||||||
|
|
||||||
else if (arg->first == ")")
|
left = left < right;
|
||||||
{
|
value_stack.push_back (left);
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -196,7 +313,7 @@ bool Expression::eval (Task& task)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (arg->second == "lvalue")
|
if (arg->second == "lvalue")
|
||||||
value_stack.push_back (Variant (context.dom.get (arg->first)));
|
value_stack.push_back (Variant (context.dom.get (arg->first, task)));
|
||||||
|
|
||||||
else if (arg->second == "int")
|
else if (arg->second == "int")
|
||||||
value_stack.push_back (Variant ((int) strtol (arg->first.c_str (), NULL, 10)));
|
value_stack.push_back (Variant ((int) strtol (arg->first.c_str (), NULL, 10)));
|
||||||
|
@ -212,12 +329,11 @@ bool Expression::eval (Task& task)
|
||||||
else
|
else
|
||||||
throw std::string ("Error: Expression::eval unrecognized operand '") + + "'.";
|
throw std::string ("Error: Expression::eval unrecognized operand '") + + "'.";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coerce stack element to boolean.
|
// Coerce stack element to boolean.
|
||||||
Variant result (value_stack.back ());
|
Variant result (value_stack.back ());
|
||||||
context.debug ("eval result=" + result.format ());
|
//context.debug ("eval result=" + result.format ());
|
||||||
value_stack.pop_back ();
|
value_stack.pop_back ();
|
||||||
bool pass_fail = result.boolean ();
|
bool pass_fail = result.boolean ();
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,9 @@ private:
|
||||||
|
|
||||||
bool is_new_style ();
|
bool is_new_style ();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Arguments _args;
|
Arguments _args;
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,7 +92,7 @@ int CmdCustom::execute (std::string& output)
|
||||||
context.tdb.commit ();
|
context.tdb.commit ();
|
||||||
context.tdb.unlock ();
|
context.tdb.unlock ();
|
||||||
|
|
||||||
////////////////////////////////////
|
// Filter.
|
||||||
Arguments f = context.args.extract_read_only_filter ();
|
Arguments f = context.args.extract_read_only_filter ();
|
||||||
Expression e (f);
|
Expression e (f);
|
||||||
|
|
||||||
|
@ -102,12 +102,6 @@ int CmdCustom::execute (std::string& output)
|
||||||
if (e.eval (*task))
|
if (e.eval (*task))
|
||||||
filtered.push_back (*task);
|
filtered.push_back (*task);
|
||||||
|
|
||||||
std::cout << "# tasks=" << tasks.size () << "\n"
|
|
||||||
<< "# filtered=" << filtered.size () << "\n";
|
|
||||||
//return 0;
|
|
||||||
|
|
||||||
////////////////////////////////////
|
|
||||||
|
|
||||||
// Sort the tasks.
|
// Sort the tasks.
|
||||||
std::vector <int> sequence;
|
std::vector <int> sequence;
|
||||||
for (unsigned int i = 0; i < filtered.size (); ++i)
|
for (unsigned int i = 0; i < filtered.size (); ++i)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue