Extension:WikiScripts

From MediaWiki.org
(Redirected from Extension:InlineScripts)
Jump to: navigation, search
MediaWiki extensions manual - list
Crystal Clear action run.png
WikiScripts

Release status: experimental

InlineScripts screenshot.png
Implementation Parser extension
Description Allows creation of scripts that evaluate to an expression by providing if/then/else control structure together with tests and a variety of functions, including arithmetic, list manipulation and string manipulation.
Author(s) Victor Vasiliev (VasilievVVTalk)
MediaWiki 1.19 or later
License GPLv2
Download
Hooks used
ParserFirstCallInit

ParserClearState
ParserLimitReport
ParserTestTables
CanonicalNamespaces
ArticleViewCustom
TitleIsWikitextPage
EditFilter
LinksUpdate
ArticleEditUpdates
ParserAfterTidy
BacklinkCacheGetPrefix
BacklinkCacheGetConditions

Check usage (experimental)

WikiScripts is an extension that allows users to write modules in a specially designed scripting language and then invoke those modules from wiki pages.

Contents

[edit] Installation

To install this extension, add the following to LocalSettings.php:

require_once("$IP/extensions/WikiScripts/WikiScripts.php");

Please bear in mind that you need MediaWiki at least r94435 (1.19) or newer to run the scripts.

There are following configuration variables;

  • $wgScriptsUseGeSHi — enables syntax highlighting of module pages via GeSHi; needs SyntaxHighlight_GeSHi of version r94443 or newer.
  • $wgScriptsAllowRecursion — indicates whether users are allowed to use Recursion. Given the fantasy of our template writers, users may do very insane things with that and hence it is unsafe and disabled by default.
  • $wgScriptsMaxCallStackDepth — the maximum nesting limit of functions.
  • $wgScriptsLimits — variable that allows to impose different limits on the script execution:
    • tokens — amount of tokens (strings, operators, keywords, etc) in the script;
    • evaluations — maximum number of evaluated operations per page (outputted in the parser limit report);
    • depth — maximum depth of the syntax tree (outputted in the parser limit report).

If you have XDebug installed, you will have to increase the function nesting limit to approximately 1000 in default configuration (or cut the value of $wgScriptsMaxCallStackDepth/$wgScriptsLimits['tokens']).

[edit] Language

The language used in the scripts is loosely based on JavaScript; however, it includes several features of other languages (PHP and Python) and is case-sensitive.

[edit] Data typing

