Expressions
- Improved strictness of attr and attmod detection, although it needs more. - Added unit tests arguments.t.cpp, to test the detection methods.
This commit is contained in:
@@ -541,6 +541,16 @@ std::vector <std::string> Arguments::list ()
|
||||
return all;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string> Arguments::operator_list ()
|
||||
{
|
||||
std::vector <std::string> all;
|
||||
for (int i = 0; i < NUM_OPERATORS; ++i)
|
||||
all.push_back (operators[i].op);
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Arguments::combine ()
|
||||
{
|
||||
@@ -594,20 +604,29 @@ bool Arguments::is_command (
|
||||
bool Arguments::is_attr (const std::string& input)
|
||||
{
|
||||
Nibbler n (input);
|
||||
|
||||
// Ensure a clean parse.
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
||||
if (n.getUntilOneOf ("=:", name))
|
||||
{
|
||||
if (name.length () == 0)
|
||||
return false;
|
||||
|
||||
if (n.skip (':') ||
|
||||
n.skip ('='))
|
||||
{
|
||||
// Exclude certain URLs, that look like attrs.
|
||||
if (input.find ('@') <= n.cursor () ||
|
||||
input.find ('/') <= n.cursor ())
|
||||
return false;
|
||||
|
||||
// Both quoted and unquoted Att's are accepted.
|
||||
// Consider removing this for a stricter parse.
|
||||
if (n.getQuoted ('"', value) ||
|
||||
n.getUntilEOS (value))
|
||||
if (n.getQuoted ('"', value) ||
|
||||
n.getQuoted ('\'', value) ||
|
||||
n.getUntil (' ', value) ||
|
||||
n.getUntilEOS (value) ||
|
||||
n.depleted ())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -622,25 +641,39 @@ bool Arguments::is_attr (const std::string& input)
|
||||
bool Arguments::is_attmod (const std::string& input)
|
||||
{
|
||||
Nibbler n (input);
|
||||
std::string name;
|
||||
std::string modifier;
|
||||
std::string value;
|
||||
|
||||
// Ensure a clean parse.
|
||||
std::string ignored;
|
||||
|
||||
if (n.getUntil (".", ignored))
|
||||
if (n.getUntilOneOf (".", name))
|
||||
{
|
||||
if (name.length () == 0)
|
||||
return false;
|
||||
|
||||
if (n.skip ('.'))
|
||||
{
|
||||
n.skip ('~');
|
||||
n.getUntilOneOf (":=", ignored);
|
||||
n.getUntilOneOf (":=", modifier);
|
||||
|
||||
if (modifier.length () == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (n.skip (':') ||
|
||||
n.skip ('='))
|
||||
{
|
||||
// Exclude certain URLs, that look like attrs.
|
||||
if (input.find ('@') <= n.cursor () ||
|
||||
input.find ('/') <= n.cursor ())
|
||||
return false;
|
||||
|
||||
// Both quoted and unquoted Att's are accepted.
|
||||
// Consider removing this for a stricter parse.
|
||||
if (n.getQuoted ('"', ignored) ||
|
||||
n.getUntilEOS (ignored))
|
||||
if (n.getQuoted ('"', value) ||
|
||||
n.getQuoted ('\'', value) ||
|
||||
n.getUntil (' ', value) ||
|
||||
n.getUntilEOS (value) ||
|
||||
n.depleted ())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -654,17 +687,20 @@ bool Arguments::is_attmod (const std::string& input)
|
||||
// /<from>/<to>/[g]
|
||||
bool Arguments::is_subst (const std::string& input)
|
||||
{
|
||||
std::string ignored;
|
||||
std::string from;
|
||||
std::string to;
|
||||
Nibbler n (input);
|
||||
if (n.skip ('/') &&
|
||||
n.getUntil ('/', ignored) &&
|
||||
n.getUntil ('/', from) &&
|
||||
n.skip ('/') &&
|
||||
n.getUntil ('/', ignored) &&
|
||||
n.getUntil ('/', to) &&
|
||||
n.skip ('/'))
|
||||
{
|
||||
n.skip ('g');
|
||||
if (n.depleted ())
|
||||
return ! Directory (input).exists (); // Ouch - expensive call.
|
||||
if (n.depleted () &&
|
||||
! Directory (input).exists () && // Ouch - expensive call.
|
||||
from.length ())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -747,8 +783,13 @@ bool Arguments::is_tag (const std::string& input)
|
||||
{
|
||||
if (input.length () > 1 &&
|
||||
(input[0] == '+' ||
|
||||
input[0] == '-'))
|
||||
input[0] == '-') &&
|
||||
noSpaces (input) &&
|
||||
input.find ('+', 1) == std::string::npos &&
|
||||
input.find ('-', 1) == std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
void resolve_aliases ();
|
||||
|
||||
std::vector <std::string> list ();
|
||||
static std::vector <std::string> operator_list ();
|
||||
std::string combine ();
|
||||
|
||||
bool find_command (std::string&);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <sstream>
|
||||
#include <Context.h>
|
||||
#include <Lexer.h>
|
||||
#include <text.h>
|
||||
#include <Expression.h>
|
||||
|
||||
extern Context context;
|
||||
@@ -55,6 +56,22 @@ bool Expression::eval (Task& task)
|
||||
std::vector <std::pair <std::string, std::string> >::iterator arg;
|
||||
for (arg = _postfix.begin (); arg != _postfix.end (); ++arg)
|
||||
{
|
||||
// if (arg->second != "op")
|
||||
// eval_stack.push_back (*arg);
|
||||
|
||||
// else
|
||||
// {
|
||||
// if (arg->first == "+")
|
||||
// {
|
||||
// pop
|
||||
// pop
|
||||
// add the two operands
|
||||
// push result
|
||||
// }
|
||||
// else if ()
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -85,7 +102,10 @@ void Expression::expand_sequence ()
|
||||
|
||||
// If there is no sequence, we're done.
|
||||
if (ids.size () == 0 && uuids.size () == 0)
|
||||
{
|
||||
_sequenced = _original;
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct the algebraic form.
|
||||
std::stringstream sequence;
|
||||
@@ -166,6 +186,10 @@ void Expression::expand_attr (const std::string& input)
|
||||
std::string value;
|
||||
Arguments::extract_attr (input, name, value);
|
||||
|
||||
// Always quote the value, so that empty values, or values containing spaces
|
||||
// are preserved.
|
||||
value = "\"" + value + "\"";
|
||||
|
||||
_infix.push_back (std::make_pair (name, "dom"));
|
||||
_infix.push_back (std::make_pair ("=", "op"));
|
||||
_infix.push_back (std::make_pair (value, "exp"));
|
||||
@@ -185,6 +209,10 @@ void Expression::expand_attmod (const std::string& input)
|
||||
std::string sense;
|
||||
Arguments::extract_attmod (input, name, mod, value, sense);
|
||||
|
||||
// Always quote the value, so that empty values, or values containing spaces
|
||||
// are preserved.
|
||||
value = "\"" + value + "\"";
|
||||
|
||||
if (mod == "before" || mod == "under" || mod == "below")
|
||||
{
|
||||
_infix.push_back (std::make_pair (name, "dom"));
|
||||
@@ -284,12 +312,17 @@ void Expression::expand_expression ()
|
||||
{
|
||||
Arguments temp;
|
||||
|
||||
// Get a list of all operators.
|
||||
std::vector <std::string> operators = Arguments::operator_list ();
|
||||
|
||||
// Look for all 'exp' args.
|
||||
std::vector <std::pair <std::string, std::string> >::iterator arg;
|
||||
for (arg = _infix.begin (); arg != _infix.end (); ++arg)
|
||||
{
|
||||
if (arg->second == "exp")
|
||||
{
|
||||
Lexer lexer (arg->first);
|
||||
/* obsolete */
|
||||
Lexer lexer (unquoteText (arg->first));
|
||||
lexer.skipWhitespace (true);
|
||||
lexer.coalesceAlpha (true);
|
||||
lexer.coalesceDigits (true);
|
||||
@@ -306,6 +339,12 @@ void Expression::expand_expression ()
|
||||
else
|
||||
temp.push_back (std::make_pair (*token, "dom"));
|
||||
}
|
||||
/* obsolete */
|
||||
/* proposed */
|
||||
/*
|
||||
Nibbler n (arg->first);
|
||||
*/
|
||||
/* proposed */
|
||||
}
|
||||
else
|
||||
temp.push_back (*arg);
|
||||
@@ -322,8 +361,6 @@ void Expression::expand_expression ()
|
||||
// Converts: <term1> <term2> <op> <exp>
|
||||
// to: <term1> and <term2> <op> <token> <token> <token>
|
||||
//
|
||||
//
|
||||
//
|
||||
// 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.
|
||||
@@ -368,7 +405,10 @@ void Expression::to_infix ()
|
||||
else if (arg->second == "word")
|
||||
expand_word (arg->first);
|
||||
|
||||
// Expressions will be converted later.
|
||||
else if (arg->second == "op")
|
||||
_infix.push_back (*arg);
|
||||
|
||||
// Skip expressions, convert later.
|
||||
else if (arg->second == "exp")
|
||||
_infix.push_back (*arg);
|
||||
|
||||
@@ -383,6 +423,7 @@ void Expression::to_infix ()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Dijkstra Shunting Algorithm.
|
||||
// http://en.wikipedia.org/wiki/Shunting-yard_algorithm
|
||||
//
|
||||
// While there are tokens to be read:
|
||||
// Read a token.
|
||||
@@ -501,9 +542,12 @@ bool Expression::is_new_style ()
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TODO Remove?
|
||||
void Expression::dump (const std::string& label)
|
||||
void Expression::dump ()
|
||||
{
|
||||
_original.dump ("Original Arguments");
|
||||
_sequenced.dump ("Sequence Expanded");
|
||||
_infix.dump ("Converted to Infix");
|
||||
_postfix.dump ("Converted to Postfix");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
private:
|
||||
void expand_sequence ();
|
||||
void expand_expression ();
|
||||
|
||||
void expand_tag (const std::string&);
|
||||
void expand_attr (const std::string&);
|
||||
void expand_attmod (const std::string&);
|
||||
@@ -52,7 +53,7 @@ private:
|
||||
void to_infix ();
|
||||
void to_postfix ();
|
||||
bool is_new_style ();
|
||||
void dump (const std::string&);
|
||||
void dump ();
|
||||
|
||||
private:
|
||||
Arguments _original;
|
||||
|
||||
@@ -97,15 +97,21 @@ int CmdCustom::execute (std::string& output)
|
||||
Expression e (f);
|
||||
|
||||
return 0;
|
||||
// TODO e.apply (tasks);
|
||||
|
||||
std::vector <Task> filtered;
|
||||
std::vector <Task>::iterator task;
|
||||
for (task = tasks.begin (); task != tasks.end (); ++task)
|
||||
if (e.eval (*task))
|
||||
filtered.push_back (*task);
|
||||
|
||||
////////////////////////////////////
|
||||
|
||||
// Sort the tasks.
|
||||
std::vector <int> sequence;
|
||||
for (unsigned int i = 0; i < tasks.size (); ++i)
|
||||
for (unsigned int i = 0; i < filtered.size (); ++i)
|
||||
sequence.push_back (i);
|
||||
|
||||
sort_tasks (tasks, sequence, reportSort);
|
||||
sort_tasks (filtered, sequence, reportSort);
|
||||
|
||||
// Configure the view.
|
||||
ViewTask view;
|
||||
@@ -153,21 +159,21 @@ return 0;
|
||||
// Render.
|
||||
// TODO Consider rc.verbose
|
||||
std::stringstream out;
|
||||
if (tasks.size ())
|
||||
if (filtered.size ())
|
||||
{
|
||||
view.truncateRows (maxrows);
|
||||
view.truncateLines (maxlines);
|
||||
|
||||
out << optionalBlankLine ()
|
||||
<< view.render (tasks, sequence)
|
||||
<< view.render (filtered, sequence)
|
||||
<< optionalBlankLine ()
|
||||
<< tasks.size ()
|
||||
<< (tasks.size () == 1 ? " task" : " tasks");
|
||||
<< filtered.size ()
|
||||
<< (filtered.size () == 1 ? " task" : " tasks");
|
||||
|
||||
if (maxrows && maxrows < (int)tasks.size ())
|
||||
if (maxrows && maxrows < (int)filtered.size ())
|
||||
out << ", " << maxrows << " shown";
|
||||
|
||||
if (maxlines && maxlines < (int)tasks.size ())
|
||||
if (maxlines && maxlines < (int)filtered.size ())
|
||||
out << ", truncated to " << maxlines - table_header << " lines";
|
||||
|
||||
out << "\n";
|
||||
|
||||
Reference in New Issue
Block a user