WIP: keyword arguments for expressions

This commit is contained in:
Matthias Koefferlein 2023-12-28 01:03:21 +01:00
parent 4a4db5ea6e
commit f685fe3adf
14 changed files with 326 additions and 107 deletions

View File

@ -431,7 +431,7 @@ public:
// .. nothing yet .. // .. nothing yet ..
} }
void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv) const void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
if (vv.size () != 0) { if (vv.size () != 0) {
throw tl::EvalError (tl::to_string (tr ("Annotation function must not have arguments")), context); throw tl::EvalError (tl::to_string (tr ("Annotation function must not have arguments")), context);

View File

@ -2194,7 +2194,7 @@ public:
// .. nothing yet .. // .. nothing yet ..
} }
void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector<tl::Variant> &args) const void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
if (args.size () > 0) { if (args.size () > 0) {
throw tl::EvalError (tl::to_string (tr ("Query function does not allow parameters")), context); throw tl::EvalError (tl::to_string (tr ("Query function does not allow parameters")), context);

View File

@ -133,7 +133,7 @@ namespace db
args.push_back (value); args.push_back (value);
} }
tl::ExpressionParserContext context; tl::ExpressionParserContext context;
ref.user_cls ()->eval_cls ()->execute (context, out, ref, m, args); ref.user_cls ()->eval_cls ()->execute (context, out, ref, m, args, 0);
ref = out; ref = out;
@ -160,7 +160,7 @@ namespace db
std::vector<tl::Variant> args; std::vector<tl::Variant> args;
tl::ExpressionParserContext context; tl::ExpressionParserContext context;
ref.user_cls ()->eval_cls ()->execute (context, out, ref, m, args); ref.user_cls ()->eval_cls ()->execute (context, out, ref, m, args, 0);
ref = out; ref = out;

View File

@ -138,7 +138,7 @@ SaveLayoutOptions::set_option_by_name (const std::string &method, const tl::Vari
tl::Variant out; tl::Variant out;
std::vector<tl::Variant> args; std::vector<tl::Variant> args;
args.push_back (value); args.push_back (value);
eval_cls->execute (context, out, options_ref, method + "=", args); eval_cls->execute (context, out, options_ref, method + "=", args, 0);
} }
tl::Variant tl::Variant
@ -151,7 +151,7 @@ SaveLayoutOptions::get_option_by_name (const std::string &method)
tl::Variant out; tl::Variant out;
std::vector<tl::Variant> args; std::vector<tl::Variant> args;
eval_cls->execute (context, out, options_ref, method, args); eval_cls->execute (context, out, options_ref, method, args, 0);
return out; return out;
} }

View File

@ -487,7 +487,7 @@ public:
// .. nothing yet .. // .. nothing yet ..
} }
void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, const std::vector<tl::Variant> &args) const void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
out = mp_proc->receiver (args); out = mp_proc->receiver (args);
} }
@ -506,7 +506,7 @@ public:
// .. nothing yet .. // .. nothing yet ..
} }
void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant & /*out*/, const std::vector<tl::Variant> &args) const void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant & /*out*/, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
mp_proc->put (m_ix, m_iy, m_tile_box, args); mp_proc->put (m_ix, m_iy, m_tile_box, args);
} }
@ -526,7 +526,7 @@ public:
// .. nothing yet .. // .. nothing yet ..
} }
void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant & /*out*/, const std::vector<tl::Variant> & /*args*/) const void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant & /*out*/, const std::vector<tl::Variant> & /*args*/, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
// TODO: ... implement .. // TODO: ... implement ..
} }

View File

@ -84,7 +84,7 @@ template<class T, bool> struct _var_user_to_string_impl;
template<class T> template<class T>
struct _var_user_to_string_impl<T, true> struct _var_user_to_string_impl<T, true>
{ {
static std::string call (const T *a, const VariantUserClassImpl * /*delegate*/) { return a->to_string (); } static std::string call (const T *a, const VariantUserClassImpl * /*delegate*/) { return a ? a->to_string () : std::string (); }
}; };
template<class T> template<class T>

View File

@ -266,9 +266,15 @@ public:
// .. nothing yet .. // .. nothing yet ..
} }
void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, const std::vector<tl::Variant> &args) const bool supports_keyword_parameters () const
{ {
if (! args.empty ()) { // for future extensions
return true;
}
void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const
{
if (! args.empty () || kwargs) {
throw tl::Exception (tl::to_string (tr ("Class '%s' is not a function - use 'new' to create a new object")), mp_var_cls->name ()); throw tl::Exception (tl::to_string (tr ("Class '%s' is not a function - use 'new' to create a new object")), mp_var_cls->name ());
} }
out = tl::Variant ((void *) 0, mp_var_cls, false); out = tl::Variant ((void *) 0, mp_var_cls, false);
@ -532,12 +538,12 @@ VariantUserClassImpl::to_double_impl (void *obj) const
} }
void void
VariantUserClassImpl::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const VariantUserClassImpl::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const
{ {
if (mp_object_cls == 0 && method == "is_a") { if (mp_object_cls == 0 && method == "is_a") {
if (args.size () != 1) { if (args.size () != 1 || kwargs) {
throw tl::EvalError (tl::to_string (tr ("'is_a' method requires exactly one argument")), context); throw tl::EvalError (tl::to_string (tr ("'is_a' method requires exactly one argument (no keyword arguments)")), context);
} }
bool ret = false; bool ret = false;
@ -550,7 +556,7 @@ VariantUserClassImpl::execute (const tl::ExpressionParserContext &context, tl::V
out = ret; out = ret;
} else if (mp_object_cls != 0 && method == "new" && args.size () == 0) { } else if (mp_object_cls != 0 && method == "new" && args.size () == 0 && ! kwargs) {
void *obj = mp_cls->create (); void *obj = mp_cls->create ();
if (obj) { if (obj) {
@ -574,8 +580,8 @@ VariantUserClassImpl::execute (const tl::ExpressionParserContext &context, tl::V
} else if (mp_object_cls == 0 && method == "dup") { } else if (mp_object_cls == 0 && method == "dup") {
if (args.size () != 0) { if (args.size () != 0 || kwargs) {
throw tl::EvalError (tl::to_string (tr ("'dup' method does not allow arguments")), context); throw tl::EvalError (tl::to_string (tr ("'dup' method does not allow arguments (no keyword arguments)")), context);
} }
void *obj = mp_cls->create (); void *obj = mp_cls->create ();
@ -602,7 +608,7 @@ VariantUserClassImpl::execute (const tl::ExpressionParserContext &context, tl::V
} else { } else {
try { try {
execute_gsi (context, out, object, method, args); execute_gsi (context, out, object, method, args, kwargs);
} catch (tl::EvalError &) { } catch (tl::EvalError &) {
throw; throw;
} catch (tl::Exception &ex) { } catch (tl::Exception &ex) {
@ -709,8 +715,92 @@ static const gsi::ClassBase *find_class_scope (const gsi::ClassBase *cls, const
return 0; return 0;
} }
inline int
num_args (const gsi::MethodBase *m)
{
return int (m->end_arguments () - m->begin_arguments ());
}
static bool
compatible_with_args (const gsi::MethodBase *m, int argc, const std::map<std::string, tl::Variant> *kwargs)
{
int nargs = num_args (m);
if (argc >= nargs) {
// no more arguments to consider
return argc == nargs && (! kwargs || kwargs->empty ());
}
if (kwargs) {
int nkwargs = int (kwargs->size ());
int kwargs_taken = 0;
while (argc < nargs) {
const gsi::ArgType &atype = m->begin_arguments () [argc];
auto i = kwargs->find (atype.spec ()->name ());
if (i == kwargs->end ()) {
if (! atype.spec ()->has_default ()) {
return false;
}
} else {
++kwargs_taken;
}
++argc;
}
// matches if all keyword arguments are taken
return kwargs_taken == nkwargs;
} else {
while (argc < nargs) {
const gsi::ArgType &atype = m->begin_arguments () [argc];
if (! atype.spec ()->has_default ()) {
return false;
}
++argc;
}
return true;
}
}
static std::string
describe_overload (const gsi::MethodBase *m, int argc, const std::map<std::string, tl::Variant> *kwargs)
{
std::string res = m->to_string ();
if (compatible_with_args (m, argc, kwargs)) {
res += " " + tl::to_string (tr ("[match candidate]"));
}
return res;
}
static std::string
describe_overloads (const ExpressionMethodTable *mt, int mid, int argc, const std::map<std::string, tl::Variant> *kwargs)
{
std::string res;
for (auto m = mt->begin (mid); m != mt->end (mid); ++m) {
res += std::string (" ") + describe_overload (*m, argc, kwargs) + "\n";
}
return res;
}
static const tl::Variant *
get_kwarg (const gsi::ArgType &atype, const std::map<std::string, tl::Variant> *kwargs)
{
if (kwargs) {
auto i = kwargs->find (atype.spec ()->name ());
if (i != kwargs->end ()) {
return &i->second;
}
}
return 0;
}
void void
VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const
{ {
tl_assert (object.is_user ()); tl_assert (object.is_user ());
@ -762,7 +852,7 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Signals are not supported inside expressions (event %s)")), method.c_str ())); throw tl::Exception (tl::sprintf (tl::to_string (tr ("Signals are not supported inside expressions (event %s)")), method.c_str ()));
} else if ((*m)->is_callback()) { } else if ((*m)->is_callback()) {
// ignore callbacks // ignore callbacks
} else if ((*m)->compatible_with_num_args ((unsigned int) args.size ())) { } else if (compatible_with_args (*m, int (args.size ()), kwargs)) {
++candidates; ++candidates;
meth = *m; meth = *m;
} }
@ -771,20 +861,7 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
// no candidate -> error // no candidate -> error
if (! meth) { if (! meth) {
throw tl::Exception (tl::to_string (tr ("Can't match arguments. Variants are:\n")) + describe_overloads (mt, mid, int (args.size ()), kwargs));
std::set<unsigned int> nargs;
for (ExpressionMethodTableEntry::method_iterator m = mt->begin (mid); m != mt->end (mid); ++m) {
nargs.insert (std::distance ((*m)->begin_arguments (), (*m)->end_arguments ()));
}
std::string nargs_s;
for (std::set<unsigned int>::const_iterator na = nargs.begin (); na != nargs.end (); ++na) {
if (na != nargs.begin ()) {
nargs_s += "/";
}
nargs_s += tl::to_string (*na);
}
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid number of arguments for method %s, class %s (got %d, expected %s)")), method.c_str (), mp_cls->name (), int (args.size ()), nargs_s));
} }
// more than one candidate -> refine by checking the arguments // more than one candidate -> refine by checking the arguments
@ -800,13 +877,16 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
if (! (*m)->is_callback () && ! (*m)->is_signal ()) { if (! (*m)->is_callback () && ! (*m)->is_signal ()) {
// check arguments (count and type) // check arguments (count and type)
bool is_valid = (*m)->compatible_with_num_args ((unsigned int) args.size ()); bool is_valid = compatible_with_args (*m, (int) args.size (), kwargs);
int sc = 0; int sc = 0;
int i = 0; int i = 0;
for (gsi::MethodBase::argument_iterator a = (*m)->begin_arguments (); is_valid && i < int (args.size ()) && a != (*m)->end_arguments (); ++a, ++i) { for (gsi::MethodBase::argument_iterator a = (*m)->begin_arguments (); is_valid && a != (*m)->end_arguments (); ++a, ++i) {
if (gsi::test_arg (*a, args [i], false /*strict*/)) { const tl::Variant *arg = i >= int (args.size ()) ? get_kwarg (*a, kwargs) : &args[i];
if (! arg) {
is_valid = a->spec ()->has_default ();
} else if (gsi::test_arg (*a, *arg, false /*strict*/)) {
++sc; ++sc;
} else if (test_arg (*a, args [i], true /*loose*/)) { } else if (test_arg (*a, *arg, true /*loose*/)) {
// non-scoring match // non-scoring match
} else { } else {
is_valid = false; is_valid = false;
@ -831,12 +911,17 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
if (is_valid) { if (is_valid) {
// otherwise take the candidate with the better score // otherwise take the candidate with the better score or the least number of arguments (faster)
if (candidates > 0 && sc > score) { if (candidates > 0) {
if (sc > score || (sc == score && num_args (meth) > num_args (*m))) {
candidates = 1; candidates = 1;
meth = *m; meth = *m;
score = sc; score = sc;
} else if (candidates == 0 || sc == score) { } else if (sc == score && num_args (meth) == num_args (*m)) {
++candidates;
meth = *m;
}
} else {
++candidates; ++candidates;
meth = *m; meth = *m;
score = sc; score = sc;
@ -851,11 +936,11 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
} }
if (! meth) { if (! meth) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("No method with matching arguments for method %s, class %s")), method.c_str (), mp_cls->name ())); throw tl::Exception (tl::to_string (tr ("No overload with matching arguments. Variants are:\n")) + describe_overloads (mt, mid, int (args.size ()), kwargs));
} }
if (candidates > 1) { if (candidates > 1) {
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Ambiguous overload variants for method %s, class %s - multiple method declarations match arguments")), method.c_str (), mp_cls->name ())); throw tl::Exception (tl::to_string (tr ("Ambiguous overload variants - multiple method declarations match arguments. Variants are:\n")) + describe_overloads (mt, mid, int (args.size ()), kwargs));
} }
if (m_is_const && ! meth->is_const ()) { if (m_is_const && ! meth->is_const ()) {
@ -869,22 +954,76 @@ VariantUserClassImpl::execute_gsi (const tl::ExpressionParserContext & /*context
} else if (meth->smt () != gsi::MethodBase::None) { } else if (meth->smt () != gsi::MethodBase::None) {
if (kwargs) {
throw tl::Exception (tl::to_string (tr ("Keyword arguments not permitted")));
}
out = special_method_impl (meth->smt (), object, args); out = special_method_impl (meth->smt (), object, args);
} else { } else {
gsi::SerialArgs arglist (meth->argsize ()); gsi::SerialArgs arglist (meth->argsize ());
tl::Heap heap; tl::Heap heap;
size_t narg = 0;
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments () && narg < args.size (); ++a, ++narg) { int iarg = 0;
int kwargs_taken = 0;
int nkwargs = kwargs ? int (kwargs->size ()) : 0;
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments (); ++a, ++iarg) {
try { try {
const tl::Variant *arg = iarg >= int (args.size ()) ? get_kwarg (*a, kwargs) : &args[iarg];
if (! arg) {
if (a->spec ()->has_default ()) {
if (kwargs_taken == nkwargs) {
// leave it to the consumer to establish the default values (that is faster)
break;
}
tl::Variant def_value = a->spec ()->default_value ();
gsi::push_arg (arglist, *a, def_value, &heap);
} else {
throw tl::Exception (tl::to_string ("No argument provided (positional or keyword) and no default value available"));
}
} else {
if (iarg >= int (args.size ())) {
++kwargs_taken;
}
// Note: this const_cast is ugly, but it will basically enable "out" parameters // Note: this const_cast is ugly, but it will basically enable "out" parameters
// TODO: clean this up. // TODO: clean this up.
gsi::push_arg (arglist, *a, const_cast<tl::Variant &> (args [narg]), &heap); gsi::push_arg (arglist, *a, const_cast<tl::Variant &> (*arg), &heap);
}
} catch (tl::Exception &ex) { } catch (tl::Exception &ex) {
std::string msg = ex.msg () + tl::sprintf (tl::to_string (tr (" (argument '%s')")), a->spec ()->name ()); std::string msg = ex.msg () + tl::sprintf (tl::to_string (tr (" (argument '%s')")), a->spec ()->name ());
throw tl::Exception (msg); throw tl::Exception (msg);
} }
}
if (kwargs_taken != nkwargs) {
// check if there are any left-over keyword parameters with unknown names
std::set<std::string> valid_names;
for (gsi::MethodBase::argument_iterator a = meth->begin_arguments (); a != meth->end_arguments (); ++a) {
valid_names.insert (a->spec ()->name ());
}
std::set<std::string> invalid_names;
for (auto i = kwargs->begin (); i != kwargs->end (); ++i) {
if (valid_names.find (i->first) == valid_names.end ()) {
invalid_names.insert (i->first);
}
}
if (invalid_names.size () > 1) {
std::string names_str = tl::join (invalid_names.begin (), invalid_names.end (), ", ");
throw tl::Exception (tl::to_string (tr ("Unknown keyword parameters: ")) + names_str);
} else if (invalid_names.size () == 1) {
throw tl::Exception (tl::to_string (tr ("Unknown keyword parameter: ")) + *invalid_names.begin ());
}
} }
SerialArgs retlist (meth->retsize ()); SerialArgs retlist (meth->retsize ());

View File

@ -55,7 +55,7 @@ public:
int to_int_impl (void *) const; int to_int_impl (void *) const;
double to_double_impl (void *) const; double to_double_impl (void *) const;
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const; virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const;
void initialize (const gsi::ClassBase *cls, const tl::VariantUserClassBase *self, const tl::VariantUserClassBase *object_cls, bool is_const); void initialize (const gsi::ClassBase *cls, const tl::VariantUserClassBase *self, const tl::VariantUserClassBase *object_cls, bool is_const);
@ -64,7 +64,7 @@ private:
const tl::VariantUserClassBase *mp_self, *mp_object_cls; const tl::VariantUserClassBase *mp_self, *mp_object_cls;
bool m_is_const; bool m_is_const;
virtual void execute_gsi (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const; virtual void execute_gsi (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs = 0) const;
bool has_method (const std::string &method) const; bool has_method (const std::string &method) const;
}; };

View File

@ -564,7 +564,7 @@ class CollectFunction
: public tl::EvalFunction : public tl::EvalFunction
{ {
public: public:
virtual void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, const std::vector<tl::Variant> &args) const virtual void execute (const tl::ExpressionParserContext & /*context*/, tl::Variant &out, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
out = tl::Variant (); out = tl::Variant ();
if (args.size () > 0) { if (args.size () > 0) {
@ -623,3 +623,32 @@ TEST(11)
v = e.parse ("var b = Trans.new(1)*Trans.new(Vector.new(10, 20))").execute (); v = e.parse ("var b = Trans.new(1)*Trans.new(Vector.new(10, 20))").execute ();
EXPECT_EQ (v.to_string (), std::string ("r90 -20,10")); EXPECT_EQ (v.to_string (), std::string ("r90 -20,10"));
} }
TEST(12)
{
// Keyword arguments are best tested on transformations, here CplxTrans
tl::Eval e;
tl::Variant v;
v = e.parse ("var t = CplxTrans.new()").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 0,0"));
v = e.parse ("var t = CplxTrans.new(1.5)").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1.5 0,0"));
v = e.parse ("var t = CplxTrans.new(1, 2)").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 1,2"));
v = e.parse ("var t = CplxTrans.new(1, y=2)").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 1,2"));
v = e.parse ("var t = CplxTrans.new(x=1, y=2)").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 1,2"));
v = e.parse ("var t = CplxTrans.new(u=DVector.new(1, 2))").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 1,2"));
v = e.parse ("var t = CplxTrans.new(DVector.new(1, 2))").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 1,2"));
v = e.parse ("var t = CplxTrans.new(u=Vector.new(1, 2))").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 1,2"));
v = e.parse ("var t = CplxTrans.new(u=[1, 2])").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1 1,2"));
v = e.parse ("var t = CplxTrans.new(mag=1.5)").execute ();
EXPECT_EQ (v.to_string (), std::string ("r0 *1.5 0,0"));
}

View File

@ -436,7 +436,7 @@ public:
// .. nothing yet .. // .. nothing yet ..
} }
void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv) const void execute (const tl::ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
if (vv.size () != 0) { if (vv.size () != 0) {
throw tl::EvalError (tl::to_string (tr ("Layer source function must not have arguments")), context); throw tl::EvalError (tl::to_string (tr ("Layer source function must not have arguments")), context);

View File

@ -531,11 +531,11 @@ private:
} }
if (! meth) { if (! meth) {
throw tl::TypeError (tl::to_string (tr ("No overload with matching arguments. Variants are:\n")) + describe_overloads (argc, kwargs)); throw tl::Exception (tl::to_string (tr ("No overload with matching arguments. Variants are:\n")) + describe_overloads (argc, kwargs));
} }
if (candidates > 1) { if (candidates > 1) {
throw tl::TypeError (tl::to_string (tr ("Ambiguous overload variants - multiple method declarations match arguments. Variants are:\n")) + describe_overloads (argc, kwargs)); throw tl::Exception (tl::to_string (tr ("Ambiguous overload variants - multiple method declarations match arguments. Variants are:\n")) + describe_overloads (argc, kwargs));
} }
if (is_const && ! meth->is_const ()) { if (is_const && ! meth->is_const ()) {

View File

@ -306,12 +306,12 @@ class TL_PUBLIC ListClass
: public EvalClass : public EvalClass
{ {
public: public:
void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const
{ {
if (method == "push") { if (method == "push") {
if (args.size () != 1) { if (args.size () != 1 || kwargs) {
throw EvalError (tl::to_string (tr ("'push' method expects one argument")), context); throw EvalError (tl::to_string (tr ("'push' method expects one argument (keyword arguments not permitted)")), context);
} }
object.push (args [0]); object.push (args [0]);
@ -319,7 +319,7 @@ public:
} else if (method == "size") { } else if (method == "size") {
if (args.size () != 0) { if (args.size () != 0 || kwargs) {
throw EvalError (tl::to_string (tr ("'size' method does not accept an argument")), context); throw EvalError (tl::to_string (tr ("'size' method does not accept an argument")), context);
} }
@ -343,12 +343,12 @@ class TL_PUBLIC ArrayClass
: public EvalClass : public EvalClass
{ {
public: public:
void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const
{ {
if (method == "insert") { if (method == "insert") {
if (args.size () != 2) { if (args.size () != 2 || kwargs) {
throw EvalError (tl::to_string (tr ("'insert' method expects two arguments")), context); throw EvalError (tl::to_string (tr ("'insert' method expects two arguments (keyword arguments not permitted)")), context);
} }
object.insert (args [0], args [1]); object.insert (args [0], args [1]);
@ -356,7 +356,7 @@ public:
} else if (method == "size") { } else if (method == "size") {
if (args.size () != 0) { if (args.size () != 0 || kwargs) {
throw EvalError (tl::to_string (tr ("'size' method does not accept an argument")), context); throw EvalError (tl::to_string (tr ("'size' method does not accept an argument")), context);
} }
@ -364,7 +364,7 @@ public:
} else if (method == "keys") { } else if (method == "keys") {
if (args.size () != 0) { if (args.size () != 0 || kwargs) {
throw EvalError (tl::to_string (tr ("'keys' method does not accept an argument")), context); throw EvalError (tl::to_string (tr ("'keys' method does not accept an argument")), context);
} }
@ -375,7 +375,7 @@ public:
} else if (method == "values") { } else if (method == "values") {
if (args.size () != 0) { if (args.size () != 0 || kwargs) {
throw EvalError (tl::to_string (tr ("'keys' method does not accept an argument")), context); throw EvalError (tl::to_string (tr ("'keys' method does not accept an argument")), context);
} }
@ -411,7 +411,7 @@ ExpressionNode::ExpressionNode (const ExpressionParserContext &context, size_t c
} }
ExpressionNode::ExpressionNode (const ExpressionNode &other, const tl::Expression *expr) ExpressionNode::ExpressionNode (const ExpressionNode &other, const tl::Expression *expr)
: m_context (other.m_context) : m_context (other.m_context), m_name (other.m_name)
{ {
m_context.set_expr (expr); m_context.set_expr (expr);
m_c.reserve (other.m_c.size ()); m_c.reserve (other.m_c.size ());
@ -517,7 +517,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "<", vv); c->execute (m_context, o, v.get (), "<", vv, 0);
v.swap (o); v.swap (o);
} else { } else {
@ -567,7 +567,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "<=", vv); c->execute (m_context, o, v.get (), "<=", vv, 0);
v.swap (o); v.swap (o);
} else { } else {
@ -617,7 +617,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), ">", vv); c->execute (m_context, o, v.get (), ">", vv, 0);
v.swap (o); v.swap (o);
} else { } else {
@ -667,7 +667,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), ">=", vv); c->execute (m_context, o, v.get (), ">=", vv, 0);
v.swap (o); v.swap (o);
} else { } else {
@ -717,7 +717,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "==", vv); c->execute (m_context, o, v.get (), "==", vv, 0);
v.swap (o); v.swap (o);
} else { } else {
@ -767,7 +767,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "!=", vv); c->execute (m_context, o, v.get (), "!=", vv, 0);
v.swap (o); v.swap (o);
} else { } else {
@ -817,7 +817,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "~", vv); c->execute (m_context, o, v.get (), "~", vv, 0);
v.swap (o); v.swap (o);
mp_eval->match_substrings ().clear (); mp_eval->match_substrings ().clear ();
@ -914,7 +914,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "!~", vv); c->execute (m_context, o, v.get (), "!~", vv, 0);
v.swap (o); v.swap (o);
} else { } else {
@ -1085,7 +1085,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "<<", vv); c->execute (m_context, o, v.get (), "<<", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_longlong ()) { } else if (v->is_longlong ()) {
@ -1141,7 +1141,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), ">>", vv); c->execute (m_context, o, v.get (), ">>", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_longlong ()) { } else if (v->is_longlong ()) {
@ -1197,7 +1197,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "+", vv); c->execute (m_context, o, v.get (), "+", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_a_string () || b->is_a_string ()) { } else if (v->is_a_string () || b->is_a_string ()) {
@ -1259,7 +1259,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "-", vv); c->execute (m_context, o, v.get (), "-", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_double () || b->is_double ()) { } else if (v->is_double () || b->is_double ()) {
@ -1319,7 +1319,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "*", vv); c->execute (m_context, o, v.get (), "*", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_a_string ()) { } else if (v->is_a_string ()) {
@ -1409,7 +1409,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "/", vv); c->execute (m_context, o, v.get (), "/", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_double () || b->is_double ()) { } else if (v->is_double () || b->is_double ()) {
@ -1493,7 +1493,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "%", vv); c->execute (m_context, o, v.get (), "%", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_ulonglong () || b->is_ulonglong ()) { } else if (v->is_ulonglong () || b->is_ulonglong ()) {
@ -1565,7 +1565,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "&", vv); c->execute (m_context, o, v.get (), "&", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_ulonglong () || b->is_ulonglong ()) { } else if (v->is_ulonglong () || b->is_ulonglong ()) {
@ -1621,7 +1621,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "|", vv); c->execute (m_context, o, v.get (), "|", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_ulonglong () || b->is_ulonglong ()) { } else if (v->is_ulonglong () || b->is_ulonglong ()) {
@ -1677,7 +1677,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*b); vv.push_back (*b);
c->execute (m_context, o, v.get (), "^", vv); c->execute (m_context, o, v.get (), "^", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_ulonglong () || b->is_ulonglong ()) { } else if (v->is_ulonglong () || b->is_ulonglong ()) {
@ -1733,7 +1733,7 @@ public:
tl::Variant o; tl::Variant o;
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
vv.push_back (*e); vv.push_back (*e);
c->execute (m_context, o, v.get (), "[]", vv); c->execute (m_context, o, v.get (), "[]", vv, 0);
v.swap (o); v.swap (o);
} else if (v->is_list ()) { } else if (v->is_list ()) {
@ -2025,12 +2025,18 @@ public:
m_c[0]->execute (v); m_c[0]->execute (v);
std::vector <tl::Variant> vv; std::vector <tl::Variant> vv;
std::map <std::string, tl::Variant> kwargs;
vv.reserve (m_c.size () - 1); vv.reserve (m_c.size () - 1);
for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin () + 1; c != m_c.end (); ++c) { for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin () + 1; c != m_c.end (); ++c) {
EvalTarget a; EvalTarget a;
(*c)->execute (a); (*c)->execute (a);
if (! (*c)->name ().empty ()) {
kwargs [(*c)->name ()] = *a;
} else {
vv.push_back (*a); vv.push_back (*a);
} }
}
const EvalClass *c = 0; const EvalClass *c = 0;
@ -2048,7 +2054,7 @@ public:
} }
tl::Variant o; tl::Variant o;
c->execute (m_context, o, v.get (), m_method, vv); c->execute (m_context, o, v.get (), m_method, vv, kwargs.empty () ? 0 : &kwargs);
v.swap (o); v.swap (o);
} }
@ -2188,16 +2194,26 @@ public:
void execute (EvalTarget &v) const void execute (EvalTarget &v) const
{ {
std::vector<tl::Variant> vv; std::vector<tl::Variant> vv;
std::map<std::string, tl::Variant> kwargs;
vv.reserve (m_c.size ()); vv.reserve (m_c.size ());
for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin (); c != m_c.end (); ++c) { for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin (); c != m_c.end (); ++c) {
EvalTarget a; EvalTarget a;
(*c)->execute (a); (*c)->execute (a);
if ((*c)->name ().empty ()) {
vv.push_back (*a); vv.push_back (*a);
} else {
kwargs[(*c)->name ()] = *a;
}
}
if (! kwargs.empty () && ! mp_func->supports_keyword_parameters ()) {
throw EvalError (tl::to_string (tr ("Keyword parameters not permitted")), m_context);
} }
tl::Variant o; tl::Variant o;
mp_func->execute (m_context, o, vv); mp_func->execute (m_context, o, vv, kwargs.empty () ? 0 : &kwargs);
v.swap (o); v.swap (o);
} }
@ -2939,7 +2955,7 @@ public:
ms_functions.erase (m_name); ms_functions.erase (m_name);
} }
void execute (const ExpressionParserContext &context, tl::Variant &out, const std::vector<tl::Variant> &args) const void execute (const ExpressionParserContext &context, tl::Variant &out, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
m_func (context, out, args); m_func (context, out, args);
} }
@ -3556,8 +3572,19 @@ Eval::eval_suffix (ExpressionParserContext &ex, std::unique_ptr<ExpressionNode>
do { do {
tl::Extractor exn = ex;
std::string n;
if (exn.try_read_word (n, "_") && exn.test ("=")) {
// keyword parameter -> read name again to skip it
ex.read_word (n, "_");
ex.expect ("=");
} else {
n.clear ();
}
std::unique_ptr<ExpressionNode> a; std::unique_ptr<ExpressionNode> a;
eval_assign (ex, a); eval_assign (ex, a);
a->set_name (n);
m->add_child (a.release ()); m->add_child (a.release ());
if (ex.test (")")) { if (ex.test (")")) {

View File

@ -188,6 +188,24 @@ public:
*/ */
void add_child (ExpressionNode *node); void add_child (ExpressionNode *node);
/**
* @brief Gets the name
*
* The name is used for named arguments for example.
*/
const std::string &name () const
{
return m_name;
}
/**
* @brief Sets the name
*/
void set_name (const std::string &name)
{
m_name = name;
}
/** /**
* @brief Execute the node * @brief Execute the node
*/ */
@ -201,6 +219,7 @@ public:
protected: protected:
std::vector <ExpressionNode *> m_c; std::vector <ExpressionNode *> m_c;
ExpressionParserContext m_context; ExpressionParserContext m_context;
std::string m_name;
/** /**
* @brief Sets the expression parent * @brief Sets the expression parent
@ -244,7 +263,7 @@ public:
* *
* If no method of this kind exists, the implementation may throw a NoMethodError. * If no method of this kind exists, the implementation may throw a NoMethodError.
*/ */
virtual void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const = 0; virtual void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const = 0;
}; };
/** /**
@ -263,6 +282,11 @@ public:
*/ */
virtual ~EvalFunction () { } virtual ~EvalFunction () { }
/**
* @brief Specifies whether keyword parameters are supported
*/
virtual bool supports_keyword_parameters () const { return false; }
/** /**
* @brief The actual execution method * @brief The actual execution method
* *
@ -270,7 +294,7 @@ public:
* @param args The arguments of the method * @param args The arguments of the method
* @return The return value * @return The return value
*/ */
virtual void execute (const ExpressionParserContext &context, tl::Variant &out, const std::vector<tl::Variant> &args) const = 0; virtual void execute (const ExpressionParserContext &context, tl::Variant &out, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const = 0;
}; };
/** /**

View File

@ -445,7 +445,7 @@ private:
class BoxClassClass : public tl::VariantUserClassBase, private tl::EvalClass class BoxClassClass : public tl::VariantUserClassBase, private tl::EvalClass
{ {
public: public:
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const; virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const;
virtual void *create () const { tl_assert (false); } virtual void *create () const { tl_assert (false); }
virtual void destroy (void *) const { tl_assert (false); } virtual void destroy (void *) const { tl_assert (false); }
@ -473,7 +473,7 @@ BoxClassClass BoxClassClass::instance;
class BoxClass : public tl::VariantUserClassImpl<Box>, private tl::EvalClass class BoxClass : public tl::VariantUserClassImpl<Box>, private tl::EvalClass
{ {
public: public:
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const; virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const;
virtual const tl::EvalClass *eval_cls () const { return this; } virtual const tl::EvalClass *eval_cls () const { return this; }
static BoxClass instance; static BoxClass instance;
@ -481,7 +481,7 @@ public:
BoxClass BoxClass::instance; BoxClass BoxClass::instance;
void BoxClass::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const void BoxClass::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
if (method == "width") { if (method == "width") {
out = object.to_user<Box> ().width (); out = object.to_user<Box> ().width ();
@ -501,7 +501,7 @@ void BoxClass::execute (const tl::ExpressionParserContext &context, tl::Variant
} }
} }
void BoxClassClass::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant & /*object*/, const std::string &method, const std::vector<tl::Variant> &args) const void BoxClassClass::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant & /*object*/, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
if (method == "new") { if (method == "new") {
out = tl::Variant (new Box (args[0].to_long(), args[1].to_long(), args[2].to_long(), args[3].to_long()), &BoxClass::instance, true); out = tl::Variant (new Box (args[0].to_long(), args[1].to_long(), args[2].to_long(), args[3].to_long()), &BoxClass::instance, true);
@ -513,7 +513,7 @@ void BoxClassClass::execute (const tl::ExpressionParserContext &context, tl::Var
class EdgeClassClass : public tl::VariantUserClassBase, private tl::EvalClass class EdgeClassClass : public tl::VariantUserClassBase, private tl::EvalClass
{ {
public: public:
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const; virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> *kwargs) const;
virtual void *create () const { tl_assert (false); } virtual void *create () const { tl_assert (false); }
virtual void destroy (void *) const { tl_assert (false); } virtual void destroy (void *) const { tl_assert (false); }
@ -541,7 +541,7 @@ EdgeClassClass EdgeClassClass::instance;
class EdgeClass : public tl::VariantUserClassImpl<Edge>, private tl::EvalClass class EdgeClass : public tl::VariantUserClassImpl<Edge>, private tl::EvalClass
{ {
public: public:
virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const virtual void execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
if (method == "dx") { if (method == "dx") {
out = object.to_user<Edge> ().dx (); out = object.to_user<Edge> ().dx ();
@ -566,7 +566,7 @@ public:
EdgeClass EdgeClass::instance; EdgeClass EdgeClass::instance;
void void
EdgeClassClass::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant & /*object*/, const std::string &method, const std::vector<tl::Variant> &args) const EdgeClassClass::execute (const tl::ExpressionParserContext &context, tl::Variant &out, tl::Variant & /*object*/, const std::string &method, const std::vector<tl::Variant> &args, const std::map<std::string, tl::Variant> * /*kwargs*/) const
{ {
if (method == "new") { if (method == "new") {
out = tl::Variant (new Edge (args[0].to_long(), args[1].to_long(), args[2].to_long(), args[3].to_long()), &EdgeClass::instance, true); out = tl::Variant (new Edge (args[0].to_long(), args[1].to_long(), args[2].to_long(), args[3].to_long()), &EdgeClass::instance, true);
@ -996,7 +996,7 @@ class F0
: public tl::EvalFunction : public tl::EvalFunction
{ {
public: public:
void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &) const void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &, const std::map<std::string, tl::Variant> *) const
{ {
out = tl::Variant (17); out = tl::Variant (17);
} }
@ -1006,7 +1006,7 @@ class F1
: public tl::EvalFunction : public tl::EvalFunction
{ {
public: public:
void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv) const void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv, const std::map<std::string, tl::Variant> *) const
{ {
out = tl::Variant (vv[0].to_long() + 1); out = tl::Variant (vv[0].to_long() + 1);
} }
@ -1016,7 +1016,7 @@ class F2
: public tl::EvalFunction : public tl::EvalFunction
{ {
public: public:
void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv) const void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv, const std::map<std::string, tl::Variant> *) const
{ {
out = tl::Variant (vv[0].to_long() + 2); out = tl::Variant (vv[0].to_long() + 2);
} }
@ -1026,7 +1026,7 @@ class F3
: public tl::EvalFunction : public tl::EvalFunction
{ {
public: public:
void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv) const void execute (const tl::ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv, const std::map<std::string, tl::Variant> *) const
{ {
out = tl::Variant (vv[0].to_long() + 3); out = tl::Variant (vv[0].to_long() + 3);
} }