SciDAVis  1.D4
Public Slots | Public Member Functions | Protected Member Functions | Static Private Member Functions | Private Attributes | Static Private Attributes
MuParserScript Class Reference

Evaluate mathematical expressions using muParser. More...

#include <MuParserScript.h>

Inheritance diagram for MuParserScript:
Script

List of all members.

Public Slots

bool compile (bool asFunction=true)
 Pre-process Code and hand it to m_parser.
QVariant eval ()
 Evaluate the Code, returning QVariant() on an error / exception.
bool exec ()
 Execute the Code, returning false on an error / exception.
bool setDouble (double value, const char *name)
 Set a (local, double-valued) variable.
bool setInt (int value, const char *name)
bool setQObject (QObject *value, const char *name)
- Public Slots inherited from Script
virtual bool setQObject (const QObject *, const char *)

Public Member Functions

 MuParserScript (ScriptingEnv *environment, const QString &code, QObject *context=0, const QString &name="<input>")
- Public Member Functions inherited from Script
virtual void addCode (const QString &code)
 Append to the code that will be executed when calling exec() or eval()
const QString code () const
 Return the code that will be executed when calling exec() or eval()
const QObject * context () const
 Return the context in which the code is to be executed.
bool emitErrors () const
 Return whether errors / exceptions are to be emitted or silently ignored.
const QString name () const
 Like QObject::name, but with unicode support.
 Script (ScriptingEnv *env, const QString &code, QObject *context=0, const QString &name="<input>")
virtual void setCode (const QString &code)
 Set the code that will be executed when calling exec() or eval()
virtual void setContext (QObject *context)
 Set the context in which the code is to be executed.
void setEmitErrors (bool yes)
 Set whether errors / exceptions are to be emitted or silently ignored.
void setName (const QString &name)
 Like QObject::setName, but with unicode support.
 ~Script ()

Protected Member Functions

ColumnresolveColumnPath (const QString &path)
 Look up the column specified by path.
bool translateLegacyFunctions (QString &input)
 Do in-place translation of overloaded functions.
- Protected Member Functions inherited from Script
void emit_error (const QString &message, int lineNumber)

Static Private Member Functions

static double matrixCellFunction (double rowIndex, double columnIndex)
 Implements cell() function for matrices.
static double statementSeparator (double a, double b)
 Implements a;b syntax, where a is evaluated only for side-effects and b is returned.
static double tableCell_Function (double columnIndex, double rowIndex)
 Implements cell_() function for tables.
static double tableCellFunction (const char *columnPath, double rowIndex)
 Implements cell() function for tables.
static double tableColumn__Function (const char *tableName, double columnIndex)
 Implements column__() function for tables.
static double tableColumn_Function (double columnIndex)
 Implements column_() function for tables.
static double tableColumnFunction (const char *columnPath)
 Implements column() function for tables.
static double * variableFactory (const char *name, void *self)
 muParser callback for registering user-defined variables

Private Attributes

mu::Parser m_parser
 muParser object doing most of the expression evaluation work
QMap< QByteArray, double > m_variables
 Stores user-visible muParser variables.

Static Private Attributes

static MuParserScripts_currentInstance = 0
 MuParserScript instance currently executing eval()

Additional Inherited Members

- Signals inherited from Script
void codeChanged ()
 This is emitted whenever the code to be executed by exec() and eval() is changed.
void error (const QString &message, const QString &scriptName, int lineNumber)
 signal an error condition / exception
void print (const QString &output)
 output generated by the code
- Protected Types inherited from Script
enum  compileStatus { notCompiled, isCompiled, compileErr }
- Protected Attributes inherited from Script
QString Code
enum Script::compileStatus compiled
QObject * Context
bool EmitErrors
ScriptingEnvEnv
QString Name

Detailed Description

Evaluate mathematical expressions using muParser.

Basically, this is an adapter between the standard mu::Parser and the scripting abstraction layer. However, some additional functionality is also provided.

The constants pi, Pi and PI as well as e and E are recognized in addition to _pi and _e, respectively. This makes it possible to easily access them without referring to the documentation. For functions, exploratory expression building is supported by interactive lists of available mathematical functions; so redundant names are not needed for them.

In addition to basic mathematical functions provided by mu::Parser, several special functions implemented in the GSL are exported. For a complete list, see #muParserScripting::math_functions.

Functionality for user-defined variables in expressions optionally supported by muParser is enabled by providing a variable factory (see variableFactory()).

Multiple statements separated by semicolon or newline are supported. Because muParser takes newlines to mean "end of expression", they are translated to semicolons before handing the code to muParser. Also, adjacent newlines/semicolons are simplified to a single semicolon, since empty statements are not possible with muParser. Technically speaking, muParser doesn't have statements at all; here, "statement" is referring to expressions which are only evaluated for side effects (namely, assigning values to user-define variables) and whose results are discarded. This is done by defining the semicolon as a low-precedence operator which always returns its right-hand argument. Also, comments are implemented by throwing away any text between a hash mark '#' and a newline during pre-processing in compile().