The language has weak typing. There are following types of data:

  • Null (null) is similar to the null in most languages. Unlike some languages, in most operations it is converted to other types, so 3 + null = 3 (while in SQL 3 + NULL = NULL).
  • Integers (int) are integer numbers.
  • Floating point numbers (float) are numbers with floating point.
  • Booleans (bool) are either true or false.
  • Strings (string) are pieces of text. They can be defined using single quotes ('a') or double quotes ("b"). You can use the escape symbol to put different unusual characets (\" is a quote symbol, \n is a new line, \t is tab, \x7A is a character with hex value 7A).
  • Lists (list) are ordered sets of different elements. They can even be nested!. You can declare them like this:
    a = [ 1, 3, 5, "a", "B", 'c', true, [ 1, 4, 2 + 2 ], null ];
You can later access the element of the list by its number (the first one would have 0). In the example above, a[4] would be "B".
  • Associated arrays (assoc) are arrays where each value is associated with certain string, called key. For example:
    a = { "Alaska" : "Juneau", "Massachusetts" : "Boston", "California" : "Sacramento" };
You can later access the element of the list by its key. In the example above, a["California"] would be "Sacramento".

In most operations, one type would be automatically converted to another. The exception is the addition operator (+), which follows the following logic:

  • If one operand is an array and the other is null, the array is returned.
  • If both operands are lists or both are associative arrays, they are merged. For example, [ 1, 3 ] + [ 2, 4 ] is [ 1, 3, 2, 4 ]
  • If one operand is list and the other is not, the non-list is either prepended or appended to the list. For example, 2 + [ 4, 7 ] is [ 2, 4, 7 ].
  • If one operand is string, both operands are converted to string and joined. For example, "foo" + 4 is "foo4"
  • If one operand is float, both operands are converted to float and added. For example, 4 + 1.5 is 5.5
  • Otherwise both operands (which may be bool, null or int) are converted to integers. For example, 2 + true + null is 3.

There are following built-in constructions useful for working with data and variables:

  • Type conversion functions: string(), int(), float() and bool().
  • length( var ) returns the length of a string or of an array.
  • isset( var ) returns whether a variable or an array item exists.
  • delete( var ) removes the variable or an array element. Please note that it throws error if the element does not exist.
  • a in b (or b contains a) differs for arrays and strings. For arrays, it returns whether the element a is present in array b (note that for checking the key you need to use isset( array[key] ). For string, it return whether the substring a is present in string b.

[edit] Control structures

The following control structures are supported:

  • if( condition ) code
  • if( condition ) code else code
  • try code catch( var ) code — allows to catch an error. For example:

try {
  a = 2 / 0;
} catch( e ) {
  return e;
}

will return "divisionbyzero".

  • for( var in array ) code — executes the code for each element of the specified array. The value of the element is stored in var.
  • for( key : value in array ) code — executes the code for each element of the specified array. The value of the element is stored in value and the key is stored in key.
  • break and continue may be used to control the flow of loop execution.

[edit] Functions

All of the script code must be placed in a module. Modules are placed in a module namespace, so a module called "List example" would have title "Module:List example".

A module contains the functions. Each function may be defined using the following syntax:

function name( argument1, argument2 ) {
  // Code here
}

The name of the function, as well as name and number of arguments, is up to you.

After that you may invoke the code from the wikitext using the following construction:

{{#invoke:Module name|Function name|Argument value 1|Argument value 2}}

You can also declare a function called main. Then you can call this function using a shorter syntax:

{{s:Module name|Argument value 1|Argument value 2}}

If you want to call another function, you will need to use the following syntax:

"Module name"::functionName( arg1, arg2 );

or, if the function is in the same module:

self::functionName( arg1, arg2 );

Instead of the string literal there may be a variable or any expression in brackets.

[edit] Returning values

There are three ways to return a value from a function. The first is using the return construction:

function joiner( a, b ) {
  return a + b;
}

Please note that all the values are passed as string. That means that if you call {{#invoke:Joiner module|joiner|3|7}}, the result will be "37", not 10. Yes, this is not PHP and you have to cast them using int() function.

Another way to return value is to use append operator. It adds the argument to the current return value of the function (the initial value is null). For example, you may append the strings:

function makeList( arr ) {
  for( element in arr ) {
    append "* " + element + "\n";
  }
}

The function above accepts the array and returns the string. You can apply the append operator to the associated array as well:

/**
 * The method below returns the following associated array:
 *   { "a" : 3, "b" : 7, "c" : 11 }
 */
function niceArray() {
  append { "a" : 3 };
  append { "b" : 7, "c" : 11 };
}

Another operator is yield. It is almost like Python, except that here it in fact return the list instead of the generator:

/**
 * Returns [ 1, "five", [ 5, 7 ] ].
 */

function niceList() {
  yield 1;
  yield "five";
  yield [ 5, 7 ];
}

You cannot use append and yield in the same function. Also, if you use return with some value, the output of append and yield will be forfeit; if you use return without any argument, the execution of function will be aborted and the append/yield value will be returned.

[edit] Operator precedence

The operators have following precedence (from the top):

  • Function calls
  • Unary operators (+5, -7)
  • Keywords in and contains.
  • Boolean inverse (!)
  • Power (**)
  • Multiplitcation (*), division (/), division by module (%)
  • Equality operators (==, !=, ===, !==)
  • Comparisons (>=, <=, >, <)
  • Logical (&, |)
  • Trinary (cond ? value if true : value if false)
  • Variable setting (varname = value, varname += value, etc)
  • Return commands (return, append, yield)

[edit] Built-in functions

There is a limited set of built-in functions without prefixes:

  • Casting operators (string() and others);
  • length() returns the length of a string or of an array;

The rest of the code is the part of the libraries. Each library has its own prefix, and after the prefix you put the underscore and the function name. Right now there are following libraries:

  • String library (str_). Please note that in all string functions (when applicable) the first argument is the string with which the operation is done.
    • str_lowercase( string )
    • str_uppercase( string )
    • str_uppercase_first( string )
    • str_url_encode( string )
    • str_anchor_encode( string )
    • str_grammar( word, case )
    • str_plural( number, variant1, variant2, ... )
    • str_length( string )
    • str_sub( string, beginning, length )
    • str_replace( string, old, new )
    • str_split( string, delimiter )
    • str_join( delimiter, bit1, bit2, ... ) — joins the argument bits, putting delimiter between them;
    • str_join_list( list, delimiter, [prefix[, postfix]] ) — joins the list of strings. If specified, prefix is added to the beginning of each string, and postfix is appended.
  • Template library (tpl_) allows the script to access the parser and the parameters of the template that invokes the script.
    • tpl_arg( argname[, default] ) returns the argument which name is specified as an argument, or the default value if it is not set (if no default is specified, it returns false).
    • tpl_named_args() returns all the named arguments to the template.
    • tpl_numbered_args() returns all the numbered arguments.
    • tpl_is_transcluded() returns whether the code is invoked from a template.

[edit] Finished example

Here is an example of a WikiScripts module:

function outputTable( columns, table ) {
 append "{| class='wikitable'\n";
 for( name : title in columns ) {
  append "! " + title + "\n";
 }

 for( row in table ) {
  append "|-\n";
  for( name : title in columns ) {
   append "| " + row[name] + "\n";
  }
 }

 append "|}\n";
}

function getHeaders() {
  return { "a" : "A's", "b" : "B's", "c" : "C's" };
}

function getTable() {
  yield { "c" : 42, "b" : 22, "a" : 33 };
  yield { "c" : 10, "b" : 21, "a" : 31 };
  yield { "a" : "abc", "b" : "def", "c" : "ghi" };
  yield { "b" : "Hello, world!", "a" : "Lol wut?", "c" : "Testing 12345" };
}

function main( a, b, c ) {
  return self::outputTable(
    self::getHeaders(),
    self::getTable() + { "a" : a, "b" : b, "c" : c };
}

The output, if we call it as {{s:list example|Pie|Cake|Lie}} will be following:

A's B's C's
33 22 42
31 21 10
abc def ghi
Lol wut? Hello, world! Testing 12345
Pie Cake Lie

[edit] Design

Personal tools
Namespaces

Variants
Actions
Navigation
Support
Download
Development
Communication
Print/export
Toolbox