Expressions

- Fixed some compiler warnings.
- Added DOM detection of primitives: int, double, string.
- Began implementation of DOM task access.
- Implemented support for .startswith, .endswith, .word and .noword.
- Removed obsolete subst.t.cpp.
This commit is contained in:
Paul Beckingham 2011-06-09 22:19:10 -04:00
parent 199bb85d88
commit 2ab24fa08b
8 changed files with 119 additions and 191 deletions

View file

@ -189,15 +189,6 @@ void Arguments::categorize ()
std::vector <std::pair <std::string, std::string> >::iterator arg;
for (arg = this->begin (); arg != this->end (); ++arg)
{
/*
std::cout << "# " << leftJustify (arg->first, 36)
<< " found_command=" << (found_command ? "true " : "false")
<< " found_sequence=" << (found_sequence ? "true " : "false")
<< " found_something_after_sequence=" << (found_something_after_sequence ? "true " : "false")
<< " found_non_sequence=" << (found_non_sequence ? "true " : "false")
<< "\n";
*/
if (!terminated)
{
// Nothing after -- is to be interpreted in any way.
@ -545,7 +536,7 @@ std::vector <std::string> Arguments::list ()
std::vector <std::string> Arguments::operator_list ()
{
std::vector <std::string> all;
for (int i = 0; i < NUM_OPERATORS; ++i)
for (unsigned int i = 0; i < NUM_OPERATORS; ++i)
all.push_back (operators[i].op);
return all;
@ -628,6 +619,7 @@ bool Arguments::is_attr (const std::string& input)
n.getUntilEOS (value) ||
n.depleted ())
{
// TODO Validate and expand attribute name
return true;
}
}
@ -675,6 +667,8 @@ bool Arguments::is_attmod (const std::string& input)
n.getUntilEOS (value) ||
n.depleted ())
{
// TODO Validate and expand attribute name
// TODO Validate and expand modifier name
return true;
}
}

View file