For backwards-compatibility purposes, we need to support table column/cell access functions with variable numbers of (string) arguments as well as overloaded functions accepting either a number or a string; plus (from old QtiPlot versions) the ambiguous syntax col(name) (where name is an unquoted column name, not a muParser expression as one would expect). All of this isn't supported by muParser and has always required more or less extensive hacks on top of it. The approach taken in this implementation is as follows:

Note that contrary to previous versions, the internal cell() function takes a column name instead of a column number argument (with legacy calls being translated to cell_() during pre-processing). The idea here is that most of the time, column() and cell() (accepting column names) should be used; usage of column_() and cell_() (accepting a column number) is generally discouraged, since moving columns is now so easy that formulas with column numbers easily break or, worse, silently produce wrong results. Finally, column__() (accepting a table name and a column number) is provided for backwards-compatibility only and highly discouraged, since it means moving columns in one table can mess up formulas in other tables all over the project. While the difference between user-visible and internal signature of cell() may lead to confusion for people reading the source code, this is deemed the lesser evil compared with inconsistent or unclear naming conventions at the user interface.


Constructor & Destructor Documentation

MuParserScript::MuParserScript ( ScriptingEnv environment,
const QString &  code,
QObject *  context = 0,
const QString &  name = "<input>" 
)

Member Function Documentation

bool MuParserScript::compile ( bool  asFunction = true)
virtualslot

Pre-process Code and hand it to m_parser.

This implements some functionality not directly supported by muParser, like overloaded functions and multi-line expressions. See class documentation of MuParserScript for details.

Reimplemented from Script.

References Script::Code, Script::compiled, Script::Context, Script::emit_error(), Script::isCompiled, m_parser, and translateLegacyFunctions().

Referenced by eval().

QVariant MuParserScript::eval ( )
virtualslot

Evaluate the Code, returning QVariant() on an error / exception.

Reimplemented from Script.

References compile(), Script::compiled, Script::emit_error(), Script::isCompiled, m_parser, and s_currentInstance.

Referenced by exec().

bool MuParserScript::exec ( )
inlinevirtualslot

Execute the Code, returning false on an error / exception.

Reimplemented from Script.

References eval().

double MuParserScript::matrixCellFunction ( double  rowIndex,
double  columnIndex 
)
staticprivate

Implements cell() function for matrices.

  • rowIndex 1-based index of row to read data from.
  • columnIndex 1-based index of column to read data from.

References Matrix::cell(), Script::Context, Matrix::numCols(), Matrix::numRows(), and s_currentInstance.

Referenced by MuParserScript().

Column * MuParserScript::resolveColumnPath ( const QString &  path)
protected

Look up the column specified by path.

Path can be either relative to the current context (e.g., simply the name of a column in the current table) or absolute (relative to the project root). For backwards compatibility, also "table/column" is supported, where "table" is searched for anywhere in the project. This shouldn't be used in new projects though, since it will be problematic once we drop the requirement of project-wide unique table names.

Also, it's possible to escape /'s in the path using Column and folder names can already contain slashes and table names will follow in a future release.

References Column::clear(), future::Table::column(), Script::Context, Table::d_future_table, Folder::findSubfolder(), MyWidget::folder(), AbstractAspect::path(), Folder::rootFolder(), and Folder::table().

Referenced by tableCellFunction(), and tableColumnFunction().

bool MuParserScript::setDouble ( double  value,
const char *  name 
)
virtualslot

Set a (local, double-valued) variable.

Other kinds of variables are not supported (integers are converted to doubles).

See also:
m_variables

Reimplemented from Script.

References Script::emit_error(), m_parser, and m_variables.

Referenced by setInt().

bool MuParserScript::setInt ( int  value,
const char *  name 
)
inlinevirtualslot

Reimplemented from Script.

References setDouble().

bool MuParserScript::setQObject ( QObject *  value,
const char *  name 
)
inlineslot
double MuParserScript::statementSeparator ( double  a,
double  b 
)
staticprivate

Implements a;b syntax, where a is evaluated only for side-effects and b is returned.

Technically, muParser handles only expressions and doesn't have a "statement" concept. However, it does support assignment to variables, which is an expression with side-effects and can be thought of as a statement.

Referenced by MuParserScript().

double MuParserScript::tableCell_Function ( double  columnIndex,
double  rowIndex 
)
staticprivate

Implements cell_() function for tables.

  • columnIndex 1-based index of column to read data from.
  • rowIndex 1-based index of row to read data from.

It is preferable to use cell() instead of this function where possible, because referring to columns via index silently breaks when moving columns.

See also:
tableColumn_Function()

References future::Table::column(), Script::Context, Table::d_future_table, Column::isInvalid(), s_currentInstance, and Column::valueAt().

Referenced by MuParserScript().

double MuParserScript::tableCellFunction ( const char *  columnPath,
double  rowIndex 
)
staticprivate

Implements cell() function for tables.

  • columnPath Path to the column to read data from. See resolveColumnPath().
  • rowIndex 1-based index of the row to read data from.
See also:
tableColumnFunction()

References Column::isInvalid(), resolveColumnPath(), s_currentInstance, and Column::valueAt().

