SciDAVis
1.D4
|
Evaluate mathematical expressions using muParser. More...
#include <MuParserScript.h>
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 | |
Column * | resolveColumnPath (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 MuParserScript * | s_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 |
ScriptingEnv * | Env |
QString | Name |
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.
MuParserScript::MuParserScript | ( | ScriptingEnv * | environment, |
const QString & | code, | ||
QObject * | context = 0 , |
||
const QString & | name = "<input>" |
||
) |
|
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().
|
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().
|
inlinevirtualslot |
|
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().
|
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().
|
virtualslot |
Set a (local, double-valued) variable.
Other kinds of variables are not supported (integers are converted to doubles).
Reimplemented from Script.
References Script::emit_error(), m_parser, and m_variables.
Referenced by setInt().
|
inlinevirtualslot |
Reimplemented from Script.
References setDouble().
|
inlineslot |
|
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().
|
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.
References future::Table::column(), Script::Context, Table::d_future_table, Column::isInvalid(), s_currentInstance, and Column::valueAt().
Referenced by MuParserScript().
|
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.References Column::isInvalid(), resolveColumnPath(), s_currentInstance, and Column::valueAt().
Referenced by MuParserScript().
|
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().
|
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.
References future::Table::column(), Script::Context, Table::d_future_table, Column::isInvalid(), m_variables, s_currentInstance, and Column::valueAt().
Referenced by MuParserScript().
|
staticprivate |
Implements column() function for tables.
columnPath
Path to the column to read data from. See resolveColumnPath().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.
References Column::isInvalid(), m_variables, resolveColumnPath(), s_currentInstance, and Column::valueAt().
Referenced by MuParserScript().
|
protected |
Do in-place translation of overloaded functions.
Recursively replaces:
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().
|
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().
|
private |
muParser object doing most of the expression evaluation work
Referenced by compile(), eval(), MuParserScript(), and setDouble().
|
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().
|
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.
Referenced by eval(), matrixCellFunction(), tableCell_Function(), tableCellFunction(), tableColumn__Function(), tableColumn_Function(), and tableColumnFunction().