mirror of https://github.com/KLayout/klayout.git
4083 lines
103 KiB
C++
4083 lines
103 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2017 Matthias Koefferlein
|
|
|
|
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
#include "tlExpression.h"
|
|
#include "tlInternational.h"
|
|
#include "tlString.h"
|
|
#include "tlGlobPattern.h"
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
|
|
// Suggestions for further functions:
|
|
// - provide date/time function
|
|
// - file functions: (drive), combine, split_path
|
|
// - file tests: exists, locate (in path), readable, writeable
|
|
// - glob: match, expand (files) - needs glob code
|
|
|
|
namespace tl
|
|
{
|
|
|
|
static std::locale c_locale ("C");
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of EvalError
|
|
|
|
EvalError::EvalError (const std::string &what, const ExpressionParserContext &context)
|
|
: tl::Exception (what + tl::to_string (QObject::tr (" at ")) + context.where ())
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of NoMethodError
|
|
|
|
NoMethodError::NoMethodError (const std::string &cls_name, const std::string &method, const ExpressionParserContext &context)
|
|
: EvalError (tl::sprintf (tl::to_string (QObject::tr ("'%s' is not a valid method name for objects of class '%s'")), method, cls_name), context)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of ExpressionParserContext
|
|
|
|
ExpressionParserContext::ExpressionParserContext ()
|
|
: mp_expr (0)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionParserContext::ExpressionParserContext (const Expression *expr, const tl::Extractor &ex)
|
|
: tl::Extractor (ex), mp_expr (expr), m_ex0 (ex)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
void
|
|
ExpressionParserContext::error (const std::string &message)
|
|
{
|
|
throw EvalError (message, *this);
|
|
}
|
|
|
|
std::string
|
|
ExpressionParserContext::where () const
|
|
{
|
|
if (mp_expr) {
|
|
|
|
size_t pos = get () - m_ex0.get ();
|
|
|
|
const char *text = mp_expr->text ();
|
|
size_t len = strlen (text);
|
|
|
|
if (pos >= len) {
|
|
return tl::to_string (QObject::tr ("end of text"));
|
|
} else {
|
|
|
|
int line = 1;
|
|
size_t col = 0;
|
|
for (size_t p = 0; p < len; ++p, ++col) {
|
|
if (text [p] == '\n') {
|
|
++line;
|
|
col = 1;
|
|
} else if (text [p] != '\r') {
|
|
++col;
|
|
}
|
|
}
|
|
|
|
std::ostringstream os;
|
|
|
|
if (line == 1) {
|
|
os << tl::to_string (QObject::tr ("position")) << " " << pos;
|
|
} else {
|
|
os << tl::to_string (QObject::tr ("line")) << " " << line << ", " << tl::to_string (QObject::tr ("position")) << " " << col;
|
|
}
|
|
|
|
os << " (";
|
|
if (pos > 0) {
|
|
os << "..";
|
|
}
|
|
for (int i = 0; i < 20 && pos < len; ++i) {
|
|
os << text [pos++];
|
|
}
|
|
if (pos < len) {
|
|
os << "..";
|
|
}
|
|
os << ")";
|
|
|
|
return os.str ();
|
|
|
|
}
|
|
|
|
} else {
|
|
return std::string (tl::to_string (QObject::tr ("[unspecified location]")));
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Utilities for evaluation
|
|
|
|
static double to_double (const ExpressionParserContext &context, const tl::Variant &v)
|
|
{
|
|
if (v.can_convert_to_double ()) {
|
|
return v.to_double ();
|
|
} else if (v.is_list ()) {
|
|
return v.get_list ().size ();
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Double precision floating point value expected")), context);
|
|
}
|
|
}
|
|
|
|
static double to_double (const ExpressionParserContext &context, const std::vector <tl::Variant> &v)
|
|
{
|
|
if (v.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Function expects a single numeric argument")), context);
|
|
}
|
|
|
|
return to_double (context, v [0]);
|
|
}
|
|
|
|
static long to_long (const ExpressionParserContext &context, const tl::Variant &v)
|
|
{
|
|
if (v.can_convert_to_long ()) {
|
|
return v.to_long ();
|
|
} else if (v.is_list ()) {
|
|
return long (v.get_list ().size ());
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Integer value expected")), context);
|
|
}
|
|
}
|
|
|
|
static unsigned long to_ulong (const ExpressionParserContext &context, const tl::Variant &v)
|
|
{
|
|
if (v.can_convert_to_ulong ()) {
|
|
return v.to_ulong ();
|
|
} else if (v.is_list ()) {
|
|
return (unsigned long) (v.get_list ().size ());
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Unsigned integer value expected")), context);
|
|
}
|
|
}
|
|
|
|
static long long to_longlong (const ExpressionParserContext &context, const tl::Variant &v)
|
|
{
|
|
if (v.can_convert_to_longlong ()) {
|
|
return v.to_longlong ();
|
|
} else if (v.is_list ()) {
|
|
return long (v.get_list ().size ());
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Integer value expected")), context);
|
|
}
|
|
}
|
|
|
|
static unsigned long long to_ulonglong (const ExpressionParserContext &context, const tl::Variant &v)
|
|
{
|
|
if (v.can_convert_to_ulonglong ()) {
|
|
return v.to_ulong ();
|
|
} else if (v.is_list ()) {
|
|
return (unsigned long long) (v.get_list ().size ());
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Unsigned integer value expected")), context);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// EvalTarget: a class that encapsulates the target of an evaluation
|
|
|
|
class TL_PUBLIC EvalTarget
|
|
{
|
|
public:
|
|
EvalTarget ()
|
|
: mp_lvalue (0), m_rvalue ()
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
void fetch ()
|
|
{
|
|
if (mp_lvalue) {
|
|
m_rvalue = *mp_lvalue;
|
|
mp_lvalue = 0;
|
|
}
|
|
}
|
|
|
|
void set (const tl::Variant &v)
|
|
{
|
|
m_rvalue = v;
|
|
mp_lvalue = 0;
|
|
}
|
|
|
|
tl::Variant &get ()
|
|
{
|
|
if (mp_lvalue != 0) {
|
|
return *mp_lvalue;
|
|
} else {
|
|
return m_rvalue;
|
|
}
|
|
}
|
|
|
|
tl::Variant *lvalue ()
|
|
{
|
|
return mp_lvalue;
|
|
}
|
|
|
|
void set_lvalue (tl::Variant *lvalue)
|
|
{
|
|
mp_lvalue = lvalue;
|
|
m_rvalue.reset ();
|
|
}
|
|
|
|
const tl::Variant *operator-> () const
|
|
{
|
|
if (mp_lvalue != 0) {
|
|
return mp_lvalue;
|
|
} else {
|
|
return &m_rvalue;
|
|
}
|
|
}
|
|
|
|
const tl::Variant &operator* () const
|
|
{
|
|
if (mp_lvalue != 0) {
|
|
return *mp_lvalue;
|
|
} else {
|
|
return m_rvalue;
|
|
}
|
|
}
|
|
|
|
void swap (tl::Variant &other)
|
|
{
|
|
fetch ();
|
|
m_rvalue.swap (other);
|
|
}
|
|
|
|
inline tl::Variant make_result ()
|
|
{
|
|
if (mp_lvalue != 0) {
|
|
// Make reference from ownership relation
|
|
tl::Object *tl_object = mp_lvalue->to_object ();
|
|
if (tl_object && !mp_lvalue->user_is_ref ()) {
|
|
return tl::Variant (tl_object, mp_lvalue->user_cls (), false);
|
|
} else {
|
|
return *mp_lvalue;
|
|
}
|
|
} else {
|
|
return m_rvalue;
|
|
}
|
|
}
|
|
|
|
private:
|
|
tl::Variant *mp_lvalue;
|
|
tl::Variant m_rvalue;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// A class object for the tl::Variant list
|
|
|
|
class TL_PUBLIC ListClass
|
|
: public EvalClass
|
|
{
|
|
public:
|
|
void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const
|
|
{
|
|
if (method == "push") {
|
|
|
|
if (args.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'push' method expects one argument")), context);
|
|
}
|
|
|
|
object.push (args [0]);
|
|
out = args [0];
|
|
|
|
} else if (method == "size") {
|
|
|
|
if (args.size () != 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'size' method does not accept an argument")), context);
|
|
}
|
|
|
|
out = object.size ();
|
|
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Unknown method")) + " '" + method + "' for list", context);
|
|
}
|
|
|
|
}
|
|
|
|
static ListClass instance;
|
|
};
|
|
|
|
ListClass ListClass::instance;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// A class object for the tl::Variant array
|
|
|
|
class TL_PUBLIC ArrayClass
|
|
: public EvalClass
|
|
{
|
|
public:
|
|
void execute (const ExpressionParserContext &context, tl::Variant &out, tl::Variant &object, const std::string &method, const std::vector<tl::Variant> &args) const
|
|
{
|
|
if (method == "insert") {
|
|
|
|
if (args.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'insert' method expects two arguments")), context);
|
|
}
|
|
|
|
object.insert (args [0], args [1]);
|
|
out = args [1];
|
|
|
|
} else if (method == "size") {
|
|
|
|
if (args.size () != 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'size' method does not accept an argument")), context);
|
|
}
|
|
|
|
out = object.array_size ();
|
|
|
|
} else if (method == "keys") {
|
|
|
|
if (args.size () != 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'keys' method does not accept an argument")), context);
|
|
}
|
|
|
|
out.set_list (object.array_size ());
|
|
for (tl::Variant::const_array_iterator a = object.begin_array (); a != object.end_array (); ++a) {
|
|
out.push (a->first);
|
|
}
|
|
|
|
} else if (method == "values") {
|
|
|
|
if (args.size () != 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'keys' method does not accept an argument")), context);
|
|
}
|
|
|
|
out.set_list (object.array_size ());
|
|
for (tl::Variant::const_array_iterator a = object.begin_array (); a != object.end_array (); ++a) {
|
|
out.push (a->second);
|
|
}
|
|
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Unknown method")) + " '" + method + "' for array", context);
|
|
}
|
|
|
|
}
|
|
|
|
static ArrayClass instance;
|
|
};
|
|
|
|
ArrayClass ArrayClass::instance;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ExpressionNode implementation
|
|
|
|
ExpressionNode::ExpressionNode (const ExpressionParserContext &context)
|
|
: m_context (context)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode::ExpressionNode (const ExpressionParserContext &context, size_t children)
|
|
: m_context (context)
|
|
{
|
|
m_c.reserve (children);
|
|
}
|
|
|
|
ExpressionNode::ExpressionNode (const ExpressionNode &other, const tl::Expression *expr)
|
|
: m_context (other.m_context)
|
|
{
|
|
m_context.set_expr (expr);
|
|
m_c.reserve (other.m_c.size ());
|
|
|
|
for (std::vector <ExpressionNode *>::const_iterator c = other.m_c.begin (); c != other.m_c.end (); ++c) {
|
|
m_c.push_back ((*c)->clone (expr));
|
|
}
|
|
}
|
|
|
|
ExpressionNode::~ExpressionNode ()
|
|
{
|
|
for (std::vector <ExpressionNode *>::const_iterator c = m_c.begin (); c != m_c.end (); ++c) {
|
|
delete *c;
|
|
}
|
|
m_c.clear ();
|
|
}
|
|
|
|
void
|
|
ExpressionNode::add_child (ExpressionNode *node)
|
|
{
|
|
m_c.push_back (node);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ExpressionNode implementations for some binary operators
|
|
|
|
/**
|
|
* @brief Assign operator node
|
|
*/
|
|
class TL_PUBLIC AssignExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
AssignExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
AssignExpressionNode (const AssignExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new AssignExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget a;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (a);
|
|
|
|
if (! v.lvalue ()) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Assignment needs a lvalue")), m_context);
|
|
}
|
|
a.swap (*v.lvalue ());
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Less operator node
|
|
*/
|
|
class TL_PUBLIC LessExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
LessExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
LessExpressionNode (const LessExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new LessExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "<", vv);
|
|
v.swap (o);
|
|
|
|
} else {
|
|
v.set (tl::Variant (*v < *b));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Less or equal operator node
|
|
*/
|
|
class TL_PUBLIC LessOrEqualExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
LessOrEqualExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
LessOrEqualExpressionNode (const LessOrEqualExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new LessOrEqualExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "<=", vv);
|
|
v.swap (o);
|
|
|
|
} else {
|
|
v.set (tl::Variant (*v < *b || *b == *v));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Greater operator node
|
|
*/
|
|
class TL_PUBLIC GreaterExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
GreaterExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
GreaterExpressionNode (const GreaterExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new GreaterExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), ">", vv);
|
|
v.swap (o);
|
|
|
|
} else {
|
|
v.set (tl::Variant (*b < *v));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Greater or equal operator node
|
|
*/
|
|
class TL_PUBLIC GreaterOrEqualExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
GreaterOrEqualExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
GreaterOrEqualExpressionNode (const GreaterOrEqualExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new GreaterOrEqualExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), ">=", vv);
|
|
v.swap (o);
|
|
|
|
} else {
|
|
v.set (tl::Variant (*b < *v || *b == *v));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Equal operator node
|
|
*/
|
|
class TL_PUBLIC EqualExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
EqualExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
EqualExpressionNode (const EqualExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new EqualExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "==", vv);
|
|
v.swap (o);
|
|
|
|
} else {
|
|
v.set (tl::Variant (*b == *v));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Not equal operator node
|
|
*/
|
|
class TL_PUBLIC NotEqualExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
NotEqualExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
NotEqualExpressionNode (const NotEqualExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new NotEqualExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "!=", vv);
|
|
v.swap (o);
|
|
|
|
} else {
|
|
v.set (tl::Variant (!(*b == *v)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Match operator node
|
|
*/
|
|
class TL_PUBLIC MatchExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
MatchExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b, tl::Eval *eval)
|
|
: ExpressionNode (context, 2), mp_eval (eval)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
MatchExpressionNode (const MatchExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), mp_eval (other.mp_eval)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new MatchExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "~", vv);
|
|
v.swap (o);
|
|
|
|
mp_eval->match_substrings ().clear ();
|
|
|
|
} else {
|
|
|
|
std::vector <std::string> substrings;
|
|
v.set (tl::GlobPattern (b->to_string ()).match (v->to_string (), substrings));
|
|
mp_eval->match_substrings ().swap (substrings);
|
|
|
|
}
|
|
}
|
|
|
|
private:
|
|
tl::Eval *mp_eval;
|
|
};
|
|
|
|
/**
|
|
* @brief Match substring reference
|
|
*/
|
|
class TL_PUBLIC MatchSubstringReferenceNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
MatchSubstringReferenceNode (const ExpressionParserContext &context, tl::Eval *eval, int index)
|
|
: ExpressionNode (context, 0), mp_eval (eval), m_index (index)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
MatchSubstringReferenceNode (const MatchSubstringReferenceNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), mp_eval (other.mp_eval), m_index (other.m_index)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new MatchSubstringReferenceNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
if (int (mp_eval->match_substrings ().size ()) > m_index && m_index >= 0) {
|
|
v.set (mp_eval->match_substrings () [m_index]);
|
|
} else {
|
|
v.set (tl::Variant ());
|
|
}
|
|
}
|
|
|
|
private:
|
|
tl::Eval *mp_eval;
|
|
int m_index;
|
|
};
|
|
|
|
/**
|
|
* @brief NoMatch operator node
|
|
*/
|
|
class TL_PUBLIC NoMatchExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
NoMatchExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
NoMatchExpressionNode (const NoMatchExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new NoMatchExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "!~", vv);
|
|
v.swap (o);
|
|
|
|
} else {
|
|
v.set (! tl::GlobPattern (b->to_string ()).match (v->to_string ()));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Logical and expression node
|
|
*/
|
|
class TL_PUBLIC LogAndExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
LogAndExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
LogAndExpressionNode (const LogAndExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new LogAndExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
// an object always evaluates to "true"
|
|
m_c[1]->execute (v);
|
|
|
|
} else {
|
|
if (v->to_bool ()) {
|
|
m_c[1]->execute (v);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Logical or expression node
|
|
*/
|
|
class TL_PUBLIC LogOrExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
LogOrExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
LogOrExpressionNode (const LogOrExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new LogOrExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
// an object always evaluates to "true"
|
|
|
|
} else {
|
|
if (! v->to_bool ()) {
|
|
m_c[1]->execute (v);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief '?:' operator expression node
|
|
*/
|
|
class TL_PUBLIC IfExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
IfExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b, ExpressionNode *c)
|
|
: ExpressionNode (context, 3)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
add_child (c);
|
|
}
|
|
|
|
IfExpressionNode (const IfExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new IfExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
|
|
if (v->to_bool ()) {
|
|
m_c[1]->execute (v);
|
|
} else {
|
|
m_c[2]->execute (v);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Shift left expression node
|
|
*/
|
|
class TL_PUBLIC ShiftLeftExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
ShiftLeftExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
ShiftLeftExpressionNode (const ShiftLeftExpressionNode &other,const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new ShiftLeftExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "<<", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_longlong ()) {
|
|
v.set (tl::Variant (v->to_longlong () << to_longlong (m_context, *b)));
|
|
} else if (v->is_ulonglong ()) {
|
|
v.set (tl::Variant (v->to_ulonglong () << to_ulonglong (m_context, *b)));
|
|
} else if (v->is_ulong ()) {
|
|
v.set (tl::Variant (v->to_ulong () << to_ulong (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_long (m_context, *v) << to_long (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Shift right expression node
|
|
*/
|
|
class TL_PUBLIC ShiftRightExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
ShiftRightExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
ShiftRightExpressionNode (const ShiftRightExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new ShiftRightExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), ">>", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_longlong ()) {
|
|
v.set (tl::Variant (v->to_longlong () >> to_longlong (m_context, *b)));
|
|
} else if (v->is_ulonglong ()) {
|
|
v.set (tl::Variant (v->to_ulonglong () >> to_ulonglong (m_context, *b)));
|
|
} else if (v->is_ulong ()) {
|
|
v.set (tl::Variant (v->to_ulong () >> to_ulong (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_long (m_context, *v) >> to_long (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Plus expression node
|
|
*/
|
|
class TL_PUBLIC PlusExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
PlusExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
PlusExpressionNode (const PlusExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new PlusExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "+", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_a_string () || b->is_a_string ()) {
|
|
v.set (tl::Variant (std::string (v->to_string ()) + b->to_string ()));
|
|
} else if (v->is_double () || b->is_double ()) {
|
|
v.set (tl::Variant (to_double (m_context, *v) + to_double (m_context, *b)));
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) + to_ulonglong (m_context, *b)));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
v.set (tl::Variant (to_longlong (m_context, *v) + to_longlong (m_context, *b)));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
v.set (tl::Variant (to_ulong (m_context, *v) + to_ulong (m_context, *b)));
|
|
} else if (v->is_long () || b->is_long ()) {
|
|
v.set (tl::Variant (to_long (m_context, *v) + to_long (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_double (m_context, *v) + to_double (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Minus expression node
|
|
*/
|
|
class TL_PUBLIC MinusExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
MinusExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
MinusExpressionNode (const MinusExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new MinusExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "-", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_double () || b->is_double ()) {
|
|
v.set (tl::Variant (to_double (m_context, *v) - to_double (m_context, *b)));
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) - to_ulonglong (m_context, *b)));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
v.set (tl::Variant (to_longlong (m_context, *v) - to_longlong (m_context, *b)));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
v.set (tl::Variant (to_ulong (m_context, *v) - to_ulong (m_context, *b)));
|
|
} else if (v->is_long () || b->is_long ()) {
|
|
v.set (tl::Variant (to_long (m_context, *v) - to_long (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_double (m_context, *v) - to_double (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Star expression node
|
|
*/
|
|
class TL_PUBLIC StarExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
StarExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
StarExpressionNode (const StarExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new StarExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "*", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_a_string ()) {
|
|
|
|
long x = to_long (m_context, *b);
|
|
if (x < 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Numeric argument of '*' operator with string must be positive")), m_context);
|
|
}
|
|
|
|
std::string s;
|
|
s.reserve (strlen (v->to_string ()) * size_t (x));
|
|
while (x-- > 0) {
|
|
s += v->to_string ();
|
|
}
|
|
|
|
v.set (tl::Variant (s));
|
|
|
|
} else if (b->is_a_string ()) {
|
|
|
|
long x = to_long (m_context, *v);
|
|
if (x < 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Numeric argument of '*' operator with string must be positive")), m_context);
|
|
}
|
|
|
|
std::string s;
|
|
s.reserve (strlen (b->to_string ()) * size_t (x));
|
|
while (x-- > 0) {
|
|
s += b->to_string ();
|
|
}
|
|
|
|
v.set (tl::Variant (s));
|
|
|
|
} else if (v->is_double () || b->is_double ()) {
|
|
v.set (tl::Variant (to_double (m_context, *v) * to_double (m_context, *b)));
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) * to_ulonglong (m_context, *b)));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
v.set (tl::Variant (to_longlong (m_context, *v) * to_longlong (m_context, *b)));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
v.set (tl::Variant (to_ulong (m_context, *v) * to_ulong (m_context, *b)));
|
|
} else if (v->is_long () || b->is_long ()) {
|
|
v.set (tl::Variant (to_long (m_context, *v) * to_long (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_double (m_context, *v) * to_double (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Slash expression node
|
|
*/
|
|
class TL_PUBLIC SlashExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
SlashExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
SlashExpressionNode (const SlashExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new SlashExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "/", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_double () || b->is_double ()) {
|
|
double d = to_double (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Division by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_double (m_context, *v) / d));
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
unsigned long long d = to_ulonglong (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Division by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) / d));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
long long d = to_longlong (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Division by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_longlong (m_context, *v) / d));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
unsigned long d = to_ulong (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Division by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_ulong (m_context, *v) / d));
|
|
} else if (v->is_long () || b->is_long ()) {
|
|
long d = to_long (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Division by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_long (m_context, *v) / d));
|
|
} else {
|
|
double d = to_double (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Division by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_double (m_context, *v) / d));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Percent expression node
|
|
*/
|
|
class TL_PUBLIC PercentExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
PercentExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
PercentExpressionNode (const PercentExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new PercentExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "%", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
unsigned long long d = to_ulonglong (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Modulo by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) % d));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
long long d = to_longlong (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Modulo by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_longlong (m_context, *v) % d));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
unsigned long d = to_ulong (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Modulo by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_ulong (m_context, *v) % d));
|
|
} else {
|
|
long d = to_long (m_context, *b);
|
|
if (d == 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Modulo by zero")), m_context);
|
|
}
|
|
v.set (tl::Variant (to_long (m_context, *v) % d));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Ampersand expression node
|
|
*/
|
|
class TL_PUBLIC AmpersandExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
AmpersandExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
AmpersandExpressionNode (const AmpersandExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new AmpersandExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "&", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) & to_ulonglong (m_context, *b)));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
v.set (tl::Variant (to_longlong (m_context, *v) & to_longlong (m_context, *b)));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
v.set (tl::Variant (to_ulong (m_context, *v) & to_ulong (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_long (m_context, *v) & to_long (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Pipe expression node
|
|
*/
|
|
class TL_PUBLIC PipeExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
PipeExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
PipeExpressionNode (const PipeExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new PipeExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "|", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) | to_ulonglong (m_context, *b)));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
v.set (tl::Variant (to_longlong (m_context, *v) | to_longlong (m_context, *b)));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
v.set (tl::Variant (to_ulong (m_context, *v) | to_ulong (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_long (m_context, *v) | to_long (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Acute expression node
|
|
*/
|
|
class TL_PUBLIC AcuteExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
AcuteExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
AcuteExpressionNode (const AcuteExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new AcuteExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget b;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (b);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*b);
|
|
c->execute (m_context, o, v.get (), "^", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_ulonglong () || b->is_ulonglong ()) {
|
|
v.set (tl::Variant (to_ulonglong (m_context, *v) ^ to_ulonglong (m_context, *b)));
|
|
} else if (v->is_longlong () || b->is_longlong ()) {
|
|
v.set (tl::Variant (to_longlong (m_context, *v) ^ to_longlong (m_context, *b)));
|
|
} else if (v->is_ulong () || b->is_ulong ()) {
|
|
v.set (tl::Variant (to_ulong (m_context, *v) ^ to_ulong (m_context, *b)));
|
|
} else {
|
|
v.set (tl::Variant (to_long (m_context, *v) ^ to_long (m_context, *b)));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Index expression node
|
|
*/
|
|
class TL_PUBLIC IndexExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
IndexExpressionNode (const ExpressionParserContext &context, ExpressionNode *a, ExpressionNode *b)
|
|
: ExpressionNode (context, 2)
|
|
{
|
|
add_child (a);
|
|
add_child (b);
|
|
}
|
|
|
|
IndexExpressionNode (const IndexExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new IndexExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
EvalTarget e;
|
|
m_c[0]->execute (v);
|
|
m_c[1]->execute (e);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
vv.push_back (*e);
|
|
c->execute (m_context, o, v.get (), "[]", vv);
|
|
v.swap (o);
|
|
|
|
} else if (v->is_list ()) {
|
|
|
|
if (! e->can_convert_to_ulong ()) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Invalid index for [] operator")), m_context);
|
|
}
|
|
unsigned long i = e->to_ulong ();
|
|
if (i >= (unsigned long) v->size ()) {
|
|
v.set (tl::Variant ());
|
|
} else if (v.lvalue ()) {
|
|
v.set_lvalue (&(v.lvalue ()->begin () [i]));
|
|
} else {
|
|
v.set (v->begin () [i]);
|
|
}
|
|
|
|
} else if (v->is_array ()) {
|
|
|
|
if (v.lvalue ()) {
|
|
tl::Variant *x = v.lvalue ()->find (*e);
|
|
if (! x) {
|
|
v.set (tl::Variant ());
|
|
} else {
|
|
v.set_lvalue (x);
|
|
}
|
|
} else {
|
|
const tl::Variant *x = v->find (*e);
|
|
if (! x) {
|
|
v.set (tl::Variant ());
|
|
} else {
|
|
v.set (*x);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("[] operator expects a list or an array")), m_context);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Unary minus expression node
|
|
*/
|
|
class TL_PUBLIC UnaryMinusExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
UnaryMinusExpressionNode (const ExpressionParserContext &context, ExpressionNode *a)
|
|
: ExpressionNode (context, 1)
|
|
{
|
|
add_child (a);
|
|
}
|
|
|
|
UnaryMinusExpressionNode (const UnaryMinusExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new UnaryMinusExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
throw EvalError (tl::to_string (QObject::tr ("Unary minus not implemented for objects")), m_context);
|
|
/*
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
c->execute (this, o, v.get (), "-", vv);
|
|
v.swap (o);
|
|
*/
|
|
|
|
} else if (v->is_long ()) {
|
|
v.set (-v->to_long ());
|
|
} else if (v->is_ulong ()) {
|
|
v.set (-long (v->to_ulong ()));
|
|
} else if (v->is_longlong ()) {
|
|
v.set (-v->to_longlong ());
|
|
} else if (v->is_ulonglong ()) {
|
|
v.set (-(long long)(v->to_ulonglong ()));
|
|
} else {
|
|
v.set (-to_double (m_context, *v));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Unary tilde expression node
|
|
*/
|
|
class TL_PUBLIC UnaryTildeExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
UnaryTildeExpressionNode (const ExpressionParserContext &context, ExpressionNode *a)
|
|
: ExpressionNode (context, 1)
|
|
{
|
|
add_child (a);
|
|
}
|
|
|
|
UnaryTildeExpressionNode (const UnaryTildeExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new UnaryTildeExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
|
|
if (v->is_user ()) {
|
|
|
|
throw EvalError (tl::to_string (QObject::tr ("Unary tilde not implemented for objects")), m_context);
|
|
/*
|
|
const EvalClass *c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object)")), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
std::vector <tl::Variant> vv;
|
|
c->execute (this, o, v.get (), "~", vv);
|
|
v.swap (o);
|
|
*/
|
|
|
|
} else if (v->is_ulong ()) {
|
|
v.set (~v->to_ulong ());
|
|
} else if (v->is_longlong ()) {
|
|
v.set (~v->to_longlong ());
|
|
} else if (v->is_ulonglong ()) {
|
|
v.set (~v->to_ulonglong ());
|
|
} else {
|
|
v.set (~to_long (m_context, *v));
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Unary not expression node
|
|
*/
|
|
class TL_PUBLIC UnaryNotExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
UnaryNotExpressionNode (const ExpressionParserContext &context, ExpressionNode *a)
|
|
: ExpressionNode (context, 1)
|
|
{
|
|
add_child (a);
|
|
}
|
|
|
|
UnaryNotExpressionNode (const UnaryNotExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new UnaryNotExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
|
|
if (v->is_user ()) {
|
|
// objects act as true
|
|
v.set (false);
|
|
} else {
|
|
v.set (! v->to_bool ());
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Constant expression node
|
|
*/
|
|
class TL_PUBLIC ConstantExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
ConstantExpressionNode (const ExpressionParserContext &context, const tl::Variant &value)
|
|
: ExpressionNode (context), m_value (value)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ConstantExpressionNode (const ConstantExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), m_value (other.m_value)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new ConstantExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
v.set (m_value);
|
|
}
|
|
|
|
private:
|
|
tl::Variant m_value;
|
|
};
|
|
|
|
/**
|
|
* @brief Evaluates a bracket expression in the context
|
|
*/
|
|
class TL_PUBLIC ContextEvaluationNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
ContextEvaluationNode (const ExpressionParserContext &context, const ContextHandler *ctx_handler, ExpressionNode *a, bool double_bracket)
|
|
: ExpressionNode (context, 1), mp_ctx_handler (ctx_handler), m_double_bracket (double_bracket)
|
|
{
|
|
add_child (a);
|
|
}
|
|
|
|
ContextEvaluationNode (const ContextEvaluationNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), mp_ctx_handler (other.mp_ctx_handler), m_double_bracket (other.m_double_bracket)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new ContextEvaluationNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
std::string s = v->to_string ();
|
|
if (m_double_bracket) {
|
|
v.set (mp_ctx_handler->eval_double_bracket (s));
|
|
} else {
|
|
v.set (mp_ctx_handler->eval_bracket (s));
|
|
}
|
|
}
|
|
|
|
private:
|
|
const ContextHandler *mp_ctx_handler;
|
|
bool m_double_bracket;
|
|
};
|
|
|
|
/**
|
|
* @brief Method call expression node
|
|
*/
|
|
class TL_PUBLIC MethodExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
MethodExpressionNode (const ExpressionParserContext &context, const std::string &method)
|
|
: ExpressionNode (context), m_method (method)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
MethodExpressionNode (const MethodExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), m_method (other.m_method)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new MethodExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
m_c[0]->execute (v);
|
|
|
|
std::vector <tl::Variant> vv;
|
|
vv.reserve (m_c.size () - 1);
|
|
for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin () + 1; c != m_c.end (); ++c) {
|
|
EvalTarget a;
|
|
(*c)->execute (a);
|
|
vv.push_back (*a);
|
|
}
|
|
|
|
const EvalClass *c = 0;
|
|
|
|
if (v->is_list ()) {
|
|
c = &ListClass::instance;
|
|
} else if (v->is_array ()) {
|
|
c = &ArrayClass::instance;
|
|
} else if (v->is_user ()) {
|
|
c = v->user_cls () ? v->user_cls ()->eval_cls () : 0;
|
|
if (! c) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (not an object) - value is %1").arg (tl::to_qstring (v->to_parsable_string ()))), m_context);
|
|
}
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Not a valid object for a method call (wrong type) - value is %1").arg (tl::to_qstring (v->to_parsable_string ()))), m_context);
|
|
}
|
|
|
|
tl::Variant o;
|
|
c->execute (m_context, o, v.get (), m_method, vv);
|
|
v.swap (o);
|
|
}
|
|
|
|
private:
|
|
std::string m_method;
|
|
};
|
|
|
|
/**
|
|
* @brief List expression node
|
|
*/
|
|
class TL_PUBLIC ListExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
ListExpressionNode (const ExpressionParserContext &context)
|
|
: ExpressionNode (context)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ListExpressionNode (const ListExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new ListExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
v.set (tl::Variant::empty_list ());
|
|
v.get ().reserve (m_c.size ());
|
|
|
|
for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin (); c != m_c.end (); ++c) {
|
|
EvalTarget a;
|
|
(*c)->execute (a);
|
|
v.get ().push (*a);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Array expression node
|
|
*/
|
|
class TL_PUBLIC ArrayExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
ArrayExpressionNode (const ExpressionParserContext &context)
|
|
: ExpressionNode (context)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ArrayExpressionNode (const ArrayExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new ArrayExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
v.set (tl::Variant::empty_array ());
|
|
for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin (); c != m_c.end (); c += 2) {
|
|
EvalTarget k, x;
|
|
c[0]->execute (k);
|
|
c[1]->execute (x);
|
|
v.get ().insert (*k, *x);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Sequence expression node
|
|
*/
|
|
class TL_PUBLIC SequenceExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
SequenceExpressionNode (const ExpressionParserContext &context)
|
|
: ExpressionNode (context)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
SequenceExpressionNode (const SequenceExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new SequenceExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin (); c != m_c.end (); ++c) {
|
|
(*c)->execute (v);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Static function expression node
|
|
*/
|
|
class TL_PUBLIC StaticFunctionExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
StaticFunctionExpressionNode (const ExpressionParserContext &context, const EvalFunction *func)
|
|
: ExpressionNode (context), mp_func (func)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
StaticFunctionExpressionNode (const StaticFunctionExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), mp_func (other.mp_func)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new StaticFunctionExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
std::vector<tl::Variant> vv;
|
|
vv.reserve (m_c.size ());
|
|
|
|
for (std::vector<ExpressionNode *>::const_iterator c = m_c.begin (); c != m_c.end (); ++c) {
|
|
EvalTarget a;
|
|
(*c)->execute (a);
|
|
vv.push_back (*a);
|
|
}
|
|
|
|
tl::Variant o;
|
|
mp_func->execute (m_context, o, vv);
|
|
v.swap (o);
|
|
}
|
|
|
|
private:
|
|
const EvalFunction *mp_func;
|
|
};
|
|
|
|
/**
|
|
* @brief Variable expression node (as RValue)
|
|
*/
|
|
class TL_PUBLIC RVariableExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
RVariableExpressionNode (const ExpressionParserContext &context, const tl::Variant *var)
|
|
: ExpressionNode (context), mp_var (var)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
RVariableExpressionNode (const RVariableExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), mp_var (other.mp_var)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new RVariableExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
v.set (*mp_var);
|
|
}
|
|
|
|
private:
|
|
const tl::Variant *mp_var;
|
|
};
|
|
|
|
/**
|
|
* @brief Variable expression node (as LValue)
|
|
*/
|
|
class TL_PUBLIC LVariableExpressionNode
|
|
: public ExpressionNode
|
|
{
|
|
public:
|
|
LVariableExpressionNode (const ExpressionParserContext &context, tl::Variant *var)
|
|
: ExpressionNode (context), mp_var (var)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
LVariableExpressionNode (const LVariableExpressionNode &other, const tl::Expression *expr)
|
|
: ExpressionNode (other, expr), mp_var (other.mp_var)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
ExpressionNode *clone (const tl::Expression *expr) const
|
|
{
|
|
return new LVariableExpressionNode (*this, expr);
|
|
}
|
|
|
|
void execute (EvalTarget &v) const
|
|
{
|
|
v.set_lvalue (mp_var);
|
|
}
|
|
|
|
private:
|
|
tl::Variant *mp_var;
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of functions
|
|
|
|
static void
|
|
sin_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = sin (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
sinh_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = sinh (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
cos_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = cos (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
cosh_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = cosh (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
tan_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = tan (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
tanh_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = tanh (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
log_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = ::log (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
log10_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = log10 (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
exp_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = exp (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
floor_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = floor (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
ceil_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = ceil (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
round_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
// VC++ does not have "round"
|
|
// out = round (to_double (context, v));
|
|
out = floor (0.5 + to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
sqrt_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = sqrt (to_double (context, v));
|
|
}
|
|
|
|
static void
|
|
abs_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
if (v.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'abs' function expects exactly one argument")), context);
|
|
}
|
|
|
|
if (v[0].is_long ()) {
|
|
out = labs (v[0].to_long ());
|
|
} else if (v[0].is_ulong ()) {
|
|
out = v[0].to_ulong ();
|
|
} else if (v[0].is_longlong ()) {
|
|
out = llabs (v[0].to_longlong ());
|
|
} else if (v[0].is_ulonglong ()) {
|
|
out = v[0].to_ulonglong ();
|
|
} else if (v[0].is_double ()) {
|
|
out = fabs (v[0].to_double ());
|
|
} else {
|
|
out = labs (to_long (context, v[0]));
|
|
}
|
|
}
|
|
|
|
static void
|
|
acos_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = acos (to_double (context, v));
|
|
}
|
|
|
|
#ifndef _MSC_VER // not available on MS VC++
|
|
static void
|
|
acosh_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = acosh (to_double (context, v));
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
asin_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = asin (to_double (context, v));
|
|
}
|
|
|
|
#ifndef _MSC_VER // not available on MS VC++
|
|
static void
|
|
asinh_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = asinh (to_double (context, v));
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
atan_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = atan (to_double (context, v));
|
|
}
|
|
|
|
#ifndef _MSC_VER // not available on MS VC++
|
|
static void
|
|
atanh_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v)
|
|
{
|
|
out = atanh (to_double (context, v));
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
min_f (const ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
out = tl::Variant ();
|
|
for (std::vector <tl::Variant>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
|
if (! v->is_nil () && (out.is_nil () || *v < out)) {
|
|
out = *v;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
max_f (const ExpressionParserContext &, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
out = tl::Variant ();
|
|
for (std::vector <tl::Variant>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
|
if (! v->is_nil () && (out.is_nil () || out < *v)) {
|
|
out = *v;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
pow_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'pow' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
out = pow (to_double (context, vv [0]), to_double (context, vv [1]));
|
|
}
|
|
|
|
static void
|
|
atan2_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'atan2' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
out = atan2 (to_double (context, vv [0]), to_double (context, vv [1]));
|
|
}
|
|
|
|
static void
|
|
to_f_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'to_f' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].to_double ();
|
|
}
|
|
|
|
static void
|
|
to_s_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'to_s' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].to_string ();
|
|
}
|
|
|
|
static void
|
|
to_i_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'to_i' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].to_long ();
|
|
}
|
|
|
|
static void
|
|
to_ui_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'to_ui' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].to_ulong ();
|
|
}
|
|
|
|
static void
|
|
to_l_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'to_l' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].to_longlong ();
|
|
}
|
|
|
|
static void
|
|
to_ul_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'to_ul' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].to_ulonglong ();
|
|
}
|
|
|
|
static void
|
|
is_string_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'is_string' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv[0].is_a_string ();
|
|
}
|
|
|
|
static void
|
|
is_numeric_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'is_numeric' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].can_convert_to_double ();
|
|
}
|
|
|
|
static void
|
|
is_array_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'is_array' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].is_list ();
|
|
}
|
|
|
|
static void
|
|
is_nil_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'is_nil' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = vv [0].is_nil ();
|
|
}
|
|
|
|
static void
|
|
gsub_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 3) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'gsub' function expects exactly three arguments")), context);
|
|
}
|
|
|
|
std::string s (vv [0].to_string ());
|
|
std::string x (vv [1].to_string ());
|
|
std::string y (vv [2].to_string ());
|
|
|
|
std::string r;
|
|
r.reserve (s.size ());
|
|
|
|
size_t p = 0;
|
|
for (size_t pp = 0; (pp = s.find (x, p)) != std::string::npos; p = pp + x.size ()) {
|
|
r += std::string (s, p, pp - p);
|
|
r += y;
|
|
}
|
|
|
|
r += std::string (s, p, std::string::npos);
|
|
|
|
out = r;
|
|
}
|
|
|
|
static void
|
|
sub_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 3) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'sub' function expects exactly three arguments")), context);
|
|
}
|
|
|
|
std::string s (vv [0].to_string ());
|
|
std::string x (vv [1].to_string ());
|
|
std::string y (vv [2].to_string ());
|
|
|
|
std::string r;
|
|
|
|
size_t p = s.find (x);
|
|
if (p != std::string::npos) {
|
|
|
|
r.reserve (s.size () + y.size () - x.size ());
|
|
r += std::string (s, 0, p);
|
|
r += y;
|
|
r += std::string (s, p + x.size ());
|
|
out = r;
|
|
|
|
} else {
|
|
out = s;
|
|
}
|
|
|
|
}
|
|
|
|
static void
|
|
find_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'find' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
std::string s (vv [0].to_string ());
|
|
std::string x (vv [1].to_string ());
|
|
|
|
size_t p = s.find (x);
|
|
if (p != std::string::npos) {
|
|
out = long (p);
|
|
} else {
|
|
out = tl::Variant ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
rfind_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'rfind' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
std::string s (vv [0].to_string ());
|
|
std::string x (vv [1].to_string ());
|
|
|
|
size_t p = s.rfind (x);
|
|
if (p != std::string::npos) {
|
|
out = long (s.size () - (p + x.size ()));
|
|
} else {
|
|
out = tl::Variant ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
len_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'len' function expects exactly one argument")), context);
|
|
}
|
|
|
|
if (vv [0].is_list ()) {
|
|
out = long (vv [0].end () - vv [0].begin ());
|
|
} else {
|
|
out = long (strlen (vv [0].to_string ()));
|
|
}
|
|
}
|
|
|
|
static void
|
|
substr_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 3 && vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'substr' function expects two or three arguments")), context);
|
|
}
|
|
|
|
std::string s (vv [0].to_string ());
|
|
|
|
long len = -1;
|
|
if (vv.size () > 2) {
|
|
len = std::max (long (0), to_long (context, vv [2]));
|
|
}
|
|
|
|
long l = to_long (context, vv [1]);
|
|
if (l < 0) {
|
|
l = long (s.size ()) + l;
|
|
if (l < 0) {
|
|
len += l;
|
|
l = 0;
|
|
}
|
|
}
|
|
|
|
size_t from = size_t (l);
|
|
|
|
if (len == 0 || from >= s.size ()) {
|
|
out = tl::Variant ("");
|
|
} else if (len < 0 || from + len >= s.size ()) {
|
|
out = std::string (s, from);
|
|
} else {
|
|
out = std::string (s, from, len);
|
|
}
|
|
}
|
|
|
|
static void
|
|
join_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'join' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
if (! vv[0].is_list ()) {
|
|
throw EvalError (tl::to_string (QObject::tr ("First argument of 'join' function must be a list")), context);
|
|
}
|
|
|
|
std::ostringstream r;
|
|
r.imbue (c_locale);
|
|
|
|
std::string s (vv [1].to_string ());
|
|
|
|
bool first = true;
|
|
for (tl::Variant::const_iterator i = vv [0].begin (); i != vv [0].end (); ++i) {
|
|
if (first) {
|
|
r << s;
|
|
first = false;
|
|
}
|
|
r << i->to_string ();
|
|
}
|
|
|
|
out = r.str ();
|
|
}
|
|
|
|
static void
|
|
item_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'item' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
if (! vv[0].is_list ()) {
|
|
throw EvalError (tl::to_string (QObject::tr ("First argument of 'item' function must be a list")), context);
|
|
}
|
|
|
|
long index = to_long (context, vv [1]);
|
|
if (index < 0 || index >= long (vv [0].end () - vv [0].begin ())) {
|
|
out = tl::Variant ();
|
|
} else {
|
|
out = *(vv [0].begin () + index);
|
|
}
|
|
}
|
|
|
|
static void
|
|
split_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'split' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
out = tl::Variant::empty_list ();
|
|
std::string t (vv [0].to_string ());
|
|
std::string s (vv [1].to_string ());
|
|
|
|
size_t p = 0;
|
|
for (size_t pp = 0; (pp = t.find (s, p)) != std::string::npos; p = pp + s.size ()) {
|
|
out.push (tl::Variant (std::string (t, p, pp - p)));
|
|
}
|
|
|
|
out.push (tl::Variant (std::string (t, p)));
|
|
}
|
|
|
|
static void
|
|
true_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'true' function must not have arguments")), context);
|
|
}
|
|
|
|
out = true;
|
|
}
|
|
|
|
static void
|
|
false_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'false' function must not have arguments")), context);
|
|
}
|
|
|
|
out = false;
|
|
}
|
|
|
|
static void
|
|
nil_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 0) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'nil' function must not have arguments")), context);
|
|
}
|
|
|
|
out = tl::Variant ();
|
|
}
|
|
|
|
static void
|
|
env_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'env' function expects exactly two arguments")), context);
|
|
}
|
|
|
|
const char *env = getenv (vv [0].to_string ());
|
|
if (env) {
|
|
out = env;
|
|
} else {
|
|
out = tl::Variant ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
error_f (const ExpressionParserContext &context, tl::Variant &, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'error' function expects exactly one argument")), context);
|
|
}
|
|
|
|
throw tl::Exception (vv [0].to_string ());
|
|
}
|
|
|
|
static void
|
|
absolute_file_path_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'absolute_file_path' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = QFileInfo (vv [0].to_qstring ()).absoluteFilePath ();
|
|
}
|
|
|
|
static void
|
|
absolute_path_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'absolute_path' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = QFileInfo (vv [0].to_qstring ()).absolutePath ();
|
|
}
|
|
|
|
static void
|
|
path_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'path' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = QFileInfo (vv [0].to_qstring ()).path ();
|
|
}
|
|
|
|
static void
|
|
basename_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'basename' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = QFileInfo (vv [0].to_qstring ()).baseName ();
|
|
}
|
|
|
|
static void
|
|
extension_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'extension' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = QFileInfo (vv [0].to_qstring ()).completeSuffix ();
|
|
}
|
|
|
|
static void
|
|
file_exists_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'file_exists' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = QFileInfo (vv [0].to_qstring ()).exists ();
|
|
}
|
|
|
|
static void
|
|
is_dir_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'is_dir' function expects exactly one argument")), context);
|
|
}
|
|
|
|
out = QFileInfo (vv [0].to_qstring ()).isDir ();
|
|
}
|
|
|
|
static void
|
|
combine_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () != 2) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'combine' function expects two arguments")), context);
|
|
}
|
|
|
|
out = QFileInfo (QDir (vv [0].to_qstring ()), vv [1].to_qstring ()).filePath ();
|
|
}
|
|
|
|
static void
|
|
sprintf_f (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () < 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'sprintf' function expects at least one argument")), context);
|
|
}
|
|
|
|
out = tl::sprintf (vv[0].to_string (), vv, 1);
|
|
}
|
|
|
|
static void
|
|
printf_f (const ExpressionParserContext &context, tl::Variant &, const std::vector <tl::Variant> &vv)
|
|
{
|
|
if (vv.size () < 1) {
|
|
throw EvalError (tl::to_string (QObject::tr ("'printf' function expects at least one argument")), context);
|
|
}
|
|
|
|
std::cout << tl::sprintf (vv[0].to_string (), vv, 1);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Definition of a function wrapper
|
|
|
|
class EvalStaticFunction
|
|
: public EvalFunction
|
|
{
|
|
typedef void (*function_t) (const ExpressionParserContext &context, tl::Variant &out, const std::vector <tl::Variant> &v);
|
|
|
|
public:
|
|
EvalStaticFunction (const std::string &name, function_t func)
|
|
: m_func (func), m_name (name)
|
|
{
|
|
ms_functions.insert (std::make_pair (name, this));
|
|
}
|
|
|
|
~EvalStaticFunction ()
|
|
{
|
|
ms_functions.erase (m_name);
|
|
}
|
|
|
|
void execute (const ExpressionParserContext &context, tl::Variant &out, const std::vector<tl::Variant> &args) const
|
|
{
|
|
m_func (context, out, args);
|
|
}
|
|
|
|
static EvalFunction *function_by_name (const std::string &name)
|
|
{
|
|
std::map <std::string, EvalFunction *>::const_iterator f = ms_functions.find (name);
|
|
if (f != ms_functions.end ()) {
|
|
return f->second;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private:
|
|
function_t m_func;
|
|
std::string m_name;
|
|
|
|
static std::map <std::string, EvalFunction *> ms_functions;
|
|
};
|
|
|
|
std::map <std::string, EvalFunction *> EvalStaticFunction::ms_functions;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of the function table
|
|
|
|
static EvalStaticFunction f1 ("sin", &sin_f);
|
|
static EvalStaticFunction f2 ("sinh", &sinh_f);
|
|
static EvalStaticFunction f3 ("cos", &cos_f);
|
|
static EvalStaticFunction f4 ("cosh", &cosh_f);
|
|
static EvalStaticFunction f5 ("tan", &tan_f);
|
|
static EvalStaticFunction f6 ("tanh", &tanh_f);
|
|
static EvalStaticFunction f7 ("log", &log_f);
|
|
static EvalStaticFunction f8 ("log10", &log10_f);
|
|
static EvalStaticFunction f9 ("exp", &exp_f);
|
|
static EvalStaticFunction f10 ("floor", &floor_f);
|
|
static EvalStaticFunction f11 ("ceil", &ceil_f);
|
|
static EvalStaticFunction f12 ("round", &round_f);
|
|
static EvalStaticFunction f13 ("sqrt", &sqrt_f);
|
|
static EvalStaticFunction f14 ("max", &max_f);
|
|
static EvalStaticFunction f15 ("min", &min_f);
|
|
static EvalStaticFunction f16 ("pow", &pow_f);
|
|
static EvalStaticFunction f17 ("acos", &acos_f);
|
|
#ifndef _MSC_VER // not available on MS VC++
|
|
static EvalStaticFunction f18 ("acosh", &acosh_f);
|
|
static EvalStaticFunction f19 ("asinh", &asinh_f);
|
|
static EvalStaticFunction f20 ("atanh", &atanh_f);
|
|
#endif
|
|
static EvalStaticFunction f21 ("asin", &asin_f);
|
|
static EvalStaticFunction f22 ("atan", &atan_f);
|
|
static EvalStaticFunction f23 ("atan2", &atan2_f);
|
|
static EvalStaticFunction f24 ("to_f", &to_f_f);
|
|
static EvalStaticFunction f25 ("to_s", &to_s_f);
|
|
static EvalStaticFunction f26 ("to_i", &to_i_f);
|
|
static EvalStaticFunction f27 ("to_ui", &to_ui_f);
|
|
static EvalStaticFunction f28 ("to_l", &to_l_f);
|
|
static EvalStaticFunction f29 ("to_ul", &to_ul_f);
|
|
static EvalStaticFunction f30 ("is_string", &is_string_f);
|
|
static EvalStaticFunction f31 ("is_numeric", &is_numeric_f);
|
|
static EvalStaticFunction f32 ("is_array", &is_array_f);
|
|
static EvalStaticFunction f33 ("is_nil", &is_nil_f);
|
|
static EvalStaticFunction f34 ("join", &join_f);
|
|
static EvalStaticFunction f35 ("split", &split_f);
|
|
static EvalStaticFunction f36 ("item", &item_f);
|
|
static EvalStaticFunction f37 ("sub", &sub_f);
|
|
static EvalStaticFunction f38 ("gsub", &gsub_f);
|
|
static EvalStaticFunction f39 ("find", &find_f);
|
|
static EvalStaticFunction f40 ("rfind", &rfind_f);
|
|
static EvalStaticFunction f41 ("len", &len_f);
|
|
static EvalStaticFunction f42 ("substr", &substr_f);
|
|
static EvalStaticFunction f43 ("env", &env_f);
|
|
static EvalStaticFunction f44 ("error", &error_f);
|
|
static EvalStaticFunction f45 ("sprintf", &sprintf_f);
|
|
static EvalStaticFunction f46 ("printf", &printf_f);
|
|
static EvalStaticFunction f47 ("false", &false_f);
|
|
static EvalStaticFunction f48 ("true", &true_f);
|
|
static EvalStaticFunction f49 ("nil", &nil_f);
|
|
static EvalStaticFunction f50 ("absolute_file_path", &absolute_file_path_f);
|
|
static EvalStaticFunction f51 ("absolute_path", &absolute_path_f);
|
|
static EvalStaticFunction f52 ("path", &path_f);
|
|
static EvalStaticFunction f53 ("basename", &basename_f);
|
|
static EvalStaticFunction f54 ("extension", &extension_f);
|
|
static EvalStaticFunction f55 ("file_exists", &file_exists_f);
|
|
static EvalStaticFunction f56 ("is_dir", &is_dir_f);
|
|
static EvalStaticFunction f57 ("combine", &combine_f);
|
|
static EvalStaticFunction f58 ("abs", &abs_f);
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of a constant wrapper
|
|
|
|
class EvalStaticConstant
|
|
{
|
|
public:
|
|
EvalStaticConstant (const std::string &name, const tl::Variant &v)
|
|
: m_var (v), m_name (name)
|
|
{
|
|
ms_constants.insert (std::make_pair (name, v));
|
|
}
|
|
|
|
static const tl::Variant *constant_by_name (const std::string &name)
|
|
{
|
|
std::map <std::string, tl::Variant>::const_iterator c = ms_constants.find (name);
|
|
if (c != ms_constants.end ()) {
|
|
return &c->second;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
private:
|
|
tl::Variant m_var;
|
|
std::string m_name;
|
|
|
|
static std::map <std::string, tl::Variant> ms_constants;
|
|
};
|
|
|
|
std::map <std::string, tl::Variant> EvalStaticConstant::ms_constants;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of the constant table
|
|
|
|
static EvalStaticConstant c1 ("M_PI", tl::Variant (M_PI));
|
|
static EvalStaticConstant c2 ("M_E", tl::Variant (M_E));
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of Expression
|
|
|
|
Expression::Expression ()
|
|
: mp_text (0), mp_eval (0)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
Expression::Expression (const Expression &d)
|
|
: mp_text (0), mp_eval (0)
|
|
{
|
|
operator= (d);
|
|
}
|
|
|
|
Expression::Expression (Eval *eval, const std::string &expr)
|
|
: mp_text (0), m_local_text (expr), mp_eval (eval)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
Expression::Expression (Eval *eval, const char *expr)
|
|
: mp_text (expr), mp_eval (eval)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
Expression &
|
|
Expression::operator= (const Expression &d)
|
|
{
|
|
if (&d != this) {
|
|
mp_eval = d.mp_eval;
|
|
m_local_text = d.m_local_text;
|
|
mp_text = d.mp_text;
|
|
if (d.m_root.get ()) {
|
|
m_root.reset (d.m_root->clone (this));
|
|
} else {
|
|
m_root.reset (0);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
tl::Variant
|
|
Expression::execute () const
|
|
{
|
|
EvalTarget v;
|
|
execute (v);
|
|
return v.make_result ();
|
|
}
|
|
|
|
void
|
|
Expression::execute (EvalTarget &v) const
|
|
{
|
|
if (m_root.get ()) {
|
|
m_root->execute (v);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Implementation of Eval
|
|
|
|
Eval Eval::m_global;
|
|
|
|
Eval::Eval (const Eval *parent, bool sloppy)
|
|
: mp_parent (parent), m_sloppy (sloppy), mp_ctx_handler (0)
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
Eval::~Eval ()
|
|
{
|
|
for (std::map <std::string, EvalFunction *>::iterator f = m_local_functions.begin (); f != m_local_functions.end (); ++f) {
|
|
delete f->second;
|
|
}
|
|
m_local_functions.clear ();
|
|
}
|
|
|
|
void
|
|
Eval::set_var (const std::string &name, const tl::Variant &var)
|
|
{
|
|
m_local_vars.insert (std::make_pair (name, tl::Variant ())).first->second = var;
|
|
}
|
|
|
|
void
|
|
Eval::define_function (const std::string &name, EvalFunction *function)
|
|
{
|
|
EvalFunction *&f = m_local_functions.insert (std::make_pair (name, (EvalFunction *) 0)).first->second;
|
|
if (f != 0) {
|
|
delete f;
|
|
}
|
|
f = function;
|
|
}
|
|
|
|
void
|
|
Eval::eval_top (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
do {
|
|
|
|
if (ex.test ("#")) {
|
|
|
|
// ignore comments after "#"
|
|
while (*ex && *ex != '\n') {
|
|
++ex;
|
|
}
|
|
|
|
} else {
|
|
|
|
std::auto_ptr<ExpressionNode> nn;
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
|
|
if (ex.test ("var")) {
|
|
|
|
eval_atomic (ex, nn, 2);
|
|
|
|
ExpressionParserContext exb = ex;
|
|
if (! exb.test ("=>") && ! exb.test ("==") && ex.test ("=")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_assign (ex, b);
|
|
nn.reset (new AssignExpressionNode (ex1, nn.release (), b.release ()));
|
|
|
|
}
|
|
|
|
} else {
|
|
eval_assign (ex, nn);
|
|
}
|
|
|
|
if (! n.get ()) {
|
|
n.reset (nn.release ());
|
|
} else if (dynamic_cast <SequenceExpressionNode *> (n.get ())) {
|
|
n->add_child (nn.release ());
|
|
} else {
|
|
SequenceExpressionNode *m = new SequenceExpressionNode (ex);
|
|
m->add_child (n.release ());
|
|
m->add_child (nn.release ());
|
|
n.reset (m);
|
|
}
|
|
|
|
if (!ex.test (";")) {
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
} while (! ex.at_end ());
|
|
}
|
|
|
|
void
|
|
Eval::eval_assign (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_if (ex, n);
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
tl::Extractor exb = ex;
|
|
if (! exb.test ("=>") && ! exb.test ("==") && ex.test ("=")) {
|
|
|
|
exb = ex;
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_assign (ex, b);
|
|
n.reset (new AssignExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_if (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_boolean (ex, n);
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test ("?")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b, c;
|
|
eval_if (ex, b);
|
|
if (! ex.test (":")) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Expected ':'")), ex);
|
|
}
|
|
eval_if (ex, c);
|
|
n.reset (new IfExpressionNode (ex1, n.release (), b.release (), c.release ()));
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_boolean (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_conditional (ex, n);
|
|
|
|
while (true) {
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test("||")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_conditional (ex, b);
|
|
n.reset (new LogOrExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test ("&&")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_conditional (ex, b);
|
|
n.reset (new LogAndExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_conditional (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_shift (ex, n);
|
|
|
|
while (true) {
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test("<=")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new LessOrEqualExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("<")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new LessExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test(">=")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new GreaterOrEqualExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test(">")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new GreaterExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("==")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new EqualExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("!=")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new NotEqualExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("~")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new MatchExpressionNode (ex1, n.release (), b.release (), this));
|
|
|
|
} else if (ex.test("!~")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_shift (ex, b);
|
|
n.reset (new NoMatchExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_shift (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_addsub (ex, n);
|
|
|
|
while (true) {
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test("<<")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_addsub (ex, b);
|
|
n.reset (new ShiftLeftExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test(">>")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_addsub (ex, b);
|
|
n.reset (new ShiftRightExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_addsub (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_product (ex, n);
|
|
|
|
while (true) {
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test("+")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_product (ex, b);
|
|
n.reset (new PlusExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("-")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_product (ex, b);
|
|
n.reset (new MinusExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_product (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_bitwise (ex, n);
|
|
|
|
while (true) {
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test("*")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_bitwise (ex, b);
|
|
n.reset (new StarExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("/")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_bitwise (ex, b);
|
|
n.reset (new SlashExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("%")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_bitwise (ex, b);
|
|
n.reset (new PercentExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_bitwise (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_unary (ex, n);
|
|
|
|
while (true) {
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
tl::Extractor exb = ex;
|
|
if (exb.test("||")) {
|
|
break; // not handled here
|
|
} else if (exb.test("&&")) {
|
|
break; // not handled here
|
|
} else if (ex.test("&")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_unary (ex, b);
|
|
n.reset (new AmpersandExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("|")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_unary (ex, b);
|
|
n.reset (new PipeExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else if (ex.test("^")) {
|
|
|
|
std::auto_ptr<ExpressionNode> b;
|
|
eval_unary (ex, b);
|
|
n.reset (new AcuteExpressionNode (ex1, n.release (), b.release ()));
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::eval_unary (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test ("!")) {
|
|
|
|
eval_unary (ex, n);
|
|
n.reset (new UnaryNotExpressionNode (ex1, n.release ()));
|
|
|
|
} else if (ex.test ("-")) {
|
|
|
|
eval_unary (ex, n);
|
|
n.reset (new UnaryMinusExpressionNode (ex1, n.release ()));
|
|
|
|
} else if (ex.test ("~")) {
|
|
|
|
eval_unary (ex, n);
|
|
n.reset (new UnaryTildeExpressionNode (ex1, n.release ()));
|
|
|
|
} else {
|
|
eval_suffix (ex, n);
|
|
}
|
|
}
|
|
|
|
static const char *operator_methods[] =
|
|
{
|
|
"==", "[]", "()",
|
|
"&&", "&", "||", "|", ">>", ">=", ">", "<<", "<=", "<",
|
|
"++", "+", "--", "-", "^", "!~", "!=", "!", "~", "%", "*", "/",
|
|
0
|
|
};
|
|
|
|
void
|
|
Eval::eval_suffix (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n)
|
|
{
|
|
eval_atomic (ex, n, 1);
|
|
|
|
while (true) {
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test (".")) {
|
|
|
|
std::string t;
|
|
// check for operators
|
|
for (const char **om = operator_methods; *om; ++om) {
|
|
if (ex.test (*om)) {
|
|
t = *om;
|
|
break;
|
|
}
|
|
}
|
|
// normal method otherwise
|
|
if (t.empty ()) {
|
|
ex.read_word (t, "_");
|
|
}
|
|
|
|
tl::Extractor exb = ex;
|
|
|
|
if (exb.test ("=>") || exb.test ("==")) { // no handled here
|
|
|
|
MethodExpressionNode *m = new MethodExpressionNode (ex1, t);
|
|
m->add_child (n.release ());
|
|
n.reset (m);
|
|
|
|
} else if (ex.test ("=")) {
|
|
|
|
t += "=";
|
|
|
|
std::auto_ptr<ExpressionNode> a;
|
|
eval_assign (ex, a);
|
|
|
|
MethodExpressionNode *m = new MethodExpressionNode (ex1, t);
|
|
m->add_child (n.release ());
|
|
n.reset (m);
|
|
|
|
m->add_child (a.release ());
|
|
|
|
} else if (ex.test ("(")) {
|
|
|
|
MethodExpressionNode *m = new MethodExpressionNode (ex1, t);
|
|
m->add_child (n.release ());
|
|
n.reset (m);
|
|
|
|
if (! ex.test (")")) {
|
|
|
|
do {
|
|
|
|
std::auto_ptr<ExpressionNode> a;
|
|
eval_assign (ex, a);
|
|
m->add_child (a.release ());
|
|
|
|
if (ex.test (")")) {
|
|
break;
|
|
} else if (! ex.test (",")) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Expected closing bracket ')'")), ex);
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
MethodExpressionNode *m = new MethodExpressionNode (ex1, t);
|
|
m->add_child (n.release ());
|
|
n.reset (m);
|
|
|
|
}
|
|
|
|
} else if (ex.test ("[")) {
|
|
|
|
std::auto_ptr<ExpressionNode> a;
|
|
eval_top (ex, a);
|
|
n.reset (new IndexExpressionNode (ex1, n.release (), a.release ()));
|
|
|
|
ex.expect ("]");
|
|
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
static void
|
|
scan_angle_bracket (tl::Extractor &ex, const char *term, std::string &s)
|
|
{
|
|
const char *p0 = ex.get ();
|
|
|
|
while (! ex.at_end ()) {
|
|
|
|
const char *p = ex.skip ();
|
|
if (ex.test (term)) {
|
|
while (p > p0 && isspace (p[-1])) {
|
|
--p;
|
|
}
|
|
s = std::string (p0, 0, p - p0);
|
|
return;
|
|
}
|
|
|
|
if (*ex == '\'' || *ex == '"') {
|
|
std::string n;
|
|
ex.read_quoted (n);
|
|
} else {
|
|
++ex;
|
|
}
|
|
|
|
}
|
|
|
|
ex.expect (term);
|
|
}
|
|
|
|
void
|
|
Eval::eval_atomic (ExpressionParserContext &ex, std::auto_ptr<ExpressionNode> &n, int am)
|
|
{
|
|
double g = 0.0;
|
|
std::string t;
|
|
|
|
ExpressionParserContext ex1 = ex;
|
|
if (ex.test ("(")) {
|
|
|
|
eval_top (ex, n);
|
|
if (! ex.test (")")) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Expected closing bracket ')'")), ex);
|
|
}
|
|
|
|
} else if (ex.test ("[")) {
|
|
|
|
n.reset (new ListExpressionNode (ex1));
|
|
|
|
if (! ex.test ("]")) {
|
|
|
|
do {
|
|
|
|
std::auto_ptr<ExpressionNode> a;
|
|
eval_top (ex, a);
|
|
n->add_child (a.release ());
|
|
|
|
if (ex.test ("]")) {
|
|
break;
|
|
} else if (! ex.test (",")) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Expected closing bracket ']'")), ex);
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
} else if (ex.test ("<<")) {
|
|
|
|
ExpressionParserContext ex0 = ex;
|
|
if (ex.test ("$") || ex.test ("\"") || ex.test ("\'") || ex.test ("(")) {
|
|
|
|
ex = ex0;
|
|
eval_addsub (ex, n);
|
|
ex.expect (">>");
|
|
|
|
if (m_sloppy) {
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant ()));
|
|
} else if (ctx_handler ()) {
|
|
n.reset (new ContextEvaluationNode (ex1, ctx_handler (), n.release (), true /*double bracket*/));
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("<<..>> expression not available in this context")), ex1);
|
|
}
|
|
|
|
} else {
|
|
|
|
std::string s;
|
|
scan_angle_bracket (ex, ">>", s);
|
|
|
|
if (m_sloppy) {
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant ()));
|
|
} else if (ctx_handler ()) {
|
|
n.reset (new ConstantExpressionNode (ex1, ctx_handler ()->eval_double_bracket (s)));
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("<<..>> expression not available in this context")), ex1);
|
|
}
|
|
|
|
}
|
|
|
|
} else if (ex.test ("<")) {
|
|
|
|
ExpressionParserContext ex0 = ex;
|
|
if (ex.test ("$") || ex.test ("\"") || ex.test ("\'") || ex.test ("(")) {
|
|
|
|
ex = ex0;
|
|
eval_addsub (ex, n);
|
|
ex.expect (">");
|
|
|
|
if (m_sloppy) {
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant ()));
|
|
} else if (ctx_handler ()) {
|
|
n.reset (new ContextEvaluationNode (ex1, ctx_handler (), n.release (), false /*single bracket*/));
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("<<..>> expression not available in this context")), ex1);
|
|
}
|
|
|
|
} else {
|
|
|
|
std::string s;
|
|
scan_angle_bracket (ex, ">", s);
|
|
|
|
if (m_sloppy) {
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant ()));
|
|
} else if (ctx_handler ()) {
|
|
n.reset (new ConstantExpressionNode (ex1, ctx_handler ()->eval_bracket (s)));
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("<..> expression not available in this context")), ex1);
|
|
}
|
|
|
|
}
|
|
|
|
} else if (ex.test ("$")) {
|
|
|
|
// match substring
|
|
int i = 0;
|
|
ex.read (i);
|
|
n.reset (new MatchSubstringReferenceNode (ex1, this, i - 1));
|
|
|
|
} else if (ex.test ("{")) {
|
|
|
|
n.reset (new ArrayExpressionNode (ex1));
|
|
|
|
if (! ex.test ("}")) {
|
|
|
|
do {
|
|
|
|
ExpressionParserContext ex2 = ex;
|
|
std::auto_ptr<ExpressionNode> k;
|
|
eval_top (ex, k);
|
|
n->add_child (k.release ());
|
|
|
|
if (ex.test ("=>")) {
|
|
std::auto_ptr<ExpressionNode> v;
|
|
eval_top (ex, v);
|
|
n->add_child (v.release ());
|
|
} else {
|
|
n->add_child (new ConstantExpressionNode (ex2, tl::Variant ()));
|
|
}
|
|
|
|
if (ex.test ("}")) {
|
|
break;
|
|
} else if (! ex.test (",")) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Expected closing bracket ']'")), ex);
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
} else if (ex.test ("0x")) {
|
|
|
|
long x = 0;
|
|
while (! ex.at_end ()) {
|
|
if (isdigit (*ex) || (tolower (*ex) <= 'f' && tolower (*ex) >= 'a')) {
|
|
if ((x * 16) / 16 != x) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Hexadecimal number overflow")), ex1);
|
|
}
|
|
x *= 16;
|
|
if (isdigit (*ex)) {
|
|
x += long (*ex - '0');
|
|
} else {
|
|
x += long (tolower (*ex) - 'a' + 10);
|
|
}
|
|
++ex;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant (x)));
|
|
|
|
} else if (ex.try_read (g)) {
|
|
|
|
bool dbu_units = false;
|
|
|
|
if (ex.test ("um2") || ex.test("micron2") || ex.test ("mic2")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1.0 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ());
|
|
}
|
|
} else if (ex.test ("nm2")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1e-6 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ());
|
|
}
|
|
} else if (ex.test ("mm2")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1e6 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ());
|
|
}
|
|
} else if (ex.test ("m2")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1e12 / (ctx_handler ()->dbu () * ctx_handler ()->dbu ());
|
|
}
|
|
} else if (ex.test ("bs")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 0.005 / ctx_handler ()->dbu ();
|
|
}
|
|
} else if (ex.test ("nm")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1e-3 / ctx_handler ()->dbu ();
|
|
}
|
|
} else if (ex.test ("um") || ex.test("micron") || ex.test ("mic")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1.0 / ctx_handler ()->dbu ();
|
|
}
|
|
} else if (ex.test ("mm")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1e3 / ctx_handler ()->dbu ();
|
|
}
|
|
} else if (ex.test ("m")) {
|
|
dbu_units = true;
|
|
if (ctx_handler ()) {
|
|
g *= 1e6 / ctx_handler ()->dbu ();
|
|
}
|
|
}
|
|
|
|
if (m_sloppy) {
|
|
|
|
if (dbu_units && ! ctx_handler ()) {
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant ()));
|
|
} else {
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant (g)));
|
|
}
|
|
|
|
} else {
|
|
|
|
if (dbu_units && ! ctx_handler ()) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Length or area value with unit requires a layout context")), ex1);
|
|
}
|
|
|
|
if (dbu_units) {
|
|
// round to integers and check whether that is possible
|
|
double gg = g;
|
|
g = floor (0.5 + g);
|
|
if (fabs (g) < 1e12 && fabs (g - gg) > 1e-3) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Value is not a multiple of the database unit")), ex1);
|
|
}
|
|
}
|
|
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant (g)));
|
|
|
|
}
|
|
|
|
} else if (ex.try_read_quoted (t)) {
|
|
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant (t)));
|
|
|
|
} else if (ex.try_read_word (t, "_")) {
|
|
|
|
ExpressionParserContext ex2 = ex;
|
|
|
|
// for a function: collect the parameter or check if it's an assignment
|
|
std::vector <tl::Variant> vv;
|
|
|
|
const EvalFunction *function = 0;
|
|
const tl::Variant *value = 0;
|
|
tl::Variant *var = 0;
|
|
|
|
resolve_var_name (t, var);
|
|
if (! var) {
|
|
if (am == 2) {
|
|
set_var (t, tl::Variant ());
|
|
resolve_var_name (t, var);
|
|
} else {
|
|
resolve_name (t, function, value);
|
|
}
|
|
}
|
|
|
|
if (function) {
|
|
|
|
n.reset (new StaticFunctionExpressionNode (ex1, function));
|
|
|
|
ExpressionParserContext exb = ex;
|
|
if (exb.test ("(")) {
|
|
|
|
// for interpolation we must not eat white spaces.
|
|
ex = exb;
|
|
|
|
if (! ex.test (")")) {
|
|
|
|
do {
|
|
|
|
std::auto_ptr<ExpressionNode> v;
|
|
eval_top (ex, v);
|
|
n->add_child (v.release ());
|
|
|
|
if (ex.test (")")) {
|
|
break;
|
|
} else if (! ex.test (",")) {
|
|
throw EvalError (tl::to_string (QObject::tr ("Expected closing bracket ')'")), ex);
|
|
}
|
|
|
|
} while (true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (value) {
|
|
n.reset (new RVariableExpressionNode (ex1, value));
|
|
} else if (var) {
|
|
n.reset (new LVariableExpressionNode (ex1, var));
|
|
} else if (m_sloppy) {
|
|
n.reset (new ConstantExpressionNode (ex1, tl::Variant ()));
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Unknown variable or function")) + " '" + t + "'", ex1);
|
|
}
|
|
|
|
} else {
|
|
throw EvalError (tl::to_string (QObject::tr ("Expected constant, function or bracket expression")), ex1);
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::resolve_var_name (const std::string &t, tl::Variant *&value)
|
|
{
|
|
value = 0;
|
|
|
|
std::map<std::string, tl::Variant>::iterator v;
|
|
v = m_local_vars.find (t);
|
|
if (v != m_local_vars.end ()) {
|
|
value = &v->second;
|
|
}
|
|
}
|
|
|
|
void
|
|
Eval::resolve_name (const std::string &t, const EvalFunction *&function, const tl::Variant *&value) const
|
|
{
|
|
function = 0;
|
|
value = 0;
|
|
|
|
std::map <std::string, EvalFunction *>::const_iterator f;
|
|
f = m_local_functions.find (t);
|
|
if (f != m_local_functions.end ()) {
|
|
function = f->second;
|
|
} else if ((function = EvalStaticFunction::function_by_name (t)) == 0) {
|
|
|
|
std::map<std::string, tl::Variant>::const_iterator v;
|
|
v = m_local_vars.find (t);
|
|
if (v != m_local_vars.end ()) {
|
|
value = &v->second;
|
|
} else {
|
|
value = EvalStaticConstant::constant_by_name (t);
|
|
}
|
|
}
|
|
|
|
if (! function && ! value) {
|
|
if (mp_parent) {
|
|
mp_parent->resolve_name (t, function, value);
|
|
} else if (this != &m_global) {
|
|
m_global.resolve_name (t, function, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
tl::Variant
|
|
Eval::eval (const std::string &s)
|
|
{
|
|
Expression expr;
|
|
parse (expr, s, true);
|
|
|
|
EvalTarget v;
|
|
expr.execute (v);
|
|
return v.make_result ();
|
|
}
|
|
|
|
void
|
|
Eval::parse (Expression &expr, const std::string &s, bool top)
|
|
{
|
|
expr = Expression (this, s);
|
|
|
|
tl::Extractor ex (s.c_str ());
|
|
tl::Extractor ex0 = ex;
|
|
ExpressionParserContext context (&expr, ex);
|
|
|
|
if (top) {
|
|
eval_top (context, expr.root ());
|
|
} else {
|
|
eval_atomic (context, expr.root (), 0);
|
|
}
|
|
|
|
context.expect_end ();
|
|
}
|
|
|
|
void
|
|
Eval::parse (Expression &expr, tl::Extractor &ex, bool top)
|
|
{
|
|
expr = Expression (this, ex.get ());
|
|
|
|
tl::Extractor ex0 = ex;
|
|
ExpressionParserContext context (&expr, ex);
|
|
|
|
if (top) {
|
|
eval_top (context, expr.root ());
|
|
} else {
|
|
eval_atomic (context, expr.root (), 0);
|
|
}
|
|
|
|
expr.set_text (std::string (ex0.get (), ex.get () - ex0.get ()));
|
|
|
|
ex = context;
|
|
}
|
|
|
|
std::string
|
|
Eval::parse_expr (tl::Extractor &ex, bool top)
|
|
{
|
|
tl::Eval eval (0, true);
|
|
Expression expr (&eval, ex.get ());
|
|
|
|
tl::Extractor ex0 = ex;
|
|
ExpressionParserContext context (&expr, ex);
|
|
|
|
std::auto_ptr<ExpressionNode> n;
|
|
if (top) {
|
|
eval.eval_top (context, n);
|
|
} else {
|
|
eval.eval_atomic (context, n, 0);
|
|
}
|
|
|
|
ex = context;
|
|
|
|
return std::string (ex0.get (), ex.get () - ex0.get ());
|
|
}
|
|
|
|
std::string
|
|
Eval::interpolate (const std::string &str)
|
|
{
|
|
std::ostringstream os;
|
|
os.imbue (c_locale);
|
|
os.precision(8);
|
|
|
|
tl::Extractor ex (str.c_str ());
|
|
|
|
while (*ex) {
|
|
if (*ex == '$') {
|
|
++ex;
|
|
if (*ex == '$') {
|
|
os << '$';
|
|
++ex;
|
|
} else {
|
|
|
|
EvalTarget v;
|
|
try {
|
|
|
|
Expression expr;
|
|
parse (expr, ex, false);
|
|
expr.execute (v);
|
|
|
|
// use default precision instead of full precision of to_string ..
|
|
if (v->is_double ()) {
|
|
os << v->to_double();
|
|
} else {
|
|
os << v->to_string ();
|
|
}
|
|
|
|
} catch (tl::Exception &ex) {
|
|
os << "[Error: " << ex.msg () << "]";
|
|
}
|
|
|
|
}
|
|
} else {
|
|
os << *ex;
|
|
++ex;
|
|
}
|
|
}
|
|
|
|
return os.str ();
|
|
}
|
|
|
|
}
|
|
|