From 2ab24fa08b96ddafd29895cb7fe48c1d7595a253 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Thu, 9 Jun 2011 22:19:10 -0400 Subject: [PATCH] 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. --- src/Arguments.cpp | 14 ++-- src/DOM.cpp | 100 +++++++++++++++++++++++++---- src/DOM.h | 1 + src/Expression.cpp | 26 +++++--- test/CMakeLists.txt | 4 +- test/subst.t.cpp | 151 -------------------------------------------- test/tdb.t.cpp | 9 +-- test/tdb2.t.cpp | 5 +- 8 files changed, 119 insertions(+), 191 deletions(-) delete mode 100644 test/subst.t.cpp diff --git a/src/Arguments.cpp b/src/Arguments.cpp index c08016efe..006dfde7b 100644 --- a/src/Arguments.cpp +++ b/src/Arguments.cpp @@ -189,15 +189,6 @@ void Arguments::categorize () std::vector >::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 Arguments::list () std::vector Arguments::operator_list () { std::vector 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; } } diff --git a/src/DOM.cpp b/src/DOM.cpp index 38dfe9e53..b7088554a 100644 --- a/src/DOM.cpp +++ b/src/DOM.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -52,28 +53,59 @@ DOM::~DOM () } //////////////////////////////////////////////////////////////////////////////// -// TODO . <-- context.tdb2 -// TODO . <-- context.tdb2 -// rc. <-- context.config -// TODO report.. <-- context.reports -// TODO stats. <-- context.stats -// TODO context. <-- args, ... +// DOM Supported References: +// rc. // -// system. <-- context.system -// system.version -// system.lua.version -// system.os +// context.program +// context.args +// context.width +// context.height +// +// . +// .{entry,start,end,due,until,wait} +// .{entry,start,end,due,until,wait}.year +// .{entry,start,end,due,until,wait}.month +// .{entry,start,end,due,until,wait}.day +// .{entry,start,end,due,until,wait}.hour +// .{entry,start,end,due,until,wait}.minute +// .{entry,start,end,due,until,wait}.second +// .description +// .project +// .priority +// .parent +// .status +// .tags +// .urgency +// .recur +// .depends +// +// . +// +// TODO report.. <-- context.reports +// TODO stats. <-- context.stats +// +// 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 . - // TODO . + // . + else if (n.getInt (id)) + { + if (n.skip ('.')) + { + std::string ref; + n.getUntilEOS (ref); + + if (ref == "description") + ; + // TODO return task.get ("description"); + } + } + + // TODO . + else if (n.getUUID (uuid)) + { + } + // TODO report. // TODO stats. @@ -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; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/DOM.h b/src/DOM.h index a7c1d98ad..d5b553902 100644 --- a/src/DOM.h +++ b/src/DOM.h @@ -41,6 +41,7 @@ public: void set (const std::string&, const std::string&); private: + bool is_primitive (const std::string&); }; #endif diff --git a/src/Expression.cpp b/src/Expression.cpp index 346d59dac..c76f3f81e 100644 --- a/src/Expression.cpp +++ b/src/Expression.cpp @@ -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 () { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 50e087a64..0519c85ba 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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} diff --git a/test/subst.t.cpp b/test/subst.t.cpp deleted file mode 100644 index 8492cb08a..000000000 --- a/test/subst.t.cpp +++ /dev/null @@ -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 -#include -#include -#include - -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 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 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 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 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 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; -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/test/tdb.t.cpp b/test/tdb.t.cpp index 581bfb965..11c4067cb 100644 --- a/test/tdb.t.cpp +++ b/test/tdb.t.cpp @@ -38,8 +38,9 @@ void get (std::vector & pending, std::vector & 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\"]"); diff --git a/test/tdb2.t.cpp b/test/tdb2.t.cpp index f41e515c5..401c86aed 100644 --- a/test/tdb2.t.cpp +++ b/test/tdb2.t.cpp @@ -38,8 +38,9 @@ void get (std::vector & pending, std::vector & 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 (); }