@ -27,6 +27,7 @@
#include <sstream>
#include <Context.h>
#include <Nibbler.h>
#include <text.h>
#include <i18n.h>
#include <DOM.h>
@ -52,28 +53,59 @@ DOM::~DOM ()
}
////////////////////////////////////////////////////////////////////////////////
// TODO <id>. <-- context.tdb2
// TODO <uuid>. <-- context.tdb2
// rc.<name> <-- context.config
// DOM Supported References:
// rc.<name>
//
// context.program
// context.args
// context.width
// 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 stats.<name> <-- context.stats
// TODO context.<name> <-- args, ...
//
// system.<name> <-- context.system
// system.version
// system.lua.version
// system.os
const std::string DOM::get (const std::string& name)
{
int len = name.length ();
Nibbler n (name);
int id;
std::string uuid;
// Primitives
if (is_primitive (name))
return name;
// rc. --> context.config
if (len > 3 &&
else if (len > 3 &&
name.substr (0, 3) == "rc.")
{
return context.config.get (name.substr (3));
}
// context.*
else if (len > 8 &&
name.substr (0, 8) == "context.")
{
@ -103,8 +135,25 @@ const std::string DOM::get (const std::string& name)
throw std::string ("DOM: Cannot get unrecognized name '") + name + "'.";
}
// TODO <id>.
// TODO <uuid>.
// <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))
{
}
// TODO report.
// TODO stats.<name>
@ -167,4 +216,29 @@ void DOM::set (const std::string& name, const std::string& value)
}
////////////////////////////////////////////////////////////////////////////////
// TODO This should return a Variant.
bool DOM::is_primitive (const std::string& input)
{
std::string s;
double d;
int i;
// String?
Nibbler n (input);
if (n.getQuoted ('"', s) && n.depleted ())
return true;
// Number?
n = Nibbler (input);
if (n.getNumber (d) && n.depleted ())
return true;
// Integer?
n = Nibbler (input);
if (n.getInt (i) && n.depleted ())
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -41,6 +41,7 @@ public:
void set (const std::string&, const std::string&);
private:
bool is_primitive (const std::string&);
};
#endif

View file

@ -39,10 +39,10 @@ extern Context context;
Expression::Expression (Arguments& arguments)
: _original (arguments)
{
expand_sequence ();
to_infix ();
expand_expression ();
to_postfix ();
expand_sequence (); // Convert sequence to expression.
to_infix (); // Old-style to infix.
expand_expression (); // Lex expressions to dom, op tokens.
to_postfix (); // Infix --> Postfix
}
////////////////////////////////////////////////////////////////////////////////
@ -211,6 +211,7 @@ void Expression::expand_attmod (const std::string& input)
// Always quote the value, so that empty values, or values containing spaces
// are preserved.
std::string raw_value = value;
value = "\"" + value + "\"";
if (mod == "before" || mod == "under" || mod == "below")
@ -263,19 +264,27 @@ void Expression::expand_attmod (const std::string& input)
}
else if (mod == "startswith" || mod == "left")
{
// TODO ?
_infix.push_back (std::make_pair (name, "dom"));
_infix.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair ("^" + raw_value, "rx"));
}
else if (mod == "endswith" || mod == "right")
{
// TODO ?
_infix.push_back (std::make_pair (name, "dom"));
_infix.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair (raw_value + "$", "rx"));
}
else if (mod == "word")
{
// TODO ?
_infix.push_back (std::make_pair (name, "dom"));
_infix.push_back (std::make_pair ("~", "op"));
_infix.push_back (std::make_pair ("\\b" + raw_value + "\\b", "rx"));
}
else if (mod == "noword")
{
// TODO ?
_infix.push_back (std::make_pair (name, "dom"));
_infix.push_back (std::make_pair ("!~", "op"));
_infix.push_back (std::make_pair ("\\b" + raw_value + "\\b", "rx"));
}
}
@ -363,7 +372,6 @@ void Expression::expand_expression ()
//
// Rules:
// 1. Two adjacent non-operator arguments have an 'and' inserted between them.
// 2. Any argument of type "exp" is lexed and replaced by tokens.
//
void Expression::to_infix ()
{

View file

@ -8,8 +8,8 @@ include_directories (${CMAKE_SOURCE_DIR}
set (test_SRCS arguments.t att.t autocomplete.t color.t config.t date.t
directory.t dom.t duration.t file.t filt.t i18n.t json.t lexer.t
list.t nibbler.t path.t record.t rx.t seq.t subst.t t.benchmark.t
t.t taskmod.t tdb.t tdb2.t text.t uri.t util.t variant.t view.t
list.t nibbler.t path.t record.t rx.t seq.t t.benchmark.t t.t
taskmod.t tdb.t tdb2.t text.t uri.t util.t variant.t view.t
json_test)
add_custom_target (test ./run_all DEPENDS ${test_SRCS}

View file

@ -1,151 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
// taskwarrior - a command line task list manager.
//
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
// All rights reserved.
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the
//
// Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor,
// Boston, MA
// 02110-1301
// USA
//
////////////////////////////////////////////////////////////////////////////////
#include <Context.h>
#include <Task.h>
#include <Subst.h>
#include <test.h>
Context context;
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
UnitTest t (18);
Task task;
task.set ("description", "one two three four");
context.config.set ("search.case.sensitive", "yes");
Subst s;
t.ok (s.valid ("/a/b/"), "valid /a/b/");
t.ok (s.valid ("/two/TWO/"), "valid /two/TWO/");
t.ok (s.valid ("/e /E /g"), "valid /e /E /g");
t.ok (s.valid ("/from/to/g"), "valid /from/to/g");
t.ok (s.valid ("/long string//"), "valid /long string//");
t.ok (s.valid ("//fail/"), "valid //fail/");
bool good = true;
try { s.parse ("/a/b/x"); } catch (...) { good = false; }
t.notok (good, "failed /a/b/x");
good = true;
try { s.parse ("//to/"); } catch (...) { good = false; }
t.notok (good, "failed //to/");
good = true;
try { s.parse ("/two/TWO/"); } catch (...) { good = false; }
t.ok (good, "parsed /two/TWO/");
if (good)
{
std::string description = task.get ("description");
std::vector <Att> annotations;
task.getAnnotations (annotations);
s.apply (description, annotations);
t.is (description, "one TWO three four", "single word subst");
}
else
{
t.fail ("failed to parse '/two/TWO/'");
}
good = true;
try { s.parse ("/e /E /g"); } catch (...) { good = false; }
t.ok (good, "parsed /e /E /g");
if (good)
{
std::string description = task.get ("description");
std::vector <Att> annotations;
task.getAnnotations (annotations);
s.apply (description, annotations);
t.is (description, "onE two threE four", "multiple word subst");
}
else
{
t.fail ("failed to parse '/e /E /g'");
}
// Now repeat the last two tests with a case-insensitive setting.
context.config.set ("search.case.sensitive", "no");
good = true;
try { s.parse ("/tWo/TWO/"); } catch (...) { good = false; }
t.ok (good, "parsed /tWo/TWO/ (rc.search.case.sensitive=no)");
if (good)
{
std::string description = task.get ("description");
std::vector <Att> annotations;
task.getAnnotations (annotations);
s.apply (description, annotations);
t.is (description, "one TWO three four", "single word subst (rc.search.case.sensitive=no)");
}
else
{
t.fail ("failed to parse '/tWo/TWO/' (rc.search.case.sensitive=no)");
}
good = true;
try { s.parse ("/E /E /g"); } catch (...) { good = false; }
t.ok (good, "parsed /E /E /g (rc.search.case.sensitive=no)");
if (good)
{
std::string description = task.get ("description");
std::vector <Att> annotations;
task.getAnnotations (annotations);
s.apply (description, annotations);
t.is (description, "onE two threE four", "multiple word subst (rc.search.case.sensitive=no)");
}
else
{
t.fail ("failed to parse '/E /E /g' (rc.search.case.sensitive=no)");
}
context.config.set ("search.case.sensitive", "yes");
good = true;
try { s.parse ("/from/to/g"); } catch (...) { good = false; }
t.ok (good, "parsed /from/to/g");
if (good)
{
std::string description = task.get ("description");
std::vector <Att> annotations;
task.getAnnotations (annotations);
s.apply (description, annotations);
t.is (description, "one two three four", "multiple word subst mismatch");
}
else
{
t.fail ("failed to parse '/from/to/g'");
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -38,8 +38,9 @@ void get (std::vector <Task>& pending, std::vector <Task>& completed)
TDB tdb;
tdb.location (".");
tdb.lock ();
tdb.loadPending (pending, context.filter);
tdb.loadCompleted (completed, context.filter);
Filter filter;
tdb.loadPending (pending, filter);
tdb.loadCompleted (completed, filter);
tdb.unlock ();
}
@ -99,7 +100,7 @@ int main (int argc, char** argv)
completed.clear ();
tdb.lock ();
tdb.load (all, context.filter);
tdb.load (all, filter);
all[0].set ("name", "value2");
tdb.update (all[0]); // P1 C0 N0 M1
tdb.commit (); // P1 C0 N0 M0
@ -117,7 +118,7 @@ int main (int argc, char** argv)
all.clear ();
tdb.lock ();
tdb.loadPending (all, context.filter);
tdb.loadPending (all, filter);
all[0].setStatus (Task::completed);
tdb.update (all[0]); // P1 C0 N0 M1
Task t2 ("[foo:\"bar\" status:\"pending\"]");

View file

@ -38,8 +38,9 @@ void get (std::vector <Task>& pending, std::vector <Task>& completed)
TDB tdb;
tdb.location (".");
tdb.lock ();
tdb.loadPending (pending, context.filter);
tdb.loadCompleted (completed, context.filter);
Filter filter;
tdb.loadPending (pending, filter);
tdb.loadCompleted (completed, filter);
tdb.unlock ();
}