Referenced by MuParserScript().

double MuParserScript::tableColumn__Function ( const char *  tableName,
double  columnIndex 
)
staticprivate

Implements column__() function for tables.

  • tableName Name of table to read data from, which can be anywhere in the project.
  • columnIndex 1-based index of column to read data from.

This function exists so that we can implement a fully backwards-compatible tablecol() function in compile(). Using it in new projects is highly discouraged, because there's a high risk of messing up column formulas all over the project by simply moving a column.

The row to read from is determined by the muParser variable "i" set during iteration of a column formula. It was never possible to explicitly specify the row when referencing external tables, so this is not implemented for the discouraged version. However, see tableCellFunction() for how to get a specific cell with the column specified by name.

References future::Table::column(), Script::Context, Table::d_future_table, MyWidget::folder(), Column::isInvalid(), m_variables, Folder::rootFolder(), s_currentInstance, Folder::table(), and Column::valueAt().

Referenced by MuParserScript().

double MuParserScript::tableColumn_Function ( double  columnIndex)
staticprivate

Implements column_() function for tables.

  • columnIndex 1-based index of the column to read data from.

It is preferable to use column() instead of this function where possible, because referring to columns via index silently breaks when moving columns.

The row to read from is determined by the muParser variable "i" set during iteration of a column formula. For explicitly specifying the row, use cell_() instead.

See also:
tableCell_Function()

References future::Table::column(), Script::Context, Table::d_future_table, Column::isInvalid(), m_variables, s_currentInstance, and Column::valueAt().

Referenced by MuParserScript().

double MuParserScript::tableColumnFunction ( const char *  columnPath)
staticprivate

Implements column() function for tables.

The row to read from is determined by the muParser variable "i" set during iteration of a column formula. For explicitly specifying the row, use cell() instead.

See also:
tableCellFunction()

References Column::isInvalid(), m_variables, resolveColumnPath(), s_currentInstance, and Column::valueAt().

Referenced by MuParserScript().

bool MuParserScript::translateLegacyFunctions ( QString &  input)
protected

Do in-place translation of overloaded functions.

Recursively replaces:

  • col("name") with column("name")
  • col(arg) with column("arg") if the current table contains a column named "arg" and with column_(arg) otherwise
  • col("name", row) with cell("name", row)
  • col(arg, row) with cell("arg", row) if the current table contains a column named "arg" and with cell_(arg, row) otherwise
  • tablecol("tableName", "columnName") with column("tableName/columnName")
  • tablecol("tableName", columnIndex) with column__("tableName", columnIndex)
  • cell(columnIndex, rowIndex) with cell_(columnIndex, rowIndex)

Also escapes occurences of / in table/column names, so that legacy formulas work with the path argument of the new column() and cell() functions (see resolveColumnPath()).

References future::Table::column(), Script::compiled, Script::compileErr, Script::Context, Table::d_future_table, and Script::emit_error().

Referenced by compile().

double * MuParserScript::variableFactory ( const char *  name,
void *  self 
)
staticprivate

muParser callback for registering user-defined variables

When encountering an unknown variable within an expression, this function gets called. Memory for the variable is allocated in m_variables and a pointer to the memory location is returned to muParser. New variables are initialized with NaN.

References m_variables.

Referenced by MuParserScript().


Member Data Documentation

MuParserScript::m_parser
private

muParser object doing most of the expression evaluation work

Referenced by compile(), eval(), MuParserScript(), and setDouble().

MuParserScript::m_variables
private

Stores user-visible muParser variables.

Variables can be defined either from the C++ side by calling setDouble() or setInt(), or from the muParser side by simply using the variable within an expression (causing muParser to call variableFactory()). In the latter case, variables will evaluate to NaN until assigned a different value within the user-specified expression.

While using QHash would provide slightly faster lookups, re-hashing potentially invalidates pointers to values in a hash; so we'd probably have to re-export all variables to muParser with the new memory locations after inserting a new variable. But it's not clear a priori whether it's safe to call mu::Parser::DefineVar() from within variableFactory() (which gets called from muParser's variable handling code), and whether this may lead to muParser re-generating its bytecode (potentially degrading performance). Or maybe a QHash<QByteArray,double*> with explicit memory allocation would be the best solution. Until someone finds the time to do a benchmark and think these issues through, we stick with QMap.

Referenced by setDouble(), tableColumn__Function(), tableColumn_Function(), tableColumnFunction(), and variableFactory().

MuParserScript * MuParserScript::s_currentInstance = 0
staticprivate

MuParserScript instance currently executing eval()

All functions exported to muParser need to be static. However, table and matrix access functions need access to the current project and table/matrix (via Context), so eval() sets this variable before actually evaluating code for the benefit of column(), cell() etc. implementations.

See also:
tableColumnFunction(), tableColumn_Function(), tableColumn__Function(), tableCellFunction()
tableCell_Function(), matrixCellFunction()

Referenced by eval(), matrixCellFunction(), tableCell_Function(), tableCellFunction(), tableColumn__Function(), tableColumn_Function(), and tableColumnFunction().


The documentation for this class was generated from the following files: