/** \file lobscript.h
*
* \brief This file contains the necessary functions for making Lobs scriptable
*
* The main function it defines is addLobsToScriptEngine(), which uses all the other
* functions and data in this file to enable a given script engine to create and manipulate
* Lobs from in-script.
*
* Note that the best resource we have found about an introduction to ECMAScript is
* <a href='http://en.wikipedia.org/wiki/ECMAScript_syntax'>the Wikipedia article
* "ECMAScript syntax"</a> (also entitled "JavaScript syntax").
*/
#ifndef LOB_SCRIPT
#define LOB_SCRIPT
#include <QtScript>
#include "lob.h"
/** \brief Adds to the given script engine all the functionality it needs to use Lobs
*
* It registers three classes with the Qt Metatype system (if it has not already done so),
* Lob, Lob*, and LobAddress. It also adds the following things to the script environment.
* Each is described below.
* <ul>
* <li>an <code>OmTypes</code> object</li>
* <li>a <code>Lob</code> constructor</li>
* <li>methods in the Lob prototype</li>
* <li>a convenience function <code>exclude()</code></li>
* </ul>
* Note that the Lob and Lob* classes get member functions as they are converted,
* while the LobAddress class, because it is not a QObject, has four useful member functions
* added, toString(), numSteps(), equal(), and less(). The first two of these function just
* like LobAddress::toString() and LobAddress::numSteps(), while the others embody the C++
* LobAddress::operator<() and LobAddress::operator==().
* Note that LobAddress objects in script have the properties
* stepTypes and stepIndices, which are arrays, the latter of which has values you can
* compare to the four extra entries in the OmTypes object (see immediately below).
*
* <h3>The OmTypes Object</h3>
* The OmTypes object in scripts has properties corresponding to the
* actual values of the OmType enum in C++. Having these values accessible in script
* allows script authors to compare results of Lob.type properties to known values,
* as follows.
* \code
* if ( myLob.type == OmTypes.String ) {
* // do something
* }
* \endcode
* Here is the table of OmType properties.
* <table>
* <tr><th>Script property</th><th>C++ value</th></tr>
* <tr><td><code>OmTypes.Integer</code></td>
* <td><code>OmIntegerType</code></td></tr>
* <tr><td><code>OmTypes.BigInteger</code></td>
* <td><code>OmBigIntegerType</code></td></tr>
* <tr><td><code>OmTypes.Float</code></td>
* <td><code>OmFloatType</code></td></tr>
* <tr><td><code>OmTypes.ByteArray</code></td>
* <td><code>OmByteArrayType</code></td></tr>
* <tr><td><code>OmTypes.Variable</code></td>
* <td><code>OmVariableType</code></td></tr>
* <tr><td><code>OmTypes.String</code></td>
* <td><code>OmStringType</code></td></tr>
* <tr><td><code>OmTypes.WideString</code></td>
* <td><code>OmWStringType</code></td></tr>
* <tr><td><code>OmTypes.Symbol</code></td>
* <td><code>OmSymbolType</code></td></tr>
* <tr><td><code>OmTypes.ProcessingInstruction</code></td>
* <td><code>OmPInstructionType</code></td></tr>
* <tr><td><code>OmTypes.Application</code></td>
* <td><code>OmApplicationType</code></td></tr>
* <tr><td><code>OmTypes.Error</code></td>
* <td><code>OmErrorType</code></td></tr>
* <tr><td><code>OmTypes.Object</code></td>
* <td><code>OmObjectType</code></td></tr>
* <tr><td><code>OmTypes.Binding</code></td>
* <td><code>OmBindingType</code></td></tr>
* <tr><td><code>OmTypes.Unknown</code></td>
* <td><code>OmUnknownType</code></td></tr>
* </table>
* It also contains a map from type codes to names, in the following sense.
* <pre>
* OmTypes[OmTypes.Integer] == "Integer"
* OmTypes[OmTypes.BigInteger] == "BigInteger"
* OmTypes[OmTypes.Float] == "Float"
* OmTypes[OmTypes.ByteArray] == "ByteArray"
* // and so on...
* </pre>
* This is useful when you have a type, and want some debugging information about it.
* For instance, in code like this:
* <code>print( "The Lob L is of type " + OmTypes[L.type] );</code>
*
* Four additional properties are added so that ownership types (as used in LobAddresses)
* can be understood in scripts.
* <table>
* <tr><th>Script property</th><th>C++ value</th></tr>
* <tr><td><code>OmTypes.None</code></td>
* <td><code>OmNode::None</code></td></tr>
* <tr><td><code>OmTypes.AsChild</code></td>
* <td><code>OmNode::AsChild</code></td></tr>
* <tr><td><code>OmTypes.AsKey</code></td>
* <td><code>OmNode::AsKey</code></td></tr>
* <tr><td><code>OmTypes.AsValue</code></td>
* <td><code>OmNode::AsValue</code></td></tr>
* </table>
*
* <h3>The Lob Constructor</h3>
* The Lob constructor in scripts works as follows.
* <table>
* <tr><th>Script code</th><th>Result</th></tr>
* <tr>
* <td><code>a = Lob();</code></td>
* <td><code>a</code> contains a new, empty Lob</td>
* </tr>
* <tr>
* <td><code>a = new Lob();</code></td>
* <td>same as previous case</td>
* </tr>
* <tr>
* <td><code>a = Lob( '<OMI>3</OMI>' );</code></td>
* <td><code>a</code> contains the OpenMath tree described by the XML code given.
* Any XML code describing a single OpenMath tree will result in a Lob
* that is just that tree. Note the difference between this and Lob::fromXML(),
* which wraps any result in a node of type OmUnknownType, even if it is only
* one node.
* So for example, in the case given to the left, we would then have
* <code>a.basicValue == 3</code> and <code>a.numChildren() == 0</code>.</td>
* </tr>
* <tr>
* <td><code>a = new Lob( '<OMI>3</OMI>' );</code></td>
* <td>same as previous case</td>
* </tr>
* <tr>
* <td><code>a = Lob( '<OMI>3</OMI><OMSTR>foo</OMSTR>' );</code></td>
* <td><code>a</code> contains an OpenMath tree whose root is of type OmUnknownType,
* and whose children are described by the XML code given.
* Any XML code describing more than one OpenMath tree will result in this kind
* of wrapping, which is the behavior Lob::fromXML() gives for any input.
* So for example, in the case given to the left, we would then have
* <code>a.type == OmTypes.Unknown</code>,
* <code>a.numChildren() == 2</code>, and
* <code>a.child(0).basicValue == 3</code>.</td>
* </tr>
* <tr>
* <td><code>a = new Lob( '<OMI>3</OMI><OMSTR>foo</OMSTR>' );</code></td>
* <td>same as previous case</td>
* </tr>
* </table>
* In addition to the above examples, the Lob constructor ensures that the prototype object
* for Lobs has a new method in it just for scripts, the equals() method. The reason for
* this is that QtScript does not automatically translate the C++ Lob::operator==() to
* script land, and so a member function must be used instead.
*
* <h3>Methods in the Lob prototype</h3>
* One method is added to the Lob prototype, so that it is available as a member function
* for all Lobs in script. It is added here because it is not necessary in C++, as
* is clear by its nature.
* <ul>
* <li><code>equals()</code> - You can call <code>anyLob.equals(anotherLob)</code> to
* check to see if they are wrapping the same OpenMath object. This is different
* from checking <code>anyLob == anotherLob</code> because this latter expression
* asks if the two are different script objects, which they may be even if they wrap
* the same OpenMath object. Thus <code>equals()</code> in script is equivalent to
* <code>Lob::operator==()</code> in C++.</li>
* <li><code>call()</code> - This function was once added to the Lob prototype, but has
* been superceded by the FunctionLob script class in the LobUtilitiesPackage.</li>
* </ul>
*
* <h3>The exclude() Function</h3>
* When calling <code>aLob.equivalentTo()</code>, there is an optional third argument for
* symbols to exclude from consideration if comparing attributes. Due to a combination of
* our design, C++ limitations, and the Qt metatype system, it became a headache to add an
* overloaded (or even differently-named) version that would be callable from script and
* take an array of symbol Lobs as the third argument. Yet this is what script writers
* expect and should get, so the <code>exclude()</code> function was created. It converts
* a sequence of symbol Lobs to a string list of names and content dictionaries of the form
* Lob::equivalentTo() expects as its third argument. So you can write code like this
* <pre>
* someLob.equivalentTo( anotherLob, true, exclude( someSymbol, anotherSymbol ) )
* </pre>
* and it translates to a call like the following in C++.
* <pre>
* someLob.equivalentTo( anotherLob, true,
* QStringList() << "name of someSymbol" << "content dictionary of someSymbol"
* << "name of anotherSymbol" << "content dictionary of anotherSymbol" );
* </pre>
* Note that any object passed to exclude that is not a symbol Lob is ignored.
* So <code>exclude( symbolLob, 3, 7 )</code> is the same as
* <code>exclude( symbolLob )</code>.
*
* <h3>The escapeXML() and unescapeXML() Functions</h3>
* For creating strings that can be safely placed inside XML expressions
* (such as <OMSTR> nodes), these two functions are handy to have in script land.
* They call the C++ functions of the same names, documented on the page for the Lob class.
*
* <h3>The escapeChars() and unescapeChars() Functions</h3>
* For creating strings limited to alphanumeric characters plus an underscore (_) out of
* any Unicode string, these two functions are handy to have in script land.
* They call the C++ functions scriptEscapeChars() and scriptUnescapeChars(),
* documented below.
*
* <h3>The codeString() Function</h3>
* For converting a string into JavaScript code that evaluates to that string, useful when
* creating strings of code. See scriptCodeString() for more information.
*
* <h3>The setHelp() and copyHelp() Functions</h3>
* The former is used to install developer help into an object, and the latter to copy help from
* one object to another. For help on how to use these functions, or for how to get developer
* help when in Lurch, type a question mark (?) alone in the developer console, and execute it.
*
* <h3>The makeLurchURN() and splitLurchURN() Functions</h3>
* These are in-script-land embodiments of Lob::makeLurchURN() and Lob::splitLurchURN().
*
* <h3>The globalNamespace Object</h3>
* The identifier <code>globalNamespace</code> is added as an attribute of the JavaScript
* global object, and refers to that object itself. This is useful for getting a list of
* all identifiers defined; one can look at the properties of the object, or ask for help on
* it in the Lurch console.
*/
void addLobsToScriptEngine ( QScriptEngine& engine );
/** \brief Escapes Unicode characters other than ASCII alphanumerics and the underscore
*
* A string containing any unicode characters can be passed as input (as \a context argument
* zero) and this function will replace all characters other than a-z, A-Z, and 0-9 with
* five-character sequences of the form _AABB, where AA is the hexadecimal (0-9, a-f)
* representation of the Unicode row of the encoded character, and BB is the hexadecimal
* representation of its Unicode cell. Thus the output from this function (returned as a
* string inside the script engine) contains only the characters a-z, A-Z, 0-9, and _.
* The inverse operation can be done with scriptUnescapeChars().
*
* For example, the string "Hello there" is encoded as "Hello_0020there" because the ASCII
* space is the Unicode character in row 00 and cell 20 (in hex, or 32 in decimal).
*/
QScriptValue scriptEscapeChars ( QScriptContext* context, QScriptEngine* engine );
/** \brief Inverts the operation of scriptEscapeChars().
*
* See the documentation for scriptEscapeChars() for more information.
*/
QScriptValue scriptUnescapeChars ( QScriptContext* context, QScriptEngine* engine );
/** \brief Used internally by scriptEscapeChars(). See its documentation for details.
*/
QString escapeChars ( QString input );
/** \brief Used internally by scriptUnescapeChars(). See its documentation for details.
*/
QString unescapeChars ( QString input );
/** \brief Convert any text into a JavaScript string literal that evaluates to that text
*
* <table>
* <tr><th>Example input</th><th>Corresponding output</th></tr>
* <tr><td>She said, "I don't think so."</td>
* <td>\code "She said, \"I don't think so.\"" \endcode</td>
* <tr><td>hello 'world'</td>
* <td>\code 'hello \'world\'' \endcode</td></tr>
* <tr><td>there is a newline<br>before these words</td>
* <td>\code 'there is a newline\\nbefore these words' \endcode</td></tr>
* <tr><td>some "quotes" and \"escaped quotes\"</td>
* <td>\code 'some "quotes" and \\\\"escaped quotes\\"' \endcode</td></tr>
* <tr><td>multi-line<br>input</td>
* <td>\code 'multi-line\\ninput' \endcode</td></tr>
* </table>
*
* Given any text as input, this routine escapes offending characters and wraps the result
* in quotes, so that the result can be used in Javascript code as a string literal
* whose value will be the original input.
*
* If you had a very long line of input, you might want the result to be
* several string literals split over several lines of code (with instances of the + operator
* to join them) for readability. To achieve this behavior, use the optional \a withBreaks
* parameter set to true.
*
* This routine is used for implementing the "paste string literal"
* action in source code editors, among many other things.
*/
QString toJavascriptString ( QString text, bool withBreaks = false );
/** \brief Escapes a string to prepare it for insertion in JavaScript code
*
* If in JavaScript, you are building a string that you will later pass to eval() (that is,
* you're building a string of JavaScript code), it can be dangerous to insert arbitrary
* strings into it. Consider this example.
* \code
* var myJSCode = 'var x = 3;\n'
* + 'var y = "' + someString + '";\n'
* + 'y.length + x';
* eval( myJSCode );
* \endcode
* In some situations, the result will be <code>someString.length + 3</code>, but not in all.
* For instance, if someString contained a double-quote character, or a newline, the eval()
* call would result in an error instead. Worse, someString might contain code that does
* something malicious.
*
* So it's helpful to escape someString for use as a JavaScript string. This routine does
* so, and should be used as in the following example.
* \code
* var myJSCode = 'var x = 3;\n'
* + 'var y = ' + codeString( someString ) + ';\n'
* + 'y.length + x';
* eval( myJSCode );
* \endcode
* Notice that the double quotes around someString have gone. This routine puts quotes
* around its result, and escapes the content appropriately for the quotes used.
*
* \see toJavascriptString()
*/
QScriptValue scriptCodeString ( QScriptContext* context, QScriptEngine* engine );
/** \brief Prints HTML-formatted help on the value passed as first parameter.
*
* If the value is an object with the helpHTML property, that value is printed.
*
* If the value is an object without that property, a message that no help is available is
* printed. (This will change to something more robust in future revisions.)
*
* If the value is a non-object, its value and type are printed. In addition, if it is a
* string, a link to search that string in online help is provided.
*
* The return value is always the script value "undefined."
*/
QScriptValue scriptHelp ( QScriptContext* context, QScriptEngine* engine );
/** \brief Utility function to prepare objects for access by scriptHelp()
*
* Looks through all data in the :/doxygen/Lurch-doxygen.*.processed files (see
* doxygenhelp.qrc) to find any information on members of the class with the given
* \a className. Any members whose information appears are decorated with .helpHTML
* attributes, whose values are strings containing HTML help on the given member.
*/
void putHelpDataInto ( QScriptValue object, QString className );
/** \brief Utility function to for reading data of the kind that is useful to scriptHelp()
*
* Looks through all data in the :/doxygen/Lurch-doxygen.*.processed files (see
* doxygenhelp.qrc) to find any information on the member with the given \a memberName
* in the class with the given \a className. If information appears satisfying these two
* criteria, the corresponding string containing HTML help on the given member is returned;
* otherwise, the empty string is.
*/
QString getHelpDataFor ( QString className, QString memberName );
/** Allows Lob to be a scriptable type, by permitting conversion from Lob to script values
*/
QScriptValue LobStarToScriptValue ( QScriptEngine* engine, Lob* const& in );
/** Allows Lob to be a scriptable type, by permitting conversion to Lob from script values
*/
void LobStarFromScriptValue ( const QScriptValue& object, Lob*& out );
/** Allows Lob to be a scriptable type, by converting it to Lob*, which is scriptable
*/
QScriptValue LobToScriptValue ( QScriptEngine* engine, const Lob& in );
/** Allows Lob to be a scriptable type, by converting it to Lob*, which is scriptable
*/
void LobFromScriptValue ( const QScriptValue& object, Lob& out );
/** Obtain a list of properties that are put into any QScriptEnvironment's global object by
* default.
*/
QStringList globalFixtures ();
/** Copies all properties from one QScriptValue to another, except for any in globalFixtures()
*/
void copyProperties ( QScriptValue from, QScriptValue to );
/** Calls qDebug() to print out a hierarchy of existing objects and their properties
*/
void debugDeepProperties ( QScriptValue v );
/** \brief Returns a short context surrounding a given line of code
*
* From the block of \a code in the given string, return just the five lines (or less)
* centered on the given \a lineNumber. This is useful for printing out errors in context.
* Line numbers are included in the output if and only if \a includeNumbers is true (the
* default).
*/
QString getContext ( QString code, int lineNumber, bool includeNumbers = true );
#endif // LOB_SCRIPT