CLI2: Added conditional expression eval

- Only non-'string' type attributes ('numeric', 'date', 'duration') support the
  evaluation of values in FILTER arguments, for example:
    due.before:now+1d
  If evaluation is supported, values need to be lexed into tokens, and if there
  are multiple tokens, parenthesize the set.
This commit is contained in:
Paul Beckingham 2015-07-13 01:09:11 -04:00
parent 9f2efa67c2
commit a09a2bc241
2 changed files with 82 additions and 1 deletions

View file

@ -1068,10 +1068,31 @@ void CLI2::desugarFilterAttributes ()
if (value == "")
value = "''";
// Some values are expressions, which need to be lexed. The best way to
// determine whether an expression is either a single value, or needs to
// be lexed, is to lex it and count the tokens. For example:
// now+1d
// This should be lexed and surrounded by parentheses:
// (
// now
// +
// 1d
// )
// Use this sequence in place of a single value.
std::vector <A2> values = lexExpression (value);
if (context.config.getInteger ("debug.parser") >= 3)
{
context.debug ("CLI2::lexExpression " + name + ":" + value);
for (auto& v : values)
context.debug (" " + v.dump ());
context.debug (" ");
}
bool found = false;
std::string canonical;
if (canonicalize (canonical, "pseudo", name))
{
// No eval.
A2 lhs (raw, Lexer::Type::identifier);
lhs.attribute ("canonical", canonical);
lhs.attribute ("value", value);
@ -1082,6 +1103,19 @@ void CLI2::desugarFilterAttributes ()
else if (canonicalize (canonical, "attribute", name) ||
canonicalize (canonical, "uda", name))
{
// Certain attribute types do not suport math.
// string --> no
// numeric --> yes
// date --> yes
// duration --> yes
bool evalSupported = true;
Column* col = context.columns[canonical];
if (col &&
col->type () == "string")
{
evalSupported = false;
}
// TODO The "!" modifier is being dropped.
A2 lhs (name, Lexer::Type::dom);
@ -1178,7 +1212,13 @@ void CLI2::desugarFilterAttributes ()
reconstructed.push_back (lhs);
reconstructed.push_back (op);
reconstructed.push_back (rhs);
if (values.size () == 1 || ! evalSupported)
reconstructed.push_back (rhs);
else
for (auto& v : values)
reconstructed.push_back (v);
found = true;
}
@ -1791,3 +1831,43 @@ void CLI2::defaultCommand ()
}
////////////////////////////////////////////////////////////////////////////////
// Some values are expressions, which need to be lexed. The best way to
// determine whether an expression is either a single value, or needs to be
// lexed, is to lex it and count the tokens. For example:
// now+1d
// This should be lexed and surrounded by parentheses:
// (
// now
// +
// 1d
// )
std::vector <A2> CLI2::lexExpression (const std::string& expression)
{
std::vector <A2> lexed;
std::string lexeme;
Lexer::Type type;
Lexer lex (expression);
while (lex.token (lexeme, type))
{
A2 token (lexeme, type);
token.tag ("FILTER");
lexed.push_back (token);
}
// If there were multiple tokens, parenthesize, because this expression will
// be used as a value.
if (lexed.size () > 1)
{
A2 openParen ("(", Lexer::Type::op);
openParen.tag ("FILTER");
A2 closeParen (")", Lexer::Type::op);
closeParen.tag ("FILTER");
lexed.insert (lexed.begin (), openParen);
lexed.push_back (closeParen);
}
return lexed;
}
////////////////////////////////////////////////////////////////////////////////