Index: trunk/extensions/WikiScripts/geshi/wikiscript.php |
— | — | @@ -0,0 +1,98 @@ |
| 2 | +<?php |
| 3 | +/************************************************************************************* |
| 4 | + * wikiscripts.php |
| 5 | + * -------------- |
| 6 | + * Author: Victor Vasiliev (vasilvv@gmail.com) |
| 7 | + * Copyright: (c) 2011 Victor Vasiliev (vasilvv@gmail.com) |
| 8 | + * Release Version: 1.0 |
| 9 | + * Date Started: 2011/08/11 |
| 10 | + * |
| 11 | + * WikiScripts language file for GeSHi. |
| 12 | + * |
| 13 | + ************************************************************************************* |
| 14 | + * |
| 15 | + * This file is part of GeSHi and MediaWiki. |
| 16 | + * |
| 17 | + * GeSHi is free software; you can redistribute it and/or modify |
| 18 | + * it under the terms of the GNU General Public License as published by |
| 19 | + * the Free Software Foundation; either version 2 of the License, or |
| 20 | + * (at your option) any later version. |
| 21 | + * |
| 22 | + * GeSHi is distributed in the hope that it will be useful, |
| 23 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 24 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 25 | + * GNU General Public License for more details. |
| 26 | + * |
| 27 | + * You should have received a copy of the GNU General Public License |
| 28 | + * along with GeSHi; if not, write to the Free Software |
| 29 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 30 | + * |
| 31 | + ************************************************************************************/ |
| 32 | + |
| 33 | +$language_data = array ( |
| 34 | + 'LANG_NAME' => 'WikiScripts', |
| 35 | + 'COMMENT_SINGLE' => array(1 => '//'), |
| 36 | + 'COMMENT_MULTI' => array('/*' => '*/'), |
| 37 | + 'CASE_KEYWORDS' => GESHI_CAPS_NO_CHANGE, |
| 38 | + 'QUOTEMARKS' => array("'", '"'), |
| 39 | + 'ESCAPE_CHAR' => '\\', |
| 40 | + 'KEYWORDS' => array( |
| 41 | + 1 => array( |
| 42 | + 'append', 'break', 'catch', 'contains', 'continue', 'delete', 'else', 'false', 'for', |
| 43 | + 'function', 'if', 'in', 'isset', 'null', 'return', 'self', 'then', 'true', 'try', 'yield', |
| 44 | + ), |
| 45 | + ), |
| 46 | + 'SYMBOLS' => array( |
| 47 | + '(', ')', '[', ']', '{', '}', |
| 48 | + '+', '-', '*', '/', |
| 49 | + '!', '&', '|', '^', |
| 50 | + '<', '>', '=', |
| 51 | + ',', ';', '?', ':', '::', |
| 52 | + ), |
| 53 | + 'CASE_SENSITIVE' => array( |
| 54 | + GESHI_COMMENTS => false, |
| 55 | + 1 => true, |
| 56 | + ), |
| 57 | + 'STYLES' => array( |
| 58 | + 'KEYWORDS' => array( |
| 59 | + 1 => 'color: #000066; font-weight: bold;', |
| 60 | + ), |
| 61 | + 'COMMENTS' => array( |
| 62 | + 1 => 'color: #006600; font-style: italic;', |
| 63 | + 2 => 'color: #009966; font-style: italic;', |
| 64 | + 'MULTI' => 'color: #006600; font-style: italic;' |
| 65 | + ), |
| 66 | + 'ESCAPE_CHAR' => array( |
| 67 | + 0 => 'color: #000099; font-weight: bold;' |
| 68 | + ), |
| 69 | + 'BRACKETS' => array( |
| 70 | + 0 => 'color: #009900;' |
| 71 | + ), |
| 72 | + 'STRINGS' => array( |
| 73 | + 0 => 'color: #3366CC;' |
| 74 | + ), |
| 75 | + 'NUMBERS' => array( |
| 76 | + 0 => 'color: #CC0000;' |
| 77 | + ), |
| 78 | + 'METHODS' => array( |
| 79 | + 1 => 'color: #660066;' |
| 80 | + ), |
| 81 | + 'SYMBOLS' => array( |
| 82 | + 0 => 'color: #339933;' |
| 83 | + ), |
| 84 | + 'REGEXPS' => array( |
| 85 | + ), |
| 86 | + 'SCRIPT' => array( |
| 87 | + 0 => '', |
| 88 | + ) |
| 89 | + ), |
| 90 | + 'URLS' => array( |
| 91 | + 1 => '', |
| 92 | + ), |
| 93 | + 'OOLANG' => false, |
| 94 | + 'REGEXPS' => array( |
| 95 | + ), |
| 96 | + 'STRICT_MODE_APPLIES' => GESHI_NEVER, |
| 97 | + 'SCRIPT_DELIMITERS' => array(), |
| 98 | + 'HIGHLIGHT_STRICT_BLOCK' => array(), |
| 99 | +); |
Index: trunk/extensions/WikiScripts/i18n/Namespaces.php |
— | — | @@ -0,0 +1,8 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$namespaceNames = array(); |
| 5 | + |
| 6 | +$namespaceNames['en'] = array( |
| 7 | + NS_MODULE => 'Module', |
| 8 | + NS_MODULE_TALK => 'Module_talk', |
| 9 | +); |
Index: trunk/extensions/WikiScripts/i18n/Magic.php |
— | — | @@ -0,0 +1,7 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$magicWords = array(); |
| 5 | + |
| 6 | +$magicWords['en'] = array( |
| 7 | + 'i' => array( 0, 'i' ), |
| 8 | +); |
Index: trunk/extensions/WikiScripts/i18n/Messages.php |
— | — | @@ -0,0 +1,54 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Internationalisation file for extension InlineScripts. |
| 5 | + * |
| 6 | + * @file |
| 7 | + * @ingroup Extensions |
| 8 | + */ |
| 9 | + |
| 10 | +$messages = array(); |
| 11 | + |
| 12 | +/** English |
| 13 | + * @author Victor Vasiliev |
| 14 | + */ |
| 15 | +$messages['en'] = array( |
| 16 | + 'inlinescripts-desc' => 'Provides a build into wikitext scripting language', |
| 17 | + |
| 18 | + 'inlinescripts-call-frommodule' => '$1::$2 called by $3::$4 at line $5', |
| 19 | + 'inlinescripts-call-fromwikitext' => '$1::$2 called by wikitext', |
| 20 | + 'inlinescripts-call-parse' => 'parse( "$1" )', |
| 21 | + |
| 22 | + 'inlinescripts-error' => 'Following parsing {{plural:$1|error|errors}} detected:', |
| 23 | + 'inlinescripts-codelocation' => 'in module $1 at line $2', |
| 24 | + |
| 25 | + 'inlinescripts-exception-unexceptedtoken' => 'Unexpected token $2 $1: expected $3 (parser state $4)', |
| 26 | + 'inlinescripts-exception-unclosedstring' => 'Unclosed string $1', |
| 27 | + 'inlinescripts-exception-unrecognisedtoken' => 'Unrecognized token $1', |
| 28 | + 'inlinescripts-exception-toomanytokens' => 'Exceeded tokens limit', |
| 29 | + 'inlinescripts-exception-toomanyevals' => 'Exceeded evaluations limit $1', |
| 30 | + 'inlinescripts-exception-recoverflow' => 'Too deep abstract syntax tree', |
| 31 | + 'inlinescripts-exception-notanarray' => 'Tried to get or set an element of a non-array $1', |
| 32 | + 'inlinescripts-exception-outofbounds' => 'Got out of array bounds $1', |
| 33 | + 'inlinescripts-exception-notenoughargs' => 'Not enough arguments for function $1', |
| 34 | + 'inlinescripts-exception-dividebyzero' => 'Division by zero $1', |
| 35 | + 'inlinescripts-exception-break' => '"break" called outside of foreach $1', |
| 36 | + 'inlinescripts-exception-continue' => '"continue" called outside of foreach $1', |
| 37 | + 'inlinescripts-exception-emptyidx' => 'Trying to get a value of an empty index $1', |
| 38 | + 'inlinescripts-exception-unknownvar' => 'Trying to use an undeclared variable $1', |
| 39 | + 'inlinescripts-exception-unknownfunction' => 'Trying to use an unnknown function $2 $1', |
| 40 | + 'inlinescripts-exception-notlist' => 'Trying to append an element to the end of \'\'associated\'\' array $1', |
| 41 | + 'inlinescripts-exception-appendyield' => 'Trying to use append and yield in the same function $1', |
| 42 | + |
| 43 | + 'inlinescripts-exception-notenoughargs-user' => 'Not enough arguments for function $2::$3 $1', |
| 44 | + 'inlinescripts-exception-nonexistent-module' => 'Call to non-existent module $2 $1', |
| 45 | + 'inlinescripts-exception-unknownfunction-user' => 'Trying to use an unnknown user function $2::$3 $1', |
| 46 | + 'inlinescripts-exception-recursion' => 'Function loop detected when calling function $2::$3 $1', |
| 47 | + 'inlinescripts-exception-toodeeprecursion' => 'The maximum function nesting limit of $2 exceeded $1', |
| 48 | + |
| 49 | + 'inlinescripts-transerror-notenoughargs-user' => 'Not enough arguments for function $1::$2', |
| 50 | + 'inlinescripts-transerror-nonexistent-module' => 'Call to non-existent module $1', |
| 51 | + 'inlinescripts-transerror-unknownfunction-user' => 'Trying to use an unnknown user function $1::$2', |
| 52 | + 'inlinescripts-transerror-recursion' => 'Function loop detected when calling function $1::$2', |
| 53 | + 'inlinescripts-transerror-nofunction' => 'Missing function name when invoking the script', |
| 54 | + 'inlinescripts-transerror-toodeeprecursion' => 'The maximum function nesting limit of $1 exceeded', |
| 55 | +); |
Property changes on: trunk/extensions/WikiScripts/i18n/Messages.php |
___________________________________________________________________ |
Added: svn:executable |
1 | 56 | + * |
Index: trunk/extensions/WikiScripts/interpreter/Data.php |
— | — | @@ -0,0 +1,268 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki: data. |
| 5 | + * Based on the AbuseFilter AFData. |
| 6 | + * Copyright (C) 2008-2011 Victor Vasiliev <vasilvv@gmail.com>, Andrew Garrett <andrew@epstone.net> |
| 7 | + * http://www.mediawiki.org/ |
| 8 | + * |
| 9 | + * This program is free software; you can redistribute it and/or modify |
| 10 | + * it under the terms of the GNU General Public License as published by |
| 11 | + * the Free Software Foundation; either version 2 of the License, or |
| 12 | + * (at your option) any later version. |
| 13 | + * |
| 14 | + * This program is distributed in the hope that it will be useful, |
| 15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | + * GNU General Public License for more details. |
| 18 | + * |
| 19 | + * You should have received a copy of the GNU General Public License along |
| 20 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 21 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 22 | + * http://www.gnu.org/copyleft/gpl.html |
| 23 | + */ |
| 24 | + |
| 25 | +if( !defined( 'MEDIAWIKI' ) ) |
| 26 | + die(); |
| 27 | + |
| 28 | +/** |
| 29 | + * Class implementing data in the scripts. |
| 30 | + */ |
| 31 | +class ISData { |
| 32 | + // Data types |
| 33 | + const DInt = 'int'; |
| 34 | + const DString = 'string'; |
| 35 | + const DNull = 'null'; |
| 36 | + const DBool = 'bool'; |
| 37 | + const DFloat = 'float'; |
| 38 | + const DList = 'list'; // int -> value |
| 39 | + const DAssoc = 'assoc'; // associative array |
| 40 | + |
| 41 | + public $type; |
| 42 | + public $data; |
| 43 | + |
| 44 | + public function __construct( $type = self::DNull, $val = null ) { |
| 45 | + $this->type = $type; |
| 46 | + $this->data = $val; |
| 47 | + } |
| 48 | + |
| 49 | + public static function newFromPHPVar( $var ) { |
| 50 | + if( is_string( $var ) ) |
| 51 | + return new ISData( self::DString, $var ); |
| 52 | + elseif( is_int( $var ) ) |
| 53 | + return new ISData( self::DInt, $var ); |
| 54 | + elseif( is_float( $var ) ) |
| 55 | + return new ISData( self::DFloat, $var ); |
| 56 | + elseif( is_bool( $var ) ) |
| 57 | + return new ISData( self::DBool, $var ); |
| 58 | + elseif( is_array( $var ) ) { |
| 59 | + if( !$var ) |
| 60 | + return new ISData( self::DList, array() ); |
| 61 | + $result = array(); |
| 62 | + foreach( $var as $item ) |
| 63 | + $result[] = self::newFromPHPVar( $item ); |
| 64 | + return new ISData( self::DList, $result ); |
| 65 | + } |
| 66 | + elseif( is_null( $var ) ) |
| 67 | + return new ISData(); |
| 68 | + else |
| 69 | + throw new ISException( |
| 70 | + "Data type " . gettype( $var ) . " is not supported by InlineScrtips" ); |
| 71 | + } |
| 72 | + |
| 73 | + public function dup() { |
| 74 | + return new ISData( $this->type, $this->data ); |
| 75 | + } |
| 76 | + |
| 77 | + public static function castTypes( $orig, $target ) { |
| 78 | + if( $orig->type == $target ) |
| 79 | + return $orig->dup(); |
| 80 | + if( $target == self::DNull ) { |
| 81 | + return new ISData(); |
| 82 | + } |
| 83 | + |
| 84 | + if( $orig->isArray() ) { |
| 85 | + if( $target == self::DBool ) |
| 86 | + return new ISData( self::DBool, (bool)count( $orig->data ) ); |
| 87 | + if( $target == self::DFloat ) { |
| 88 | + return new ISData( self::DFloat, doubleval( count( $orig->data ) ) ); |
| 89 | + } |
| 90 | + if( $target == self::DInt ) { |
| 91 | + return new ISData( self::DInt, intval( count( $orig->data ) ) ); |
| 92 | + } |
| 93 | + if( $target == self::DString ) { |
| 94 | + $s = array(); |
| 95 | + foreach( $orig->data as $item ) |
| 96 | + $s[] = $item->toString(); |
| 97 | + return new ISData( self::DString, implode( "\n", $s ) ); |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + if( $target == self::DBool ) { |
| 102 | + return new ISData( self::DBool, (bool)$orig->data ); |
| 103 | + } |
| 104 | + if( $target == self::DFloat ) { |
| 105 | + return new ISData( self::DFloat, doubleval( $orig->data ) ); |
| 106 | + } |
| 107 | + if( $target == self::DInt ) { |
| 108 | + return new ISData( self::DInt, intval( $orig->data ) ); |
| 109 | + } |
| 110 | + if( $target == self::DString ) { |
| 111 | + return new ISData( self::DString, strval( $orig->data ) ); |
| 112 | + } |
| 113 | + if( $target == self::DList ) { |
| 114 | + return new ISData( self::DList, array( $orig ) ); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + public static function boolInvert( $value ) { |
| 119 | + return new ISData( self::DBool, !$value->toBool() ); |
| 120 | + } |
| 121 | + |
| 122 | + public static function pow( $base, $exponent ) { |
| 123 | + if( $base->type == self::DInt && $exponent->type == self::DInt ) |
| 124 | + return new ISData( self::DInt, pow( $base->toInt(), $exponent->toInt() ) ); |
| 125 | + else |
| 126 | + return new ISData( self::DFloat, pow( $base->toFloat(), $exponent->toFloat() ) ); |
| 127 | + } |
| 128 | + |
| 129 | + // Checks whether a is in b |
| 130 | + public static function keywordIn( $a, $b ) { |
| 131 | + if( $b->isArray() ) { |
| 132 | + foreach( $b->data as $elem ) { |
| 133 | + if( self::equals( $elem, $a ) ) |
| 134 | + return new ISData( self::DBool, true ); |
| 135 | + } |
| 136 | + return new ISData( self::DBool, false ); |
| 137 | + } else { |
| 138 | + $a = $a->toString(); |
| 139 | + $b = $b->toString(); |
| 140 | + |
| 141 | + if( $a == '' || $b == '' ) { |
| 142 | + return new ISData( self::DBool, false ); |
| 143 | + } |
| 144 | + |
| 145 | + return new ISData( self::DBool, in_string( $a, $b ) ); |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + public static function equals( $d1, $d2 ) { |
| 150 | + return $d1->data == $d2->data; |
| 151 | + } |
| 152 | + |
| 153 | + public static function unaryMinus( $data ) { |
| 154 | + if( $data->type == self::DInt ) { |
| 155 | + return new ISData( $data->type, -$data->toInt() ); |
| 156 | + } else { |
| 157 | + return new ISData( $data->type, -$data->toFloat() ); |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + public static function compareOp( $a, $b, $op ) { |
| 162 | + if( $op == '==' ) |
| 163 | + return new ISData( self::DBool, self::equals( $a, $b ) ); |
| 164 | + if( $op == '!=' ) |
| 165 | + return new ISData( self::DBool, !self::equals( $a, $b ) ); |
| 166 | + if( $op == '===' ) |
| 167 | + return new ISData( self::DBool, $a->type == $b->type && self::equals( $a, $b ) ); |
| 168 | + if( $op == '!==' ) |
| 169 | + return new ISData( self::DBool, $a->type != $b->type || !self::equals( $a, $b ) ); |
| 170 | + $a = $a->toString(); |
| 171 | + $b = $b->toString(); |
| 172 | + if( $op == '>' ) |
| 173 | + return new ISData( self::DBool, $a > $b ); |
| 174 | + if( $op == '<' ) |
| 175 | + return new ISData( self::DBool, $a < $b ); |
| 176 | + if( $op == '>=' ) |
| 177 | + return new ISData( self::DBool, $a >= $b ); |
| 178 | + if( $op == '<=' ) |
| 179 | + return new ISData( self::DBool, $a <= $b ); |
| 180 | + throw new ISException( "Invalid comparison operation: {$op}" ); // Should never happen |
| 181 | + } |
| 182 | + |
| 183 | + public static function mulRel( $a, $b, $op, $module, $pos ) { |
| 184 | + // Figure out the type. |
| 185 | + if( ( $a->type == self::DFloat || $b->type == self::DFloat ) && |
| 186 | + $op != '/' ) { |
| 187 | + $type = self::DInt; |
| 188 | + $a = $a->toInt(); |
| 189 | + $b = $b->toInt(); |
| 190 | + } else { |
| 191 | + $type = self::DFloat; |
| 192 | + $a = $a->toFloat(); |
| 193 | + $b = $b->toFloat(); |
| 194 | + } |
| 195 | + |
| 196 | + if( $op != '*' && $b == 0 ) { |
| 197 | + throw new ISUserVisibleException( 'dividebyzero', $module, $pos, array($a) ); |
| 198 | + } |
| 199 | + |
| 200 | + $data = null; |
| 201 | + if( $op == '*' ) |
| 202 | + $data = $a * $b; |
| 203 | + elseif( $op == '/' ) |
| 204 | + $data = $a / $b; |
| 205 | + elseif( $op == '%' ) |
| 206 | + $data = $a % $b; |
| 207 | + else |
| 208 | + throw new ISException( "Invalid multiplication-related operation: {$op}" ); // Should never happen |
| 209 | + |
| 210 | + if( $type == self::DInt ) |
| 211 | + $data = intval( $data ); |
| 212 | + else |
| 213 | + $data = doubleval( $data ); |
| 214 | + |
| 215 | + return new ISData( $type, $data ); |
| 216 | + } |
| 217 | + |
| 218 | + public static function sum( $a, $b ) { |
| 219 | + if( $a->type == self::DString || $b->type == self::DString ) |
| 220 | + return new ISData( self::DString, $a->toString() . $b->toString() ); |
| 221 | + elseif( $a->type == self::DList && $b->type == self::DList ) |
| 222 | + return new ISData( self::DList, array_merge( $a->toList(), $b->toList() ) ); |
| 223 | + elseif( $a->type == self::DList ) |
| 224 | + return new ISData( self::DList, array_merge( $a->toList(), array( $b ) ) ); |
| 225 | + elseif( $a->type == self::DAssoc && $b->type == self::DAssoc ) |
| 226 | + return new ISData( self::DAssoc, array_merge( $a->toAssoc(), $b->toAssoc() ) ); |
| 227 | + elseif( $a->type == self::DInt && $b->type == self::DInt ) |
| 228 | + return new ISData( self::DInt, $a->toInt() + $b->toInt() ); |
| 229 | + else |
| 230 | + return new ISData( self::DFloat, $a->toFloat() + $b->toFloat() ); |
| 231 | + } |
| 232 | + |
| 233 | + public static function sub( $a, $b ) { |
| 234 | + if( $a->type == self::DInt && $b->type == self::DInt ) |
| 235 | + return new ISData( self::DInt, $a->toInt() - $b->toInt() ); |
| 236 | + else |
| 237 | + return new ISData( self::DFloat, $a->toFloat() - $b->toFloat() ); |
| 238 | + } |
| 239 | + |
| 240 | + public function isArray() { |
| 241 | + return $this->type == self::DList || $this->type == self::DAssoc; |
| 242 | + } |
| 243 | + |
| 244 | + |
| 245 | + /** Convert shorteners */ |
| 246 | + public function toBool() { |
| 247 | + return self::castTypes( $this, self::DBool )->data; |
| 248 | + } |
| 249 | + |
| 250 | + public function toString() { |
| 251 | + return self::castTypes( $this, self::DString )->data; |
| 252 | + } |
| 253 | + |
| 254 | + public function toFloat() { |
| 255 | + return self::castTypes( $this, self::DFloat )->data; |
| 256 | + } |
| 257 | + |
| 258 | + public function toInt() { |
| 259 | + return self::castTypes( $this, self::DInt )->data; |
| 260 | + } |
| 261 | + |
| 262 | + public function toList() { |
| 263 | + return self::castTypes( $this, self::DList )->data; |
| 264 | + } |
| 265 | + |
| 266 | + public function toAssoc() { |
| 267 | + return self::castTypes( $this, self::DAssoc )->data; |
| 268 | + } |
| 269 | +} |
Property changes on: trunk/extensions/WikiScripts/interpreter/Data.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 270 | + native |
Index: trunk/extensions/WikiScripts/interpreter/Scanner.php |
— | — | @@ -0,0 +1,340 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki: scanner. |
| 5 | + * Based on the AbuseFilter scanner. |
| 6 | + * Copyright (C) 2008-2011 Victor Vasiliev <vasilvv@gmail.com>, Andrew Garrett <andrew@epstone.net> |
| 7 | + * http://www.mediawiki.org/ |
| 8 | + * |
| 9 | + * This program is free software; you can redistribute it and/or modify |
| 10 | + * it under the terms of the GNU General Public License as published by |
| 11 | + * the Free Software Foundation; either version 2 of the License, or |
| 12 | + * (at your option) any later version. |
| 13 | + * |
| 14 | + * This program is distributed in the hope that it will be useful, |
| 15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | + * GNU General Public License for more details. |
| 18 | + * |
| 19 | + * You should have received a copy of the GNU General Public License along |
| 20 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 21 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 22 | + * http://www.gnu.org/copyleft/gpl.html |
| 23 | + */ |
| 24 | + |
| 25 | +if( !defined( 'MEDIAWIKI' ) ) |
| 26 | + die(); |
| 27 | + |
| 28 | +/** |
| 29 | + * Lexical analizator for inline scripts. Splits strings to tokens. |
| 30 | + */ |
| 31 | + |
| 32 | +require_once( 'Shared.php' ); |
| 33 | + |
| 34 | +class ISScanner implements Iterator { |
| 35 | + var $mModule, $mCode, $mPos, $mCur, $mEof; |
| 36 | + |
| 37 | + // Order is important. The punctuation-matching regex requires that |
| 38 | + // ** comes before *, etc. They are sorted to make it easy to spot |
| 39 | + // such errors. |
| 40 | + static $mOps = array( |
| 41 | + '!==', '!=', '!', // Inequality |
| 42 | + '+=', '-=', // Setting 1 |
| 43 | + '*=', '/=', // Setting 2 |
| 44 | + '**', '*', // Multiplication/exponentiation |
| 45 | + '/', '+', '-', '%', // Other arithmetic |
| 46 | + '&', '|', '^', // Logic |
| 47 | + '?', '::', ':', // Ternery |
| 48 | + '<=','<', // Less than |
| 49 | + '>=', '>', // Greater than |
| 50 | + '===', '==', '=', // Equality |
| 51 | + ',', ';', // Comma, semicolon |
| 52 | + '(', '[', '{', // Braces |
| 53 | + ')', ']', '}', // Braces |
| 54 | + ); |
| 55 | + |
| 56 | + static $mKeywords = array( |
| 57 | + 'append', 'break', 'catch', 'contains', 'continue', 'delete', 'else', 'false', 'for', |
| 58 | + 'function', 'if', 'in', 'isset', 'null', 'return', 'self', 'then', 'true', 'try', 'yield', |
| 59 | + ); |
| 60 | + |
| 61 | + public function __construct( $module, $code ) { |
| 62 | + $this->mModule = $module; |
| 63 | + $this->mCode = $code; |
| 64 | + $this->rewind(); |
| 65 | + } |
| 66 | + |
| 67 | + public function rewind() { |
| 68 | + $this->mPos = 0; |
| 69 | + $this->mCur = null; |
| 70 | + $this->mEof = false; |
| 71 | + $this->move(); |
| 72 | + } |
| 73 | + |
| 74 | + public function current() { |
| 75 | + return $this->mCur; |
| 76 | + } |
| 77 | + |
| 78 | + public function key() { |
| 79 | + return $this->mPos; |
| 80 | + } |
| 81 | + |
| 82 | + public function next() { |
| 83 | + return $this->move(); |
| 84 | + } |
| 85 | + |
| 86 | + public function valid() { |
| 87 | + return !$this->mEof; |
| 88 | + } |
| 89 | + |
| 90 | + private function move() { |
| 91 | + if( $this->mEof || ( $this->mCur && $this->mCur->type == ISToken::TEnd ) ) { |
| 92 | + $this->mEof = true; |
| 93 | + return $this->mCur = null; |
| 94 | + } |
| 95 | + list( $val, $type ) = $this->nextToken(); |
| 96 | + |
| 97 | + $lineno = count( explode( "\n", substr( $this->mCode, 0, $this->mPos ) ) ); |
| 98 | + return $this->mCur = new ISToken( $type, $val, $lineno ); |
| 99 | + } |
| 100 | + |
| 101 | + private function nextToken() { |
| 102 | + $tok = ''; |
| 103 | + |
| 104 | + // Spaces |
| 105 | + $matches = array(); |
| 106 | + if ( preg_match( '/\s+/uA', $this->mCode, $matches, 0, $this->mPos ) ) |
| 107 | + $this->mPos += strlen($matches[0]); |
| 108 | + |
| 109 | + if( $this->mPos >= strlen($this->mCode) ) |
| 110 | + return array( null, ISToken::TEnd ); |
| 111 | + |
| 112 | + // Comments |
| 113 | + if ( substr($this->mCode, $this->mPos, 2) == '/*' ) { |
| 114 | + $this->mPos = strpos( $this->mCode, '*/', $this->mPos ) + 2; |
| 115 | + return self::nextToken(); |
| 116 | + } |
| 117 | + |
| 118 | + if( substr( $this->mCode, $this->mPos, 2 ) == '//' ) { |
| 119 | + $newlinePos = strpos( $this->mCode, "\n", $this->mPos ); |
| 120 | + if( $newlinePos === false ) { |
| 121 | + return array( null, ISToken::TEnd ); |
| 122 | + } else { |
| 123 | + $this->mPos = $newlinePos + 1; |
| 124 | + return self::nextToken(); |
| 125 | + } |
| 126 | + } |
| 127 | + |
| 128 | + // Strings |
| 129 | + if( $this->mCode[$this->mPos] == '"' || $this->mCode[$this->mPos] == "'" ) { |
| 130 | + $type = $this->mCode[$this->mPos]; |
| 131 | + $this->mPos++; |
| 132 | + $strLen = strlen($this->mCode); |
| 133 | + while( $this->mPos < $strLen ) { |
| 134 | + if( $this->mCode[$this->mPos] == $type ) { |
| 135 | + $this->mPos++; |
| 136 | + return array( $tok, ISToken::TString ); |
| 137 | + } |
| 138 | + |
| 139 | + // Performance: Use a PHP function (implemented in C) |
| 140 | + // to scan ahead. |
| 141 | + $addLength = strcspn( $this->mCode, $type."\\", $this->mPos ); |
| 142 | + if ($addLength) { |
| 143 | + $tok .= substr( $this->mCode, $this->mPos, $addLength ); |
| 144 | + $this->mPos += $addLength; |
| 145 | + } elseif( $this->mCode[$this->mPos] == '\\' ) { |
| 146 | + switch( $this->mCode[$this->mPos + 1] ) { |
| 147 | + case '\\': |
| 148 | + $tok .= '\\'; |
| 149 | + break; |
| 150 | + case $type: |
| 151 | + $tok .= $type; |
| 152 | + break; |
| 153 | + case 'n'; |
| 154 | + $tok .= "\n"; |
| 155 | + break; |
| 156 | + case 'r': |
| 157 | + $tok .= "\r"; |
| 158 | + break; |
| 159 | + case 't': |
| 160 | + $tok .= "\t"; |
| 161 | + break; |
| 162 | + case 'x': |
| 163 | + $chr = substr( $this->mCode, $this->mPos + 2, 2 ); |
| 164 | + |
| 165 | + if ( preg_match( '/^[0-9A-Fa-f]{2}$/', $chr ) ) { |
| 166 | + $chr = base_convert( $chr, 16, 10 ); |
| 167 | + $tok .= chr($chr); |
| 168 | + $this->mPos += 2; # \xXX -- 2 done later |
| 169 | + } else { |
| 170 | + $tok .= 'x'; |
| 171 | + } |
| 172 | + break; |
| 173 | + default: |
| 174 | + $tok .= "\\" . $this->mCode[$this->mPos + 1]; |
| 175 | + } |
| 176 | + $this->mPos+=2; |
| 177 | + } else { |
| 178 | + $tok .= $this->mCode[$this->mPos]; |
| 179 | + $this->mPos++; |
| 180 | + } |
| 181 | + } |
| 182 | + throw new ISUserVisibleException( 'unclosedstring', $this->mModule, $this->mPos, array() ); |
| 183 | + } |
| 184 | + |
| 185 | + // Find operators |
| 186 | + static $operator_regex = null; |
| 187 | + // Match using a regex. Regexes are faster than PHP |
| 188 | + if (!$operator_regex) { |
| 189 | + $quoted_operators = array(); |
| 190 | + |
| 191 | + foreach( self::$mOps as $op ) |
| 192 | + $quoted_operators[] = preg_quote( $op, '/' ); |
| 193 | + $operator_regex = '/('.implode('|', $quoted_operators).')/A'; |
| 194 | + } |
| 195 | + |
| 196 | + $matches = array(); |
| 197 | + |
| 198 | + preg_match( $operator_regex, $this->mCode, $matches, 0, $this->mPos ); |
| 199 | + |
| 200 | + if( count( $matches ) ) { |
| 201 | + $tok = $matches[0]; |
| 202 | + $this->mPos += strlen( $tok ); |
| 203 | + return array( $tok, $this->getOperatorType( $tok ) ); |
| 204 | + } |
| 205 | + |
| 206 | + // Find bare numbers |
| 207 | + $bases = array( 'b' => 2, |
| 208 | + 'x' => 16, |
| 209 | + 'o' => 8 ); |
| 210 | + $baseChars = array( |
| 211 | + 2 => '[01]', |
| 212 | + 16 => '[0-9A-Fa-f]', |
| 213 | + 8 => '[0-8]', |
| 214 | + 10 => '[0-9.]', |
| 215 | + ); |
| 216 | + $baseClass = '['.implode('', array_keys($bases)).']'; |
| 217 | + $radixRegex = "/([0-9A-Fa-f]+(?:\.\d*)?|\.\d+)($baseClass)?/Au"; |
| 218 | + $matches = array(); |
| 219 | + |
| 220 | + if ( preg_match( $radixRegex, $this->mCode, $matches, 0, $this->mPos ) ) { |
| 221 | + $input = $matches[1]; |
| 222 | + $baseChar = @$matches[2]; |
| 223 | + $num = null; |
| 224 | + // Sometimes the base char gets mixed in with the rest of it because |
| 225 | + // the regex targets hex, too. |
| 226 | + // This mostly happens with binary |
| 227 | + if (!$baseChar && !empty( $bases[ substr( $input, -1 ) ] ) ) { |
| 228 | + $baseChar = substr( $input, -1, 1 ); |
| 229 | + $input = substr( $input, 0, -1 ); |
| 230 | + } |
| 231 | + |
| 232 | + if( $baseChar ) |
| 233 | + $base = $bases[$baseChar]; |
| 234 | + else |
| 235 | + $base = 10; |
| 236 | + |
| 237 | + // Check against the appropriate character class for input validation |
| 238 | + $baseRegex = "/^".$baseChars[$base]."+$/"; |
| 239 | + |
| 240 | + if ( preg_match( $baseRegex, $input ) ) { |
| 241 | + if ($base != 10) { |
| 242 | + $num = base_convert( $input, $base, 10 ); |
| 243 | + } else { |
| 244 | + $num = $input; |
| 245 | + } |
| 246 | + |
| 247 | + $this->mPos += strlen( $matches[0] ); |
| 248 | + |
| 249 | + $float = in_string( '.', $input ); |
| 250 | + |
| 251 | + return array( |
| 252 | + $float |
| 253 | + ? doubleval( $num ) |
| 254 | + : intval( $num ), |
| 255 | + $float |
| 256 | + ? ISToken::TFloat |
| 257 | + : ISToken::TInt, |
| 258 | + ); |
| 259 | + } |
| 260 | + } |
| 261 | + |
| 262 | + // The rest are considered IDs |
| 263 | + |
| 264 | + // Regex match > PHP |
| 265 | + $idSymbolRegex = '/[0-9A-Za-z_]+/A'; |
| 266 | + $matches = array(); |
| 267 | + |
| 268 | + if ( preg_match( $idSymbolRegex, $this->mCode, $matches, 0, $this->mPos ) ) { |
| 269 | + $tok = $matches[0]; |
| 270 | + |
| 271 | + $type = in_array( $tok, self::$mKeywords ) |
| 272 | + ? $tok : ISToken::TID; |
| 273 | + |
| 274 | + $this->mPos += strlen( $tok ); |
| 275 | + return array( $tok, $type ); |
| 276 | + } |
| 277 | + |
| 278 | + throw new ISUserVisibleException( |
| 279 | + 'unrecognisedtoken', $this->mModule, $this->mPos, array( substr( $this->mCode, $this->mPos ) ) ); |
| 280 | + } |
| 281 | + |
| 282 | + private static function getOperatorType( $op ) { |
| 283 | + switch( $op ) { |
| 284 | + case '::': |
| 285 | + return ISToken::TDoubleColon; |
| 286 | + case ':': |
| 287 | + return ISToken::TColon; |
| 288 | + case ',': |
| 289 | + return ISToken::TComma; |
| 290 | + case '>': |
| 291 | + case '<': |
| 292 | + case '>=': |
| 293 | + case '<=': |
| 294 | + return ISToken::TCompareOperator; |
| 295 | + case '==': |
| 296 | + case '!=': |
| 297 | + case '===': |
| 298 | + case '!==': |
| 299 | + return ISToken::TEqualsToOperator; |
| 300 | + case '!': |
| 301 | + return ISToken::TBoolInvert; |
| 302 | + case '(': |
| 303 | + return ISToken::TLeftBracket; |
| 304 | + case '{': |
| 305 | + return ISToken::TLeftCurly; |
| 306 | + case '[': |
| 307 | + return ISToken::TLeftSquare; |
| 308 | + case '&': |
| 309 | + case '|': |
| 310 | + case '^': |
| 311 | + return ISToken::TLogicalOperator; |
| 312 | + case '*': |
| 313 | + case '/': |
| 314 | + case '%': |
| 315 | + return ISToken::TMulOperator; |
| 316 | + case '**': |
| 317 | + return ISToken::TPow; |
| 318 | + case ')': |
| 319 | + return ISToken::TRightBracket; |
| 320 | + case '}': |
| 321 | + return ISToken::TRightCurly; |
| 322 | + case ']': |
| 323 | + return ISToken::TRightSquare; |
| 324 | + case ';': |
| 325 | + return ISToken::TSemicolon; |
| 326 | + case '=': |
| 327 | + case '+=': |
| 328 | + case '-=': |
| 329 | + case '*=': |
| 330 | + case '/=': |
| 331 | + return ISToken::TSet; |
| 332 | + case '+': |
| 333 | + case '-': |
| 334 | + return ISToken::TSumOperator; |
| 335 | + case '?': |
| 336 | + return ISToken::TTrinary; |
| 337 | + default: |
| 338 | + throw new ISException( "Invalid operator: {$op}" ); |
| 339 | + } |
| 340 | + } |
| 341 | +} |
Property changes on: trunk/extensions/WikiScripts/interpreter/Scanner.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 342 | + native |
Index: trunk/extensions/WikiScripts/interpreter/LRParser.php |
— | — | @@ -0,0 +1,114 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * LR parser for inline scripts. |
| 6 | + * Inputs tokens and LR table (ACTION/GOTO). |
| 7 | + * Outputs parser tree. |
| 8 | + * |
| 9 | + * See http://en.wikipedia.org/wiki/LR_parser for details of how does that works. |
| 10 | + */ |
| 11 | + |
| 12 | +require_once( 'LRTableVersion.php' ); |
| 13 | + |
| 14 | +class ISLRParser implements ISParser { |
| 15 | + const Shift = 0; |
| 16 | + const Reduce = 1; |
| 17 | + const Accept = 2; |
| 18 | + |
| 19 | + static $mLoaded, $mNonterminals, $mProductions, $mAction, $mGoto; |
| 20 | + |
| 21 | + public static function getVersion() { |
| 22 | + return IS_LR_VERSION; |
| 23 | + } |
| 24 | + |
| 25 | + private function loadGrammar() { |
| 26 | + wfProfileIn( __METHOD__ ); |
| 27 | + |
| 28 | + if( self::$mLoaded ) |
| 29 | + return; |
| 30 | + |
| 31 | + require_once( 'LRTable.php' ); |
| 32 | + |
| 33 | + self::$mNonterminals = ISLRTable::$nonterminals; |
| 34 | + self::$mProductions = ISLRTable::$productions; |
| 35 | + self::$mAction = ISLRTable::$action; |
| 36 | + self::$mGoto = ISLRTable::$goto; |
| 37 | + self::$mLoaded = true; |
| 38 | + |
| 39 | + wfProfileOut( __METHOD__ ); |
| 40 | + } |
| 41 | + |
| 42 | + public function needsScanner() { |
| 43 | + return true; |
| 44 | + } |
| 45 | + |
| 46 | + public function parse( $scanner, $module, $maxTokens ) { |
| 47 | + self::loadGrammar(); |
| 48 | + |
| 49 | + $states = array( array( null, 0 ) ); |
| 50 | + $scanner->rewind(); |
| 51 | + $tokenCount = 0; |
| 52 | + |
| 53 | + wfProfileIn( __METHOD__ ); |
| 54 | + |
| 55 | + for( ; ; ) { |
| 56 | + $token = $scanner->current(); |
| 57 | + $cur = $token->type; |
| 58 | + if( !$token ) { |
| 59 | + wfProfileOut( __METHOD__ ); |
| 60 | + throw new ISException( 'Non-token input in LRParser::parse' ); |
| 61 | + } |
| 62 | + |
| 63 | + $tokenCount++; |
| 64 | + if( $tokenCount > $maxTokens ) { |
| 65 | + wfProfileOut( __METHOD__ ); |
| 66 | + throw new ISUserVisibleException( 'toomanytokens', $module, $token->line ); |
| 67 | + } |
| 68 | + |
| 69 | + list( $stateval, $state ) = end( $states ); |
| 70 | + $act = @self::$mAction[$state][$cur]; |
| 71 | + if( !$act ) { |
| 72 | + wfProfileOut( __METHOD__ ); |
| 73 | + throw new ISUserVisibleException( 'unexceptedtoken', $module, $token->line, |
| 74 | + array( $token, implode( ', ', array_keys( @self::$mAction[$state] ) ), $state ) ); |
| 75 | + } |
| 76 | + if( $act[0] == self::Shift ) { |
| 77 | + $states[] = array( $token, $act[1] ); |
| 78 | + $scanner->next(); |
| 79 | + } elseif( $act[0] == self::Reduce ) { |
| 80 | + list( $nonterm, $prod ) = self::$mProductions[$act[1]]; |
| 81 | + $len = count( $prod ); |
| 82 | + |
| 83 | + // Change state |
| 84 | + $str = array(); |
| 85 | + for( $i = 0; $i < $len; $i++ ) |
| 86 | + $str[] = array_pop( $states ); |
| 87 | + $str = array_reverse( $str ); |
| 88 | + list( $stateval, $state ) = end( $states ); |
| 89 | + |
| 90 | + $node = new ISParserTreeNode( $this, $nonterm ); |
| 91 | + foreach( $str as $symbol ) { |
| 92 | + list( $val ) = $symbol; |
| 93 | + $node->addChild( $val ); |
| 94 | + } |
| 95 | + $states[] = array( $node, self::$mGoto[$state][$nonterm] ); |
| 96 | + } elseif( $act[0] == self::Accept ) { |
| 97 | + break; |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + wfProfileOut( __METHOD__ ); |
| 102 | + |
| 103 | + return new ISParserOutput( $states[1][0], $tokenCount ); |
| 104 | + } |
| 105 | + |
| 106 | + public function getSyntaxErrors( $input, $module, $maxTokens ) { |
| 107 | + try { |
| 108 | + $this->parse( $input, $module, $maxTokens ); |
| 109 | + } catch( ISUserVisibleException $e ) { |
| 110 | + return array( $e->getMessage() ); |
| 111 | + } |
| 112 | + |
| 113 | + return array(); |
| 114 | + } |
| 115 | +} |
Property changes on: trunk/extensions/WikiScripts/interpreter/LRParser.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 116 | + native |
Index: trunk/extensions/WikiScripts/interpreter/LRTableVersion.php |
— | — | @@ -0,0 +1,9 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * This file includes timestamp which indicates the version of LRTable.php file. |
| 6 | + * Since the file is too large, loading it every time is expensive and we store the |
| 7 | + * version in separate file. |
| 8 | + */ |
| 9 | + |
| 10 | +define( 'IS_LR_VERSION', "2011-08-13 21:53:42" ); |
Index: trunk/extensions/WikiScripts/interpreter/EvaluationContext.php |
— | — | @@ -0,0 +1,764 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki. |
| 5 | + * Copyright (C) 2009-2011 Victor Vasiliev <vasilvv@gmail.com> |
| 6 | + * http://www.mediawiki.org/ |
| 7 | + * |
| 8 | + * This program is free software; you can redistribute it and/or modify |
| 9 | + * it under the terms of the GNU General Public License as published by |
| 10 | + * the Free Software Foundation; either version 2 of the License, or |
| 11 | + * (at your option) any later version. |
| 12 | + * |
| 13 | + * This program is distributed in the hope that it will be useful, |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | + * GNU General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU General Public License along |
| 19 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 20 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 21 | + * http://www.gnu.org/copyleft/gpl.html |
| 22 | + */ |
| 23 | + |
| 24 | +if( !defined( 'MEDIAWIKI' ) ) |
| 25 | + die(); |
| 26 | + |
| 27 | +/** |
| 28 | + * An internal class used by InlineScript. Used to evaluate a parsed code |
| 29 | + * in a sepereate context with its own output, variables and parser frame. |
| 30 | + * |
| 31 | + * Handles evaluation of an individual functions. |
| 32 | + */ |
| 33 | +class ISEvaluationContext { |
| 34 | + var $mVars, $mFrame, $mName, $mInterpreter, $mModule; |
| 35 | + |
| 36 | + var $mOutput, $mListOutput; |
| 37 | + |
| 38 | + static $mFunctions = array( |
| 39 | + /* String functions */ |
| 40 | + 'lc' => 'funcLc', |
| 41 | + 'uc' => 'funcUc', |
| 42 | + 'ucfirst' => 'funcUcFirst', |
| 43 | + 'urlencode' => 'funcUrlencode', |
| 44 | + 'grammar' => 'funcGrammar', |
| 45 | + 'plural' => 'funcPlural', |
| 46 | + 'anchorencode' => 'funcAnchorEncode', |
| 47 | + 'strlen' => 'funcStrlen', |
| 48 | + 'substr' => 'funcSubstr', |
| 49 | + 'strreplace' => 'funcStrreplace', |
| 50 | + 'split' => 'funcSplit', |
| 51 | + |
| 52 | + /* Array functions */ |
| 53 | + 'join' => 'funcJoin', |
| 54 | + 'count' => 'funcCount', |
| 55 | + |
| 56 | + /* Parser interaction functions */ |
| 57 | + 'arg' => 'funcArg', |
| 58 | + 'args' => 'funcArgs', |
| 59 | + 'isTranscluded' => 'funcIsTranscluded', |
| 60 | + 'parse' => 'funcParse', |
| 61 | + |
| 62 | + /* Cast functions */ |
| 63 | + 'string' => 'castString', |
| 64 | + 'int' => 'castInt', |
| 65 | + 'float' => 'castFloat', |
| 66 | + 'bool' => 'castBool', |
| 67 | + ); |
| 68 | + |
| 69 | + public function __construct( $interpreter, $module, $name, $frame ) { |
| 70 | + $this->mVars = array(); |
| 71 | + $this->mOut = ''; |
| 72 | + $this->mModule = $module; |
| 73 | + $this->mModuleName = $module->getName(); |
| 74 | + $this->mName = $name; |
| 75 | + $this->mInterpreter = $interpreter; |
| 76 | + $this->mParser = $interpreter->getParser(); |
| 77 | + $this->mFrame = $frame; |
| 78 | + |
| 79 | + $this->mOutput = new ISData(); |
| 80 | + $this->mListOutput = array(); |
| 81 | + } |
| 82 | + |
| 83 | + public function getModule() { |
| 84 | + return $this->mModule; |
| 85 | + } |
| 86 | + |
| 87 | + public function getFrame() { |
| 88 | + return $this->mFrame; |
| 89 | + } |
| 90 | + |
| 91 | + public function getOutput() { |
| 92 | + if( $this->mOutput->type != ISData::DNull ) { |
| 93 | + return $this->mOutput; |
| 94 | + } elseif( $this->mListOutput ) { |
| 95 | + return new ISData( ISData::DList, $this->mListOutput ); |
| 96 | + } else { |
| 97 | + return new ISData(); |
| 98 | + } |
| 99 | + } |
| 100 | + |
| 101 | + public function setArgument( $name, $value ) { |
| 102 | + $this->mVars[$name] = $value->dup(); |
| 103 | + } |
| 104 | + |
| 105 | + /** |
| 106 | + * The core interpreter method. Evaluates a single AST node. |
| 107 | + * The $rec parameter must be increated by 1 each time the function is called |
| 108 | + * recursively. |
| 109 | + */ |
| 110 | + public function evaluateNode( $node, $rec ) { |
| 111 | + if( !$node instanceof ISParserTreeNode ) { |
| 112 | + throw new ISException( 'evaluateNode() accepts only nonterminals' ); |
| 113 | + } |
| 114 | + |
| 115 | + if( !$this->mInterpreter->checkRecursionLimit( $rec ) ) { |
| 116 | + throw new ISUserVisibleException( 'recoverflow', $this->mModuleName, $this->getLine( $node ) ); |
| 117 | + } |
| 118 | + |
| 119 | + $c = $node->getChildren(); |
| 120 | + switch( $node->getType() ) { |
| 121 | + case 'stmts': |
| 122 | + $stmts = array(); |
| 123 | + while( isset( $c[1] ) ) { |
| 124 | + array_unshift( $stmts, $c[1] ); |
| 125 | + $c = $c[0]->getChildren(); |
| 126 | + } |
| 127 | + array_unshift( $stmts, $c[0] ); |
| 128 | + foreach( $stmts as $stmt ) |
| 129 | + $res = $this->evaluateNode( $stmt, $rec + 1 ); |
| 130 | + return $res; |
| 131 | + case 'stmt': |
| 132 | + if( $c[0] instanceof ISToken ) { |
| 133 | + switch( $c[0]->type ) { |
| 134 | + case 'leftcurly': |
| 135 | + return $this->evaluateNode( $c[1], $rec + 1 ); |
| 136 | + case 'if': |
| 137 | + $cond = $this->evaluateNode( $c[2], $rec + 1 ); |
| 138 | + if( $cond->toBool() ) { |
| 139 | + return $this->evaluateNode( $c[4], $rec + 1 ); |
| 140 | + } else { |
| 141 | + if( isset( $c[6] ) ) { |
| 142 | + return $this->evaluateNode( $c[6], $rec + 1 ); |
| 143 | + } else { |
| 144 | + return new ISData(); |
| 145 | + } |
| 146 | + } |
| 147 | + case 'for': |
| 148 | + $array = $this->evaluateNode( $c[4], $rec + 1 ); |
| 149 | + if( !$array->isArray() ) |
| 150 | + throw new ISUserVisibleException( 'invalidforeach', $this->mModuleName, $c[0]->line ); |
| 151 | + $last = new ISData(); |
| 152 | + $lvalues = $c[2]->getChildren(); |
| 153 | + |
| 154 | + foreach( $array->data as $key => $item ) { |
| 155 | + // <forlvalue> ::= <lvalue> | <lvalue> colon <lvalue> |
| 156 | + if( count( $lvalues ) > 1 ) { |
| 157 | + $this->setVar( $lvalues[0], ISData::newFromPHPVar( $key ), $rec ); |
| 158 | + $this->setVar( $lvalues[2], $item, $rec ); |
| 159 | + } else { |
| 160 | + $this->setVar( $lvalues[0], $item, $rec ); |
| 161 | + } |
| 162 | + try { |
| 163 | + $last = $this->evaluateNode( $c[6], $rec + 1 ); |
| 164 | + } catch( ISUserVisibleException $e ) { |
| 165 | + if( $e->getExceptionID() == 'break' ) |
| 166 | + break; |
| 167 | + elseif( $e->getExceptionID() == 'continue' ) |
| 168 | + continue; |
| 169 | + else |
| 170 | + throw $e; |
| 171 | + } |
| 172 | + } |
| 173 | + return $last; |
| 174 | + case 'try': |
| 175 | + try { |
| 176 | + return $this->evaluateNode( $c[1], $rec + 1 ); |
| 177 | + } catch( ISUserVisibleException $e ) { |
| 178 | + if( $e instanceof ISControlException ) { |
| 179 | + throw $e; |
| 180 | + } else { |
| 181 | + $this->setVar( $c[4], new ISData( ISData::DString, $e->getExceptionID() ), $rec ); |
| 182 | + return $this->evaluateNode( $c[6], $rec + 1 ); |
| 183 | + } |
| 184 | + } |
| 185 | + default: |
| 186 | + throw new ISException( "Unknown keyword: {$c[0]->type}" ); |
| 187 | + } |
| 188 | + } else { |
| 189 | + return $this->evaluateNode( $c[0], $rec + 1 ); |
| 190 | + } |
| 191 | + case 'exprreturn': |
| 192 | + switch( $c[0]->value ) { |
| 193 | + case 'return': |
| 194 | + if( isset( $c[1] ) ) { |
| 195 | + $retval = $this->evaluateNode( $c[1], $rec + 1 ); |
| 196 | + $empty = false; |
| 197 | + } else { |
| 198 | + $retval = new ISData(); |
| 199 | + $empty = true; |
| 200 | + } |
| 201 | + throw new ISReturnException( $retval, $empty ); |
| 202 | + case 'append': |
| 203 | + if( $this->mListOutput ) { |
| 204 | + throw new ISUserVisibleException( 'appendyield', $this->mModuleName, $c[0]->line ); |
| 205 | + } |
| 206 | + |
| 207 | + $this->mOutput = ISData::sum( $this->mOutput, $this->evaluateNode( $c[1], $rec + 1 ) ); |
| 208 | + break 2; |
| 209 | + case 'yield': |
| 210 | + if( $this->mOutput->type != ISData::DNull ) { |
| 211 | + throw new ISUserVisibleException( 'appendyield', $this->mModuleName, $c[0]->line ); |
| 212 | + } |
| 213 | + |
| 214 | + $this->mListOutput[] = $this->evaluateNode( $c[1], $rec + 1 ); |
| 215 | + break 2; |
| 216 | + default: |
| 217 | + throw new ISException( "Unknown return keyword: {$c[0]->value}" ); |
| 218 | + } |
| 219 | + case 'exprset': |
| 220 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 221 | + if( $c[1]->value == '=' ) { |
| 222 | + $new = $this->evaluateNode( $c[2], $rec + 1 ); |
| 223 | + $this->setVar( $c[0], $new, $rec ); |
| 224 | + return $new; |
| 225 | + } else { |
| 226 | + $old = $this->getVar( $c[0], $rec, false ); |
| 227 | + $new = $this->evaluateNode( $c[2], $rec + 1 ); |
| 228 | + $new = $this->getValueForSetting( $old, $new, |
| 229 | + $c[1]->value, $c[1]->line ); |
| 230 | + $this->setVar( $c[0], $new, $rec ); |
| 231 | + return $new; |
| 232 | + } |
| 233 | + case 'exprtrinary': |
| 234 | + $cond = $this->evaluateNode( $c[0], $rec + 1 ); |
| 235 | + if( $cond->toBool() ) { |
| 236 | + return $this->evaluateNode( $c[2], $rec + 1 ); |
| 237 | + } else { |
| 238 | + return $this->evaluateNode( $c[4], $rec + 1 ); |
| 239 | + } |
| 240 | + case 'exprlogical': |
| 241 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 242 | + $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
| 243 | + switch( $c[1]->value ) { |
| 244 | + case '&': |
| 245 | + if( !$arg1->toBool() ) |
| 246 | + return new ISData( ISData::DBool, false ); |
| 247 | + else |
| 248 | + return $this->evaluateNode( $c[2], $rec + 1 ); |
| 249 | + case '|': |
| 250 | + if( $arg1->toBool() ) |
| 251 | + return new ISData( ISData::DBool, true ); |
| 252 | + else |
| 253 | + return $this->evaluateNode( $c[2], $rec + 1 ); |
| 254 | + case '^': |
| 255 | + $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
| 256 | + return new ISData( ISData::DBool, $arg1->toBool() xor $arg2->toBool() ); |
| 257 | + default: |
| 258 | + throw new ISException( "Invalid logical operation: {$c[1]->value}" ); |
| 259 | + } |
| 260 | + case 'exprequals': |
| 261 | + case 'exprcompare': |
| 262 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 263 | + $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
| 264 | + $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
| 265 | + return ISData::compareOp( $arg1, $arg2, $c[1]->value ); |
| 266 | + case 'exprsum': |
| 267 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 268 | + $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
| 269 | + $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
| 270 | + switch( $c[1]->value ) { |
| 271 | + case '+': |
| 272 | + return ISData::sum( $arg1, $arg2 ); |
| 273 | + case '-': |
| 274 | + return ISData::sub( $arg1, $arg2 ); |
| 275 | + } |
| 276 | + case 'exprmul': |
| 277 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 278 | + $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
| 279 | + $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
| 280 | + return ISData::mulRel( $arg1, $arg2, $c[1]->value, $this->mModuleName, $c[1]->line ); |
| 281 | + case 'exprpow': |
| 282 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 283 | + $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
| 284 | + $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
| 285 | + return ISData::pow( $arg1, $arg2 ); |
| 286 | + case 'exprkeyword': |
| 287 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 288 | + $arg1 = $this->evaluateNode( $c[0], $rec + 1 ); |
| 289 | + $arg2 = $this->evaluateNode( $c[2], $rec + 1 ); |
| 290 | + switch( $c[1]->value ) { |
| 291 | + case 'in': |
| 292 | + return ISData::keywordIn( $arg1, $arg2 ); |
| 293 | + case 'contains': |
| 294 | + return ISData::keywordIn( $arg2, $arg1 ); |
| 295 | + default: |
| 296 | + throw new ISException( "Invalid keyword: {$c[1]->value}" ); |
| 297 | + } |
| 298 | + case 'exprinvert': |
| 299 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[0]->line ); |
| 300 | + $arg = $this->evaluateNode( $c[1], $rec + 1 ); |
| 301 | + return ISData::boolInvert( $arg ); |
| 302 | + case 'exprunary': |
| 303 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[0]->line ); |
| 304 | + $arg = $this->evaluateNode( $c[1], $rec + 1 ); |
| 305 | + if( $c[0]->value == '-' ) |
| 306 | + return ISData::unaryMinus( $arg ); |
| 307 | + else |
| 308 | + return $arg; |
| 309 | + case 'exprfunction': |
| 310 | + // <exprFunction> ::= <funcid> leftbracket <commaListPlain> rightbracket | <funcid> leftbracket rightbracket |
| 311 | + // <exprFunction> ::= <varfunc> leftbracket <lvalue> rightbracket | <exprAtom> |
| 312 | + // <varfunc> ::= isset | delete |
| 313 | + // <funcid> ::= id | <exprAtom> doublecolon id | self doublecolon id |
| 314 | + |
| 315 | + $this->mInterpreter->increaseEvaluationsCount( $this->mModuleName, $c[1]->line ); |
| 316 | + if( $c[0]->getType() == 'funcid' ) { |
| 317 | + if( $c[2] instanceof ISParserTreeNode ) { |
| 318 | + $args = $this->parseArray( $c[2], $rec, $dummy ); |
| 319 | + } else { |
| 320 | + $args = array(); |
| 321 | + } |
| 322 | + |
| 323 | + $idch = $c[0]->getChildren(); |
| 324 | + if( count( $idch ) == 1 ) { |
| 325 | + $funcname = $idch[0]->value; |
| 326 | + if( !isset( self::$mFunctions[$funcname] ) ) |
| 327 | + throw new ISUserVisibleException( 'unknownfunction', $this->mModuleName, $idch[0]->line, array( $funcname ) ); |
| 328 | + $func = self::$mFunctions[$funcname]; |
| 329 | + return $this->$func( $args, $idch[0]->line ); |
| 330 | + } else { |
| 331 | + $funcname = $idch[2]->value; |
| 332 | + if( $idch[0] instanceof ISToken ) { |
| 333 | + // self::function() |
| 334 | + $module = $this->mModule; |
| 335 | + } else { |
| 336 | + // "ModuleName"::function() |
| 337 | + $module = $this->evaluateNode( $idch[0], $rec + 1 )->toString(); |
| 338 | + } |
| 339 | + return $this->mInterpreter->invokeUserFunctionFromModule( |
| 340 | + $module, $funcname, $args, $this, $idch[1]->line ); |
| 341 | + } |
| 342 | + } else { |
| 343 | + $type = $c[0]->mChildren[0]->value; |
| 344 | + switch( $type ) { |
| 345 | + case 'isset': |
| 346 | + $val = $this->getVar( $c[2], $rec, true ); |
| 347 | + return new ISData( ISData::DBool, $val !== null ); |
| 348 | + case 'delete': |
| 349 | + $this->deleteVar( $c[2], $rec ); |
| 350 | + return new ISData(); |
| 351 | + default: |
| 352 | + throw new ISException( "Unknown keyword: {$type}" ); |
| 353 | + } |
| 354 | + } |
| 355 | + case 'expratom': |
| 356 | + if( $c[0] instanceof ISParserTreeNode ) { |
| 357 | + if( $c[0]->getType() == 'atom' ) { |
| 358 | + list( $val ) = $c[0]->getChildren(); |
| 359 | + switch( $val->type ) { |
| 360 | + case 'string': |
| 361 | + return new ISData( ISData::DString, $val->value ); |
| 362 | + case 'int': |
| 363 | + return new ISData( ISData::DInt, $val->value ); |
| 364 | + case 'float': |
| 365 | + return new ISData( ISData::DFloat, $val->value ); |
| 366 | + case 'true': |
| 367 | + return new ISData( ISData::DBool, true ); |
| 368 | + case 'false': |
| 369 | + return new ISData( ISData::DBool, false ); |
| 370 | + case 'null': |
| 371 | + return new ISData(); |
| 372 | + } |
| 373 | + } else { |
| 374 | + return $this->getVar( $c[0], $rec ); |
| 375 | + } |
| 376 | + } else { |
| 377 | + switch( $c[0]->type ) { |
| 378 | + case 'leftbracket': |
| 379 | + return $this->evaluateNode( $c[1], $rec + 1 ); |
| 380 | + case 'leftsquare': |
| 381 | + case 'leftcurly': |
| 382 | + $arraytype = null; |
| 383 | + $array = $this->parseArray( $c[1], $rec + 1, $arraytype ); |
| 384 | + return new ISData( $arraytype, $array ); |
| 385 | + case 'break': |
| 386 | + throw new ISControlException( 'break', $this->mModuleName, $c[0]->line ); |
| 387 | + case 'continue': |
| 388 | + throw new ISControlException( 'continue', $this->mModuleName, $c[0]->line ); |
| 389 | + } |
| 390 | + } |
| 391 | + default: |
| 392 | + $type = $node->getType(); |
| 393 | + throw new ISException( "Invalid node type passed to evaluateNode(): {$type}" ); |
| 394 | + } |
| 395 | + } |
| 396 | + |
| 397 | + /* |
| 398 | + * Converts commaList* to a PHP array. |
| 399 | + */ |
| 400 | + protected function parseArray( $node, $rec, &$arraytype ) { |
| 401 | + $c = $node->getChildren(); |
| 402 | + $type = $node->getType(); |
| 403 | + if( $type == 'commalist' ) { |
| 404 | + return $this->parseArray( $c[0], $rec, $arraytype ); |
| 405 | + } |
| 406 | + |
| 407 | + wfProfileIn( __METHOD__ ); |
| 408 | + |
| 409 | + // <commaListWhatever> ::= <commaListWhatever> comma <expr> | <expr> |
| 410 | + $elements = $result = array(); |
| 411 | + while( isset( $c[2] ) ) { |
| 412 | + array_unshift( $elements, $c[2] ); |
| 413 | + $c = $c[0]->getChildren(); |
| 414 | + } |
| 415 | + array_unshift( $elements, $c[0] ); |
| 416 | + |
| 417 | + switch( $type ) { |
| 418 | + case 'commalistplain': |
| 419 | + foreach( $elements as $elem ) { |
| 420 | + $result[] = $this->evaluateNode( $elem, $rec + 1 ); |
| 421 | + } |
| 422 | + |
| 423 | + $arraytype = ISData::DList; |
| 424 | + wfProfileOut( __METHOD__ ); |
| 425 | + return $result; |
| 426 | + |
| 427 | + case 'commalistassoc': |
| 428 | + foreach( $elements as $elem ) { |
| 429 | + //<keyValue> ::= <expr> colon <expr> |
| 430 | + list( $key, $crap, $value ) = $elem->getChildren(); |
| 431 | + $key = $this->evaluateNode( $key, $rec + 1 ); |
| 432 | + $value = $this->evaluateNode( $value, $rec + 1 ); |
| 433 | + $result[ $key->toString() ] = $value; |
| 434 | + } |
| 435 | + |
| 436 | + $arraytype = ISData::DAssoc; |
| 437 | + wfProfileOut( __METHOD__ ); |
| 438 | + return $result; |
| 439 | + } |
| 440 | + } |
| 441 | + |
| 442 | + /** |
| 443 | + * Returns a value of the variable in $lval. If $nullIfNotSet is set to true, |
| 444 | + * returns null if variable does not exist, otherwise throws an exception. |
| 445 | + */ |
| 446 | + protected function getVar( $lval, $rec, $nullIfNotSet = false ) { |
| 447 | + // <lvalue> ::= id | <lvalue> <arrayIdx> |
| 448 | + // <arrayIdx> ::= leftsquare <expr> rightsquare | leftsquare rightsquare |
| 449 | + |
| 450 | + if( !$this->mInterpreter->checkRecursionLimit( $rec ) ) { |
| 451 | + throw new ISUserVisibleException( 'recoverflow', $this->mModuleName, $this->getLine( $node ) ); |
| 452 | + } |
| 453 | + |
| 454 | + $c = $lval->getChildren(); |
| 455 | + if( $c[0] instanceof ISToken ) { |
| 456 | + // Variable ID |
| 457 | + $varname = $c[0]->value; |
| 458 | + if( !isset( $this->mVars[$varname] ) ) { |
| 459 | + if( $nullIfNotSet ) |
| 460 | + return null; |
| 461 | + else |
| 462 | + throw new ISUserVisibleException( 'unknownvar', $this->mModuleName, $c[0]->line, array( $varname ) ); |
| 463 | + } |
| 464 | + return $this->mVars[$varname]; |
| 465 | + } else { |
| 466 | + // Array element |
| 467 | + $idxchildren = $c[1]->getChildren(); |
| 468 | + $var = $this->getVar( $c[0], $rec + 1, $nullIfNotSet ); |
| 469 | + if( $nullIfNotSet && $var === null ) |
| 470 | + return null; |
| 471 | + |
| 472 | + if( count( $idxchildren ) == 2 ) { |
| 473 | + // x = a[]. a[] is still legitimage in a[] = x |
| 474 | + throw new ISUserVisibleException( 'emptyidx', $this->mModuleName, $idxchildren[0]->line ); |
| 475 | + } |
| 476 | + |
| 477 | + switch( $var->type ) { |
| 478 | + case ISData::DList: |
| 479 | + $idx = $this->evaluateNode( $idxchildren[1], $rec + 1 )->toInt(); |
| 480 | + if( $idx >= count( $var->data ) ) { |
| 481 | + if( $nullIfNotSet ) |
| 482 | + return null; |
| 483 | + else |
| 484 | + throw new ISUserVisibleException( 'outofbounds', $this->mModuleName, $idxchildren[0]->line ); |
| 485 | + } |
| 486 | + return $var->data[$idx]; |
| 487 | + case ISData::DAssoc: |
| 488 | + $idx = $this->evaluateNode( $idxchildren[1], $rec + 1 )->toString(); |
| 489 | + if( !isset( $var->data[$idx] ) ) { |
| 490 | + if( $nullIfNotSet ) |
| 491 | + return null; |
| 492 | + else |
| 493 | + throw new ISUserVisibleException( 'outofbounds', $this->mModuleName, $idxchildren[0]->line ); |
| 494 | + } |
| 495 | + return $var->data[$idx]; |
| 496 | + default: |
| 497 | + throw new ISUserVisibleException( 'notanarray', $this->mModuleName, $idxchildren[0]->line ); |
| 498 | + } |
| 499 | + } |
| 500 | + } |
| 501 | + |
| 502 | + /** |
| 503 | + * Gets the line of the first terminal in the node. |
| 504 | + */ |
| 505 | + protected function getLine( $node ) { |
| 506 | + while( $node instanceof ISParserTreeNode ) { |
| 507 | + $children = $node->getChildren(); |
| 508 | + $node = $children[0]; |
| 509 | + } |
| 510 | + return $node->line; |
| 511 | + } |
| 512 | + |
| 513 | + /** |
| 514 | + * Changes the value of variable or array element specified in $lval to $newval. |
| 515 | + */ |
| 516 | + protected function setVar( $lval, $newval, $rec ) { |
| 517 | + $var = &$this->setVarGetRef( $lval, $rec ); |
| 518 | + $var = $newval; |
| 519 | + unset( $var ); |
| 520 | + } |
| 521 | + |
| 522 | + /** |
| 523 | + * Recursive function that return the link to the place |
| 524 | + * where the new value of the variable must be set. |
| 525 | + */ |
| 526 | + protected function &setVarGetRef( $lval, $rec ) { |
| 527 | + if( !$this->mInterpreter->checkRecursionLimit( $rec ) ) { |
| 528 | + throw new ISUserVisibleException( 'recoverflow', $this->mModuleName, $this->getLine( $node ) ); |
| 529 | + } |
| 530 | + |
| 531 | + $c = $lval->getChildren(); |
| 532 | + if( count( $c ) == 1 ) { |
| 533 | + if( !isset( $this->mVars[ $c[0]->value ] ) ) |
| 534 | + $this->mVars[ $c[0]->value ] = new ISPlaceholder(); |
| 535 | + return $this->mVars[ $c[0]->value ]; |
| 536 | + } else { |
| 537 | + $ref = &$this->setVarGetRef( $c[0], $rec + 1 ); |
| 538 | + |
| 539 | + // <arrayIdx> ::= leftsquare <expr> rightsquare | leftsquare rightsquare |
| 540 | + $idxc = $c[1]->getChildren(); |
| 541 | + if( $ref instanceof ISPlaceholder ) { |
| 542 | + if( count( $idxc ) > 2 ) { |
| 543 | + $index = $this->evaluateNode( $idxc[1], $rec + 1 ); |
| 544 | + $ref = new ISData( ISData::DAssoc, array() ); |
| 545 | + } else { |
| 546 | + $ref = new ISData( ISData::DList, array() ); |
| 547 | + } |
| 548 | + } |
| 549 | + |
| 550 | + switch( $ref->type ) { |
| 551 | + case ISData::DList: |
| 552 | + if( count( $idxc ) > 2 ) { |
| 553 | + $index = $this->evaluateNode( $idxc[1], $rec + 1 ); |
| 554 | + $key = $index->toInt(); |
| 555 | + |
| 556 | + if( $key < 0 || $key > count( $ref->data ) ) |
| 557 | + throw new ISUserVisibleException( 'outofbounds', $this->mModuleName, $idxc[0]->line ); |
| 558 | + } else { |
| 559 | + $key = count( $ref->data ); |
| 560 | + } |
| 561 | + |
| 562 | + if( !isset( $ref->data[$key] ) ) |
| 563 | + $ref->data[$key] = new ISPlaceholder(); |
| 564 | + |
| 565 | + return $ref->data[$key]; |
| 566 | + case ISData::DAssoc: |
| 567 | + if( count( $idxc ) > 2 ) { |
| 568 | + if( !isset( $index ) ) |
| 569 | + $index = $this->evaluateNode( $idxc[1], $rec + 1 ); |
| 570 | + $key = $index->toString(); |
| 571 | + |
| 572 | + if( !isset( $ref->data[$key] ) ) |
| 573 | + $ref->data[$key] = new ISPlaceholder(); |
| 574 | + return $ref->data[$key]; |
| 575 | + } else { |
| 576 | + throw new ISUserVisibleException( 'notlist', $this->mModuleName, $idxc[0]->line ); |
| 577 | + } |
| 578 | + break; |
| 579 | + default: |
| 580 | + throw new ISUserVisibleException( 'notanarray', $this->mModuleName, $idxc[0]->line ); |
| 581 | + } |
| 582 | + } |
| 583 | + } |
| 584 | + |
| 585 | + protected function getValueForSetting( $old, $new, $set, $line ) { |
| 586 | + switch( $set ) { |
| 587 | + case '+=': |
| 588 | + return ISData::sum( $old, $new ); |
| 589 | + case '-=': |
| 590 | + return ISData::sub( $old, $new ); |
| 591 | + case '*=': |
| 592 | + return ISData::mulRel( $old, $new, '*', $line ); |
| 593 | + case '/=': |
| 594 | + return ISData::mulRel( $old, $new, '/', $line ); |
| 595 | + default: |
| 596 | + return $new; |
| 597 | + } |
| 598 | + } |
| 599 | + |
| 600 | + protected function checkParamsCount( $args, $pos, $count ) { |
| 601 | + if( count( $args ) < $count ) |
| 602 | + throw new ISUserVisibleException( 'notenoughargs', $this->mModuleName, $pos ); |
| 603 | + } |
| 604 | + |
| 605 | + protected function deleteVar( $lval, $rec ) { |
| 606 | + $c = $lval->getChildren(); |
| 607 | + $line = $c[0]->line; |
| 608 | + $varname = $c[0]->value; |
| 609 | + if( isset( $c[1] ) ) { |
| 610 | + throw new ISException( 'delete() is not usable for array elements' ); |
| 611 | + } |
| 612 | + unset( $this->mVars[$varname] ); |
| 613 | + } |
| 614 | + |
| 615 | + /** Functions */ |
| 616 | + protected function funcArg( $args, $pos ) { |
| 617 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 618 | + |
| 619 | + $argName = $args[0]->toString(); |
| 620 | + $default = isset( $args[1] ) ? $args[1] : new ISData(); |
| 621 | + if( $this->mFrame->getArgument( $argName ) === false ) |
| 622 | + return $default; |
| 623 | + else |
| 624 | + return new ISData( ISData::DString, $this->mFrame->getArgument( $argName ) ); |
| 625 | + } |
| 626 | + |
| 627 | + protected function funcArgs( $args, $pos ) { |
| 628 | + return ISData::newFromPHPVar( $this->mFrame->getNumberedArguments() ); |
| 629 | + } |
| 630 | + |
| 631 | + protected function funcIsTranscluded( $args, $pos ) { |
| 632 | + return new ISData( ISData::DBool, $this->mFrame->isTemplate() ); |
| 633 | + } |
| 634 | + |
| 635 | + protected function funcParse( $args, $pos ) { |
| 636 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 637 | + |
| 638 | + $text = $args[0]->toString(); |
| 639 | + $this->mInterpreter->mCallStack->addParse( $text ); |
| 640 | + |
| 641 | + $oldOT = $this->mParser->mOutputType; |
| 642 | + $this->mParser->setOutputType( Parser::OT_PREPROCESS ); |
| 643 | + $parsed = $this->mParser->replaceVariables( $text, $this->mFrame ); |
| 644 | + $parsed = $this->mParser->mStripState->unstripBoth( $parsed ); |
| 645 | + $this->mParser->setOutputType( $oldOT ); |
| 646 | + |
| 647 | + $this->mInterpreter->mCallStack->pop(); |
| 648 | + return new ISData( ISData::DString, $parsed ); |
| 649 | + } |
| 650 | + |
| 651 | + protected function funcLc( $args, $pos ) { |
| 652 | + global $wgContLang; |
| 653 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 654 | + return new ISData( ISData::DString, $wgContLang->lc( $args[0]->toString() ) ); |
| 655 | + } |
| 656 | + |
| 657 | + protected function funcUc( $args, $pos ) { |
| 658 | + global $wgContLang; |
| 659 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 660 | + return new ISData( ISData::DString, $wgContLang->uc( $args[0]->toString() ) ); |
| 661 | + } |
| 662 | + |
| 663 | + protected function funcUcFirst( $args, $pos ) { |
| 664 | + global $wgContLang; |
| 665 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 666 | + return new ISData( ISData::DString, $wgContLang->ucfirst( $args[0]->toString() ) ); |
| 667 | + } |
| 668 | + |
| 669 | + protected function funcUrlencode( $args, $pos ) { |
| 670 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 671 | + return new ISData( ISData::DString, urlencode( $args[0]->toString() ) ); |
| 672 | + } |
| 673 | + |
| 674 | + protected function funcAnchorEncode( $args, $pos ) { |
| 675 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 676 | + |
| 677 | + $s = urlencode( $args[0]->toString() ); |
| 678 | + $s = strtr( $s, array( '%' => '.', '+' => '_' ) ); |
| 679 | + $s = str_replace( '.3A', ':', $s ); |
| 680 | + |
| 681 | + return new ISData( ISData::DString, $s ); |
| 682 | + } |
| 683 | + |
| 684 | + protected function funcGrammar( $args, $pos ) { |
| 685 | + $this->checkParamsCount( $args, $pos, 2 ); |
| 686 | + list( $case, $word ) = $args; |
| 687 | + $res = $this->mParser->getFunctionLang()->convertGrammar( |
| 688 | + $word->toString(), $case->toString() ); |
| 689 | + return new ISData( ISData::DString, $res ); |
| 690 | + } |
| 691 | + |
| 692 | + protected function funcPlural( $args, $pos ) { |
| 693 | + $this->checkParamsCount( $args, $pos, 2 ); |
| 694 | + $num = $args[0]->toInt(); |
| 695 | + for( $i = 1; $i < count( $args ); $i++ ) |
| 696 | + $forms[] = $args[$i]->toString(); |
| 697 | + $res = $this->mParser->getFunctionLang()->convertPlural( $num, $forms ); |
| 698 | + return new ISData( ISData::DString, $res ); |
| 699 | + } |
| 700 | + |
| 701 | + protected function funcStrlen( $args, $pos ) { |
| 702 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 703 | + return new ISData( ISData::DInt, mb_strlen( $args[0]->toString() ) ); |
| 704 | + } |
| 705 | + |
| 706 | + protected function funcSubstr( $args, $pos ) { |
| 707 | + $this->checkParamsCount( $args, $pos, 3 ); |
| 708 | + $s = $args[0]->toString(); |
| 709 | + $start = $args[1]->toInt(); |
| 710 | + $end = $args[2]->toInt(); |
| 711 | + return new ISData( ISData::DString, mb_substr( $s, $start, $end ) ); |
| 712 | + } |
| 713 | + |
| 714 | + protected function funcStrreplace( $args, $pos ) { |
| 715 | + $this->checkParamsCount( $args, $pos, 3 ); |
| 716 | + $s = $args[0]->toString(); |
| 717 | + $old = $args[1]->toString(); |
| 718 | + $new = $args[2]->toString(); |
| 719 | + return new ISData( ISData::DString, str_replace( $old, $new, $s ) ); |
| 720 | + } |
| 721 | + |
| 722 | + protected function funcSplit( $args, $pos ) { |
| 723 | + $this->checkParamsCount( $args, $pos, 2 ); |
| 724 | + $list = explode( $args[0]->toString(), $args[1]->toString() ); |
| 725 | + return ISData::newFromPHPVar( $list ); |
| 726 | + } |
| 727 | + |
| 728 | + protected function funcJoin( $args, $pos ) { |
| 729 | + $this->checkParamsCount( $args, $pos, 2 ); |
| 730 | + $seperator = $args[0]->toString(); |
| 731 | + if( $args[1]->type == ISData::DList ) { |
| 732 | + $bits = $args[1]->data; |
| 733 | + } else { |
| 734 | + $bits = array_slice( $args, 1 ); |
| 735 | + } |
| 736 | + foreach( $bits as &$bit ) |
| 737 | + $bit = $bit->toString(); |
| 738 | + return new ISData( ISData::DString, implode( $seperator, $bits ) ); |
| 739 | + } |
| 740 | + |
| 741 | + protected function funcCount( $args, $pos ) { |
| 742 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 743 | + return new ISData( ISData::DInt, count( $args[0]->toList()->data ) ); |
| 744 | + } |
| 745 | + |
| 746 | + protected function castString( $args, $pos ) { |
| 747 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 748 | + return ISData::castTypes( $args[0], ISData::DString ); |
| 749 | + } |
| 750 | + |
| 751 | + protected function castInt( $args, $pos ) { |
| 752 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 753 | + return ISData::castTypes( $args[0], ISData::DInt ); |
| 754 | + } |
| 755 | + |
| 756 | + protected function castFloat( $args, $pos ) { |
| 757 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 758 | + return ISData::castTypes( $args[0], ISData::DFloat ); |
| 759 | + } |
| 760 | + |
| 761 | + protected function castBool( $args, $pos ) { |
| 762 | + $this->checkParamsCount( $args, $pos, 1 ); |
| 763 | + return ISData::castTypes( $args[0], ISData::DBool ); |
| 764 | + } |
| 765 | +} |
Index: trunk/extensions/WikiScripts/interpreter/syntax.txt |
— | — | @@ -0,0 +1,45 @@ |
| 2 | +<module> ::= <functions> |
| 3 | +<functions> ::= <function> <functions> | <function> |
| 4 | + |
| 5 | +<function> ::= function id leftbracket <args> rightbracket leftcurly <stmts> rightcurly |
| 6 | +<function> ::= function id leftbracket rightbracket leftcurly <stmts> rightcurly |
| 7 | +<args> ::= id comma <args> | id |
| 8 | + |
| 9 | +<stmts> ::= <stmts> <stmt> | <stmt> |
| 10 | +<stmt> ::= <expr> semicolon |
| 11 | +<stmt> ::= if leftbracket <expr> rightbracket <stmt> |
| 12 | +<stmt> ::= if leftbracket <expr> rightbracket <stmt> else <stmt> |
| 13 | +<stmt> ::= for leftbracket <forlvalue> in <expr> rightbracket <stmt> |
| 14 | +<stmt> ::= try <stmt> catch leftbracket <lvalue> rightbracket <stmt> |
| 15 | +<stmt> ::= leftcurly <stmts> rightcurly |
| 16 | + |
| 17 | +<expr> ::= <exprReturn> |
| 18 | +<exprReturn> ::= return | return <exprSet> | <exprSet> |
| 19 | +<exprReturn> ::= append <exprSet> | yield <exprSet> |
| 20 | +<exprSet> ::= <lvalue> setto <exprSet> | <exprTrinary> |
| 21 | +<exprTrinary> ::= <exprLogical> trinary <exprTrinary> colon <exprTrinary> | <exprLogical> |
| 22 | +<exprLogical> ::= <exprLogical> logicop <exprCompare> | <exprCompare> |
| 23 | +<exprCompare> ::= <exprCompare> compareop <exprEquals> | <exprEquals> |
| 24 | +<exprEquals> ::= <exprSum> equalsto <exprSum> | <exprSum> |
| 25 | +<exprSum> ::= <exprSum> sum <exprMul> | <exprMul> |
| 26 | +<exprMul> ::= <exprMul> mul <exprPow> | <exprPow> |
| 27 | +<exprPow> ::= <exprInvert> pow <exprPow> | <exprInvert> |
| 28 | +<exprInvert> ::= invert <exprKeyword> | <exprKeyword> |
| 29 | +<exprKeyword> ::= <exprUnary> in <exprUnary> | <exprUnary> contains <exprUnary> | <exprUnary> |
| 30 | +<exprUnary> ::= sum <exprFunction> | <exprFunction> |
| 31 | +<exprFunction> ::= <funcid> leftbracket <commaListPlain> rightbracket | <funcid> leftbracket rightbracket |
| 32 | +<exprFunction> ::= <varfunc> leftbracket <lvalue> rightbracket | <exprAtom> |
| 33 | +<exprAtom> ::= <lvalue> | <atom> | break | continue |
| 34 | +<exprAtom> ::= leftbracket <expr> rightbracket |
| 35 | +<exprAtom> ::= leftsquare <commaListPlain> rightsquare | leftcurly <commaListAssoc> rightcurly |
| 36 | + |
| 37 | +<varfunc> ::= isset | delete |
| 38 | +<funcid> ::= id | <exprAtom> doublecolon id | self doublecolon id |
| 39 | + |
| 40 | +<commaListPlain> ::= <commaListPlain> comma <expr> | <expr> |
| 41 | +<commaListAssoc> ::= <commaListAssoc> comma <keyValue> | <keyValue> |
| 42 | +<keyValue> ::= <expr> colon <expr> |
| 43 | +<atom> ::= string | int | float | true | false | null |
| 44 | +<lvalue> ::= id | <lvalue> <arrayIdx> |
| 45 | +<arrayIdx> ::= leftsquare <expr> rightsquare | leftsquare rightsquare |
| 46 | +<forlvalue> ::= <lvalue> | <lvalue> colon <lvalue> |
Property changes on: trunk/extensions/WikiScripts/interpreter/syntax.txt |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 47 | + native |
Index: trunk/extensions/WikiScripts/interpreter/CallStack.php |
— | — | @@ -0,0 +1,90 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +abstract class ISCallStackEntry { |
| 5 | + abstract function toString(); |
| 6 | +} |
| 7 | + |
| 8 | +abstract class ISCallStackFunctionEntry extends ISCallStackEntry { |
| 9 | + public $module; |
| 10 | + public $function; |
| 11 | +} |
| 12 | + |
| 13 | +class ISCallStackFunctionFromModuleEntry extends ISCallStackFunctionEntry { |
| 14 | + public $invokingModule; |
| 15 | + public $line; |
| 16 | + |
| 17 | + public function toString() { |
| 18 | + return wfMsg( 'inlinescripts-call-frommodule', $this->module, $this->function, |
| 19 | + $this->invokingModule, $this->line ); |
| 20 | + } |
| 21 | +} |
| 22 | + |
| 23 | +class ISCallStackFunctionFromWikitextEntry extends ISCallStackFunctionEntry { |
| 24 | + public function toString() { |
| 25 | + return wfMsg( 'inlinescripts-call-frommodule', $this->module, $this->function ); |
| 26 | + } |
| 27 | +} |
| 28 | + |
| 29 | +class ISCallStackParseEntry extends ISCallStackEntry { |
| 30 | + public $text; |
| 31 | + |
| 32 | + public function toString() { |
| 33 | + return wfMsg( 'inlinescripts-call-parse', $this->text ); |
| 34 | + } |
| 35 | +} |
| 36 | + |
| 37 | +class ISCallStack { |
| 38 | + var $mInterpreter, $mStack; |
| 39 | + |
| 40 | + public function __construct( $interpreter ) { |
| 41 | + $this->mInterpreter = $interpreter; |
| 42 | + $this->mStack = array(); |
| 43 | + } |
| 44 | + |
| 45 | + public function pop() { |
| 46 | + array_pop( $this->mStack ); |
| 47 | + } |
| 48 | + |
| 49 | + public function isFull() { |
| 50 | + global $wgInlineScriptsMaxCallStackDepth; |
| 51 | + |
| 52 | + return count( $this->mStack ) >= $wgInlineScriptsMaxCallStackDepth; |
| 53 | + } |
| 54 | + |
| 55 | + public function contains( $module, $name ) { |
| 56 | + foreach( $this->mStack as $entry ) { |
| 57 | + if( $entry instanceof ISCallStackFunctionEntry ) { |
| 58 | + if( $entry->module == $module && $entry->function == $name ) { |
| 59 | + return true; |
| 60 | + } |
| 61 | + } |
| 62 | + } |
| 63 | + return false; |
| 64 | + } |
| 65 | + |
| 66 | + public function addFunctionFromModule( $module, $name, $invokingModule, $line ) { |
| 67 | + $entry = new ISCallStackFunctionFromModuleEntry(); |
| 68 | + $entry->module = $module; |
| 69 | + $entry->function = $name; |
| 70 | + $entry->invokingModule = $invokingModule; |
| 71 | + $entry->line = $line; |
| 72 | + $this->mStack[] = $entry; |
| 73 | + } |
| 74 | + |
| 75 | + public function addFunctionFromWikitext( $module, $name ) { |
| 76 | + $entry = new ISCallStackFunctionFromWikitextEntry(); |
| 77 | + $entry->module = $module; |
| 78 | + $entry->function = $name; |
| 79 | + $this->mStack[] = $entry; |
| 80 | + } |
| 81 | + |
| 82 | + public function addParse( $wikitext ) { |
| 83 | + if( strlen( $wikitext ) > 64 ) { |
| 84 | + $wikitext = substr( $wikitext, 0, 64 ) . "..."; |
| 85 | + } |
| 86 | + |
| 87 | + $entry = new ISCallStackParseEntry(); |
| 88 | + $entry->text = $wikitext; |
| 89 | + $this->mStack[] = $entry; |
| 90 | + } |
| 91 | +} |
Index: trunk/extensions/WikiScripts/interpreter/Interpreter.php |
— | — | @@ -0,0 +1,484 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki: interpreter. |
| 5 | + * Copyright (C) 2009-2011 Victor Vasiliev <vasilvv@gmail.com> |
| 6 | + * http://www.mediawiki.org/ |
| 7 | + * |
| 8 | + * This program is free software; you can redistribute it and/or modify |
| 9 | + * it under the terms of the GNU General Public License as published by |
| 10 | + * the Free Software Foundation; either version 2 of the License, or |
| 11 | + * (at your option) any later version. |
| 12 | + * |
| 13 | + * This program is distributed in the hope that it will be useful, |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | + * GNU General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU General Public License along |
| 19 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 20 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 21 | + * http://www.gnu.org/copyleft/gpl.html |
| 22 | + */ |
| 23 | + |
| 24 | +if( !defined( 'MEDIAWIKI' ) ) |
| 25 | + die(); |
| 26 | + |
| 27 | +require_once( 'Shared.php' ); |
| 28 | +require_once( 'Data.php' ); |
| 29 | +require_once( 'EvaluationContext.php' ); |
| 30 | +require_once( 'CallStack.php' ); |
| 31 | + |
| 32 | +/** |
| 33 | + * The global interpreter object. Each parser has one. |
| 34 | + */ |
| 35 | +class ISInterpreter { |
| 36 | + const ParserVersion = 1; |
| 37 | + |
| 38 | + var $mParser, $mUseCache, $mUsedModules, $mCallStack; |
| 39 | + var $mMaxRecursion, $mEvaluations; |
| 40 | + var $mParserCache; // Unserializing can be expensive as well |
| 41 | + |
| 42 | + static $mCodeParser; |
| 43 | + |
| 44 | + public function __construct( $parser ) { |
| 45 | + global $wgInlineScriptsUseCache; |
| 46 | + |
| 47 | + $this->mParser = $parser; |
| 48 | + $this->mUseCache = $wgInlineScriptsUseCache; |
| 49 | + |
| 50 | + $this->mCallStack = new ISCallStack( $this ); |
| 51 | + $this->mUsedModules = array(); |
| 52 | + $this->mMaxRecursion = |
| 53 | + $this->mEvaluations = |
| 54 | + 0; |
| 55 | + } |
| 56 | + |
| 57 | + public static function invokeCodeParser( $code, $module, $method = 'parse' ) { |
| 58 | + global $wgInlineScriptsParserClass, $wgInlineScriptsLimits; |
| 59 | + |
| 60 | + if( !self::$mCodeParser ) { |
| 61 | + self::$mCodeParser = new $wgInlineScriptsParserClass(); |
| 62 | + } |
| 63 | + |
| 64 | + if( self::$mCodeParser->needsScanner() ) { |
| 65 | + $input = new ISScanner( $module, $code ); |
| 66 | + } else { |
| 67 | + $input = $code; |
| 68 | + } |
| 69 | + |
| 70 | + return self::$mCodeParser->$method( $input, $module, $wgInlineScriptsLimits['tokens'] ); |
| 71 | + } |
| 72 | + |
| 73 | + /** |
| 74 | + * Invalidate the module by title. |
| 75 | + */ |
| 76 | + public static function invalidateModule( $title ) { |
| 77 | + global $parserMemc; |
| 78 | + |
| 79 | + $key = ISModule::getCacheKey( $title ); |
| 80 | + $parserMemc->delete( $key ); |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * Checks the syntax of the script and returns an array of syntax errors. |
| 85 | + */ |
| 86 | + public static function getSyntaxErrors( $module, $text ) { |
| 87 | + return self::invokeCodeParser( $text, $module, 'getSyntaxErrors' ); |
| 88 | + } |
| 89 | + |
| 90 | + /** |
| 91 | + * Disable cache for benchmarking or debugging purposes. |
| 92 | + */ |
| 93 | + public function disableCache() { |
| 94 | + $this->mUseCache = false; |
| 95 | + } |
| 96 | + |
| 97 | + /** |
| 98 | + * Get the wikitext parser linked to the interpreter. |
| 99 | + */ |
| 100 | + public function getParser() { |
| 101 | + return $this->mParser; |
| 102 | + } |
| 103 | + |
| 104 | + /** Limit handling code */ |
| 105 | + |
| 106 | + /** |
| 107 | + * Check whether the argument is more than recursion limit. |
| 108 | + * |
| 109 | + * @return Boolean |
| 110 | + */ |
| 111 | + public function checkRecursionLimit( $rec ) { |
| 112 | + global $wgInlineScriptsLimits; |
| 113 | + if( $rec > $this->mMaxRecursion ) |
| 114 | + $this->mMaxRecursion = $rec; |
| 115 | + return $rec <= $wgInlineScriptsLimits['depth']; |
| 116 | + } |
| 117 | + |
| 118 | + /** |
| 119 | + * Increases the number of evaluations. |
| 120 | + * |
| 121 | + * @param $module ISModule Module where the evaluation happens |
| 122 | + * @param $line int Line number of the evaluation |
| 123 | + * @return Boolean |
| 124 | + */ |
| 125 | + public function increaseEvaluationsCount( $module, $line ) { |
| 126 | + global $wgInlineScriptsLimits; |
| 127 | + $this->mEvaluations++; |
| 128 | + if( $this->mEvaluations > $wgInlineScriptsLimits['evaluations'] ) |
| 129 | + throw new ISUserVisibleException( 'toomanyevals', $module, $line ); |
| 130 | + } |
| 131 | + |
| 132 | + public function getMaxTokensLeft() { |
| 133 | + global $wgInlineScriptsLimits; |
| 134 | + return $wgInlineScriptsLimits['tokens']; |
| 135 | + } |
| 136 | + |
| 137 | + /** |
| 138 | + * Adds the title of the module used by the parser for tracking purposes. |
| 139 | + * |
| 140 | + * @param $title Title Title of the module. |
| 141 | + */ |
| 142 | + public function addModuleTitle( $title ) { |
| 143 | + if( !in_array( $title->getText(), $this->mUsedModules ) ) |
| 144 | + $this->mUsedModules[] = $title->getDBkey(); |
| 145 | + } |
| 146 | + |
| 147 | + /** Module loading code */ |
| 148 | + |
| 149 | + /** |
| 150 | + * Loads module from cache or from page and parses it. Cached as much as possible. |
| 151 | + * |
| 152 | + * @param $title Title Title of the module to load. |
| 153 | + */ |
| 154 | + public function getModule( $title ) { |
| 155 | + global $parserMemc; |
| 156 | + |
| 157 | + wfProfileIn( __METHOD__ ); |
| 158 | + |
| 159 | + // Add nominal title. Real title may differ due to redirects |
| 160 | + $this->addModuleTitle( $title ); |
| 161 | + |
| 162 | + // Try local cache |
| 163 | + $key = ISModule::getCacheKey( $title ); |
| 164 | + if( $this->mUseCache && isset( $this->mParserCache[$key] ) ) { |
| 165 | + $module = $this->mParserCache[$key]; |
| 166 | + $this->addModuleTitle( $module->getTitle() ); |
| 167 | + wfProfileOut( __METHOD__ ); |
| 168 | + return $module; |
| 169 | + } |
| 170 | + |
| 171 | + // Try the object cache |
| 172 | + wfProfileIn( __METHOD__ . '-unserialize' ); |
| 173 | + $cached = $parserMemc->get( $key ); |
| 174 | + wfProfileOut( __METHOD__ . '-unserialize' ); |
| 175 | + if( $this->mUseCache && @$cached instanceof ISModule && !$cached->isOutOfDate() ) { |
| 176 | + $this->mParserCache[$key] = $cached; |
| 177 | + $this->addModuleTitle( $cached->getTitle() ); |
| 178 | + wfProfileOut( __METHOD__ ); |
| 179 | + return $cached; |
| 180 | + } |
| 181 | + |
| 182 | + // Load from database |
| 183 | + $rev = self::getModuleRev( $title ); |
| 184 | + if( !$rev || $rev->getTitle()->getNamespace() != NS_MODULE ) { |
| 185 | + return false; |
| 186 | + } |
| 187 | + |
| 188 | + // Parse |
| 189 | + $moduleName = $rev->getTitle()->getText(); |
| 190 | + $out = self::invokeCodeParser( $rev->getText(), $moduleName ); |
| 191 | + $module = ISModule::newFromParserOutput( $this, $rev->getTitle(), $rev->getId(), $out ); |
| 192 | + |
| 193 | + // Save to cache |
| 194 | + $this->mParserCache[$key] = $module; |
| 195 | + $parserMemc->set( $key, $module ); |
| 196 | + $this->addModuleTitle( $module->getTitle() ); |
| 197 | + |
| 198 | + wfProfileOut( __METHOD__ ); |
| 199 | + return $module; |
| 200 | + } |
| 201 | + |
| 202 | + /** |
| 203 | + * Fetches the revision for given module title. |
| 204 | + */ |
| 205 | + private function getModuleRev( $title ) { |
| 206 | + $rev = Revision::newFromTitle( $title ); |
| 207 | + if( $rev && $real = Title::newFromRedirect( $rev->getText() ) ) { |
| 208 | + $rev = Revision::newFromTitle( $real ); |
| 209 | + } |
| 210 | + return $rev; |
| 211 | + } |
| 212 | + |
| 213 | + /** Function evaluation code */ |
| 214 | + |
| 215 | + /** |
| 216 | + * Invokes the user function from script code. |
| 217 | + * |
| 218 | + * @param $module ISModule/string Module or its name |
| 219 | + * @param $name string Name of the function |
| 220 | + * @param $args array(ISData) Arguments of the function |
| 221 | + * @param $parentContext ISEvaluationContext The context from which the function was invoked |
| 222 | + * @param $line The line from which the function was invoked. |
| 223 | + * @return ISData |
| 224 | + */ |
| 225 | + public function invokeUserFunctionFromModule( $module, $name, $args, $parentContext, $line ) { |
| 226 | + global $wgInlineScriptsAllowRecursion, $wgInlineScriptsMaxCallStackDepth; |
| 227 | + |
| 228 | + // Load module |
| 229 | + if( $module instanceof ISModule ) { |
| 230 | + $moduleName = $module->getName(); |
| 231 | + } else { |
| 232 | + $moduleName = $module; |
| 233 | + |
| 234 | + $moduleTitle = Title::makeTitleSafe( NS_MODULE, $moduleName ); |
| 235 | + if( !$moduleTitle instanceof Title || $moduleTitle->getNamespace() != NS_MODULE ) { |
| 236 | + throw new ISUserVisibleException( 'nonexistent-module', $parentContext->mModuleName, $line, array( $moduleName ) ); |
| 237 | + } |
| 238 | + |
| 239 | + $module = $this->getModule( $moduleTitle ); |
| 240 | + if( !$module ) { |
| 241 | + throw new ISUserVisibleException( 'nonexistent-module', $parentContext->mModuleName, $line, array( $moduleName ) ); |
| 242 | + } |
| 243 | + } |
| 244 | + |
| 245 | + // Load the function and handle possible errors |
| 246 | + $function = $module->getFunction( $name ); |
| 247 | + if( !$function ) { |
| 248 | + throw new ISUserVisibleException( 'unknownfunction-user', $parentContext->mModuleName, $line, array( $moduleName, $name ) ); |
| 249 | + } |
| 250 | + if( count( $args ) < $function->getMinArgCount() ) { |
| 251 | + throw new ISUserVisibleException( 'notenoughargs-user', $parentContext->mModuleName, $line, array( $moduleName, $name ) ); |
| 252 | + } |
| 253 | + if( !$wgInlineScriptsAllowRecursion && $this->mCallStack->contains( $moduleName, $name ) ) { |
| 254 | + throw new ISUserVisibleException( 'recursion', $parentContext->mModuleName, $line, array( $moduleName, $name ) ); |
| 255 | + } |
| 256 | + if( $this->mCallStack->isFull() ) { |
| 257 | + throw new ISUserVisibleException( 'toodeeprecursion', $parentContext->mModuleName, $line, array( $wgInlineScriptsMaxCallStackDepth ) ); |
| 258 | + } |
| 259 | + |
| 260 | + // Prepare the context and the arguments |
| 261 | + $context = new ISEvaluationContext( $this, $module, $name, $parentContext->getFrame() ); |
| 262 | + foreach( $args as $n => $arg ) { |
| 263 | + if( isset( $function->args[$n] ) ) { |
| 264 | + $argname = $function->args[$n]; |
| 265 | + $context->setArgument( $argname, $arg ); |
| 266 | + } |
| 267 | + } |
| 268 | + |
| 269 | + // Push function into call stack |
| 270 | + $this->mCallStack->addFunctionFromModule( $moduleName, $name, $parentContext->mModuleName, $line ); |
| 271 | + |
| 272 | + // Finally execute it! |
| 273 | + $result = $this->doInvokeFunction( $function, $context ); |
| 274 | + |
| 275 | + // Pop out of the call stack and return |
| 276 | + $this->mCallStack->pop(); |
| 277 | + return $result; |
| 278 | + } |
| 279 | + |
| 280 | + /** |
| 281 | + * Invokes the user function from wikitext. |
| 282 | + * |
| 283 | + * @param $module string The name of the module |
| 284 | + * @param $name string Name of the function |
| 285 | + * @param $args array(string) Arguments of the function |
| 286 | + * @param $frame PPFrame The parser frame from which the function was invoked |
| 287 | + * @return string |
| 288 | + */ |
| 289 | + public function invokeUserFunctionFromWikitext( $moduleName, $name, $args, $frame ) { |
| 290 | + global $wgInlineScriptsAllowRecursion; |
| 291 | + |
| 292 | + // Load module |
| 293 | + $moduleTitle = Title::makeTitleSafe( NS_MODULE, $moduleName ); |
| 294 | + if( !$moduleTitle instanceof Title || $moduleTitle->getNamespace() != NS_MODULE ) { |
| 295 | + throw new ISTransclusionException( 'nonexistent-module', array( $moduleName ) ); |
| 296 | + } |
| 297 | + |
| 298 | + $module = $this->getModule( $moduleTitle ); |
| 299 | + if( !$module ) { |
| 300 | + throw new ISTransclusionException( 'nonexistent-module', array( $moduleName ) ); |
| 301 | + } |
| 302 | + |
| 303 | + // Load the function and handle possible errors |
| 304 | + $function = $module->getFunction( $name ); |
| 305 | + if( !$function ) { |
| 306 | + throw new ISTransclusionException( 'unknownfunction-user', array( $moduleName, $name ) ); |
| 307 | + } |
| 308 | + if( count( $args ) < $function->getMinArgCount() ) { |
| 309 | + throw new ISTransclusionException( 'notenoughargs-user', array( $moduleName, $name ) ); |
| 310 | + } |
| 311 | + if( !$wgInlineScriptsAllowRecursion && $this->mCallStack->contains( $moduleName, $name ) ) { |
| 312 | + throw new ISTransclusionException( 'recursion', array( $moduleName, $name ) ); |
| 313 | + } |
| 314 | + if( $this->mCallStack->isFull() ) { |
| 315 | + // Depsite seeming an unlikely place, this may actually happen if the user will try to bypass the |
| 316 | + // stack depth limit by using parse( '{{i:module|func}}' ) |
| 317 | + throw new ISTransclusionException( 'toodeeprecursion', array( $wgInlineScriptsMaxCallStackDepth ) ); |
| 318 | + } |
| 319 | + |
| 320 | + // Prepare the context and the arguments |
| 321 | + $context = new ISEvaluationContext( $this, $module, $name, $frame ); |
| 322 | + foreach( $args as $n => $arg ) { |
| 323 | + if( isset( $function->args[$n] ) ) { |
| 324 | + $argname = $function->args[$n]; |
| 325 | + $context->setArgument( $argname, new ISData( ISData::DString, strval( $arg ) ) ); |
| 326 | + } |
| 327 | + } |
| 328 | + |
| 329 | + // Push function into call stack |
| 330 | + $this->mCallStack->addFunctionFromWikitext( $moduleName, $name ); |
| 331 | + |
| 332 | + // Finally execute it! |
| 333 | + $result = $this->doInvokeFunction( $function, $context ); |
| 334 | + |
| 335 | + // Pop out of the call stack and return |
| 336 | + $this->mCallStack->pop(); |
| 337 | + return $result->toString(); |
| 338 | + } |
| 339 | + |
| 340 | + protected function doInvokeFunction( $function, $context ) { |
| 341 | + // Indicates whether the data from append/yield should be used |
| 342 | + $useOutput = true; |
| 343 | + $result = new ISData(); |
| 344 | + |
| 345 | + try { |
| 346 | + $context->evaluateNode( $function->body, 0 ); |
| 347 | + } catch( ISException $e ) { |
| 348 | + if( $e instanceof ISReturnException ) { |
| 349 | + $result = $e->getResult(); |
| 350 | + $useOutput = $e->isEmpty(); |
| 351 | + } else { |
| 352 | + $this->mCallStack->pop(); |
| 353 | + throw $e; |
| 354 | + } |
| 355 | + } |
| 356 | + |
| 357 | + if( $useOutput ) { |
| 358 | + $result = $context->getOutput(); |
| 359 | + } |
| 360 | + |
| 361 | + return $result; |
| 362 | + } |
| 363 | +} |
| 364 | + |
| 365 | +/** |
| 366 | + * Represents an individual module. |
| 367 | + */ |
| 368 | +class ISModule { |
| 369 | + var $mTitle, $mFunctions, $mParserVersion; |
| 370 | + |
| 371 | + // Revision ID |
| 372 | + // Not used now, will be used if we ever introduce the function output cache |
| 373 | + var $mRevID; |
| 374 | + |
| 375 | + protected function __construct() {} |
| 376 | + |
| 377 | + /** |
| 378 | + * Initializes module from the code parser output. |
| 379 | + */ |
| 380 | + public static function newFromParserOutput( $interpreter, $title, $revid, $output ) { |
| 381 | + $m = new ISModule(); |
| 382 | + $m->mTitle = $title; |
| 383 | + $m->mRevID = $revid; |
| 384 | + $m->mParserVersion = $output->getVersion(); |
| 385 | + $m->mFunctions = array(); |
| 386 | + |
| 387 | + $cur = $output->getParserTree(); |
| 388 | + for( ; ; ) { |
| 389 | + $curch = $cur->getChildren(); |
| 390 | + $funcnode = $curch[0]; |
| 391 | + |
| 392 | + // <function> ::= function id leftbracket <arglist> rightbracket leftcurly <stmts> rightcurly (total 8) |
| 393 | + // <function> ::= function id leftbracket rightbracket leftcurly <stmts> rightcurly (total 7) |
| 394 | + $c = $funcnode->getChildren(); |
| 395 | + $func = new ISFunction(); |
| 396 | + $func->name = $c[1]->value; |
| 397 | + |
| 398 | + if( $funcnode->getChildrenCount() == 8 ) { |
| 399 | + $func->body = $c[6]; |
| 400 | + $func->args = self::parseArgs( $c[3] ); |
| 401 | + } else { |
| 402 | + $func->body = $c[5]; |
| 403 | + $func->args = array(); |
| 404 | + } |
| 405 | + $m->mFunctions[$func->name] = $func; |
| 406 | + |
| 407 | + if( $cur->hasSingleChild() ) |
| 408 | + break; |
| 409 | + else |
| 410 | + $cur = $curch[1]; |
| 411 | + } |
| 412 | + |
| 413 | + return $m; |
| 414 | + } |
| 415 | + |
| 416 | + /** |
| 417 | + * Converts the argument list node into an array. |
| 418 | + */ |
| 419 | + private static function parseArgs( $argsnode ) { |
| 420 | + $args = array(); |
| 421 | + $cur = $argsnode; |
| 422 | + for( ; ; ) { |
| 423 | + $c = $cur->getChildren(); |
| 424 | + $args[] = $c[0]->value; |
| 425 | + |
| 426 | + if( $cur->hasSingleChild() ) |
| 427 | + break; |
| 428 | + else |
| 429 | + $cur = $c[2]; |
| 430 | + } |
| 431 | + return $args; |
| 432 | + } |
| 433 | + |
| 434 | + /** |
| 435 | + * Gets the cache key for a module. |
| 436 | + */ |
| 437 | + public static function getCacheKey( $title ) { |
| 438 | + return 'scripts:module:' . sha1( $title->getText() ); |
| 439 | + } |
| 440 | + |
| 441 | + /** |
| 442 | + * Returns the name of a module. |
| 443 | + */ |
| 444 | + public function getName() { |
| 445 | + return $this->mTitle->getText(); |
| 446 | + } |
| 447 | + |
| 448 | + /** |
| 449 | + * Returns the title of a module. |
| 450 | + */ |
| 451 | + public function getTitle() { |
| 452 | + return $this->mTitle; |
| 453 | + } |
| 454 | + |
| 455 | + /** |
| 456 | + * Returns a specific function or null if it does not exist. |
| 457 | + */ |
| 458 | + public function getFunction( $name ) { |
| 459 | + if( isset( $this->mFunctions[$name] ) ) |
| 460 | + return $this->mFunctions[$name]; |
| 461 | + else |
| 462 | + return null; |
| 463 | + } |
| 464 | + |
| 465 | + /** |
| 466 | + * Returns whether the module should be reparsed or not. |
| 467 | + */ |
| 468 | + public function isOutOfDate() { |
| 469 | + global $wgInlineScriptsParserClass; |
| 470 | + return $wgInlineScriptsParserClass::getVersion() != $this->mParserVersion; |
| 471 | + } |
| 472 | +} |
| 473 | + |
| 474 | +/** |
| 475 | + * Represents a function. |
| 476 | + */ |
| 477 | +class ISFunction { |
| 478 | + public $name; |
| 479 | + public $args; |
| 480 | + public $body; |
| 481 | + |
| 482 | + public function getMinArgCount() { |
| 483 | + return count( $this->args ); |
| 484 | + } |
| 485 | +} |
Property changes on: trunk/extensions/WikiScripts/interpreter/Interpreter.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 486 | + native |
Index: trunk/extensions/WikiScripts/interpreter/benchmark/benchmark.php |
— | — | @@ -0,0 +1,54 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Initial very basic framework for doing some benchmark tests, comparing |
| 6 | + * scripts in the inline script to equivalent raw PHP execution (eval'd) |
| 7 | + * |
| 8 | + * <brion@pobox.com> 2010-04-14 |
| 9 | + */ |
| 10 | + |
| 11 | +if (php_sapi_name() != 'cli') { |
| 12 | + die("cli only"); |
| 13 | +} |
| 14 | + |
| 15 | +require_once "../../../../maintenance/commandLine.inc"; |
| 16 | + |
| 17 | +require_once "../../InlineScripts.php"; // if ext not already enabled |
| 18 | + |
| 19 | +$testcases = array(array( |
| 20 | +'script' => <<<END_SCRIPT |
| 21 | +"Hello, world!"; |
| 22 | +END_SCRIPT |
| 23 | +, |
| 24 | +'php' => <<<END_PHP |
| 25 | +return "Hello, world!"; |
| 26 | +END_PHP |
| 27 | +)); |
| 28 | + |
| 29 | +function runtest( $lang, $source ) { |
| 30 | + if ($lang == 'php') { |
| 31 | + return eval($source); |
| 32 | + } else { |
| 33 | + $scriptParser = new ISInterpreter(); |
| 34 | + $parser = new Parser(); |
| 35 | + $frame = null; //new Frame(); |
| 36 | + return $scriptParser->evaluate( $source, $parser, $frame ); |
| 37 | + } |
| 38 | +} |
| 39 | + |
| 40 | +$runs = 10; |
| 41 | +foreach( $testcases as $testcase ) { |
| 42 | + foreach( $testcase as $lang => $code ) { |
| 43 | + $start = microtime( true ); |
| 44 | + $result = runtest( $lang, $code ); |
| 45 | + $delta1 = microtime( true ) - $start; |
| 46 | + for ($i = 1; $i < $runs; $i++) { |
| 47 | + runtest( $lang, $code ); |
| 48 | + } |
| 49 | + $delta = (microtime( true ) - $start) / $runs; |
| 50 | + printf( "%s: %0.3f ms first, %0.3f ms avg of %d runs\n", |
| 51 | + $lang, $delta1 * 1000.0, $delta * 1000.0, $runs ); |
| 52 | + var_dump($result); |
| 53 | + print "\n"; |
| 54 | + } |
| 55 | +} |
Property changes on: trunk/extensions/WikiScripts/interpreter/benchmark/benchmark.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 56 | + native |
Index: trunk/extensions/WikiScripts/interpreter/LRTable.php |
— | — | @@ -0,0 +1,2288 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Autogenerated SLR-table for inline scripts language. |
| 6 | + * |
| 7 | + * You should not try to modify it manually (it's very easy to break). |
| 8 | + * Use syntax.txt and buildLRTables.php insteaed. |
| 9 | + * |
| 10 | + * Actions have following syntax |
| 11 | + * array( 0, N ) means "shift and go to state N" |
| 12 | + * array( 1, N ) means "reduce to production N" |
| 13 | + * array( 2 ) means "accept" |
| 14 | + * null means "error" |
| 15 | + * |
| 16 | + * Terminals are referred by names, nonterminals - by ids. |
| 17 | + * |
| 18 | + * Variables has following format: |
| 19 | + * * $nonterminals is a nonterminal ID -> name map. |
| 20 | + * * $productions is a ID -> array( nonterminal, body ) map. |
| 21 | + * * Production body is an array of production symbols |
| 22 | + * |
| 23 | + * Generated on 2011-08-13 21:53:42. |
| 24 | + */ |
| 25 | + |
| 26 | +class ISLRTable { |
| 27 | + |
| 28 | +const Timestamp = '2011-08-13 21:53:42'; |
| 29 | + |
| 30 | +static $nonterminals = array( |
| 31 | + 0 => 'module', |
| 32 | + 1 => 'functions', |
| 33 | + 2 => 'function', |
| 34 | + 3 => 'args', |
| 35 | + 4 => 'stmts', |
| 36 | + 5 => 'stmt', |
| 37 | + 6 => 'expr', |
| 38 | + 7 => 'forlvalue', |
| 39 | + 8 => 'lvalue', |
| 40 | + 9 => 'exprreturn', |
| 41 | + 10 => 'exprset', |
| 42 | + 11 => 'exprtrinary', |
| 43 | + 12 => 'exprlogical', |
| 44 | + 13 => 'exprcompare', |
| 45 | + 14 => 'exprequals', |
| 46 | + 15 => 'exprsum', |
| 47 | + 16 => 'exprmul', |
| 48 | + 17 => 'exprpow', |
| 49 | + 18 => 'exprinvert', |
| 50 | + 19 => 'exprkeyword', |
| 51 | + 20 => 'exprunary', |
| 52 | + 21 => 'exprfunction', |
| 53 | + 22 => 'funcid', |
| 54 | + 23 => 'commalistplain', |
| 55 | + 24 => 'varfunc', |
| 56 | + 25 => 'expratom', |
| 57 | + 26 => 'atom', |
| 58 | + 27 => 'commalistassoc', |
| 59 | + 28 => 'keyvalue', |
| 60 | + 29 => 'arrayidx', |
| 61 | +); |
| 62 | + |
| 63 | +static $productions = array( |
| 64 | + 0 => array( 0, array( 1 ) ), |
| 65 | + 1 => array( 1, array( 2, 1 ) ), |
| 66 | + 2 => array( 1, array( 2 ) ), |
| 67 | + 3 => array( 2, array( 'function', 'id', 'leftbracket', 3, 'rightbracket', 'leftcurly', 4, 'rightcurly' ) ), |
| 68 | + 4 => array( 2, array( 'function', 'id', 'leftbracket', 'rightbracket', 'leftcurly', 4, 'rightcurly' ) ), |
| 69 | + 5 => array( 3, array( 'id', 'comma', 3 ) ), |
| 70 | + 6 => array( 3, array( 'id' ) ), |
| 71 | + 7 => array( 4, array( 4, 5 ) ), |
| 72 | + 8 => array( 4, array( 5 ) ), |
| 73 | + 9 => array( 5, array( 6, 'semicolon' ) ), |
| 74 | + 10 => array( 5, array( 'if', 'leftbracket', 6, 'rightbracket', 5 ) ), |
| 75 | + 11 => array( 5, array( 'if', 'leftbracket', 6, 'rightbracket', 5, 'else', 5 ) ), |
| 76 | + 12 => array( 5, array( 'for', 'leftbracket', 7, 'in', 6, 'rightbracket', 5 ) ), |
| 77 | + 13 => array( 5, array( 'try', 5, 'catch', 'leftbracket', 8, 'rightbracket', 5 ) ), |
| 78 | + 14 => array( 5, array( 'leftcurly', 4, 'rightcurly' ) ), |
| 79 | + 15 => array( 6, array( 9 ) ), |
| 80 | + 16 => array( 9, array( 'return' ) ), |
| 81 | + 17 => array( 9, array( 'return', 10 ) ), |
| 82 | + 18 => array( 9, array( 10 ) ), |
| 83 | + 19 => array( 9, array( 'append', 10 ) ), |
| 84 | + 20 => array( 9, array( 'yield', 10 ) ), |
| 85 | + 21 => array( 10, array( 8, 'setto', 10 ) ), |
| 86 | + 22 => array( 10, array( 11 ) ), |
| 87 | + 23 => array( 11, array( 12, 'trinary', 11, 'colon', 11 ) ), |
| 88 | + 24 => array( 11, array( 12 ) ), |
| 89 | + 25 => array( 12, array( 12, 'logicop', 13 ) ), |
| 90 | + 26 => array( 12, array( 13 ) ), |
| 91 | + 27 => array( 13, array( 13, 'compareop', 14 ) ), |
| 92 | + 28 => array( 13, array( 14 ) ), |
| 93 | + 29 => array( 14, array( 15, 'equalsto', 15 ) ), |
| 94 | + 30 => array( 14, array( 15 ) ), |
| 95 | + 31 => array( 15, array( 15, 'sum', 16 ) ), |
| 96 | + 32 => array( 15, array( 16 ) ), |
| 97 | + 33 => array( 16, array( 16, 'mul', 17 ) ), |
| 98 | + 34 => array( 16, array( 17 ) ), |
| 99 | + 35 => array( 17, array( 18, 'pow', 17 ) ), |
| 100 | + 36 => array( 17, array( 18 ) ), |
| 101 | + 37 => array( 18, array( 'invert', 19 ) ), |
| 102 | + 38 => array( 18, array( 19 ) ), |
| 103 | + 39 => array( 19, array( 20, 'in', 20 ) ), |
| 104 | + 40 => array( 19, array( 20, 'contains', 20 ) ), |
| 105 | + 41 => array( 19, array( 20 ) ), |
| 106 | + 42 => array( 20, array( 'sum', 21 ) ), |
| 107 | + 43 => array( 20, array( 21 ) ), |
| 108 | + 44 => array( 21, array( 22, 'leftbracket', 23, 'rightbracket' ) ), |
| 109 | + 45 => array( 21, array( 22, 'leftbracket', 'rightbracket' ) ), |
| 110 | + 46 => array( 21, array( 24, 'leftbracket', 8, 'rightbracket' ) ), |
| 111 | + 47 => array( 21, array( 25 ) ), |
| 112 | + 48 => array( 25, array( 8 ) ), |
| 113 | + 49 => array( 25, array( 26 ) ), |
| 114 | + 50 => array( 25, array( 'break' ) ), |
| 115 | + 51 => array( 25, array( 'continue' ) ), |
| 116 | + 52 => array( 25, array( 'leftbracket', 6, 'rightbracket' ) ), |
| 117 | + 53 => array( 25, array( 'leftsquare', 23, 'rightsquare' ) ), |
| 118 | + 54 => array( 25, array( 'leftcurly', 27, 'rightcurly' ) ), |
| 119 | + 55 => array( 24, array( 'isset' ) ), |
| 120 | + 56 => array( 24, array( 'delete' ) ), |
| 121 | + 57 => array( 22, array( 'id' ) ), |
| 122 | + 58 => array( 22, array( 25, 'doublecolon', 'id' ) ), |
| 123 | + 59 => array( 22, array( 'self', 'doublecolon', 'id' ) ), |
| 124 | + 60 => array( 23, array( 23, 'comma', 6 ) ), |
| 125 | + 61 => array( 23, array( 6 ) ), |
| 126 | + 62 => array( 27, array( 27, 'comma', 28 ) ), |
| 127 | + 63 => array( 27, array( 28 ) ), |
| 128 | + 64 => array( 28, array( 6, 'colon', 6 ) ), |
| 129 | + 65 => array( 26, array( 'string' ) ), |
| 130 | + 66 => array( 26, array( 'int' ) ), |
| 131 | + 67 => array( 26, array( 'float' ) ), |
| 132 | + 68 => array( 26, array( 'true' ) ), |
| 133 | + 69 => array( 26, array( 'false' ) ), |
| 134 | + 70 => array( 26, array( 'null' ) ), |
| 135 | + 71 => array( 8, array( 'id' ) ), |
| 136 | + 72 => array( 8, array( 8, 29 ) ), |
| 137 | + 73 => array( 29, array( 'leftsquare', 6, 'rightsquare' ) ), |
| 138 | + 74 => array( 29, array( 'leftsquare', 'rightsquare' ) ), |
| 139 | + 75 => array( 7, array( 8 ) ), |
| 140 | + 76 => array( 7, array( 8, 'colon', 8 ) ), |
| 141 | +); |
| 142 | + |
| 143 | +static $action = array( |
| 144 | + 0 => array( |
| 145 | + 'function' => array( 0, 1 ), |
| 146 | + ), |
| 147 | + 1 => array( |
| 148 | + 'id' => array( 0, 4 ), |
| 149 | + ), |
| 150 | + 2 => array( |
| 151 | + '$' => array( 2, null ), |
| 152 | + ), |
| 153 | + 3 => array( |
| 154 | + '$' => array( 1, 2 ), |
| 155 | + 'function' => array( 0, 1 ), |
| 156 | + ), |
| 157 | + 4 => array( |
| 158 | + 'leftbracket' => array( 0, 6 ), |
| 159 | + ), |
| 160 | + 5 => array( |
| 161 | + '$' => array( 1, 1 ), |
| 162 | + ), |
| 163 | + 6 => array( |
| 164 | + 'rightbracket' => array( 0, 8 ), |
| 165 | + 'id' => array( 0, 7 ), |
| 166 | + ), |
| 167 | + 7 => array( |
| 168 | + 'comma' => array( 0, 10 ), |
| 169 | + 'rightbracket' => array( 1, 6 ), |
| 170 | + ), |
| 171 | + 8 => array( |
| 172 | + 'leftcurly' => array( 0, 11 ), |
| 173 | + ), |
| 174 | + 9 => array( |
| 175 | + 'rightbracket' => array( 0, 12 ), |
| 176 | + ), |
| 177 | + 10 => array( |
| 178 | + 'id' => array( 0, 7 ), |
| 179 | + ), |
| 180 | + 11 => array( |
| 181 | + 'if' => array( 0, 17 ), |
| 182 | + 'for' => array( 0, 18 ), |
| 183 | + 'try' => array( 0, 19 ), |
| 184 | + 'leftcurly' => array( 0, 16 ), |
| 185 | + 'return' => array( 0, 20 ), |
| 186 | + 'append' => array( 0, 21 ), |
| 187 | + 'yield' => array( 0, 22 ), |
| 188 | + 'id' => array( 0, 14 ), |
| 189 | + 'invert' => array( 0, 24 ), |
| 190 | + 'sum' => array( 0, 23 ), |
| 191 | + 'self' => array( 0, 30 ), |
| 192 | + 'isset' => array( 0, 28 ), |
| 193 | + 'delete' => array( 0, 29 ), |
| 194 | + 'break' => array( 0, 25 ), |
| 195 | + 'continue' => array( 0, 26 ), |
| 196 | + 'leftbracket' => array( 0, 15 ), |
| 197 | + 'leftsquare' => array( 0, 27 ), |
| 198 | + 'string' => array( 0, 31 ), |
| 199 | + 'int' => array( 0, 32 ), |
| 200 | + 'float' => array( 0, 33 ), |
| 201 | + 'true' => array( 0, 34 ), |
| 202 | + 'false' => array( 0, 35 ), |
| 203 | + 'null' => array( 0, 36 ), |
| 204 | + ), |
| 205 | + 12 => array( |
| 206 | + 'leftcurly' => array( 0, 58 ), |
| 207 | + ), |
| 208 | + 13 => array( |
| 209 | + 'rightbracket' => array( 1, 5 ), |
| 210 | + ), |
| 211 | + 14 => array( |
| 212 | + 'rightbracket' => array( 1, 71 ), |
| 213 | + 'setto' => array( 1, 71 ), |
| 214 | + 'in' => array( 1, 71 ), |
| 215 | + 'pow' => array( 1, 71 ), |
| 216 | + 'equalsto' => array( 1, 71 ), |
| 217 | + 'trinary' => array( 1, 71 ), |
| 218 | + 'semicolon' => array( 1, 71 ), |
| 219 | + 'colon' => array( 1, 71 ), |
| 220 | + 'logicop' => array( 1, 71 ), |
| 221 | + 'compareop' => array( 1, 71 ), |
| 222 | + 'sum' => array( 1, 71 ), |
| 223 | + 'mul' => array( 1, 71 ), |
| 224 | + 'contains' => array( 1, 71 ), |
| 225 | + 'leftsquare' => array( 1, 71 ), |
| 226 | + 'doublecolon' => array( 1, 71 ), |
| 227 | + 'rightsquare' => array( 1, 71 ), |
| 228 | + 'comma' => array( 1, 71 ), |
| 229 | + 'rightcurly' => array( 1, 71 ), |
| 230 | + 'leftbracket' => array( 1, 57 ), |
| 231 | + ), |
| 232 | + 15 => array( |
| 233 | + 'return' => array( 0, 20 ), |
| 234 | + 'append' => array( 0, 21 ), |
| 235 | + 'yield' => array( 0, 22 ), |
| 236 | + 'id' => array( 0, 14 ), |
| 237 | + 'invert' => array( 0, 24 ), |
| 238 | + 'sum' => array( 0, 23 ), |
| 239 | + 'self' => array( 0, 30 ), |
| 240 | + 'isset' => array( 0, 28 ), |
| 241 | + 'delete' => array( 0, 29 ), |
| 242 | + 'break' => array( 0, 25 ), |
| 243 | + 'continue' => array( 0, 26 ), |
| 244 | + 'leftbracket' => array( 0, 15 ), |
| 245 | + 'leftsquare' => array( 0, 27 ), |
| 246 | + 'leftcurly' => array( 0, 59 ), |
| 247 | + 'string' => array( 0, 31 ), |
| 248 | + 'int' => array( 0, 32 ), |
| 249 | + 'float' => array( 0, 33 ), |
| 250 | + 'true' => array( 0, 34 ), |
| 251 | + 'false' => array( 0, 35 ), |
| 252 | + 'null' => array( 0, 36 ), |
| 253 | + ), |
| 254 | + 16 => array( |
| 255 | + 'if' => array( 0, 17 ), |
| 256 | + 'for' => array( 0, 18 ), |
| 257 | + 'try' => array( 0, 19 ), |
| 258 | + 'leftcurly' => array( 0, 16 ), |
| 259 | + 'return' => array( 0, 20 ), |
| 260 | + 'append' => array( 0, 21 ), |
| 261 | + 'yield' => array( 0, 22 ), |
| 262 | + 'id' => array( 0, 14 ), |
| 263 | + 'invert' => array( 0, 24 ), |
| 264 | + 'sum' => array( 0, 23 ), |
| 265 | + 'self' => array( 0, 30 ), |
| 266 | + 'isset' => array( 0, 28 ), |
| 267 | + 'delete' => array( 0, 29 ), |
| 268 | + 'break' => array( 0, 25 ), |
| 269 | + 'continue' => array( 0, 26 ), |
| 270 | + 'leftbracket' => array( 0, 15 ), |
| 271 | + 'leftsquare' => array( 0, 27 ), |
| 272 | + 'string' => array( 0, 31 ), |
| 273 | + 'int' => array( 0, 32 ), |
| 274 | + 'float' => array( 0, 33 ), |
| 275 | + 'true' => array( 0, 34 ), |
| 276 | + 'false' => array( 0, 35 ), |
| 277 | + 'null' => array( 0, 36 ), |
| 278 | + ), |
| 279 | + 17 => array( |
| 280 | + 'leftbracket' => array( 0, 65 ), |
| 281 | + ), |
| 282 | + 18 => array( |
| 283 | + 'leftbracket' => array( 0, 66 ), |
| 284 | + ), |
| 285 | + 19 => array( |
| 286 | + 'if' => array( 0, 17 ), |
| 287 | + 'for' => array( 0, 18 ), |
| 288 | + 'try' => array( 0, 19 ), |
| 289 | + 'leftcurly' => array( 0, 16 ), |
| 290 | + 'return' => array( 0, 20 ), |
| 291 | + 'append' => array( 0, 21 ), |
| 292 | + 'yield' => array( 0, 22 ), |
| 293 | + 'id' => array( 0, 14 ), |
| 294 | + 'invert' => array( 0, 24 ), |
| 295 | + 'sum' => array( 0, 23 ), |
| 296 | + 'self' => array( 0, 30 ), |
| 297 | + 'isset' => array( 0, 28 ), |
| 298 | + 'delete' => array( 0, 29 ), |
| 299 | + 'break' => array( 0, 25 ), |
| 300 | + 'continue' => array( 0, 26 ), |
| 301 | + 'leftbracket' => array( 0, 15 ), |
| 302 | + 'leftsquare' => array( 0, 27 ), |
| 303 | + 'string' => array( 0, 31 ), |
| 304 | + 'int' => array( 0, 32 ), |
| 305 | + 'float' => array( 0, 33 ), |
| 306 | + 'true' => array( 0, 34 ), |
| 307 | + 'false' => array( 0, 35 ), |
| 308 | + 'null' => array( 0, 36 ), |
| 309 | + ), |
| 310 | + 20 => array( |
| 311 | + 'semicolon' => array( 1, 16 ), |
| 312 | + 'rightbracket' => array( 1, 16 ), |
| 313 | + 'rightsquare' => array( 1, 16 ), |
| 314 | + 'comma' => array( 1, 16 ), |
| 315 | + 'colon' => array( 1, 16 ), |
| 316 | + 'rightcurly' => array( 1, 16 ), |
| 317 | + 'id' => array( 0, 14 ), |
| 318 | + 'invert' => array( 0, 24 ), |
| 319 | + 'sum' => array( 0, 23 ), |
| 320 | + 'self' => array( 0, 30 ), |
| 321 | + 'isset' => array( 0, 28 ), |
| 322 | + 'delete' => array( 0, 29 ), |
| 323 | + 'break' => array( 0, 25 ), |
| 324 | + 'continue' => array( 0, 26 ), |
| 325 | + 'leftbracket' => array( 0, 15 ), |
| 326 | + 'leftsquare' => array( 0, 27 ), |
| 327 | + 'leftcurly' => array( 0, 59 ), |
| 328 | + 'string' => array( 0, 31 ), |
| 329 | + 'int' => array( 0, 32 ), |
| 330 | + 'float' => array( 0, 33 ), |
| 331 | + 'true' => array( 0, 34 ), |
| 332 | + 'false' => array( 0, 35 ), |
| 333 | + 'null' => array( 0, 36 ), |
| 334 | + ), |
| 335 | + 21 => array( |
| 336 | + 'id' => array( 0, 14 ), |
| 337 | + 'invert' => array( 0, 24 ), |
| 338 | + 'sum' => array( 0, 23 ), |
| 339 | + 'self' => array( 0, 30 ), |
| 340 | + 'isset' => array( 0, 28 ), |
| 341 | + 'delete' => array( 0, 29 ), |
| 342 | + 'break' => array( 0, 25 ), |
| 343 | + 'continue' => array( 0, 26 ), |
| 344 | + 'leftbracket' => array( 0, 15 ), |
| 345 | + 'leftsquare' => array( 0, 27 ), |
| 346 | + 'leftcurly' => array( 0, 59 ), |
| 347 | + 'string' => array( 0, 31 ), |
| 348 | + 'int' => array( 0, 32 ), |
| 349 | + 'float' => array( 0, 33 ), |
| 350 | + 'true' => array( 0, 34 ), |
| 351 | + 'false' => array( 0, 35 ), |
| 352 | + 'null' => array( 0, 36 ), |
| 353 | + ), |
| 354 | + 22 => array( |
| 355 | + 'id' => array( 0, 14 ), |
| 356 | + 'invert' => array( 0, 24 ), |
| 357 | + 'sum' => array( 0, 23 ), |
| 358 | + 'self' => array( 0, 30 ), |
| 359 | + 'isset' => array( 0, 28 ), |
| 360 | + 'delete' => array( 0, 29 ), |
| 361 | + 'break' => array( 0, 25 ), |
| 362 | + 'continue' => array( 0, 26 ), |
| 363 | + 'leftbracket' => array( 0, 15 ), |
| 364 | + 'leftsquare' => array( 0, 27 ), |
| 365 | + 'leftcurly' => array( 0, 59 ), |
| 366 | + 'string' => array( 0, 31 ), |
| 367 | + 'int' => array( 0, 32 ), |
| 368 | + 'float' => array( 0, 33 ), |
| 369 | + 'true' => array( 0, 34 ), |
| 370 | + 'false' => array( 0, 35 ), |
| 371 | + 'null' => array( 0, 36 ), |
| 372 | + ), |
| 373 | + 23 => array( |
| 374 | + 'id' => array( 0, 71 ), |
| 375 | + 'self' => array( 0, 30 ), |
| 376 | + 'isset' => array( 0, 28 ), |
| 377 | + 'delete' => array( 0, 29 ), |
| 378 | + 'break' => array( 0, 25 ), |
| 379 | + 'continue' => array( 0, 26 ), |
| 380 | + 'leftbracket' => array( 0, 15 ), |
| 381 | + 'leftsquare' => array( 0, 27 ), |
| 382 | + 'leftcurly' => array( 0, 59 ), |
| 383 | + 'string' => array( 0, 31 ), |
| 384 | + 'int' => array( 0, 32 ), |
| 385 | + 'float' => array( 0, 33 ), |
| 386 | + 'true' => array( 0, 34 ), |
| 387 | + 'false' => array( 0, 35 ), |
| 388 | + 'null' => array( 0, 36 ), |
| 389 | + ), |
| 390 | + 24 => array( |
| 391 | + 'sum' => array( 0, 23 ), |
| 392 | + 'id' => array( 0, 71 ), |
| 393 | + 'self' => array( 0, 30 ), |
| 394 | + 'isset' => array( 0, 28 ), |
| 395 | + 'delete' => array( 0, 29 ), |
| 396 | + 'break' => array( 0, 25 ), |
| 397 | + 'continue' => array( 0, 26 ), |
| 398 | + 'leftbracket' => array( 0, 15 ), |
| 399 | + 'leftsquare' => array( 0, 27 ), |
| 400 | + 'leftcurly' => array( 0, 59 ), |
| 401 | + 'string' => array( 0, 31 ), |
| 402 | + 'int' => array( 0, 32 ), |
| 403 | + 'float' => array( 0, 33 ), |
| 404 | + 'true' => array( 0, 34 ), |
| 405 | + 'false' => array( 0, 35 ), |
| 406 | + 'null' => array( 0, 36 ), |
| 407 | + ), |
| 408 | + 25 => array( |
| 409 | + 'in' => array( 1, 50 ), |
| 410 | + 'pow' => array( 1, 50 ), |
| 411 | + 'equalsto' => array( 1, 50 ), |
| 412 | + 'trinary' => array( 1, 50 ), |
| 413 | + 'semicolon' => array( 1, 50 ), |
| 414 | + 'rightbracket' => array( 1, 50 ), |
| 415 | + 'colon' => array( 1, 50 ), |
| 416 | + 'logicop' => array( 1, 50 ), |
| 417 | + 'compareop' => array( 1, 50 ), |
| 418 | + 'sum' => array( 1, 50 ), |
| 419 | + 'mul' => array( 1, 50 ), |
| 420 | + 'contains' => array( 1, 50 ), |
| 421 | + 'doublecolon' => array( 1, 50 ), |
| 422 | + 'rightsquare' => array( 1, 50 ), |
| 423 | + 'comma' => array( 1, 50 ), |
| 424 | + 'rightcurly' => array( 1, 50 ), |
| 425 | + ), |
| 426 | + 26 => array( |
| 427 | + 'in' => array( 1, 51 ), |
| 428 | + 'pow' => array( 1, 51 ), |
| 429 | + 'equalsto' => array( 1, 51 ), |
| 430 | + 'trinary' => array( 1, 51 ), |
| 431 | + 'semicolon' => array( 1, 51 ), |
| 432 | + 'rightbracket' => array( 1, 51 ), |
| 433 | + 'colon' => array( 1, 51 ), |
| 434 | + 'logicop' => array( 1, 51 ), |
| 435 | + 'compareop' => array( 1, 51 ), |
| 436 | + 'sum' => array( 1, 51 ), |
| 437 | + 'mul' => array( 1, 51 ), |
| 438 | + 'contains' => array( 1, 51 ), |
| 439 | + 'doublecolon' => array( 1, 51 ), |
| 440 | + 'rightsquare' => array( 1, 51 ), |
| 441 | + 'comma' => array( 1, 51 ), |
| 442 | + 'rightcurly' => array( 1, 51 ), |
| 443 | + ), |
| 444 | + 27 => array( |
| 445 | + 'return' => array( 0, 20 ), |
| 446 | + 'append' => array( 0, 21 ), |
| 447 | + 'yield' => array( 0, 22 ), |
| 448 | + 'id' => array( 0, 14 ), |
| 449 | + 'invert' => array( 0, 24 ), |
| 450 | + 'sum' => array( 0, 23 ), |
| 451 | + 'self' => array( 0, 30 ), |
| 452 | + 'isset' => array( 0, 28 ), |
| 453 | + 'delete' => array( 0, 29 ), |
| 454 | + 'break' => array( 0, 25 ), |
| 455 | + 'continue' => array( 0, 26 ), |
| 456 | + 'leftbracket' => array( 0, 15 ), |
| 457 | + 'leftsquare' => array( 0, 27 ), |
| 458 | + 'leftcurly' => array( 0, 59 ), |
| 459 | + 'string' => array( 0, 31 ), |
| 460 | + 'int' => array( 0, 32 ), |
| 461 | + 'float' => array( 0, 33 ), |
| 462 | + 'true' => array( 0, 34 ), |
| 463 | + 'false' => array( 0, 35 ), |
| 464 | + 'null' => array( 0, 36 ), |
| 465 | + ), |
| 466 | + 28 => array( |
| 467 | + 'leftbracket' => array( 1, 55 ), |
| 468 | + ), |
| 469 | + 29 => array( |
| 470 | + 'leftbracket' => array( 1, 56 ), |
| 471 | + ), |
| 472 | + 30 => array( |
| 473 | + 'doublecolon' => array( 0, 77 ), |
| 474 | + ), |
| 475 | + 31 => array( |
| 476 | + 'in' => array( 1, 65 ), |
| 477 | + 'pow' => array( 1, 65 ), |
| 478 | + 'equalsto' => array( 1, 65 ), |
| 479 | + 'trinary' => array( 1, 65 ), |
| 480 | + 'semicolon' => array( 1, 65 ), |
| 481 | + 'rightbracket' => array( 1, 65 ), |
| 482 | + 'colon' => array( 1, 65 ), |
| 483 | + 'logicop' => array( 1, 65 ), |
| 484 | + 'compareop' => array( 1, 65 ), |
| 485 | + 'sum' => array( 1, 65 ), |
| 486 | + 'mul' => array( 1, 65 ), |
| 487 | + 'contains' => array( 1, 65 ), |
| 488 | + 'doublecolon' => array( 1, 65 ), |
| 489 | + 'rightsquare' => array( 1, 65 ), |
| 490 | + 'comma' => array( 1, 65 ), |
| 491 | + 'rightcurly' => array( 1, 65 ), |
| 492 | + ), |
| 493 | + 32 => array( |
| 494 | + 'in' => array( 1, 66 ), |
| 495 | + 'pow' => array( 1, 66 ), |
| 496 | + 'equalsto' => array( 1, 66 ), |
| 497 | + 'trinary' => array( 1, 66 ), |
| 498 | + 'semicolon' => array( 1, 66 ), |
| 499 | + 'rightbracket' => array( 1, 66 ), |
| 500 | + 'colon' => array( 1, 66 ), |
| 501 | + 'logicop' => array( 1, 66 ), |
| 502 | + 'compareop' => array( 1, 66 ), |
| 503 | + 'sum' => array( 1, 66 ), |
| 504 | + 'mul' => array( 1, 66 ), |
| 505 | + 'contains' => array( 1, 66 ), |
| 506 | + 'doublecolon' => array( 1, 66 ), |
| 507 | + 'rightsquare' => array( 1, 66 ), |
| 508 | + 'comma' => array( 1, 66 ), |
| 509 | + 'rightcurly' => array( 1, 66 ), |
| 510 | + ), |
| 511 | + 33 => array( |
| 512 | + 'in' => array( 1, 67 ), |
| 513 | + 'pow' => array( 1, 67 ), |
| 514 | + 'equalsto' => array( 1, 67 ), |
| 515 | + 'trinary' => array( 1, 67 ), |
| 516 | + 'semicolon' => array( 1, 67 ), |
| 517 | + 'rightbracket' => array( 1, 67 ), |
| 518 | + 'colon' => array( 1, 67 ), |
| 519 | + 'logicop' => array( 1, 67 ), |
| 520 | + 'compareop' => array( 1, 67 ), |
| 521 | + 'sum' => array( 1, 67 ), |
| 522 | + 'mul' => array( 1, 67 ), |
| 523 | + 'contains' => array( 1, 67 ), |
| 524 | + 'doublecolon' => array( 1, 67 ), |
| 525 | + 'rightsquare' => array( 1, 67 ), |
| 526 | + 'comma' => array( 1, 67 ), |
| 527 | + 'rightcurly' => array( 1, 67 ), |
| 528 | + ), |
| 529 | + 34 => array( |
| 530 | + 'in' => array( 1, 68 ), |
| 531 | + 'pow' => array( 1, 68 ), |
| 532 | + 'equalsto' => array( 1, 68 ), |
| 533 | + 'trinary' => array( 1, 68 ), |
| 534 | + 'semicolon' => array( 1, 68 ), |
| 535 | + 'rightbracket' => array( 1, 68 ), |
| 536 | + 'colon' => array( 1, 68 ), |
| 537 | + 'logicop' => array( 1, 68 ), |
| 538 | + 'compareop' => array( 1, 68 ), |
| 539 | + 'sum' => array( 1, 68 ), |
| 540 | + 'mul' => array( 1, 68 ), |
| 541 | + 'contains' => array( 1, 68 ), |
| 542 | + 'doublecolon' => array( 1, 68 ), |
| 543 | + 'rightsquare' => array( 1, 68 ), |
| 544 | + 'comma' => array( 1, 68 ), |
| 545 | + 'rightcurly' => array( 1, 68 ), |
| 546 | + ), |
| 547 | + 35 => array( |
| 548 | + 'in' => array( 1, 69 ), |
| 549 | + 'pow' => array( 1, 69 ), |
| 550 | + 'equalsto' => array( 1, 69 ), |
| 551 | + 'trinary' => array( 1, 69 ), |
| 552 | + 'semicolon' => array( 1, 69 ), |
| 553 | + 'rightbracket' => array( 1, 69 ), |
| 554 | + 'colon' => array( 1, 69 ), |
| 555 | + 'logicop' => array( 1, 69 ), |
| 556 | + 'compareop' => array( 1, 69 ), |
| 557 | + 'sum' => array( 1, 69 ), |
| 558 | + 'mul' => array( 1, 69 ), |
| 559 | + 'contains' => array( 1, 69 ), |
| 560 | + 'doublecolon' => array( 1, 69 ), |
| 561 | + 'rightsquare' => array( 1, 69 ), |
| 562 | + 'comma' => array( 1, 69 ), |
| 563 | + 'rightcurly' => array( 1, 69 ), |
| 564 | + ), |
| 565 | + 36 => array( |
| 566 | + 'in' => array( 1, 70 ), |
| 567 | + 'pow' => array( 1, 70 ), |
| 568 | + 'equalsto' => array( 1, 70 ), |
| 569 | + 'trinary' => array( 1, 70 ), |
| 570 | + 'semicolon' => array( 1, 70 ), |
| 571 | + 'rightbracket' => array( 1, 70 ), |
| 572 | + 'colon' => array( 1, 70 ), |
| 573 | + 'logicop' => array( 1, 70 ), |
| 574 | + 'compareop' => array( 1, 70 ), |
| 575 | + 'sum' => array( 1, 70 ), |
| 576 | + 'mul' => array( 1, 70 ), |
| 577 | + 'contains' => array( 1, 70 ), |
| 578 | + 'doublecolon' => array( 1, 70 ), |
| 579 | + 'rightsquare' => array( 1, 70 ), |
| 580 | + 'comma' => array( 1, 70 ), |
| 581 | + 'rightcurly' => array( 1, 70 ), |
| 582 | + ), |
| 583 | + 37 => array( |
| 584 | + 'rightcurly' => array( 0, 78 ), |
| 585 | + 'if' => array( 0, 17 ), |
| 586 | + 'for' => array( 0, 18 ), |
| 587 | + 'try' => array( 0, 19 ), |
| 588 | + 'leftcurly' => array( 0, 16 ), |
| 589 | + 'return' => array( 0, 20 ), |
| 590 | + 'append' => array( 0, 21 ), |
| 591 | + 'yield' => array( 0, 22 ), |
| 592 | + 'id' => array( 0, 14 ), |
| 593 | + 'invert' => array( 0, 24 ), |
| 594 | + 'sum' => array( 0, 23 ), |
| 595 | + 'self' => array( 0, 30 ), |
| 596 | + 'isset' => array( 0, 28 ), |
| 597 | + 'delete' => array( 0, 29 ), |
| 598 | + 'break' => array( 0, 25 ), |
| 599 | + 'continue' => array( 0, 26 ), |
| 600 | + 'leftbracket' => array( 0, 15 ), |
| 601 | + 'leftsquare' => array( 0, 27 ), |
| 602 | + 'string' => array( 0, 31 ), |
| 603 | + 'int' => array( 0, 32 ), |
| 604 | + 'float' => array( 0, 33 ), |
| 605 | + 'true' => array( 0, 34 ), |
| 606 | + 'false' => array( 0, 35 ), |
| 607 | + 'null' => array( 0, 36 ), |
| 608 | + ), |
| 609 | + 38 => array( |
| 610 | + 'rightcurly' => array( 1, 8 ), |
| 611 | + 'if' => array( 1, 8 ), |
| 612 | + 'for' => array( 1, 8 ), |
| 613 | + 'try' => array( 1, 8 ), |
| 614 | + 'leftcurly' => array( 1, 8 ), |
| 615 | + 'return' => array( 1, 8 ), |
| 616 | + 'append' => array( 1, 8 ), |
| 617 | + 'yield' => array( 1, 8 ), |
| 618 | + 'id' => array( 1, 8 ), |
| 619 | + 'invert' => array( 1, 8 ), |
| 620 | + 'sum' => array( 1, 8 ), |
| 621 | + 'break' => array( 1, 8 ), |
| 622 | + 'continue' => array( 1, 8 ), |
| 623 | + 'leftbracket' => array( 1, 8 ), |
| 624 | + 'leftsquare' => array( 1, 8 ), |
| 625 | + 'self' => array( 1, 8 ), |
| 626 | + 'isset' => array( 1, 8 ), |
| 627 | + 'delete' => array( 1, 8 ), |
| 628 | + 'string' => array( 1, 8 ), |
| 629 | + 'int' => array( 1, 8 ), |
| 630 | + 'float' => array( 1, 8 ), |
| 631 | + 'true' => array( 1, 8 ), |
| 632 | + 'false' => array( 1, 8 ), |
| 633 | + 'null' => array( 1, 8 ), |
| 634 | + ), |
| 635 | + 39 => array( |
| 636 | + 'semicolon' => array( 0, 80 ), |
| 637 | + ), |
| 638 | + 40 => array( |
| 639 | + 'setto' => array( 0, 81 ), |
| 640 | + 'in' => array( 1, 48 ), |
| 641 | + 'pow' => array( 1, 48 ), |
| 642 | + 'equalsto' => array( 1, 48 ), |
| 643 | + 'trinary' => array( 1, 48 ), |
| 644 | + 'semicolon' => array( 1, 48 ), |
| 645 | + 'rightbracket' => array( 1, 48 ), |
| 646 | + 'colon' => array( 1, 48 ), |
| 647 | + 'logicop' => array( 1, 48 ), |
| 648 | + 'compareop' => array( 1, 48 ), |
| 649 | + 'sum' => array( 1, 48 ), |
| 650 | + 'mul' => array( 1, 48 ), |
| 651 | + 'contains' => array( 1, 48 ), |
| 652 | + 'doublecolon' => array( 1, 48 ), |
| 653 | + 'rightsquare' => array( 1, 48 ), |
| 654 | + 'comma' => array( 1, 48 ), |
| 655 | + 'rightcurly' => array( 1, 48 ), |
| 656 | + 'leftsquare' => array( 0, 82 ), |
| 657 | + ), |
| 658 | + 41 => array( |
| 659 | + 'semicolon' => array( 1, 15 ), |
| 660 | + 'rightbracket' => array( 1, 15 ), |
| 661 | + 'rightsquare' => array( 1, 15 ), |
| 662 | + 'comma' => array( 1, 15 ), |
| 663 | + 'colon' => array( 1, 15 ), |
| 664 | + 'rightcurly' => array( 1, 15 ), |
| 665 | + ), |
| 666 | + 42 => array( |
| 667 | + 'semicolon' => array( 1, 18 ), |
| 668 | + 'rightbracket' => array( 1, 18 ), |
| 669 | + 'rightsquare' => array( 1, 18 ), |
| 670 | + 'comma' => array( 1, 18 ), |
| 671 | + 'colon' => array( 1, 18 ), |
| 672 | + 'rightcurly' => array( 1, 18 ), |
| 673 | + ), |
| 674 | + 43 => array( |
| 675 | + 'semicolon' => array( 1, 22 ), |
| 676 | + 'rightbracket' => array( 1, 22 ), |
| 677 | + 'rightsquare' => array( 1, 22 ), |
| 678 | + 'comma' => array( 1, 22 ), |
| 679 | + 'colon' => array( 1, 22 ), |
| 680 | + 'rightcurly' => array( 1, 22 ), |
| 681 | + ), |
| 682 | + 44 => array( |
| 683 | + 'trinary' => array( 0, 84 ), |
| 684 | + 'semicolon' => array( 1, 24 ), |
| 685 | + 'rightbracket' => array( 1, 24 ), |
| 686 | + 'colon' => array( 1, 24 ), |
| 687 | + 'rightsquare' => array( 1, 24 ), |
| 688 | + 'comma' => array( 1, 24 ), |
| 689 | + 'rightcurly' => array( 1, 24 ), |
| 690 | + 'logicop' => array( 0, 85 ), |
| 691 | + ), |
| 692 | + 45 => array( |
| 693 | + 'trinary' => array( 1, 26 ), |
| 694 | + 'semicolon' => array( 1, 26 ), |
| 695 | + 'rightbracket' => array( 1, 26 ), |
| 696 | + 'colon' => array( 1, 26 ), |
| 697 | + 'logicop' => array( 1, 26 ), |
| 698 | + 'rightsquare' => array( 1, 26 ), |
| 699 | + 'comma' => array( 1, 26 ), |
| 700 | + 'rightcurly' => array( 1, 26 ), |
| 701 | + 'compareop' => array( 0, 86 ), |
| 702 | + ), |
| 703 | + 46 => array( |
| 704 | + 'trinary' => array( 1, 28 ), |
| 705 | + 'semicolon' => array( 1, 28 ), |
| 706 | + 'rightbracket' => array( 1, 28 ), |
| 707 | + 'colon' => array( 1, 28 ), |
| 708 | + 'logicop' => array( 1, 28 ), |
| 709 | + 'compareop' => array( 1, 28 ), |
| 710 | + 'rightsquare' => array( 1, 28 ), |
| 711 | + 'comma' => array( 1, 28 ), |
| 712 | + 'rightcurly' => array( 1, 28 ), |
| 713 | + ), |
| 714 | + 47 => array( |
| 715 | + 'equalsto' => array( 0, 87 ), |
| 716 | + 'trinary' => array( 1, 30 ), |
| 717 | + 'semicolon' => array( 1, 30 ), |
| 718 | + 'rightbracket' => array( 1, 30 ), |
| 719 | + 'colon' => array( 1, 30 ), |
| 720 | + 'logicop' => array( 1, 30 ), |
| 721 | + 'compareop' => array( 1, 30 ), |
| 722 | + 'rightsquare' => array( 1, 30 ), |
| 723 | + 'comma' => array( 1, 30 ), |
| 724 | + 'rightcurly' => array( 1, 30 ), |
| 725 | + 'sum' => array( 0, 88 ), |
| 726 | + ), |
| 727 | + 48 => array( |
| 728 | + 'equalsto' => array( 1, 32 ), |
| 729 | + 'trinary' => array( 1, 32 ), |
| 730 | + 'semicolon' => array( 1, 32 ), |
| 731 | + 'rightbracket' => array( 1, 32 ), |
| 732 | + 'colon' => array( 1, 32 ), |
| 733 | + 'logicop' => array( 1, 32 ), |
| 734 | + 'compareop' => array( 1, 32 ), |
| 735 | + 'sum' => array( 1, 32 ), |
| 736 | + 'rightsquare' => array( 1, 32 ), |
| 737 | + 'comma' => array( 1, 32 ), |
| 738 | + 'rightcurly' => array( 1, 32 ), |
| 739 | + 'mul' => array( 0, 89 ), |
| 740 | + ), |
| 741 | + 49 => array( |
| 742 | + 'equalsto' => array( 1, 34 ), |
| 743 | + 'trinary' => array( 1, 34 ), |
| 744 | + 'semicolon' => array( 1, 34 ), |
| 745 | + 'rightbracket' => array( 1, 34 ), |
| 746 | + 'colon' => array( 1, 34 ), |
| 747 | + 'logicop' => array( 1, 34 ), |
| 748 | + 'compareop' => array( 1, 34 ), |
| 749 | + 'sum' => array( 1, 34 ), |
| 750 | + 'mul' => array( 1, 34 ), |
| 751 | + 'rightsquare' => array( 1, 34 ), |
| 752 | + 'comma' => array( 1, 34 ), |
| 753 | + 'rightcurly' => array( 1, 34 ), |
| 754 | + ), |
| 755 | + 50 => array( |
| 756 | + 'pow' => array( 0, 90 ), |
| 757 | + 'equalsto' => array( 1, 36 ), |
| 758 | + 'trinary' => array( 1, 36 ), |
| 759 | + 'semicolon' => array( 1, 36 ), |
| 760 | + 'rightbracket' => array( 1, 36 ), |
| 761 | + 'colon' => array( 1, 36 ), |
| 762 | + 'logicop' => array( 1, 36 ), |
| 763 | + 'compareop' => array( 1, 36 ), |
| 764 | + 'sum' => array( 1, 36 ), |
| 765 | + 'mul' => array( 1, 36 ), |
| 766 | + 'rightsquare' => array( 1, 36 ), |
| 767 | + 'comma' => array( 1, 36 ), |
| 768 | + 'rightcurly' => array( 1, 36 ), |
| 769 | + ), |
| 770 | + 51 => array( |
| 771 | + 'pow' => array( 1, 38 ), |
| 772 | + 'equalsto' => array( 1, 38 ), |
| 773 | + 'trinary' => array( 1, 38 ), |
| 774 | + 'semicolon' => array( 1, 38 ), |
| 775 | + 'rightbracket' => array( 1, 38 ), |
| 776 | + 'colon' => array( 1, 38 ), |
| 777 | + 'logicop' => array( 1, 38 ), |
| 778 | + 'compareop' => array( 1, 38 ), |
| 779 | + 'sum' => array( 1, 38 ), |
| 780 | + 'mul' => array( 1, 38 ), |
| 781 | + 'rightsquare' => array( 1, 38 ), |
| 782 | + 'comma' => array( 1, 38 ), |
| 783 | + 'rightcurly' => array( 1, 38 ), |
| 784 | + ), |
| 785 | + 52 => array( |
| 786 | + 'in' => array( 0, 91 ), |
| 787 | + 'contains' => array( 0, 92 ), |
| 788 | + 'pow' => array( 1, 41 ), |
| 789 | + 'equalsto' => array( 1, 41 ), |
| 790 | + 'trinary' => array( 1, 41 ), |
| 791 | + 'semicolon' => array( 1, 41 ), |
| 792 | + 'rightbracket' => array( 1, 41 ), |
| 793 | + 'colon' => array( 1, 41 ), |
| 794 | + 'logicop' => array( 1, 41 ), |
| 795 | + 'compareop' => array( 1, 41 ), |
| 796 | + 'sum' => array( 1, 41 ), |
| 797 | + 'mul' => array( 1, 41 ), |
| 798 | + 'rightsquare' => array( 1, 41 ), |
| 799 | + 'comma' => array( 1, 41 ), |
| 800 | + 'rightcurly' => array( 1, 41 ), |
| 801 | + ), |
| 802 | + 53 => array( |
| 803 | + 'in' => array( 1, 43 ), |
| 804 | + 'pow' => array( 1, 43 ), |
| 805 | + 'equalsto' => array( 1, 43 ), |
| 806 | + 'trinary' => array( 1, 43 ), |
| 807 | + 'semicolon' => array( 1, 43 ), |
| 808 | + 'rightbracket' => array( 1, 43 ), |
| 809 | + 'colon' => array( 1, 43 ), |
| 810 | + 'logicop' => array( 1, 43 ), |
| 811 | + 'compareop' => array( 1, 43 ), |
| 812 | + 'sum' => array( 1, 43 ), |
| 813 | + 'mul' => array( 1, 43 ), |
| 814 | + 'contains' => array( 1, 43 ), |
| 815 | + 'rightsquare' => array( 1, 43 ), |
| 816 | + 'comma' => array( 1, 43 ), |
| 817 | + 'rightcurly' => array( 1, 43 ), |
| 818 | + ), |
| 819 | + 54 => array( |
| 820 | + 'leftbracket' => array( 0, 93 ), |
| 821 | + ), |
| 822 | + 55 => array( |
| 823 | + 'leftbracket' => array( 0, 94 ), |
| 824 | + ), |
| 825 | + 56 => array( |
| 826 | + 'in' => array( 1, 47 ), |
| 827 | + 'pow' => array( 1, 47 ), |
| 828 | + 'equalsto' => array( 1, 47 ), |
| 829 | + 'trinary' => array( 1, 47 ), |
| 830 | + 'semicolon' => array( 1, 47 ), |
| 831 | + 'rightbracket' => array( 1, 47 ), |
| 832 | + 'colon' => array( 1, 47 ), |
| 833 | + 'logicop' => array( 1, 47 ), |
| 834 | + 'compareop' => array( 1, 47 ), |
| 835 | + 'sum' => array( 1, 47 ), |
| 836 | + 'mul' => array( 1, 47 ), |
| 837 | + 'contains' => array( 1, 47 ), |
| 838 | + 'rightsquare' => array( 1, 47 ), |
| 839 | + 'comma' => array( 1, 47 ), |
| 840 | + 'rightcurly' => array( 1, 47 ), |
| 841 | + 'doublecolon' => array( 0, 95 ), |
| 842 | + ), |
| 843 | + 57 => array( |
| 844 | + 'in' => array( 1, 49 ), |
| 845 | + 'pow' => array( 1, 49 ), |
| 846 | + 'equalsto' => array( 1, 49 ), |
| 847 | + 'trinary' => array( 1, 49 ), |
| 848 | + 'semicolon' => array( 1, 49 ), |
| 849 | + 'rightbracket' => array( 1, 49 ), |
| 850 | + 'colon' => array( 1, 49 ), |
| 851 | + 'logicop' => array( 1, 49 ), |
| 852 | + 'compareop' => array( 1, 49 ), |
| 853 | + 'sum' => array( 1, 49 ), |
| 854 | + 'mul' => array( 1, 49 ), |
| 855 | + 'contains' => array( 1, 49 ), |
| 856 | + 'doublecolon' => array( 1, 49 ), |
| 857 | + 'rightsquare' => array( 1, 49 ), |
| 858 | + 'comma' => array( 1, 49 ), |
| 859 | + 'rightcurly' => array( 1, 49 ), |
| 860 | + ), |
| 861 | + 58 => array( |
| 862 | + 'if' => array( 0, 17 ), |
| 863 | + 'for' => array( 0, 18 ), |
| 864 | + 'try' => array( 0, 19 ), |
| 865 | + 'leftcurly' => array( 0, 16 ), |
| 866 | + 'return' => array( 0, 20 ), |
| 867 | + 'append' => array( 0, 21 ), |
| 868 | + 'yield' => array( 0, 22 ), |
| 869 | + 'id' => array( 0, 14 ), |
| 870 | + 'invert' => array( 0, 24 ), |
| 871 | + 'sum' => array( 0, 23 ), |
| 872 | + 'self' => array( 0, 30 ), |
| 873 | + 'isset' => array( 0, 28 ), |
| 874 | + 'delete' => array( 0, 29 ), |
| 875 | + 'break' => array( 0, 25 ), |
| 876 | + 'continue' => array( 0, 26 ), |
| 877 | + 'leftbracket' => array( 0, 15 ), |
| 878 | + 'leftsquare' => array( 0, 27 ), |
| 879 | + 'string' => array( 0, 31 ), |
| 880 | + 'int' => array( 0, 32 ), |
| 881 | + 'float' => array( 0, 33 ), |
| 882 | + 'true' => array( 0, 34 ), |
| 883 | + 'false' => array( 0, 35 ), |
| 884 | + 'null' => array( 0, 36 ), |
| 885 | + ), |
| 886 | + 59 => array( |
| 887 | + 'return' => array( 0, 20 ), |
| 888 | + 'append' => array( 0, 21 ), |
| 889 | + 'yield' => array( 0, 22 ), |
| 890 | + 'id' => array( 0, 14 ), |
| 891 | + 'invert' => array( 0, 24 ), |
| 892 | + 'sum' => array( 0, 23 ), |
| 893 | + 'self' => array( 0, 30 ), |
| 894 | + 'isset' => array( 0, 28 ), |
| 895 | + 'delete' => array( 0, 29 ), |
| 896 | + 'break' => array( 0, 25 ), |
| 897 | + 'continue' => array( 0, 26 ), |
| 898 | + 'leftbracket' => array( 0, 15 ), |
| 899 | + 'leftsquare' => array( 0, 27 ), |
| 900 | + 'leftcurly' => array( 0, 59 ), |
| 901 | + 'string' => array( 0, 31 ), |
| 902 | + 'int' => array( 0, 32 ), |
| 903 | + 'float' => array( 0, 33 ), |
| 904 | + 'true' => array( 0, 34 ), |
| 905 | + 'false' => array( 0, 35 ), |
| 906 | + 'null' => array( 0, 36 ), |
| 907 | + ), |
| 908 | + 60 => array( |
| 909 | + 'rightbracket' => array( 0, 98 ), |
| 910 | + ), |
| 911 | + 61 => array( |
| 912 | + 'rightcurly' => array( 0, 99 ), |
| 913 | + 'if' => array( 0, 17 ), |
| 914 | + 'for' => array( 0, 18 ), |
| 915 | + 'try' => array( 0, 19 ), |
| 916 | + 'leftcurly' => array( 0, 16 ), |
| 917 | + 'return' => array( 0, 20 ), |
| 918 | + 'append' => array( 0, 21 ), |
| 919 | + 'yield' => array( 0, 22 ), |
| 920 | + 'id' => array( 0, 14 ), |
| 921 | + 'invert' => array( 0, 24 ), |
| 922 | + 'sum' => array( 0, 23 ), |
| 923 | + 'self' => array( 0, 30 ), |
| 924 | + 'isset' => array( 0, 28 ), |
| 925 | + 'delete' => array( 0, 29 ), |
| 926 | + 'break' => array( 0, 25 ), |
| 927 | + 'continue' => array( 0, 26 ), |
| 928 | + 'leftbracket' => array( 0, 15 ), |
| 929 | + 'leftsquare' => array( 0, 27 ), |
| 930 | + 'string' => array( 0, 31 ), |
| 931 | + 'int' => array( 0, 32 ), |
| 932 | + 'float' => array( 0, 33 ), |
| 933 | + 'true' => array( 0, 34 ), |
| 934 | + 'false' => array( 0, 35 ), |
| 935 | + 'null' => array( 0, 36 ), |
| 936 | + ), |
| 937 | + 62 => array( |
| 938 | + 'semicolon' => array( 0, 80 ), |
| 939 | + 'colon' => array( 0, 100 ), |
| 940 | + ), |
| 941 | + 63 => array( |
| 942 | + 'rightcurly' => array( 0, 101 ), |
| 943 | + 'comma' => array( 0, 102 ), |
| 944 | + ), |
| 945 | + 64 => array( |
| 946 | + 'rightcurly' => array( 1, 63 ), |
| 947 | + 'comma' => array( 1, 63 ), |
| 948 | + ), |
| 949 | + 65 => array( |
| 950 | + 'return' => array( 0, 20 ), |
| 951 | + 'append' => array( 0, 21 ), |
| 952 | + 'yield' => array( 0, 22 ), |
| 953 | + 'id' => array( 0, 14 ), |
| 954 | + 'invert' => array( 0, 24 ), |
| 955 | + 'sum' => array( 0, 23 ), |
| 956 | + 'self' => array( 0, 30 ), |
| 957 | + 'isset' => array( 0, 28 ), |
| 958 | + 'delete' => array( 0, 29 ), |
| 959 | + 'break' => array( 0, 25 ), |
| 960 | + 'continue' => array( 0, 26 ), |
| 961 | + 'leftbracket' => array( 0, 15 ), |
| 962 | + 'leftsquare' => array( 0, 27 ), |
| 963 | + 'leftcurly' => array( 0, 59 ), |
| 964 | + 'string' => array( 0, 31 ), |
| 965 | + 'int' => array( 0, 32 ), |
| 966 | + 'float' => array( 0, 33 ), |
| 967 | + 'true' => array( 0, 34 ), |
| 968 | + 'false' => array( 0, 35 ), |
| 969 | + 'null' => array( 0, 36 ), |
| 970 | + ), |
| 971 | + 66 => array( |
| 972 | + 'id' => array( 0, 104 ), |
| 973 | + ), |
| 974 | + 67 => array( |
| 975 | + 'catch' => array( 0, 107 ), |
| 976 | + ), |
| 977 | + 68 => array( |
| 978 | + 'semicolon' => array( 1, 17 ), |
| 979 | + 'rightbracket' => array( 1, 17 ), |
| 980 | + 'rightsquare' => array( 1, 17 ), |
| 981 | + 'comma' => array( 1, 17 ), |
| 982 | + 'colon' => array( 1, 17 ), |
| 983 | + 'rightcurly' => array( 1, 17 ), |
| 984 | + ), |
| 985 | + 69 => array( |
| 986 | + 'semicolon' => array( 1, 19 ), |
| 987 | + 'rightbracket' => array( 1, 19 ), |
| 988 | + 'rightsquare' => array( 1, 19 ), |
| 989 | + 'comma' => array( 1, 19 ), |
| 990 | + 'colon' => array( 1, 19 ), |
| 991 | + 'rightcurly' => array( 1, 19 ), |
| 992 | + ), |
| 993 | + 70 => array( |
| 994 | + 'semicolon' => array( 1, 20 ), |
| 995 | + 'rightbracket' => array( 1, 20 ), |
| 996 | + 'rightsquare' => array( 1, 20 ), |
| 997 | + 'comma' => array( 1, 20 ), |
| 998 | + 'colon' => array( 1, 20 ), |
| 999 | + 'rightcurly' => array( 1, 20 ), |
| 1000 | + ), |
| 1001 | + 71 => array( |
| 1002 | + 'leftbracket' => array( 1, 57 ), |
| 1003 | + 'rightbracket' => array( 1, 71 ), |
| 1004 | + 'setto' => array( 1, 71 ), |
| 1005 | + 'in' => array( 1, 71 ), |
| 1006 | + 'pow' => array( 1, 71 ), |
| 1007 | + 'equalsto' => array( 1, 71 ), |
| 1008 | + 'trinary' => array( 1, 71 ), |
| 1009 | + 'semicolon' => array( 1, 71 ), |
| 1010 | + 'colon' => array( 1, 71 ), |
| 1011 | + 'logicop' => array( 1, 71 ), |
| 1012 | + 'compareop' => array( 1, 71 ), |
| 1013 | + 'sum' => array( 1, 71 ), |
| 1014 | + 'mul' => array( 1, 71 ), |
| 1015 | + 'contains' => array( 1, 71 ), |
| 1016 | + 'leftsquare' => array( 1, 71 ), |
| 1017 | + 'doublecolon' => array( 1, 71 ), |
| 1018 | + 'rightsquare' => array( 1, 71 ), |
| 1019 | + 'comma' => array( 1, 71 ), |
| 1020 | + 'rightcurly' => array( 1, 71 ), |
| 1021 | + ), |
| 1022 | + 72 => array( |
| 1023 | + 'in' => array( 1, 48 ), |
| 1024 | + 'pow' => array( 1, 48 ), |
| 1025 | + 'equalsto' => array( 1, 48 ), |
| 1026 | + 'trinary' => array( 1, 48 ), |
| 1027 | + 'semicolon' => array( 1, 48 ), |
| 1028 | + 'rightbracket' => array( 1, 48 ), |
| 1029 | + 'colon' => array( 1, 48 ), |
| 1030 | + 'logicop' => array( 1, 48 ), |
| 1031 | + 'compareop' => array( 1, 48 ), |
| 1032 | + 'sum' => array( 1, 48 ), |
| 1033 | + 'mul' => array( 1, 48 ), |
| 1034 | + 'contains' => array( 1, 48 ), |
| 1035 | + 'doublecolon' => array( 1, 48 ), |
| 1036 | + 'rightsquare' => array( 1, 48 ), |
| 1037 | + 'comma' => array( 1, 48 ), |
| 1038 | + 'rightcurly' => array( 1, 48 ), |
| 1039 | + 'leftsquare' => array( 0, 82 ), |
| 1040 | + ), |
| 1041 | + 73 => array( |
| 1042 | + 'in' => array( 1, 42 ), |
| 1043 | + 'pow' => array( 1, 42 ), |
| 1044 | + 'equalsto' => array( 1, 42 ), |
| 1045 | + 'trinary' => array( 1, 42 ), |
| 1046 | + 'semicolon' => array( 1, 42 ), |
| 1047 | + 'rightbracket' => array( 1, 42 ), |
| 1048 | + 'colon' => array( 1, 42 ), |
| 1049 | + 'logicop' => array( 1, 42 ), |
| 1050 | + 'compareop' => array( 1, 42 ), |
| 1051 | + 'sum' => array( 1, 42 ), |
| 1052 | + 'mul' => array( 1, 42 ), |
| 1053 | + 'contains' => array( 1, 42 ), |
| 1054 | + 'rightsquare' => array( 1, 42 ), |
| 1055 | + 'comma' => array( 1, 42 ), |
| 1056 | + 'rightcurly' => array( 1, 42 ), |
| 1057 | + ), |
| 1058 | + 74 => array( |
| 1059 | + 'pow' => array( 1, 37 ), |
| 1060 | + 'equalsto' => array( 1, 37 ), |
| 1061 | + 'trinary' => array( 1, 37 ), |
| 1062 | + 'semicolon' => array( 1, 37 ), |
| 1063 | + 'rightbracket' => array( 1, 37 ), |
| 1064 | + 'colon' => array( 1, 37 ), |
| 1065 | + 'logicop' => array( 1, 37 ), |
| 1066 | + 'compareop' => array( 1, 37 ), |
| 1067 | + 'sum' => array( 1, 37 ), |
| 1068 | + 'mul' => array( 1, 37 ), |
| 1069 | + 'rightsquare' => array( 1, 37 ), |
| 1070 | + 'comma' => array( 1, 37 ), |
| 1071 | + 'rightcurly' => array( 1, 37 ), |
| 1072 | + ), |
| 1073 | + 75 => array( |
| 1074 | + 'rightbracket' => array( 1, 61 ), |
| 1075 | + 'rightsquare' => array( 1, 61 ), |
| 1076 | + 'comma' => array( 1, 61 ), |
| 1077 | + ), |
| 1078 | + 76 => array( |
| 1079 | + 'rightsquare' => array( 0, 109 ), |
| 1080 | + 'comma' => array( 0, 108 ), |
| 1081 | + ), |
| 1082 | + 77 => array( |
| 1083 | + 'id' => array( 0, 110 ), |
| 1084 | + ), |
| 1085 | + 78 => array( |
| 1086 | + 'function' => array( 1, 4 ), |
| 1087 | + '$' => array( 1, 4 ), |
| 1088 | + ), |
| 1089 | + 79 => array( |
| 1090 | + 'rightcurly' => array( 1, 7 ), |
| 1091 | + 'if' => array( 1, 7 ), |
| 1092 | + 'for' => array( 1, 7 ), |
| 1093 | + 'try' => array( 1, 7 ), |
| 1094 | + 'leftcurly' => array( 1, 7 ), |
| 1095 | + 'return' => array( 1, 7 ), |
| 1096 | + 'append' => array( 1, 7 ), |
| 1097 | + 'yield' => array( 1, 7 ), |
| 1098 | + 'id' => array( 1, 7 ), |
| 1099 | + 'invert' => array( 1, 7 ), |
| 1100 | + 'sum' => array( 1, 7 ), |
| 1101 | + 'break' => array( 1, 7 ), |
| 1102 | + 'continue' => array( 1, 7 ), |
| 1103 | + 'leftbracket' => array( 1, 7 ), |
| 1104 | + 'leftsquare' => array( 1, 7 ), |
| 1105 | + 'self' => array( 1, 7 ), |
| 1106 | + 'isset' => array( 1, 7 ), |
| 1107 | + 'delete' => array( 1, 7 ), |
| 1108 | + 'string' => array( 1, 7 ), |
| 1109 | + 'int' => array( 1, 7 ), |
| 1110 | + 'float' => array( 1, 7 ), |
| 1111 | + 'true' => array( 1, 7 ), |
| 1112 | + 'false' => array( 1, 7 ), |
| 1113 | + 'null' => array( 1, 7 ), |
| 1114 | + ), |
| 1115 | + 80 => array( |
| 1116 | + 'rightcurly' => array( 1, 9 ), |
| 1117 | + 'if' => array( 1, 9 ), |
| 1118 | + 'for' => array( 1, 9 ), |
| 1119 | + 'try' => array( 1, 9 ), |
| 1120 | + 'leftcurly' => array( 1, 9 ), |
| 1121 | + 'return' => array( 1, 9 ), |
| 1122 | + 'append' => array( 1, 9 ), |
| 1123 | + 'yield' => array( 1, 9 ), |
| 1124 | + 'id' => array( 1, 9 ), |
| 1125 | + 'invert' => array( 1, 9 ), |
| 1126 | + 'sum' => array( 1, 9 ), |
| 1127 | + 'break' => array( 1, 9 ), |
| 1128 | + 'continue' => array( 1, 9 ), |
| 1129 | + 'leftbracket' => array( 1, 9 ), |
| 1130 | + 'leftsquare' => array( 1, 9 ), |
| 1131 | + 'self' => array( 1, 9 ), |
| 1132 | + 'isset' => array( 1, 9 ), |
| 1133 | + 'delete' => array( 1, 9 ), |
| 1134 | + 'string' => array( 1, 9 ), |
| 1135 | + 'int' => array( 1, 9 ), |
| 1136 | + 'float' => array( 1, 9 ), |
| 1137 | + 'true' => array( 1, 9 ), |
| 1138 | + 'false' => array( 1, 9 ), |
| 1139 | + 'null' => array( 1, 9 ), |
| 1140 | + 'else' => array( 1, 9 ), |
| 1141 | + 'catch' => array( 1, 9 ), |
| 1142 | + ), |
| 1143 | + 81 => array( |
| 1144 | + 'id' => array( 0, 14 ), |
| 1145 | + 'invert' => array( 0, 24 ), |
| 1146 | + 'sum' => array( 0, 23 ), |
| 1147 | + 'self' => array( 0, 30 ), |
| 1148 | + 'isset' => array( 0, 28 ), |
| 1149 | + 'delete' => array( 0, 29 ), |
| 1150 | + 'break' => array( 0, 25 ), |
| 1151 | + 'continue' => array( 0, 26 ), |
| 1152 | + 'leftbracket' => array( 0, 15 ), |
| 1153 | + 'leftsquare' => array( 0, 27 ), |
| 1154 | + 'leftcurly' => array( 0, 59 ), |
| 1155 | + 'string' => array( 0, 31 ), |
| 1156 | + 'int' => array( 0, 32 ), |
| 1157 | + 'float' => array( 0, 33 ), |
| 1158 | + 'true' => array( 0, 34 ), |
| 1159 | + 'false' => array( 0, 35 ), |
| 1160 | + 'null' => array( 0, 36 ), |
| 1161 | + ), |
| 1162 | + 82 => array( |
| 1163 | + 'rightsquare' => array( 0, 112 ), |
| 1164 | + 'return' => array( 0, 20 ), |
| 1165 | + 'append' => array( 0, 21 ), |
| 1166 | + 'yield' => array( 0, 22 ), |
| 1167 | + 'id' => array( 0, 14 ), |
| 1168 | + 'invert' => array( 0, 24 ), |
| 1169 | + 'sum' => array( 0, 23 ), |
| 1170 | + 'self' => array( 0, 30 ), |
| 1171 | + 'isset' => array( 0, 28 ), |
| 1172 | + 'delete' => array( 0, 29 ), |
| 1173 | + 'break' => array( 0, 25 ), |
| 1174 | + 'continue' => array( 0, 26 ), |
| 1175 | + 'leftbracket' => array( 0, 15 ), |
| 1176 | + 'leftsquare' => array( 0, 27 ), |
| 1177 | + 'leftcurly' => array( 0, 59 ), |
| 1178 | + 'string' => array( 0, 31 ), |
| 1179 | + 'int' => array( 0, 32 ), |
| 1180 | + 'float' => array( 0, 33 ), |
| 1181 | + 'true' => array( 0, 34 ), |
| 1182 | + 'false' => array( 0, 35 ), |
| 1183 | + 'null' => array( 0, 36 ), |
| 1184 | + ), |
| 1185 | + 83 => array( |
| 1186 | + 'rightbracket' => array( 1, 72 ), |
| 1187 | + 'setto' => array( 1, 72 ), |
| 1188 | + 'in' => array( 1, 72 ), |
| 1189 | + 'pow' => array( 1, 72 ), |
| 1190 | + 'equalsto' => array( 1, 72 ), |
| 1191 | + 'trinary' => array( 1, 72 ), |
| 1192 | + 'semicolon' => array( 1, 72 ), |
| 1193 | + 'colon' => array( 1, 72 ), |
| 1194 | + 'logicop' => array( 1, 72 ), |
| 1195 | + 'compareop' => array( 1, 72 ), |
| 1196 | + 'sum' => array( 1, 72 ), |
| 1197 | + 'mul' => array( 1, 72 ), |
| 1198 | + 'contains' => array( 1, 72 ), |
| 1199 | + 'leftsquare' => array( 1, 72 ), |
| 1200 | + 'doublecolon' => array( 1, 72 ), |
| 1201 | + 'rightsquare' => array( 1, 72 ), |
| 1202 | + 'comma' => array( 1, 72 ), |
| 1203 | + 'rightcurly' => array( 1, 72 ), |
| 1204 | + ), |
| 1205 | + 84 => array( |
| 1206 | + 'invert' => array( 0, 24 ), |
| 1207 | + 'sum' => array( 0, 23 ), |
| 1208 | + 'id' => array( 0, 71 ), |
| 1209 | + 'self' => array( 0, 30 ), |
| 1210 | + 'isset' => array( 0, 28 ), |
| 1211 | + 'delete' => array( 0, 29 ), |
| 1212 | + 'break' => array( 0, 25 ), |
| 1213 | + 'continue' => array( 0, 26 ), |
| 1214 | + 'leftbracket' => array( 0, 15 ), |
| 1215 | + 'leftsquare' => array( 0, 27 ), |
| 1216 | + 'leftcurly' => array( 0, 59 ), |
| 1217 | + 'string' => array( 0, 31 ), |
| 1218 | + 'int' => array( 0, 32 ), |
| 1219 | + 'float' => array( 0, 33 ), |
| 1220 | + 'true' => array( 0, 34 ), |
| 1221 | + 'false' => array( 0, 35 ), |
| 1222 | + 'null' => array( 0, 36 ), |
| 1223 | + ), |
| 1224 | + 85 => array( |
| 1225 | + 'invert' => array( 0, 24 ), |
| 1226 | + 'sum' => array( 0, 23 ), |
| 1227 | + 'id' => array( 0, 71 ), |
| 1228 | + 'self' => array( 0, 30 ), |
| 1229 | + 'isset' => array( 0, 28 ), |
| 1230 | + 'delete' => array( 0, 29 ), |
| 1231 | + 'break' => array( 0, 25 ), |
| 1232 | + 'continue' => array( 0, 26 ), |
| 1233 | + 'leftbracket' => array( 0, 15 ), |
| 1234 | + 'leftsquare' => array( 0, 27 ), |
| 1235 | + 'leftcurly' => array( 0, 59 ), |
| 1236 | + 'string' => array( 0, 31 ), |
| 1237 | + 'int' => array( 0, 32 ), |
| 1238 | + 'float' => array( 0, 33 ), |
| 1239 | + 'true' => array( 0, 34 ), |
| 1240 | + 'false' => array( 0, 35 ), |
| 1241 | + 'null' => array( 0, 36 ), |
| 1242 | + ), |
| 1243 | + 86 => array( |
| 1244 | + 'invert' => array( 0, 24 ), |
| 1245 | + 'sum' => array( 0, 23 ), |
| 1246 | + 'id' => array( 0, 71 ), |
| 1247 | + 'self' => array( 0, 30 ), |
| 1248 | + 'isset' => array( 0, 28 ), |
| 1249 | + 'delete' => array( 0, 29 ), |
| 1250 | + 'break' => array( 0, 25 ), |
| 1251 | + 'continue' => array( 0, 26 ), |
| 1252 | + 'leftbracket' => array( 0, 15 ), |
| 1253 | + 'leftsquare' => array( 0, 27 ), |
| 1254 | + 'leftcurly' => array( 0, 59 ), |
| 1255 | + 'string' => array( 0, 31 ), |
| 1256 | + 'int' => array( 0, 32 ), |
| 1257 | + 'float' => array( 0, 33 ), |
| 1258 | + 'true' => array( 0, 34 ), |
| 1259 | + 'false' => array( 0, 35 ), |
| 1260 | + 'null' => array( 0, 36 ), |
| 1261 | + ), |
| 1262 | + 87 => array( |
| 1263 | + 'invert' => array( 0, 24 ), |
| 1264 | + 'sum' => array( 0, 23 ), |
| 1265 | + 'id' => array( 0, 71 ), |
| 1266 | + 'self' => array( 0, 30 ), |
| 1267 | + 'isset' => array( 0, 28 ), |
| 1268 | + 'delete' => array( 0, 29 ), |
| 1269 | + 'break' => array( 0, 25 ), |
| 1270 | + 'continue' => array( 0, 26 ), |
| 1271 | + 'leftbracket' => array( 0, 15 ), |
| 1272 | + 'leftsquare' => array( 0, 27 ), |
| 1273 | + 'leftcurly' => array( 0, 59 ), |
| 1274 | + 'string' => array( 0, 31 ), |
| 1275 | + 'int' => array( 0, 32 ), |
| 1276 | + 'float' => array( 0, 33 ), |
| 1277 | + 'true' => array( 0, 34 ), |
| 1278 | + 'false' => array( 0, 35 ), |
| 1279 | + 'null' => array( 0, 36 ), |
| 1280 | + ), |
| 1281 | + 88 => array( |
| 1282 | + 'invert' => array( 0, 24 ), |
| 1283 | + 'sum' => array( 0, 23 ), |
| 1284 | + 'id' => array( 0, 71 ), |
| 1285 | + 'self' => array( 0, 30 ), |
| 1286 | + 'isset' => array( 0, 28 ), |
| 1287 | + 'delete' => array( 0, 29 ), |
| 1288 | + 'break' => array( 0, 25 ), |
| 1289 | + 'continue' => array( 0, 26 ), |
| 1290 | + 'leftbracket' => array( 0, 15 ), |
| 1291 | + 'leftsquare' => array( 0, 27 ), |
| 1292 | + 'leftcurly' => array( 0, 59 ), |
| 1293 | + 'string' => array( 0, 31 ), |
| 1294 | + 'int' => array( 0, 32 ), |
| 1295 | + 'float' => array( 0, 33 ), |
| 1296 | + 'true' => array( 0, 34 ), |
| 1297 | + 'false' => array( 0, 35 ), |
| 1298 | + 'null' => array( 0, 36 ), |
| 1299 | + ), |
| 1300 | + 89 => array( |
| 1301 | + 'invert' => array( 0, 24 ), |
| 1302 | + 'sum' => array( 0, 23 ), |
| 1303 | + 'id' => array( 0, 71 ), |
| 1304 | + 'self' => array( 0, 30 ), |
| 1305 | + 'isset' => array( 0, 28 ), |
| 1306 | + 'delete' => array( 0, 29 ), |
| 1307 | + 'break' => array( 0, 25 ), |
| 1308 | + 'continue' => array( 0, 26 ), |
| 1309 | + 'leftbracket' => array( 0, 15 ), |
| 1310 | + 'leftsquare' => array( 0, 27 ), |
| 1311 | + 'leftcurly' => array( 0, 59 ), |
| 1312 | + 'string' => array( 0, 31 ), |
| 1313 | + 'int' => array( 0, 32 ), |
| 1314 | + 'float' => array( 0, 33 ), |
| 1315 | + 'true' => array( 0, 34 ), |
| 1316 | + 'false' => array( 0, 35 ), |
| 1317 | + 'null' => array( 0, 36 ), |
| 1318 | + ), |
| 1319 | + 90 => array( |
| 1320 | + 'invert' => array( 0, 24 ), |
| 1321 | + 'sum' => array( 0, 23 ), |
| 1322 | + 'id' => array( 0, 71 ), |
| 1323 | + 'self' => array( 0, 30 ), |
| 1324 | + 'isset' => array( 0, 28 ), |
| 1325 | + 'delete' => array( 0, 29 ), |
| 1326 | + 'break' => array( 0, 25 ), |
| 1327 | + 'continue' => array( 0, 26 ), |
| 1328 | + 'leftbracket' => array( 0, 15 ), |
| 1329 | + 'leftsquare' => array( 0, 27 ), |
| 1330 | + 'leftcurly' => array( 0, 59 ), |
| 1331 | + 'string' => array( 0, 31 ), |
| 1332 | + 'int' => array( 0, 32 ), |
| 1333 | + 'float' => array( 0, 33 ), |
| 1334 | + 'true' => array( 0, 34 ), |
| 1335 | + 'false' => array( 0, 35 ), |
| 1336 | + 'null' => array( 0, 36 ), |
| 1337 | + ), |
| 1338 | + 91 => array( |
| 1339 | + 'sum' => array( 0, 23 ), |
| 1340 | + 'id' => array( 0, 71 ), |
| 1341 | + 'self' => array( 0, 30 ), |
| 1342 | + 'isset' => array( 0, 28 ), |
| 1343 | + 'delete' => array( 0, 29 ), |
| 1344 | + 'break' => array( 0, 25 ), |
| 1345 | + 'continue' => array( 0, 26 ), |
| 1346 | + 'leftbracket' => array( 0, 15 ), |
| 1347 | + 'leftsquare' => array( 0, 27 ), |
| 1348 | + 'leftcurly' => array( 0, 59 ), |
| 1349 | + 'string' => array( 0, 31 ), |
| 1350 | + 'int' => array( 0, 32 ), |
| 1351 | + 'float' => array( 0, 33 ), |
| 1352 | + 'true' => array( 0, 34 ), |
| 1353 | + 'false' => array( 0, 35 ), |
| 1354 | + 'null' => array( 0, 36 ), |
| 1355 | + ), |
| 1356 | + 92 => array( |
| 1357 | + 'sum' => array( 0, 23 ), |
| 1358 | + 'id' => array( 0, 71 ), |
| 1359 | + 'self' => array( 0, 30 ), |
| 1360 | + 'isset' => array( 0, 28 ), |
| 1361 | + 'delete' => array( 0, 29 ), |
| 1362 | + 'break' => array( 0, 25 ), |
| 1363 | + 'continue' => array( 0, 26 ), |
| 1364 | + 'leftbracket' => array( 0, 15 ), |
| 1365 | + 'leftsquare' => array( 0, 27 ), |
| 1366 | + 'leftcurly' => array( 0, 59 ), |
| 1367 | + 'string' => array( 0, 31 ), |
| 1368 | + 'int' => array( 0, 32 ), |
| 1369 | + 'float' => array( 0, 33 ), |
| 1370 | + 'true' => array( 0, 34 ), |
| 1371 | + 'false' => array( 0, 35 ), |
| 1372 | + 'null' => array( 0, 36 ), |
| 1373 | + ), |
| 1374 | + 93 => array( |
| 1375 | + 'rightbracket' => array( 0, 123 ), |
| 1376 | + 'return' => array( 0, 20 ), |
| 1377 | + 'append' => array( 0, 21 ), |
| 1378 | + 'yield' => array( 0, 22 ), |
| 1379 | + 'id' => array( 0, 14 ), |
| 1380 | + 'invert' => array( 0, 24 ), |
| 1381 | + 'sum' => array( 0, 23 ), |
| 1382 | + 'self' => array( 0, 30 ), |
| 1383 | + 'isset' => array( 0, 28 ), |
| 1384 | + 'delete' => array( 0, 29 ), |
| 1385 | + 'break' => array( 0, 25 ), |
| 1386 | + 'continue' => array( 0, 26 ), |
| 1387 | + 'leftbracket' => array( 0, 15 ), |
| 1388 | + 'leftsquare' => array( 0, 27 ), |
| 1389 | + 'leftcurly' => array( 0, 59 ), |
| 1390 | + 'string' => array( 0, 31 ), |
| 1391 | + 'int' => array( 0, 32 ), |
| 1392 | + 'float' => array( 0, 33 ), |
| 1393 | + 'true' => array( 0, 34 ), |
| 1394 | + 'false' => array( 0, 35 ), |
| 1395 | + 'null' => array( 0, 36 ), |
| 1396 | + ), |
| 1397 | + 94 => array( |
| 1398 | + 'id' => array( 0, 104 ), |
| 1399 | + ), |
| 1400 | + 95 => array( |
| 1401 | + 'id' => array( 0, 126 ), |
| 1402 | + ), |
| 1403 | + 96 => array( |
| 1404 | + 'rightcurly' => array( 0, 127 ), |
| 1405 | + 'if' => array( 0, 17 ), |
| 1406 | + 'for' => array( 0, 18 ), |
| 1407 | + 'try' => array( 0, 19 ), |
| 1408 | + 'leftcurly' => array( 0, 16 ), |
| 1409 | + 'return' => array( 0, 20 ), |
| 1410 | + 'append' => array( 0, 21 ), |
| 1411 | + 'yield' => array( 0, 22 ), |
| 1412 | + 'id' => array( 0, 14 ), |
| 1413 | + 'invert' => array( 0, 24 ), |
| 1414 | + 'sum' => array( 0, 23 ), |
| 1415 | + 'self' => array( 0, 30 ), |
| 1416 | + 'isset' => array( 0, 28 ), |
| 1417 | + 'delete' => array( 0, 29 ), |
| 1418 | + 'break' => array( 0, 25 ), |
| 1419 | + 'continue' => array( 0, 26 ), |
| 1420 | + 'leftbracket' => array( 0, 15 ), |
| 1421 | + 'leftsquare' => array( 0, 27 ), |
| 1422 | + 'string' => array( 0, 31 ), |
| 1423 | + 'int' => array( 0, 32 ), |
| 1424 | + 'float' => array( 0, 33 ), |
| 1425 | + 'true' => array( 0, 34 ), |
| 1426 | + 'false' => array( 0, 35 ), |
| 1427 | + 'null' => array( 0, 36 ), |
| 1428 | + ), |
| 1429 | + 97 => array( |
| 1430 | + 'colon' => array( 0, 100 ), |
| 1431 | + ), |
| 1432 | + 98 => array( |
| 1433 | + 'in' => array( 1, 52 ), |
| 1434 | + 'pow' => array( 1, 52 ), |
| 1435 | + 'equalsto' => array( 1, 52 ), |
| 1436 | + 'trinary' => array( 1, 52 ), |
| 1437 | + 'semicolon' => array( 1, 52 ), |
| 1438 | + 'rightbracket' => array( 1, 52 ), |
| 1439 | + 'colon' => array( 1, 52 ), |
| 1440 | + 'logicop' => array( 1, 52 ), |
| 1441 | + 'compareop' => array( 1, 52 ), |
| 1442 | + 'sum' => array( 1, 52 ), |
| 1443 | + 'mul' => array( 1, 52 ), |
| 1444 | + 'contains' => array( 1, 52 ), |
| 1445 | + 'doublecolon' => array( 1, 52 ), |
| 1446 | + 'rightsquare' => array( 1, 52 ), |
| 1447 | + 'comma' => array( 1, 52 ), |
| 1448 | + 'rightcurly' => array( 1, 52 ), |
| 1449 | + ), |
| 1450 | + 99 => array( |
| 1451 | + 'rightcurly' => array( 1, 14 ), |
| 1452 | + 'if' => array( 1, 14 ), |
| 1453 | + 'for' => array( 1, 14 ), |
| 1454 | + 'try' => array( 1, 14 ), |
| 1455 | + 'leftcurly' => array( 1, 14 ), |
| 1456 | + 'return' => array( 1, 14 ), |
| 1457 | + 'append' => array( 1, 14 ), |
| 1458 | + 'yield' => array( 1, 14 ), |
| 1459 | + 'id' => array( 1, 14 ), |
| 1460 | + 'invert' => array( 1, 14 ), |
| 1461 | + 'sum' => array( 1, 14 ), |
| 1462 | + 'break' => array( 1, 14 ), |
| 1463 | + 'continue' => array( 1, 14 ), |
| 1464 | + 'leftbracket' => array( 1, 14 ), |
| 1465 | + 'leftsquare' => array( 1, 14 ), |
| 1466 | + 'self' => array( 1, 14 ), |
| 1467 | + 'isset' => array( 1, 14 ), |
| 1468 | + 'delete' => array( 1, 14 ), |
| 1469 | + 'string' => array( 1, 14 ), |
| 1470 | + 'int' => array( 1, 14 ), |
| 1471 | + 'float' => array( 1, 14 ), |
| 1472 | + 'true' => array( 1, 14 ), |
| 1473 | + 'false' => array( 1, 14 ), |
| 1474 | + 'null' => array( 1, 14 ), |
| 1475 | + 'else' => array( 1, 14 ), |
| 1476 | + 'catch' => array( 1, 14 ), |
| 1477 | + ), |
| 1478 | + 100 => array( |
| 1479 | + 'return' => array( 0, 20 ), |
| 1480 | + 'append' => array( 0, 21 ), |
| 1481 | + 'yield' => array( 0, 22 ), |
| 1482 | + 'id' => array( 0, 14 ), |
| 1483 | + 'invert' => array( 0, 24 ), |
| 1484 | + 'sum' => array( 0, 23 ), |
| 1485 | + 'self' => array( 0, 30 ), |
| 1486 | + 'isset' => array( 0, 28 ), |
| 1487 | + 'delete' => array( 0, 29 ), |
| 1488 | + 'break' => array( 0, 25 ), |
| 1489 | + 'continue' => array( 0, 26 ), |
| 1490 | + 'leftbracket' => array( 0, 15 ), |
| 1491 | + 'leftsquare' => array( 0, 27 ), |
| 1492 | + 'leftcurly' => array( 0, 59 ), |
| 1493 | + 'string' => array( 0, 31 ), |
| 1494 | + 'int' => array( 0, 32 ), |
| 1495 | + 'float' => array( 0, 33 ), |
| 1496 | + 'true' => array( 0, 34 ), |
| 1497 | + 'false' => array( 0, 35 ), |
| 1498 | + 'null' => array( 0, 36 ), |
| 1499 | + ), |
| 1500 | + 101 => array( |
| 1501 | + 'in' => array( 1, 54 ), |
| 1502 | + 'pow' => array( 1, 54 ), |
| 1503 | + 'equalsto' => array( 1, 54 ), |
| 1504 | + 'trinary' => array( 1, 54 ), |
| 1505 | + 'semicolon' => array( 1, 54 ), |
| 1506 | + 'rightbracket' => array( 1, 54 ), |
| 1507 | + 'colon' => array( 1, 54 ), |
| 1508 | + 'logicop' => array( 1, 54 ), |
| 1509 | + 'compareop' => array( 1, 54 ), |
| 1510 | + 'sum' => array( 1, 54 ), |
| 1511 | + 'mul' => array( 1, 54 ), |
| 1512 | + 'contains' => array( 1, 54 ), |
| 1513 | + 'doublecolon' => array( 1, 54 ), |
| 1514 | + 'rightsquare' => array( 1, 54 ), |
| 1515 | + 'comma' => array( 1, 54 ), |
| 1516 | + 'rightcurly' => array( 1, 54 ), |
| 1517 | + ), |
| 1518 | + 102 => array( |
| 1519 | + 'return' => array( 0, 20 ), |
| 1520 | + 'append' => array( 0, 21 ), |
| 1521 | + 'yield' => array( 0, 22 ), |
| 1522 | + 'id' => array( 0, 14 ), |
| 1523 | + 'invert' => array( 0, 24 ), |
| 1524 | + 'sum' => array( 0, 23 ), |
| 1525 | + 'self' => array( 0, 30 ), |
| 1526 | + 'isset' => array( 0, 28 ), |
| 1527 | + 'delete' => array( 0, 29 ), |
| 1528 | + 'break' => array( 0, 25 ), |
| 1529 | + 'continue' => array( 0, 26 ), |
| 1530 | + 'leftbracket' => array( 0, 15 ), |
| 1531 | + 'leftsquare' => array( 0, 27 ), |
| 1532 | + 'leftcurly' => array( 0, 59 ), |
| 1533 | + 'string' => array( 0, 31 ), |
| 1534 | + 'int' => array( 0, 32 ), |
| 1535 | + 'float' => array( 0, 33 ), |
| 1536 | + 'true' => array( 0, 34 ), |
| 1537 | + 'false' => array( 0, 35 ), |
| 1538 | + 'null' => array( 0, 36 ), |
| 1539 | + ), |
| 1540 | + 103 => array( |
| 1541 | + 'rightbracket' => array( 0, 130 ), |
| 1542 | + ), |
| 1543 | + 104 => array( |
| 1544 | + 'rightbracket' => array( 1, 71 ), |
| 1545 | + 'setto' => array( 1, 71 ), |
| 1546 | + 'in' => array( 1, 71 ), |
| 1547 | + 'pow' => array( 1, 71 ), |
| 1548 | + 'equalsto' => array( 1, 71 ), |
| 1549 | + 'trinary' => array( 1, 71 ), |
| 1550 | + 'semicolon' => array( 1, 71 ), |
| 1551 | + 'colon' => array( 1, 71 ), |
| 1552 | + 'logicop' => array( 1, 71 ), |
| 1553 | + 'compareop' => array( 1, 71 ), |
| 1554 | + 'sum' => array( 1, 71 ), |
| 1555 | + 'mul' => array( 1, 71 ), |
| 1556 | + 'contains' => array( 1, 71 ), |
| 1557 | + 'leftsquare' => array( 1, 71 ), |
| 1558 | + 'doublecolon' => array( 1, 71 ), |
| 1559 | + 'rightsquare' => array( 1, 71 ), |
| 1560 | + 'comma' => array( 1, 71 ), |
| 1561 | + 'rightcurly' => array( 1, 71 ), |
| 1562 | + ), |
| 1563 | + 105 => array( |
| 1564 | + 'in' => array( 0, 131 ), |
| 1565 | + ), |
| 1566 | + 106 => array( |
| 1567 | + 'in' => array( 1, 75 ), |
| 1568 | + 'colon' => array( 0, 132 ), |
| 1569 | + 'leftsquare' => array( 0, 82 ), |
| 1570 | + ), |
| 1571 | + 107 => array( |
| 1572 | + 'leftbracket' => array( 0, 133 ), |
| 1573 | + ), |
| 1574 | + 108 => array( |
| 1575 | + 'return' => array( 0, 20 ), |
| 1576 | + 'append' => array( 0, 21 ), |
| 1577 | + 'yield' => array( 0, 22 ), |
| 1578 | + 'id' => array( 0, 14 ), |
| 1579 | + 'invert' => array( 0, 24 ), |
| 1580 | + 'sum' => array( 0, 23 ), |
| 1581 | + 'self' => array( 0, 30 ), |
| 1582 | + 'isset' => array( 0, 28 ), |
| 1583 | + 'delete' => array( 0, 29 ), |
| 1584 | + 'break' => array( 0, 25 ), |
| 1585 | + 'continue' => array( 0, 26 ), |
| 1586 | + 'leftbracket' => array( 0, 15 ), |
| 1587 | + 'leftsquare' => array( 0, 27 ), |
| 1588 | + 'leftcurly' => array( 0, 59 ), |
| 1589 | + 'string' => array( 0, 31 ), |
| 1590 | + 'int' => array( 0, 32 ), |
| 1591 | + 'float' => array( 0, 33 ), |
| 1592 | + 'true' => array( 0, 34 ), |
| 1593 | + 'false' => array( 0, 35 ), |
| 1594 | + 'null' => array( 0, 36 ), |
| 1595 | + ), |
| 1596 | + 109 => array( |
| 1597 | + 'in' => array( 1, 53 ), |
| 1598 | + 'pow' => array( 1, 53 ), |
| 1599 | + 'equalsto' => array( 1, 53 ), |
| 1600 | + 'trinary' => array( 1, 53 ), |
| 1601 | + 'semicolon' => array( 1, 53 ), |
| 1602 | + 'rightbracket' => array( 1, 53 ), |
| 1603 | + 'colon' => array( 1, 53 ), |
| 1604 | + 'logicop' => array( 1, 53 ), |
| 1605 | + 'compareop' => array( 1, 53 ), |
| 1606 | + 'sum' => array( 1, 53 ), |
| 1607 | + 'mul' => array( 1, 53 ), |
| 1608 | + 'contains' => array( 1, 53 ), |
| 1609 | + 'doublecolon' => array( 1, 53 ), |
| 1610 | + 'rightsquare' => array( 1, 53 ), |
| 1611 | + 'comma' => array( 1, 53 ), |
| 1612 | + 'rightcurly' => array( 1, 53 ), |
| 1613 | + ), |
| 1614 | + 110 => array( |
| 1615 | + 'leftbracket' => array( 1, 59 ), |
| 1616 | + ), |
| 1617 | + 111 => array( |
| 1618 | + 'semicolon' => array( 1, 21 ), |
| 1619 | + 'rightbracket' => array( 1, 21 ), |
| 1620 | + 'rightsquare' => array( 1, 21 ), |
| 1621 | + 'comma' => array( 1, 21 ), |
| 1622 | + 'colon' => array( 1, 21 ), |
| 1623 | + 'rightcurly' => array( 1, 21 ), |
| 1624 | + ), |
| 1625 | + 112 => array( |
| 1626 | + 'rightbracket' => array( 1, 74 ), |
| 1627 | + 'setto' => array( 1, 74 ), |
| 1628 | + 'in' => array( 1, 74 ), |
| 1629 | + 'pow' => array( 1, 74 ), |
| 1630 | + 'equalsto' => array( 1, 74 ), |
| 1631 | + 'trinary' => array( 1, 74 ), |
| 1632 | + 'semicolon' => array( 1, 74 ), |
| 1633 | + 'colon' => array( 1, 74 ), |
| 1634 | + 'logicop' => array( 1, 74 ), |
| 1635 | + 'compareop' => array( 1, 74 ), |
| 1636 | + 'sum' => array( 1, 74 ), |
| 1637 | + 'mul' => array( 1, 74 ), |
| 1638 | + 'contains' => array( 1, 74 ), |
| 1639 | + 'leftsquare' => array( 1, 74 ), |
| 1640 | + 'doublecolon' => array( 1, 74 ), |
| 1641 | + 'rightsquare' => array( 1, 74 ), |
| 1642 | + 'comma' => array( 1, 74 ), |
| 1643 | + 'rightcurly' => array( 1, 74 ), |
| 1644 | + ), |
| 1645 | + 113 => array( |
| 1646 | + 'rightsquare' => array( 0, 135 ), |
| 1647 | + ), |
| 1648 | + 114 => array( |
| 1649 | + 'colon' => array( 0, 136 ), |
| 1650 | + ), |
| 1651 | + 115 => array( |
| 1652 | + 'trinary' => array( 1, 25 ), |
| 1653 | + 'semicolon' => array( 1, 25 ), |
| 1654 | + 'rightbracket' => array( 1, 25 ), |
| 1655 | + 'colon' => array( 1, 25 ), |
| 1656 | + 'logicop' => array( 1, 25 ), |
| 1657 | + 'rightsquare' => array( 1, 25 ), |
| 1658 | + 'comma' => array( 1, 25 ), |
| 1659 | + 'rightcurly' => array( 1, 25 ), |
| 1660 | + 'compareop' => array( 0, 86 ), |
| 1661 | + ), |
| 1662 | + 116 => array( |
| 1663 | + 'trinary' => array( 1, 27 ), |
| 1664 | + 'semicolon' => array( 1, 27 ), |
| 1665 | + 'rightbracket' => array( 1, 27 ), |
| 1666 | + 'colon' => array( 1, 27 ), |
| 1667 | + 'logicop' => array( 1, 27 ), |
| 1668 | + 'compareop' => array( 1, 27 ), |
| 1669 | + 'rightsquare' => array( 1, 27 ), |
| 1670 | + 'comma' => array( 1, 27 ), |
| 1671 | + 'rightcurly' => array( 1, 27 ), |
| 1672 | + ), |
| 1673 | + 117 => array( |
| 1674 | + 'trinary' => array( 1, 29 ), |
| 1675 | + 'semicolon' => array( 1, 29 ), |
| 1676 | + 'rightbracket' => array( 1, 29 ), |
| 1677 | + 'colon' => array( 1, 29 ), |
| 1678 | + 'logicop' => array( 1, 29 ), |
| 1679 | + 'compareop' => array( 1, 29 ), |
| 1680 | + 'rightsquare' => array( 1, 29 ), |
| 1681 | + 'comma' => array( 1, 29 ), |
| 1682 | + 'rightcurly' => array( 1, 29 ), |
| 1683 | + 'sum' => array( 0, 88 ), |
| 1684 | + ), |
| 1685 | + 118 => array( |
| 1686 | + 'equalsto' => array( 1, 31 ), |
| 1687 | + 'trinary' => array( 1, 31 ), |
| 1688 | + 'semicolon' => array( 1, 31 ), |
| 1689 | + 'rightbracket' => array( 1, 31 ), |
| 1690 | + 'colon' => array( 1, 31 ), |
| 1691 | + 'logicop' => array( 1, 31 ), |
| 1692 | + 'compareop' => array( 1, 31 ), |
| 1693 | + 'sum' => array( 1, 31 ), |
| 1694 | + 'rightsquare' => array( 1, 31 ), |
| 1695 | + 'comma' => array( 1, 31 ), |
| 1696 | + 'rightcurly' => array( 1, 31 ), |
| 1697 | + 'mul' => array( 0, 89 ), |
| 1698 | + ), |
| 1699 | + 119 => array( |
| 1700 | + 'equalsto' => array( 1, 33 ), |
| 1701 | + 'trinary' => array( 1, 33 ), |
| 1702 | + 'semicolon' => array( 1, 33 ), |
| 1703 | + 'rightbracket' => array( 1, 33 ), |
| 1704 | + 'colon' => array( 1, 33 ), |
| 1705 | + 'logicop' => array( 1, 33 ), |
| 1706 | + 'compareop' => array( 1, 33 ), |
| 1707 | + 'sum' => array( 1, 33 ), |
| 1708 | + 'mul' => array( 1, 33 ), |
| 1709 | + 'rightsquare' => array( 1, 33 ), |
| 1710 | + 'comma' => array( 1, 33 ), |
| 1711 | + 'rightcurly' => array( 1, 33 ), |
| 1712 | + ), |
| 1713 | + 120 => array( |
| 1714 | + 'equalsto' => array( 1, 35 ), |
| 1715 | + 'trinary' => array( 1, 35 ), |
| 1716 | + 'semicolon' => array( 1, 35 ), |
| 1717 | + 'rightbracket' => array( 1, 35 ), |
| 1718 | + 'colon' => array( 1, 35 ), |
| 1719 | + 'logicop' => array( 1, 35 ), |
| 1720 | + 'compareop' => array( 1, 35 ), |
| 1721 | + 'sum' => array( 1, 35 ), |
| 1722 | + 'mul' => array( 1, 35 ), |
| 1723 | + 'rightsquare' => array( 1, 35 ), |
| 1724 | + 'comma' => array( 1, 35 ), |
| 1725 | + 'rightcurly' => array( 1, 35 ), |
| 1726 | + ), |
| 1727 | + 121 => array( |
| 1728 | + 'pow' => array( 1, 39 ), |
| 1729 | + 'equalsto' => array( 1, 39 ), |
| 1730 | + 'trinary' => array( 1, 39 ), |
| 1731 | + 'semicolon' => array( 1, 39 ), |
| 1732 | + 'rightbracket' => array( 1, 39 ), |
| 1733 | + 'colon' => array( 1, 39 ), |
| 1734 | + 'logicop' => array( 1, 39 ), |
| 1735 | + 'compareop' => array( 1, 39 ), |
| 1736 | + 'sum' => array( 1, 39 ), |
| 1737 | + 'mul' => array( 1, 39 ), |
| 1738 | + 'rightsquare' => array( 1, 39 ), |
| 1739 | + 'comma' => array( 1, 39 ), |
| 1740 | + 'rightcurly' => array( 1, 39 ), |
| 1741 | + ), |
| 1742 | + 122 => array( |
| 1743 | + 'pow' => array( 1, 40 ), |
| 1744 | + 'equalsto' => array( 1, 40 ), |
| 1745 | + 'trinary' => array( 1, 40 ), |
| 1746 | + 'semicolon' => array( 1, 40 ), |
| 1747 | + 'rightbracket' => array( 1, 40 ), |
| 1748 | + 'colon' => array( 1, 40 ), |
| 1749 | + 'logicop' => array( 1, 40 ), |
| 1750 | + 'compareop' => array( 1, 40 ), |
| 1751 | + 'sum' => array( 1, 40 ), |
| 1752 | + 'mul' => array( 1, 40 ), |
| 1753 | + 'rightsquare' => array( 1, 40 ), |
| 1754 | + 'comma' => array( 1, 40 ), |
| 1755 | + 'rightcurly' => array( 1, 40 ), |
| 1756 | + ), |
| 1757 | + 123 => array( |
| 1758 | + 'in' => array( 1, 45 ), |
| 1759 | + 'pow' => array( 1, 45 ), |
| 1760 | + 'equalsto' => array( 1, 45 ), |
| 1761 | + 'trinary' => array( 1, 45 ), |
| 1762 | + 'semicolon' => array( 1, 45 ), |
| 1763 | + 'rightbracket' => array( 1, 45 ), |
| 1764 | + 'colon' => array( 1, 45 ), |
| 1765 | + 'logicop' => array( 1, 45 ), |
| 1766 | + 'compareop' => array( 1, 45 ), |
| 1767 | + 'sum' => array( 1, 45 ), |
| 1768 | + 'mul' => array( 1, 45 ), |
| 1769 | + 'contains' => array( 1, 45 ), |
| 1770 | + 'rightsquare' => array( 1, 45 ), |
| 1771 | + 'comma' => array( 1, 45 ), |
| 1772 | + 'rightcurly' => array( 1, 45 ), |
| 1773 | + ), |
| 1774 | + 124 => array( |
| 1775 | + 'rightbracket' => array( 0, 137 ), |
| 1776 | + 'comma' => array( 0, 108 ), |
| 1777 | + ), |
| 1778 | + 125 => array( |
| 1779 | + 'rightbracket' => array( 0, 138 ), |
| 1780 | + 'leftsquare' => array( 0, 82 ), |
| 1781 | + ), |
| 1782 | + 126 => array( |
| 1783 | + 'leftbracket' => array( 1, 58 ), |
| 1784 | + ), |
| 1785 | + 127 => array( |
| 1786 | + 'function' => array( 1, 3 ), |
| 1787 | + '$' => array( 1, 3 ), |
| 1788 | + ), |
| 1789 | + 128 => array( |
| 1790 | + 'rightcurly' => array( 1, 64 ), |
| 1791 | + 'comma' => array( 1, 64 ), |
| 1792 | + ), |
| 1793 | + 129 => array( |
| 1794 | + 'rightcurly' => array( 1, 62 ), |
| 1795 | + 'comma' => array( 1, 62 ), |
| 1796 | + ), |
| 1797 | + 130 => array( |
| 1798 | + 'if' => array( 0, 17 ), |
| 1799 | + 'for' => array( 0, 18 ), |
| 1800 | + 'try' => array( 0, 19 ), |
| 1801 | + 'leftcurly' => array( 0, 16 ), |
| 1802 | + 'return' => array( 0, 20 ), |
| 1803 | + 'append' => array( 0, 21 ), |
| 1804 | + 'yield' => array( 0, 22 ), |
| 1805 | + 'id' => array( 0, 14 ), |
| 1806 | + 'invert' => array( 0, 24 ), |
| 1807 | + 'sum' => array( 0, 23 ), |
| 1808 | + 'self' => array( 0, 30 ), |
| 1809 | + 'isset' => array( 0, 28 ), |
| 1810 | + 'delete' => array( 0, 29 ), |
| 1811 | + 'break' => array( 0, 25 ), |
| 1812 | + 'continue' => array( 0, 26 ), |
| 1813 | + 'leftbracket' => array( 0, 15 ), |
| 1814 | + 'leftsquare' => array( 0, 27 ), |
| 1815 | + 'string' => array( 0, 31 ), |
| 1816 | + 'int' => array( 0, 32 ), |
| 1817 | + 'float' => array( 0, 33 ), |
| 1818 | + 'true' => array( 0, 34 ), |
| 1819 | + 'false' => array( 0, 35 ), |
| 1820 | + 'null' => array( 0, 36 ), |
| 1821 | + ), |
| 1822 | + 131 => array( |
| 1823 | + 'return' => array( 0, 20 ), |
| 1824 | + 'append' => array( 0, 21 ), |
| 1825 | + 'yield' => array( 0, 22 ), |
| 1826 | + 'id' => array( 0, 14 ), |
| 1827 | + 'invert' => array( 0, 24 ), |
| 1828 | + 'sum' => array( 0, 23 ), |
| 1829 | + 'self' => array( 0, 30 ), |
| 1830 | + 'isset' => array( 0, 28 ), |
| 1831 | + 'delete' => array( 0, 29 ), |
| 1832 | + 'break' => array( 0, 25 ), |
| 1833 | + 'continue' => array( 0, 26 ), |
| 1834 | + 'leftbracket' => array( 0, 15 ), |
| 1835 | + 'leftsquare' => array( 0, 27 ), |
| 1836 | + 'leftcurly' => array( 0, 59 ), |
| 1837 | + 'string' => array( 0, 31 ), |
| 1838 | + 'int' => array( 0, 32 ), |
| 1839 | + 'float' => array( 0, 33 ), |
| 1840 | + 'true' => array( 0, 34 ), |
| 1841 | + 'false' => array( 0, 35 ), |
| 1842 | + 'null' => array( 0, 36 ), |
| 1843 | + ), |
| 1844 | + 132 => array( |
| 1845 | + 'id' => array( 0, 104 ), |
| 1846 | + ), |
| 1847 | + 133 => array( |
| 1848 | + 'id' => array( 0, 104 ), |
| 1849 | + ), |
| 1850 | + 134 => array( |
| 1851 | + 'rightbracket' => array( 1, 60 ), |
| 1852 | + 'rightsquare' => array( 1, 60 ), |
| 1853 | + 'comma' => array( 1, 60 ), |
| 1854 | + ), |
| 1855 | + 135 => array( |
| 1856 | + 'rightbracket' => array( 1, 73 ), |
| 1857 | + 'setto' => array( 1, 73 ), |
| 1858 | + 'in' => array( 1, 73 ), |
| 1859 | + 'pow' => array( 1, 73 ), |
| 1860 | + 'equalsto' => array( 1, 73 ), |
| 1861 | + 'trinary' => array( 1, 73 ), |
| 1862 | + 'semicolon' => array( 1, 73 ), |
| 1863 | + 'colon' => array( 1, 73 ), |
| 1864 | + 'logicop' => array( 1, 73 ), |
| 1865 | + 'compareop' => array( 1, 73 ), |
| 1866 | + 'sum' => array( 1, 73 ), |
| 1867 | + 'mul' => array( 1, 73 ), |
| 1868 | + 'contains' => array( 1, 73 ), |
| 1869 | + 'leftsquare' => array( 1, 73 ), |
| 1870 | + 'doublecolon' => array( 1, 73 ), |
| 1871 | + 'rightsquare' => array( 1, 73 ), |
| 1872 | + 'comma' => array( 1, 73 ), |
| 1873 | + 'rightcurly' => array( 1, 73 ), |
| 1874 | + ), |
| 1875 | + 136 => array( |
| 1876 | + 'invert' => array( 0, 24 ), |
| 1877 | + 'sum' => array( 0, 23 ), |
| 1878 | + 'id' => array( 0, 71 ), |
| 1879 | + 'self' => array( 0, 30 ), |
| 1880 | + 'isset' => array( 0, 28 ), |
| 1881 | + 'delete' => array( 0, 29 ), |
| 1882 | + 'break' => array( 0, 25 ), |
| 1883 | + 'continue' => array( 0, 26 ), |
| 1884 | + 'leftbracket' => array( 0, 15 ), |
| 1885 | + 'leftsquare' => array( 0, 27 ), |
| 1886 | + 'leftcurly' => array( 0, 59 ), |
| 1887 | + 'string' => array( 0, 31 ), |
| 1888 | + 'int' => array( 0, 32 ), |
| 1889 | + 'float' => array( 0, 33 ), |
| 1890 | + 'true' => array( 0, 34 ), |
| 1891 | + 'false' => array( 0, 35 ), |
| 1892 | + 'null' => array( 0, 36 ), |
| 1893 | + ), |
| 1894 | + 137 => array( |
| 1895 | + 'in' => array( 1, 44 ), |
| 1896 | + 'pow' => array( 1, 44 ), |
| 1897 | + 'equalsto' => array( 1, 44 ), |
| 1898 | + 'trinary' => array( 1, 44 ), |
| 1899 | + 'semicolon' => array( 1, 44 ), |
| 1900 | + 'rightbracket' => array( 1, 44 ), |
| 1901 | + 'colon' => array( 1, 44 ), |
| 1902 | + 'logicop' => array( 1, 44 ), |
| 1903 | + 'compareop' => array( 1, 44 ), |
| 1904 | + 'sum' => array( 1, 44 ), |
| 1905 | + 'mul' => array( 1, 44 ), |
| 1906 | + 'contains' => array( 1, 44 ), |
| 1907 | + 'rightsquare' => array( 1, 44 ), |
| 1908 | + 'comma' => array( 1, 44 ), |
| 1909 | + 'rightcurly' => array( 1, 44 ), |
| 1910 | + ), |
| 1911 | + 138 => array( |
| 1912 | + 'in' => array( 1, 46 ), |
| 1913 | + 'pow' => array( 1, 46 ), |
| 1914 | + 'equalsto' => array( 1, 46 ), |
| 1915 | + 'trinary' => array( 1, 46 ), |
| 1916 | + 'semicolon' => array( 1, 46 ), |
| 1917 | + 'rightbracket' => array( 1, 46 ), |
| 1918 | + 'colon' => array( 1, 46 ), |
| 1919 | + 'logicop' => array( 1, 46 ), |
| 1920 | + 'compareop' => array( 1, 46 ), |
| 1921 | + 'sum' => array( 1, 46 ), |
| 1922 | + 'mul' => array( 1, 46 ), |
| 1923 | + 'contains' => array( 1, 46 ), |
| 1924 | + 'rightsquare' => array( 1, 46 ), |
| 1925 | + 'comma' => array( 1, 46 ), |
| 1926 | + 'rightcurly' => array( 1, 46 ), |
| 1927 | + ), |
| 1928 | + 139 => array( |
| 1929 | + 'rightcurly' => array( 1, 10 ), |
| 1930 | + 'if' => array( 1, 10 ), |
| 1931 | + 'for' => array( 1, 10 ), |
| 1932 | + 'try' => array( 1, 10 ), |
| 1933 | + 'leftcurly' => array( 1, 10 ), |
| 1934 | + 'return' => array( 1, 10 ), |
| 1935 | + 'append' => array( 1, 10 ), |
| 1936 | + 'yield' => array( 1, 10 ), |
| 1937 | + 'id' => array( 1, 10 ), |
| 1938 | + 'invert' => array( 1, 10 ), |
| 1939 | + 'sum' => array( 1, 10 ), |
| 1940 | + 'break' => array( 1, 10 ), |
| 1941 | + 'continue' => array( 1, 10 ), |
| 1942 | + 'leftbracket' => array( 1, 10 ), |
| 1943 | + 'leftsquare' => array( 1, 10 ), |
| 1944 | + 'self' => array( 1, 10 ), |
| 1945 | + 'isset' => array( 1, 10 ), |
| 1946 | + 'delete' => array( 1, 10 ), |
| 1947 | + 'string' => array( 1, 10 ), |
| 1948 | + 'int' => array( 1, 10 ), |
| 1949 | + 'float' => array( 1, 10 ), |
| 1950 | + 'true' => array( 1, 10 ), |
| 1951 | + 'false' => array( 1, 10 ), |
| 1952 | + 'null' => array( 1, 10 ), |
| 1953 | + 'else' => array( 0, 144 ), |
| 1954 | + 'catch' => array( 1, 10 ), |
| 1955 | + ), |
| 1956 | + 140 => array( |
| 1957 | + 'rightbracket' => array( 0, 145 ), |
| 1958 | + ), |
| 1959 | + 141 => array( |
| 1960 | + 'in' => array( 1, 76 ), |
| 1961 | + 'leftsquare' => array( 0, 82 ), |
| 1962 | + ), |
| 1963 | + 142 => array( |
| 1964 | + 'rightbracket' => array( 0, 146 ), |
| 1965 | + 'leftsquare' => array( 0, 82 ), |
| 1966 | + ), |
| 1967 | + 143 => array( |
| 1968 | + 'semicolon' => array( 1, 23 ), |
| 1969 | + 'rightbracket' => array( 1, 23 ), |
| 1970 | + 'colon' => array( 1, 23 ), |
| 1971 | + 'rightsquare' => array( 1, 23 ), |
| 1972 | + 'comma' => array( 1, 23 ), |
| 1973 | + 'rightcurly' => array( 1, 23 ), |
| 1974 | + ), |
| 1975 | + 144 => array( |
| 1976 | + 'if' => array( 0, 17 ), |
| 1977 | + 'for' => array( 0, 18 ), |
| 1978 | + 'try' => array( 0, 19 ), |
| 1979 | + 'leftcurly' => array( 0, 16 ), |
| 1980 | + 'return' => array( 0, 20 ), |
| 1981 | + 'append' => array( 0, 21 ), |
| 1982 | + 'yield' => array( 0, 22 ), |
| 1983 | + 'id' => array( 0, 14 ), |
| 1984 | + 'invert' => array( 0, 24 ), |
| 1985 | + 'sum' => array( 0, 23 ), |
| 1986 | + 'self' => array( 0, 30 ), |
| 1987 | + 'isset' => array( 0, 28 ), |
| 1988 | + 'delete' => array( 0, 29 ), |
| 1989 | + 'break' => array( 0, 25 ), |
| 1990 | + 'continue' => array( 0, 26 ), |
| 1991 | + 'leftbracket' => array( 0, 15 ), |
| 1992 | + 'leftsquare' => array( 0, 27 ), |
| 1993 | + 'string' => array( 0, 31 ), |
| 1994 | + 'int' => array( 0, 32 ), |
| 1995 | + 'float' => array( 0, 33 ), |
| 1996 | + 'true' => array( 0, 34 ), |
| 1997 | + 'false' => array( 0, 35 ), |
| 1998 | + 'null' => array( 0, 36 ), |
| 1999 | + ), |
| 2000 | + 145 => array( |
| 2001 | + 'if' => array( 0, 17 ), |
| 2002 | + 'for' => array( 0, 18 ), |
| 2003 | + 'try' => array( 0, 19 ), |
| 2004 | + 'leftcurly' => array( 0, 16 ), |
| 2005 | + 'return' => array( 0, 20 ), |
| 2006 | + 'append' => array( 0, 21 ), |
| 2007 | + 'yield' => array( 0, 22 ), |
| 2008 | + 'id' => array( 0, 14 ), |
| 2009 | + 'invert' => array( 0, 24 ), |
| 2010 | + 'sum' => array( 0, 23 ), |
| 2011 | + 'self' => array( 0, 30 ), |
| 2012 | + 'isset' => array( 0, 28 ), |
| 2013 | + 'delete' => array( 0, 29 ), |
| 2014 | + 'break' => array( 0, 25 ), |
| 2015 | + 'continue' => array( 0, 26 ), |
| 2016 | + 'leftbracket' => array( 0, 15 ), |
| 2017 | + 'leftsquare' => array( 0, 27 ), |
| 2018 | + 'string' => array( 0, 31 ), |
| 2019 | + 'int' => array( 0, 32 ), |
| 2020 | + 'float' => array( 0, 33 ), |
| 2021 | + 'true' => array( 0, 34 ), |
| 2022 | + 'false' => array( 0, 35 ), |
| 2023 | + 'null' => array( 0, 36 ), |
| 2024 | + ), |
| 2025 | + 146 => array( |
| 2026 | + 'if' => array( 0, 17 ), |
| 2027 | + 'for' => array( 0, 18 ), |
| 2028 | + 'try' => array( 0, 19 ), |
| 2029 | + 'leftcurly' => array( 0, 16 ), |
| 2030 | + 'return' => array( 0, 20 ), |
| 2031 | + 'append' => array( 0, 21 ), |
| 2032 | + 'yield' => array( 0, 22 ), |
| 2033 | + 'id' => array( 0, 14 ), |
| 2034 | + 'invert' => array( 0, 24 ), |
| 2035 | + 'sum' => array( 0, 23 ), |
| 2036 | + 'self' => array( 0, 30 ), |
| 2037 | + 'isset' => array( 0, 28 ), |
| 2038 | + 'delete' => array( 0, 29 ), |
| 2039 | + 'break' => array( 0, 25 ), |
| 2040 | + 'continue' => array( 0, 26 ), |
| 2041 | + 'leftbracket' => array( 0, 15 ), |
| 2042 | + 'leftsquare' => array( 0, 27 ), |
| 2043 | + 'string' => array( 0, 31 ), |
| 2044 | + 'int' => array( 0, 32 ), |
| 2045 | + 'float' => array( 0, 33 ), |
| 2046 | + 'true' => array( 0, 34 ), |
| 2047 | + 'false' => array( 0, 35 ), |
| 2048 | + 'null' => array( 0, 36 ), |
| 2049 | + ), |
| 2050 | + 147 => array( |
| 2051 | + 'rightcurly' => array( 1, 11 ), |
| 2052 | + 'if' => array( 1, 11 ), |
| 2053 | + 'for' => array( 1, 11 ), |
| 2054 | + 'try' => array( 1, 11 ), |
| 2055 | + 'leftcurly' => array( 1, 11 ), |
| 2056 | + 'return' => array( 1, 11 ), |
| 2057 | + 'append' => array( 1, 11 ), |
| 2058 | + 'yield' => array( 1, 11 ), |
| 2059 | + 'id' => array( 1, 11 ), |
| 2060 | + 'invert' => array( 1, 11 ), |
| 2061 | + 'sum' => array( 1, 11 ), |
| 2062 | + 'break' => array( 1, 11 ), |
| 2063 | + 'continue' => array( 1, 11 ), |
| 2064 | + 'leftbracket' => array( 1, 11 ), |
| 2065 | + 'leftsquare' => array( 1, 11 ), |
| 2066 | + 'self' => array( 1, 11 ), |
| 2067 | + 'isset' => array( 1, 11 ), |
| 2068 | + 'delete' => array( 1, 11 ), |
| 2069 | + 'string' => array( 1, 11 ), |
| 2070 | + 'int' => array( 1, 11 ), |
| 2071 | + 'float' => array( 1, 11 ), |
| 2072 | + 'true' => array( 1, 11 ), |
| 2073 | + 'false' => array( 1, 11 ), |
| 2074 | + 'null' => array( 1, 11 ), |
| 2075 | + 'else' => array( 1, 11 ), |
| 2076 | + 'catch' => array( 1, 11 ), |
| 2077 | + ), |
| 2078 | + 148 => array( |
| 2079 | + 'rightcurly' => array( 1, 12 ), |
| 2080 | + 'if' => array( 1, 12 ), |
| 2081 | + 'for' => array( 1, 12 ), |
| 2082 | + 'try' => array( 1, 12 ), |
| 2083 | + 'leftcurly' => array( 1, 12 ), |
| 2084 | + 'return' => array( 1, 12 ), |
| 2085 | + 'append' => array( 1, 12 ), |
| 2086 | + 'yield' => array( 1, 12 ), |
| 2087 | + 'id' => array( 1, 12 ), |
| 2088 | + 'invert' => array( 1, 12 ), |
| 2089 | + 'sum' => array( 1, 12 ), |
| 2090 | + 'break' => array( 1, 12 ), |
| 2091 | + 'continue' => array( 1, 12 ), |
| 2092 | + 'leftbracket' => array( 1, 12 ), |
| 2093 | + 'leftsquare' => array( 1, 12 ), |
| 2094 | + 'self' => array( 1, 12 ), |
| 2095 | + 'isset' => array( 1, 12 ), |
| 2096 | + 'delete' => array( 1, 12 ), |
| 2097 | + 'string' => array( 1, 12 ), |
| 2098 | + 'int' => array( 1, 12 ), |
| 2099 | + 'float' => array( 1, 12 ), |
| 2100 | + 'true' => array( 1, 12 ), |
| 2101 | + 'false' => array( 1, 12 ), |
| 2102 | + 'null' => array( 1, 12 ), |
| 2103 | + 'else' => array( 1, 12 ), |
| 2104 | + 'catch' => array( 1, 12 ), |
| 2105 | + ), |
| 2106 | + 149 => array( |
| 2107 | + 'rightcurly' => array( 1, 13 ), |
| 2108 | + 'if' => array( 1, 13 ), |
| 2109 | + 'for' => array( 1, 13 ), |
| 2110 | + 'try' => array( 1, 13 ), |
| 2111 | + 'leftcurly' => array( 1, 13 ), |
| 2112 | + 'return' => array( 1, 13 ), |
| 2113 | + 'append' => array( 1, 13 ), |
| 2114 | + 'yield' => array( 1, 13 ), |
| 2115 | + 'id' => array( 1, 13 ), |
| 2116 | + 'invert' => array( 1, 13 ), |
| 2117 | + 'sum' => array( 1, 13 ), |
| 2118 | + 'break' => array( 1, 13 ), |
| 2119 | + 'continue' => array( 1, 13 ), |
| 2120 | + 'leftbracket' => array( 1, 13 ), |
| 2121 | + 'leftsquare' => array( 1, 13 ), |
| 2122 | + 'self' => array( 1, 13 ), |
| 2123 | + 'isset' => array( 1, 13 ), |
| 2124 | + 'delete' => array( 1, 13 ), |
| 2125 | + 'string' => array( 1, 13 ), |
| 2126 | + 'int' => array( 1, 13 ), |
| 2127 | + 'float' => array( 1, 13 ), |
| 2128 | + 'true' => array( 1, 13 ), |
| 2129 | + 'false' => array( 1, 13 ), |
| 2130 | + 'null' => array( 1, 13 ), |
| 2131 | + 'else' => array( 1, 13 ), |
| 2132 | + 'catch' => array( 1, 13 ), |
| 2133 | + ), |
| 2134 | +); |
| 2135 | + |
| 2136 | +static $goto = array( |
| 2137 | + 0 => array( 1 => 2, 2 => 3 ), |
| 2138 | + 1 => array(), |
| 2139 | + 2 => array(), |
| 2140 | + 3 => array( 1 => 5, 2 => 3 ), |
| 2141 | + 4 => array(), |
| 2142 | + 5 => array(), |
| 2143 | + 6 => array( 3 => 9 ), |
| 2144 | + 7 => array(), |
| 2145 | + 8 => array(), |
| 2146 | + 9 => array(), |
| 2147 | + 10 => array( 3 => 13 ), |
| 2148 | + 11 => array( 4 => 37, 5 => 38, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2149 | + 12 => array(), |
| 2150 | + 13 => array(), |
| 2151 | + 14 => array(), |
| 2152 | + 15 => array( 6 => 60, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2153 | + 16 => array( 4 => 61, 27 => 63, 5 => 38, 28 => 64, 6 => 62, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2154 | + 17 => array(), |
| 2155 | + 18 => array(), |
| 2156 | + 19 => array( 5 => 67, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2157 | + 20 => array( 10 => 68, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2158 | + 21 => array( 10 => 69, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2159 | + 22 => array( 10 => 70, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2160 | + 23 => array( 21 => 73, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2161 | + 24 => array( 19 => 74, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2162 | + 25 => array(), |
| 2163 | + 26 => array(), |
| 2164 | + 27 => array( 23 => 76, 6 => 75, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2165 | + 28 => array(), |
| 2166 | + 29 => array(), |
| 2167 | + 30 => array(), |
| 2168 | + 31 => array(), |
| 2169 | + 32 => array(), |
| 2170 | + 33 => array(), |
| 2171 | + 34 => array(), |
| 2172 | + 35 => array(), |
| 2173 | + 36 => array(), |
| 2174 | + 37 => array( 5 => 79, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2175 | + 38 => array(), |
| 2176 | + 39 => array(), |
| 2177 | + 40 => array( 29 => 83 ), |
| 2178 | + 41 => array(), |
| 2179 | + 42 => array(), |
| 2180 | + 43 => array(), |
| 2181 | + 44 => array(), |
| 2182 | + 45 => array(), |
| 2183 | + 46 => array(), |
| 2184 | + 47 => array(), |
| 2185 | + 48 => array(), |
| 2186 | + 49 => array(), |
| 2187 | + 50 => array(), |
| 2188 | + 51 => array(), |
| 2189 | + 52 => array(), |
| 2190 | + 53 => array(), |
| 2191 | + 54 => array(), |
| 2192 | + 55 => array(), |
| 2193 | + 56 => array(), |
| 2194 | + 57 => array(), |
| 2195 | + 58 => array( 4 => 96, 5 => 38, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2196 | + 59 => array( 27 => 63, 28 => 64, 6 => 97, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2197 | + 60 => array(), |
| 2198 | + 61 => array( 5 => 79, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2199 | + 62 => array(), |
| 2200 | + 63 => array(), |
| 2201 | + 64 => array(), |
| 2202 | + 65 => array( 6 => 103, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2203 | + 66 => array( 7 => 105, 8 => 106 ), |
| 2204 | + 67 => array(), |
| 2205 | + 68 => array(), |
| 2206 | + 69 => array(), |
| 2207 | + 70 => array(), |
| 2208 | + 71 => array(), |
| 2209 | + 72 => array( 29 => 83 ), |
| 2210 | + 73 => array(), |
| 2211 | + 74 => array(), |
| 2212 | + 75 => array(), |
| 2213 | + 76 => array(), |
| 2214 | + 77 => array(), |
| 2215 | + 78 => array(), |
| 2216 | + 79 => array(), |
| 2217 | + 80 => array(), |
| 2218 | + 81 => array( 10 => 111, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2219 | + 82 => array( 6 => 113, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2220 | + 83 => array(), |
| 2221 | + 84 => array( 11 => 114, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2222 | + 85 => array( 13 => 115, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2223 | + 86 => array( 14 => 116, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2224 | + 87 => array( 15 => 117, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2225 | + 88 => array( 16 => 118, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2226 | + 89 => array( 17 => 119, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2227 | + 90 => array( 17 => 120, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2228 | + 91 => array( 20 => 121, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2229 | + 92 => array( 20 => 122, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2230 | + 93 => array( 23 => 124, 6 => 75, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2231 | + 94 => array( 8 => 125 ), |
| 2232 | + 95 => array(), |
| 2233 | + 96 => array( 5 => 79, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2234 | + 97 => array(), |
| 2235 | + 98 => array(), |
| 2236 | + 99 => array(), |
| 2237 | + 100 => array( 6 => 128, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2238 | + 101 => array(), |
| 2239 | + 102 => array( 28 => 129, 6 => 97, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2240 | + 103 => array(), |
| 2241 | + 104 => array(), |
| 2242 | + 105 => array(), |
| 2243 | + 106 => array( 29 => 83 ), |
| 2244 | + 107 => array(), |
| 2245 | + 108 => array( 6 => 134, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2246 | + 109 => array(), |
| 2247 | + 110 => array(), |
| 2248 | + 111 => array(), |
| 2249 | + 112 => array(), |
| 2250 | + 113 => array(), |
| 2251 | + 114 => array(), |
| 2252 | + 115 => array(), |
| 2253 | + 116 => array(), |
| 2254 | + 117 => array(), |
| 2255 | + 118 => array(), |
| 2256 | + 119 => array(), |
| 2257 | + 120 => array(), |
| 2258 | + 121 => array(), |
| 2259 | + 122 => array(), |
| 2260 | + 123 => array(), |
| 2261 | + 124 => array(), |
| 2262 | + 125 => array( 29 => 83 ), |
| 2263 | + 126 => array(), |
| 2264 | + 127 => array(), |
| 2265 | + 128 => array(), |
| 2266 | + 129 => array(), |
| 2267 | + 130 => array( 5 => 139, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2268 | + 131 => array( 6 => 140, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2269 | + 132 => array( 8 => 141 ), |
| 2270 | + 133 => array( 8 => 142 ), |
| 2271 | + 134 => array(), |
| 2272 | + 135 => array(), |
| 2273 | + 136 => array( 11 => 143, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 8 => 72, 26 => 57 ), |
| 2274 | + 137 => array(), |
| 2275 | + 138 => array(), |
| 2276 | + 139 => array(), |
| 2277 | + 140 => array(), |
| 2278 | + 141 => array( 29 => 83 ), |
| 2279 | + 142 => array( 29 => 83 ), |
| 2280 | + 143 => array(), |
| 2281 | + 144 => array( 5 => 147, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2282 | + 145 => array( 5 => 148, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2283 | + 146 => array( 5 => 149, 6 => 39, 9 => 41, 10 => 42, 8 => 40, 11 => 43, 12 => 44, 13 => 45, 14 => 46, 15 => 47, 16 => 48, 17 => 49, 18 => 50, 19 => 51, 20 => 52, 21 => 53, 22 => 54, 24 => 55, 25 => 56, 26 => 57 ), |
| 2284 | + 147 => array(), |
| 2285 | + 148 => array(), |
| 2286 | + 149 => array(), |
| 2287 | +); |
| 2288 | + |
| 2289 | +} |
Property changes on: trunk/extensions/WikiScripts/interpreter/LRTable.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 2290 | + native |
Index: trunk/extensions/WikiScripts/interpreter/Shared.php |
— | — | @@ -0,0 +1,261 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki: implementation-independent interface |
| 5 | + * for scripts parser. |
| 6 | + * Copyright (C) 2009-2011 Victor Vasiliev <vasilvv@gmail.com> |
| 7 | + * http://www.mediawiki.org/ |
| 8 | + * |
| 9 | + * This program is free software; you can redistribute it and/or modify |
| 10 | + * it under the terms of the GNU General Public License as published by |
| 11 | + * the Free Software Foundation; either version 2 of the License, or |
| 12 | + * (at your option) any later version. |
| 13 | + * |
| 14 | + * This program is distributed in the hope that it will be useful, |
| 15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | + * GNU General Public License for more details. |
| 18 | + * |
| 19 | + * You should have received a copy of the GNU General Public License along |
| 20 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 21 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 22 | + * http://www.gnu.org/copyleft/gpl.html |
| 23 | + */ |
| 24 | + |
| 25 | +if( !defined( 'MEDIAWIKI' ) ) |
| 26 | + die(); |
| 27 | + |
| 28 | +/** |
| 29 | + * This class represents a terminal of the script grammar. |
| 30 | + */ |
| 31 | +class ISToken { |
| 32 | + // Constant values should match ones in syntax.txt |
| 33 | + const TEnd = '$'; |
| 34 | + const TAppend = 'append'; |
| 35 | + const TBreak = 'break'; |
| 36 | + const TCatch = 'catch'; |
| 37 | + const TColon = 'colon'; // : |
| 38 | + const TCompareOperator = 'compareop'; // <, >, <= or >= |
| 39 | + const TComma = 'comma'; // , |
| 40 | + const TContains = 'contains'; |
| 41 | + const TContinue = 'continue'; |
| 42 | + const TDelete = 'delete'; |
| 43 | + const TDoubleColon = 'doublecolon'; |
| 44 | + const TElse = 'else'; |
| 45 | + const TEqualsToOperator = 'equalsto'; // ==, ===, != or !== |
| 46 | + const TFalse = 'false'; |
| 47 | + const TFloat = 'float'; |
| 48 | + const TFor = 'for'; |
| 49 | + const TID = 'id'; |
| 50 | + const TIf = 'if'; |
| 51 | + const TIn = 'in'; |
| 52 | + const TInt = 'int'; |
| 53 | + const TBoolInvert = 'invert'; // ! |
| 54 | + const TIsset = 'isset'; |
| 55 | + const TLeftBracket = 'leftbracket'; // ( |
| 56 | + const TLeftCurly = 'leftcurly'; // { |
| 57 | + const TLeftSquare = 'leftsquare'; // [ |
| 58 | + const TLogicalOperator = 'logicop'; // &, | or ^ |
| 59 | + const TMulOperator = 'mul'; // *, / or % |
| 60 | + const TNull = 'null'; |
| 61 | + const TPow = 'pow'; // ** |
| 62 | + const TReturn = 'return'; |
| 63 | + const TRightBracket = 'rightbracket'; // ) |
| 64 | + const TRightCurly = 'rightcurly'; // } |
| 65 | + const TRightSquare = 'rightsquare'; // ] |
| 66 | + const TSemicolon = 'semicolon'; // ; |
| 67 | + const TSet = 'setto'; // = |
| 68 | + const TSelf = 'self'; |
| 69 | + const TString = 'string'; |
| 70 | + const TSumOperator = 'sum'; // + or - |
| 71 | + const TTrinary = 'trinary'; // ? |
| 72 | + const TTrue = 'true'; |
| 73 | + const TTry = 'try'; |
| 74 | + const TYield = 'yield'; |
| 75 | + |
| 76 | + var $type; |
| 77 | + var $value; |
| 78 | + var $line; |
| 79 | + |
| 80 | + public function __construct( $type = self::TEnd, $value = null, $line = 0 ) { |
| 81 | + $this->type = $type; |
| 82 | + $this->value = $value; |
| 83 | + $this->line = $line; |
| 84 | + } |
| 85 | + |
| 86 | + function __toString() { |
| 87 | + return "{$this->value}"; |
| 88 | + } |
| 89 | +} |
| 90 | + |
| 91 | +/** |
| 92 | + * This class represents a non-terminal of the script grammar. |
| 93 | + */ |
| 94 | +class ISParserTreeNode { |
| 95 | + var $mType, $mChildren; |
| 96 | + |
| 97 | + public function __construct( $parser, $id ) { |
| 98 | + $parserClass = get_class( $parser ); |
| 99 | + $this->mType = $parserClass::$mNonterminals[$id]; |
| 100 | + } |
| 101 | + |
| 102 | + public function addChild( $node ) { |
| 103 | + // Since we do not want a long chain of "exprSomething -> exprWhatever" in the parser tree, |
| 104 | + // we cut it out at the parsing stage |
| 105 | + if( $node instanceof ISParserTreeNode ) { |
| 106 | + $children = $node->getChildren(); |
| 107 | + if( count( $children ) == 1 && strpos( $node->mType, "expr" ) === 0 |
| 108 | + && strpos( @$children[0]->mType, "expr" ) === 0 ) { |
| 109 | + $this->mChildren[] = $children[0]; |
| 110 | + return; |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + $this->mChildren[] = $node; |
| 115 | + } |
| 116 | + |
| 117 | + public function getChildren() { |
| 118 | + return $this->mChildren; |
| 119 | + } |
| 120 | + |
| 121 | + public function getChildrenCount() { |
| 122 | + return count( $this->mChildren ); |
| 123 | + } |
| 124 | + |
| 125 | + public function hasSingleChild() { |
| 126 | + return count( $this->mChildren ) == 1; |
| 127 | + } |
| 128 | + |
| 129 | + public function getType() { |
| 130 | + return $this->mType; |
| 131 | + } |
| 132 | + |
| 133 | + public function __toString() { |
| 134 | + $r = $this->formatStringArray(); |
| 135 | + return implode( "\n", $r ); |
| 136 | + } |
| 137 | + |
| 138 | + public function formatStringArray() { |
| 139 | + $s = array( "<nonterminal type=\"{$this->mType}\">" ); |
| 140 | + foreach( $this->mChildren as $child ) { |
| 141 | + if( $child instanceof ISParserTreeNode ) { |
| 142 | + $sub = $child->formatStringArray(); |
| 143 | + foreach( $sub as $str ) |
| 144 | + $s[] = "\t" . $str; |
| 145 | + } else { |
| 146 | + $s[] = "\t<terminal type=\"{$child->type}\" value=\"{$child->value}\" />"; |
| 147 | + } |
| 148 | + } |
| 149 | + $s[] = "</nonterminal>"; |
| 150 | + return $s; |
| 151 | + } |
| 152 | +} |
| 153 | + |
| 154 | +/** |
| 155 | + * Generalized script parser. |
| 156 | + */ |
| 157 | +interface ISParser { |
| 158 | + /** |
| 159 | + * If this function returns true, code scanner is passed to parse(). |
| 160 | + * Otherwise, code itself is passed. |
| 161 | + */ |
| 162 | + public function needsScanner(); |
| 163 | + |
| 164 | + /** |
| 165 | + * Parses code (in text or scanner) to parser tree. |
| 166 | + * @param input ISScanner Input (scanner or string) |
| 167 | + * @param maxTokens int Maximal amount of tokens |
| 168 | + * @return ISParserTreeNode |
| 169 | + */ |
| 170 | + public function parse( $input, $module, $maxTokens ); |
| 171 | + |
| 172 | + /** |
| 173 | + * Returns an array of the syntax errors in the code |
| 174 | + * @param input ISSCanner Input (scanner or string) |
| 175 | + * @param maxTokens int Maximal amount of tokens |
| 176 | + * @return array(string) |
| 177 | + */ |
| 178 | + public function getSyntaxErrors( $input, $moudle, $maxTokens ); |
| 179 | +} |
| 180 | + |
| 181 | +class ISException extends MWException {} |
| 182 | + |
| 183 | +// Exceptions that we might conceivably want to report to ordinary users |
| 184 | +// (i.e. exceptions that don't represent bugs in the extension itself) |
| 185 | +class ISUserVisibleException extends ISException { |
| 186 | + function __construct( $exception_id, $module, $line, $params = array() ) { |
| 187 | + $codelocation = wfMsg( 'inlinescripts-codelocation', $module, $line ); |
| 188 | + $msg = wfMsgExt( 'inlinescripts-exception-' . $exception_id, array(), array_merge( array( $codelocation ), $params ) ); |
| 189 | + parent::__construct( $msg ); |
| 190 | + |
| 191 | + $this->mExceptionID = $exception_id; |
| 192 | + $this->mLine = $line; |
| 193 | + $this->mModule = $module; |
| 194 | + $this->mParams = $params; |
| 195 | + } |
| 196 | + |
| 197 | + public function getExceptionID() { |
| 198 | + return $this->mExceptionID; |
| 199 | + } |
| 200 | +} |
| 201 | + |
| 202 | +/** |
| 203 | + * Exceptions caused by the error on script transclusion error, i.e. not in script. |
| 204 | + */ |
| 205 | +class ISTransclusionException extends ISException { |
| 206 | + function __construct( $exception_id, $params = array() ) { |
| 207 | + $msg = wfMsgExt( 'inlinescripts-transerror-' . $exception_id, array(), $params ); |
| 208 | + parent::__construct( $msg ); |
| 209 | + |
| 210 | + $this->mExceptionID = $exception_id; |
| 211 | + $this->mParams = $params; |
| 212 | + } |
| 213 | +} |
| 214 | + |
| 215 | +/** |
| 216 | + * Exceptions used for control structures that need to break out of deep function |
| 217 | + * nesting level (e.g. break or continue). |
| 218 | + */ |
| 219 | +class ISControlException extends ISUserVisibleException {} |
| 220 | + |
| 221 | +/** |
| 222 | + * Exception that allows to return from a function. |
| 223 | + */ |
| 224 | +class ISReturnException extends ISControlException { |
| 225 | + function __construct( $result, $empty ) { |
| 226 | + $this->mResult = $result; |
| 227 | + $this->mEmpty = $empty; |
| 228 | + } |
| 229 | + |
| 230 | + function getResult() { |
| 231 | + return $this->mResult; |
| 232 | + } |
| 233 | + |
| 234 | + function isEmpty() { |
| 235 | + return $this->mEmpty; |
| 236 | + } |
| 237 | +} |
| 238 | + |
| 239 | +/** |
| 240 | + * Code parser output. |
| 241 | + */ |
| 242 | +class ISParserOutput { |
| 243 | + var $mTree, $mTokensCount, $mVersion; |
| 244 | + |
| 245 | + public function __construct( $tree, $tokens ) { |
| 246 | + global $wgInlineScriptsParserClass; |
| 247 | + $this->mTree = $tree; |
| 248 | + $this->mTokensCount = $tokens; |
| 249 | + $this->mVersion = $wgInlineScriptsParserClass::getVersion(); |
| 250 | + } |
| 251 | + |
| 252 | + public function getParserTree() { |
| 253 | + return $this->mTree; |
| 254 | + } |
| 255 | + |
| 256 | + public function getVersion() { |
| 257 | + return $this->mVersion; |
| 258 | + } |
| 259 | +} |
| 260 | + |
| 261 | +// Used by ISEvaluationContext::setVar |
| 262 | +class ISPlaceholder {} |
Property changes on: trunk/extensions/WikiScripts/interpreter/Shared.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 263 | + native |
Index: trunk/extensions/WikiScripts/interpreter/buildLRTables.php |
— | — | @@ -0,0 +1,561 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * An ugly tool to build SLR-tables. |
| 6 | + * |
| 7 | + * Reads a BNF-ish grammar (strings without <> are terminals) from |
| 8 | + * syntax.txt file and output following files: |
| 9 | + * * LRTableBuildReport.html with misc debug information |
| 10 | + * * LRTable.php, ACTION/GOTO table for grammar in PHP |
| 11 | + * |
| 12 | + * This code requires cleanup, but it's not used outside of development |
| 13 | + * process. |
| 14 | + * |
| 15 | + * This code contains grammar-specific hack to force parser to shift "else" |
| 16 | + * on shift/reduce conflict in "if( ... ) ... (!) else ..." state |
| 17 | + */ |
| 18 | + |
| 19 | +require_once( dirname( dirname( dirname( dirname( __FILE__ ) ) ) ) . '/maintenance/commandLine.inc' ); |
| 20 | + |
| 21 | +class Grammar { |
| 22 | + var $mTerminals, $mNonterminals, $mProductions, $mSymbols; |
| 23 | + var $mFirst, $mFollow, $mAction, $mGoto; |
| 24 | + |
| 25 | + private function __construct() { |
| 26 | + $this->mTerminals = |
| 27 | + $this->mNonterminals = |
| 28 | + $this->mProductions = |
| 29 | + array(); |
| 30 | + } |
| 31 | + |
| 32 | + private function getNonterminalID( $name ) { |
| 33 | + if( !in_array( $name, $this->mNonterminals ) ) |
| 34 | + $this->mNonterminals[] = $name; |
| 35 | + return array_search( $name, $this->mNonterminals ); |
| 36 | + } |
| 37 | + |
| 38 | + private function addProduction( $nonterm, $prod ) { |
| 39 | + $this->mProductions[] = array( $nonterm, $prod ); |
| 40 | + } |
| 41 | + |
| 42 | + private function getProdsForNt( $nonterm ) { |
| 43 | + $prods = array(); |
| 44 | + for( $i = 0; $i < count( $this->mProductions ); $i++ ) { |
| 45 | + $prod = $this->mProductions[$i]; |
| 46 | + if( $prod[0] == $nonterm ) |
| 47 | + $prods[$i] = $prod[1]; |
| 48 | + } |
| 49 | + return $prods; |
| 50 | + } |
| 51 | + |
| 52 | + private function getNtName( $id ) { |
| 53 | + return $this->mNonterminals[$id]; |
| 54 | + } |
| 55 | + |
| 56 | + public static function parse( $def ) { |
| 57 | + $g = new Grammar(); |
| 58 | + $def = strtolower( $def ); |
| 59 | + $lines = explode( "\n", $def ); |
| 60 | + for( $i = 1; $i <= count( $lines ); $i++ ) { |
| 61 | + $line = trim( $lines[$i - 1] ); |
| 62 | + if( !$line ) |
| 63 | + continue; |
| 64 | + |
| 65 | + $namevalpailr = self::parseLine( $g, $line, $i ); |
| 66 | + if( $namevalpailr ) { |
| 67 | + list( $name, $vals ) = $namevalpailr; |
| 68 | + foreach( $vals as $val ) |
| 69 | + $g->addProduction( $name, $val ); |
| 70 | + } |
| 71 | + } |
| 72 | + foreach( $g->mProductions as $prod ) { |
| 73 | + list( $ntid, $prod ) = $prod; |
| 74 | + foreach( $prod as $symbol ) |
| 75 | + if( is_string( $symbol ) && !in_array( $symbol, $g->mTerminals ) ) |
| 76 | + $g->mTerminals[] = $symbol; |
| 77 | + } |
| 78 | + $g->mTerminals[] = '$'; |
| 79 | + $g->mSymbols = array_merge( $g->mTerminals, array_keys( $g->mNonterminals ) ); |
| 80 | + return $g; |
| 81 | + } |
| 82 | + |
| 83 | + private static function parseLine( $g, $line, $lnum ) { |
| 84 | + $i = 0; |
| 85 | + wfSuppressWarnings(); // @ doesn't help to supress "uninitialized string offset" warning |
| 86 | + |
| 87 | + self::skipWhitespace( $line, $i ); |
| 88 | + if( $line[$i] == '#' ) |
| 89 | + return null; |
| 90 | + if( $line[$i] != '<' ) |
| 91 | + die( "Invalid BNF at line $lnum" ); |
| 92 | + $i++; |
| 93 | + |
| 94 | + $end = strpos( $line, '>', $i ); |
| 95 | + if( $end === false ) |
| 96 | + die( "Invalid BNF at line $lnum" ); |
| 97 | + $name = $g->getNonterminalID( substr( $line, $i, $end - $i ) ); |
| 98 | + $i = $end + 1; |
| 99 | + |
| 100 | + self::skipWhitespace( $line, $i ); |
| 101 | + if( substr( $line, $i, 3 ) != '::=' ) |
| 102 | + die( "Invalid BNF at line $lnum" ); |
| 103 | + $i += 3; |
| 104 | + |
| 105 | + $prods = array(); |
| 106 | + $curProd = array(); |
| 107 | + while( $i + 1 < strlen( $line ) ) { |
| 108 | + self::skipWhitespace( $line, $i ); |
| 109 | + if( $line[$i] == '|' ) { |
| 110 | + $prods[] = $curProd; |
| 111 | + $curProd = array(); |
| 112 | + $i++; |
| 113 | + } elseif( $line[$i] == '<' ) { |
| 114 | + $i++; |
| 115 | + $end = strpos( $line, '>', $i ); |
| 116 | + if( $end === false ) |
| 117 | + die( "Invalid BNF at line $lnum" ); |
| 118 | + $curProd[] = $g->getNonterminalID( substr( $line, $i, $end - $i ) ); |
| 119 | + $i = $end + 1; |
| 120 | + } else { |
| 121 | + for( $termName = ''; ctype_alnum( $line[$i] ); $i++ ) |
| 122 | + $termName .= $line[$i]; |
| 123 | + if( !$termName ) |
| 124 | + die( "Invalid BNF at line $lnum" ); |
| 125 | + $curProd[] = $termName; |
| 126 | + } |
| 127 | + } |
| 128 | + $prods[] = $curProd; |
| 129 | + wfRestoreWarnings(); |
| 130 | + return array( $name, $prods ); |
| 131 | + } |
| 132 | + |
| 133 | + private static function skipWhitespace( $line, &$pos ) { |
| 134 | + while( ctype_space( $line[$pos] ) && $pos + 1 < strlen( $line ) ) |
| 135 | + $pos++; |
| 136 | + } |
| 137 | + |
| 138 | + private function buildFirstTable() { |
| 139 | + foreach( $this->mSymbols as $symbol ) |
| 140 | + $this->mFirst[$symbol] = array(); |
| 141 | + |
| 142 | + foreach( $this->mTerminals as $t ) |
| 143 | + $this->mFirst[$t][] = $t; |
| 144 | + |
| 145 | + for( ; ; ) { |
| 146 | + $added = 0; |
| 147 | + foreach( $this->mProductions as $prodbundle ) { |
| 148 | + list( $nt, $prod ) = $prodbundle; |
| 149 | + foreach( $this->mFirst[$prod[0]] as $e ) { |
| 150 | + if( !in_array( $e, $this->mFirst[$nt] ) ) { |
| 151 | + $this->mFirst[$nt][] = $e; |
| 152 | + $added++; |
| 153 | + } |
| 154 | + } |
| 155 | + } |
| 156 | + if( !$added ) |
| 157 | + break; |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + private function buildFollowTable() { |
| 162 | + foreach( $this->mSymbols as $symbol ) |
| 163 | + $this->mFollow[$symbol] = array(); |
| 164 | + $this->mFollow[0][] = '$'; |
| 165 | + for( ; ; ) { |
| 166 | + $added = 0; |
| 167 | + foreach( $this->mProductions as $prodbundle ) { |
| 168 | + list( $nt, $prod ) = $prodbundle; |
| 169 | + for( $i = 0; $i < count( $prod ) - 1; $i++ ) { |
| 170 | + $symbol = $prod[$i]; |
| 171 | + if( is_int( $symbol ) ) { |
| 172 | + foreach( $this->mFirst[$prod[$i + 1]] as $fsymbol ) { |
| 173 | + if( !in_array( $fsymbol, $this->mFollow[$symbol] ) ) { |
| 174 | + $this->mFollow[$symbol][] = $fsymbol; |
| 175 | + $added++; |
| 176 | + } |
| 177 | + } |
| 178 | + } |
| 179 | + } |
| 180 | + $last = end( $prod ); |
| 181 | + if( is_int( $last ) ) { |
| 182 | + foreach( $this->mFollow[$nt] as $symbol ) { |
| 183 | + if( !in_array( $symbol, $this->mFollow[$last] ) ) { |
| 184 | + $this->mFollow[$last][] = $symbol; |
| 185 | + } |
| 186 | + } |
| 187 | + } |
| 188 | + } |
| 189 | + if( !$added ) |
| 190 | + break; |
| 191 | + } |
| 192 | + } |
| 193 | + |
| 194 | + private function itemsClosure( $items ) { |
| 195 | + for( ; ; ) { |
| 196 | + $oldsize = count( $items ); |
| 197 | + foreach( $items as $item ) { |
| 198 | + list( $prodid, $idx ) = $item; |
| 199 | + list( $unused, $prod ) = $this->mProductions[$prodid]; |
| 200 | + if( is_int( @$prod[$idx] ) ) { |
| 201 | + foreach( $this->getProdsForNt( $prod[$idx] ) as $id => $newProd ) { |
| 202 | + $item = array( $id, 0 ); |
| 203 | + if( !in_array( $item, $items ) ) |
| 204 | + $items[] = $item; |
| 205 | + } |
| 206 | + } |
| 207 | + } |
| 208 | + if( count( $items ) == $oldsize ) |
| 209 | + return $items; |
| 210 | + } |
| 211 | + } |
| 212 | + |
| 213 | + public function itemsGoto( $items, $symbol ) { |
| 214 | + if( is_null( $symbol ) ) |
| 215 | + return array(); |
| 216 | + $result = array(); |
| 217 | + foreach( $items as $item ) { |
| 218 | + list( $prodid, $idx ) = $item; |
| 219 | + $prod = $this->mProductions[$prodid][1]; |
| 220 | + if( @$prod[$idx] === $symbol ) |
| 221 | + $result[] = array( $prodid, $idx + 1 ); |
| 222 | + } |
| 223 | + return $this->itemsClosure( $result ); |
| 224 | + } |
| 225 | + |
| 226 | + public function buildCanonicalSet() { |
| 227 | + $r = array( $this->itemsClosure( array( array( 0, 0 ) ) ) ); |
| 228 | + $symbols = array_merge( $this->mTerminals, array_keys( $this->mNonterminals ) ); |
| 229 | + for( ; ; ) { |
| 230 | + $oldsize = count( $r ); |
| 231 | + foreach( $r as $set ) { |
| 232 | + foreach( $symbols as $symbol ) { |
| 233 | + $goto = $this->itemsGoto( $set, $symbol ); |
| 234 | + if( $goto && !in_array( $goto, $r ) ) |
| 235 | + $r[] = $goto; |
| 236 | + } |
| 237 | + } |
| 238 | + if( $oldsize == count( $r ) ) |
| 239 | + break; |
| 240 | + } |
| 241 | + return $r; |
| 242 | + } |
| 243 | + |
| 244 | + public function buildLRTable() { |
| 245 | + $this->buildFirstTable(); |
| 246 | + $this->buildFollowTable(); |
| 247 | + $canonSet = $this->buildCanonicalSet(); |
| 248 | + $actionTable = array(); |
| 249 | + $gotoTable = array(); |
| 250 | + for( $i = 0; $i < count( $canonSet ); $i++ ) { |
| 251 | + $set = $canonSet[$i]; |
| 252 | + $row = $rowGoto = array(); |
| 253 | + foreach( $set as $item ) { |
| 254 | + list( $prodid, $idx ) = $item; |
| 255 | + list( $nt, $prod ) = $this->mProductions[$prodid]; |
| 256 | + $goto = $this->itemsGoto( $set, @$prod[$idx] ); |
| 257 | + for( $j = 0; $j < count( $canonSet ); $j++ ) { |
| 258 | + if( $goto == $canonSet[$j] ) { |
| 259 | + if( is_string( $prod[$idx] ) ) { |
| 260 | + $act = array( 'shift', $j ); |
| 261 | + if( isset( $row[$prod[$idx]] ) && $row[$prod[$idx]] != $act ) |
| 262 | + if( $prod[0] != 'if' ) // Grammar-specific manual hack for "hanging if" problem |
| 263 | + $this->conflictError( $i, $set, $row[$prod[$idx]], $act, $prod[$idx] ); |
| 264 | + $row[$prod[$idx]] = $act; |
| 265 | + } else { |
| 266 | + $rowGoto[$prod[$idx]] = $j; |
| 267 | + } |
| 268 | + } |
| 269 | + } |
| 270 | + if( $idx == count( $prod ) ) { |
| 271 | + if( $prodid ) { |
| 272 | + foreach( $this->mFollow[$nt] as $symbol ) { |
| 273 | + $act = array( 'reduce', $prodid ); |
| 274 | + if( isset( $row[$symbol] ) && $row[$symbol] != $act ) { |
| 275 | + $this->conflictError( $i, $set, $row[$symbol], $act, $symbol ); |
| 276 | + } |
| 277 | + $row[$symbol] = $act; |
| 278 | + } |
| 279 | + } else { |
| 280 | + $row['$'] = array( 'accept' ); |
| 281 | + } |
| 282 | + } |
| 283 | + } |
| 284 | + $actionTable[$i] = $row; |
| 285 | + $gotoTable[$i] = $rowGoto; |
| 286 | + } |
| 287 | + $this->mAction = $actionTable; |
| 288 | + $this->mGoto = $gotoTable; |
| 289 | + } |
| 290 | + |
| 291 | + /** Debug */ |
| 292 | + public function formatProduction( $prodid ) { |
| 293 | + list( $subj, $val ) = $this->mProductions[$prodid]; |
| 294 | + $s = array( $this->getNtName( $subj ), "->" ); |
| 295 | + foreach( $val as $symbol ) { |
| 296 | + if( is_string( $symbol ) ) |
| 297 | + $s[] = strtoupper( $symbol ); |
| 298 | + else |
| 299 | + $s[] = $this->getNtName( $symbol ); |
| 300 | + } |
| 301 | + return implode( ' ', $s ); |
| 302 | + } |
| 303 | + |
| 304 | + public function formatItem( $item ) { |
| 305 | + list( $prodid, $idx ) = $item; |
| 306 | + list( $subj, $val ) = $this->mProductions[$prodid]; |
| 307 | + $s = array( $this->getNtName( $subj ), "->" ); |
| 308 | + for( $i = 0; $i <= count( $val ); $i++ ) { |
| 309 | + if( $i == $idx ) |
| 310 | + $s[] = '(!)'; |
| 311 | + if( $symbol = @$val[$i] ) { |
| 312 | + if( is_string( $symbol ) ) |
| 313 | + $s[] = strtoupper( $symbol ); |
| 314 | + else |
| 315 | + $s[] = $this->getNtName( $symbol ); |
| 316 | + } |
| 317 | + } |
| 318 | + return implode( ' ', $s ); |
| 319 | + } |
| 320 | + |
| 321 | + public function formatAction( $act ) { |
| 322 | + @list( $name, $arg ) = $act; |
| 323 | + if( $name == 'shift' ) { |
| 324 | + return "Shift to state {$arg}"; |
| 325 | + } |
| 326 | + if( $name == 'reduce' ) { |
| 327 | + $prod = $this->formatProduction( $arg ); |
| 328 | + return "Reduce to production {$arg} ({$prod})"; |
| 329 | + } |
| 330 | + if( $name == 'accept' ) { |
| 331 | + return "Accept"; |
| 332 | + } |
| 333 | + } |
| 334 | + |
| 335 | + public function conflictError( $id, $state, $act1, $act2, $symbol ) { |
| 336 | + echo "Found conflict in state {$id} for symbol {$symbol}.\n"; |
| 337 | + echo "Conflicting actions:\n"; |
| 338 | + foreach( array( $act1, $act2 ) as $act ) { |
| 339 | + $str = $this->formatAction( $act ); |
| 340 | + echo "* {$str}\n"; |
| 341 | + } |
| 342 | + echo "Items of the state:\n"; |
| 343 | + foreach( $state as $item ) { |
| 344 | + $str = $this->formatItem( $item ); |
| 345 | + echo "* {$str}\n"; |
| 346 | + } |
| 347 | + exit; |
| 348 | + } |
| 349 | + |
| 350 | + public function buildHTMLDump() { |
| 351 | + $s = <<<END |
| 352 | +<html> |
| 353 | +<head> |
| 354 | +<title>Inline scripts LR table dump</title> |
| 355 | +<style type="text/css"> |
| 356 | +table { |
| 357 | + margin: 1em 1em 1em 0; |
| 358 | + background: #f9f9f9; |
| 359 | + border: 1px #aaa solid; |
| 360 | + border-collapse: collapse; |
| 361 | +} |
| 362 | +th, td { |
| 363 | + border: 1px #aaa solid; |
| 364 | + padding: 0.2em; |
| 365 | +} |
| 366 | +th { |
| 367 | + background: #f2f2f2; |
| 368 | + text-align: center; |
| 369 | +} |
| 370 | +caption { |
| 371 | + font-weight: bold; |
| 372 | +} |
| 373 | +</style> |
| 374 | +</head> |
| 375 | +<body> |
| 376 | +<p>Here is the dump of LR table itself, as well as data used to build it.</p> |
| 377 | +<p>Navigate: <a href="#first">FIRST()</a> | <a href="#follow">FOLLOW()</a> | <a href="#prods">Productions</a> |
| 378 | + | <a href="#table">ACTION/GOTO</a></p> |
| 379 | +END; |
| 380 | + |
| 381 | + $s .= "<h1><a name='first' id='first'>FIRST()</h1><table><tr><th>Symbol</th><th>FIRST(Symbol)</th></tr>\n"; |
| 382 | + foreach( $this->mFirst as $item => $val ) { |
| 383 | + $itemname = is_int( $item ) ? '<i>' . $this->getNtName( $item ) . '</i>' |
| 384 | + : "<b>{$item}</b>"; |
| 385 | + $s .= "<tr><td>{$itemname}</td><td>" . implode( ', ', $val ) . "</td></tr>\n"; |
| 386 | + } |
| 387 | + $s .= "</table>\n"; |
| 388 | + |
| 389 | + $s .= "<h1><a name='follow' id='follow'>FOLLOW()</h1><table><tr><th>Symbol</th><th>FOLLOW(Symbol)</th></tr>\n"; |
| 390 | + foreach( $this->mFollow as $item => $val ) { |
| 391 | + if( !$val ) continue; |
| 392 | + $itemname = is_int( $item ) ? '<i>' . $this->getNtName( $item ) . '</i>' |
| 393 | + : "<b>{$item}</b>"; |
| 394 | + $s .= "<tr><td>{$itemname}</td><td>" . implode( ', ', $val ) . "</td></tr>\n"; |
| 395 | + } |
| 396 | + $s .= "</table>\n"; |
| 397 | + |
| 398 | + $s .= "<h1><a name='prods' id='prods'>Productions</h1><table><tr><th>ID</th><th>Production</th></tr>\n"; |
| 399 | + foreach( $this->mProductions as $id => $val ) { |
| 400 | + $str = $this->formatProduction( $id ); |
| 401 | + $s .= "<tr><td><b>{$id}</b></td><td>{$str}</td></tr>\n"; |
| 402 | + } |
| 403 | + $s .= "</table>\n"; |
| 404 | + |
| 405 | + $termLen = count( $this->mTerminals ); |
| 406 | + $nontermLen = count( $this->mNonterminals ); |
| 407 | + $s .= "<h1><a name='table' id='action'>LR-table (ACTION/GOTO)</h1><table><tr><th rowspan=2>State ID</th>" . |
| 408 | + "<th colspan={$termLen}>ACTION</th><th colspan={$nontermLen}>GOTO</th></tr><tr><th>" . |
| 409 | + implode( '</th><th>', $this->mTerminals ) . '</th><th>' . implode( '</th><th>', array_values( $this->mNonterminals ) ) . "</th></tr>\n"; |
| 410 | + for( $id = 0; $id < count( $this->mAction ); $id++ ) { |
| 411 | + $row = $this->mAction[$id]; |
| 412 | + $goto = $this->mGoto[$id]; |
| 413 | + $s .= "\t<tr><td><b>{$id}</b></td>"; |
| 414 | + foreach( $this->mTerminals as $t ) { |
| 415 | + $act = @$row[$t]; |
| 416 | + if( $act ) { |
| 417 | + switch( $act[0] ) { |
| 418 | + case 'shift': |
| 419 | + $s .= "<td>s{$act[1]}</td>"; break; |
| 420 | + case 'reduce': |
| 421 | + $s .= "<td>r{$act[1]}</td>"; break; |
| 422 | + case 'accept': |
| 423 | + $s .= "<td>acc</td>"; break; |
| 424 | + } |
| 425 | + } else { |
| 426 | + $s .= "<td></td>"; |
| 427 | + } |
| 428 | + } |
| 429 | + foreach( $this->mNonterminals as $ntid => $ntname ) { |
| 430 | + if( isset( $goto[$ntid] ) ) { |
| 431 | + $s .= "<td>{$goto[$ntid]}</td>"; |
| 432 | + } else { |
| 433 | + $s .= "<td></td>"; |
| 434 | + } |
| 435 | + } |
| 436 | + $s .= "</tr>\n"; |
| 437 | + } |
| 438 | + $s .= "</table>\n"; |
| 439 | + |
| 440 | + $s .= "<hr/><p>Autogenerated on " . gmdate( 'Y-m-d H:i:s' ) . "</p></body></html>"; |
| 441 | + return $s; |
| 442 | + } |
| 443 | + |
| 444 | + private function formatArray( $array ) { |
| 445 | + if( !$array ) |
| 446 | + return 'array()'; |
| 447 | + foreach( $array as &$item ) { |
| 448 | + if( is_string( $item ) ) |
| 449 | + $item = "'{$item}'"; |
| 450 | + } |
| 451 | + return 'array( ' . implode( ', ', $array ) . ' )'; |
| 452 | + } |
| 453 | + |
| 454 | + private function formatAssocArray( $array ) { |
| 455 | + if( !$array ) |
| 456 | + return 'array()'; |
| 457 | + $result = array(); |
| 458 | + foreach( $array as $k => $v ) { |
| 459 | + if( is_string( $v ) ) |
| 460 | + $v = "'{$v}'"; |
| 461 | + $result[] = "{$k} => {$v}"; |
| 462 | + } |
| 463 | + return 'array( ' . implode( ', ', $result ) . ' )'; |
| 464 | + } |
| 465 | + |
| 466 | + public function buildPHPFile( $ts ) { |
| 467 | + $date = $ts; |
| 468 | + $s = <<<ENDOFHEADER |
| 469 | +<?php |
| 470 | + |
| 471 | +/** |
| 472 | + * Autogenerated SLR-table for inline scripts language. |
| 473 | + * |
| 474 | + * You should not try to modify it manually (it's very easy to break). |
| 475 | + * Use syntax.txt and buildLRTables.php insteaed. |
| 476 | + * |
| 477 | + * Actions have following syntax |
| 478 | + * array( 0, N ) means "shift and go to state N" |
| 479 | + * array( 1, N ) means "reduce to production N" |
| 480 | + * array( 2 ) means "accept" |
| 481 | + * null means "error" |
| 482 | + * |
| 483 | + * Terminals are referred by names, nonterminals - by ids. |
| 484 | + * |
| 485 | + * Variables has following format: |
| 486 | + * * \$nonterminals is a nonterminal ID -> name map. |
| 487 | + * * \$productions is a ID -> array( nonterminal, body ) map. |
| 488 | + * * Production body is an array of production symbols |
| 489 | + * |
| 490 | + * Generated on {$date}. |
| 491 | + */ |
| 492 | + |
| 493 | +class ISLRTable { |
| 494 | + |
| 495 | +const Timestamp = '{$date}'; |
| 496 | + |
| 497 | + |
| 498 | +ENDOFHEADER; |
| 499 | + |
| 500 | + $s .= "static \$nonterminals = array(\n"; |
| 501 | + foreach( $this->mNonterminals as $id => $val ) { |
| 502 | + $s .= "\t{$id} => '{$val}',\n"; |
| 503 | + } |
| 504 | + $s .= ");\n\n"; |
| 505 | + |
| 506 | + $s .= "static \$productions = array(\n"; |
| 507 | + foreach( $this->mProductions as $id => $val ) { |
| 508 | + $body = $this->formatArray( $val[1] ); |
| 509 | + $s .= "\t{$id} => array( {$val[0]}, {$body} ),\n"; |
| 510 | + } |
| 511 | + $s .= ");\n\n"; |
| 512 | + |
| 513 | + $s .= "static \$action = array(\n"; |
| 514 | + foreach( $this->mAction as $id => $row ) { |
| 515 | + $s .= "\t{$id} => array(\n"; |
| 516 | + foreach( $row as $t => $action ) { |
| 517 | + if( $action[0] == 'shift' ) |
| 518 | + $s .= "\t\t'{$t}' => array( 0, {$action[1]} ),\n"; |
| 519 | + if( $action[0] == 'reduce' ) |
| 520 | + $s .= "\t\t'{$t}' => array( 1, {$action[1]} ),\n"; |
| 521 | + if( $action[0] == 'accept' ) |
| 522 | + $s .= "\t\t'{$t}' => array( 2, null ),\n"; |
| 523 | + } |
| 524 | + $s .= "\t),\n"; |
| 525 | + } |
| 526 | + $s .= ");\n\n"; |
| 527 | + |
| 528 | + $s .= "static \$goto = array(\n"; |
| 529 | + foreach( $this->mGoto as $id => $row ) { |
| 530 | + $body = $this->formatAssocArray( $row ); |
| 531 | + $s .= "\t{$id} => {$body},\n"; |
| 532 | + } |
| 533 | + $s .= ");\n\n"; |
| 534 | + |
| 535 | + $s .= "}\n"; |
| 536 | + return $s; |
| 537 | + } |
| 538 | + |
| 539 | + public function buildPHPVersionFile( $ts ) { |
| 540 | + return <<<EOF |
| 541 | +<?php |
| 542 | + |
| 543 | +/** |
| 544 | + * This file includes timestamp which indicates the version of LRTable.php file. |
| 545 | + * Since the file is too large, loading it every time is expensive and we store the |
| 546 | + * version in separate file. |
| 547 | + */ |
| 548 | + |
| 549 | +define( 'IS_LR_VERSION', "{$ts}" ); |
| 550 | + |
| 551 | +EOF; |
| 552 | + } |
| 553 | +} |
| 554 | + |
| 555 | +$ts = gmdate( 'Y-m-d H:i:s' ); |
| 556 | + |
| 557 | +$definition = file_get_contents( dirname( __FILE__ ) . '/syntax.txt' ); |
| 558 | +$grammar = Grammar::parse( $definition ); |
| 559 | +$grammar->buildLRTable(); |
| 560 | +file_put_contents( 'LRTableBuildReport.html', $grammar->buildHTMLDump() ); |
| 561 | +file_put_contents( 'LRTable.php', $grammar->buildPHPFile( $ts ) ); |
| 562 | +file_put_contents( 'LRTableVersion.php', $grammar->buildPHPVersionFile( $ts ) ); |
Property changes on: trunk/extensions/WikiScripts/interpreter/buildLRTables.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 563 | + native |
Index: trunk/extensions/WikiScripts/inlinescripts.sql |
— | — | @@ -0,0 +1,16 @@ |
| 2 | +-- |
| 3 | +-- Track script inclusions. |
| 4 | +-- |
| 5 | +CREATE TABLE /*_*/scriptlinks ( |
| 6 | + -- Key to the page_id of the page containing the link. |
| 7 | + sl_from int unsigned NOT NULL default 0, |
| 8 | + |
| 9 | + -- Key to page_title of the target page. |
| 10 | + -- The target page may or may not exist, and due to renames |
| 11 | + -- and deletions may refer to different page records as time |
| 12 | + -- goes by. |
| 13 | + sl_to varchar(255) binary NOT NULL default '' |
| 14 | +) /*$wgDBTableOptions*/; |
| 15 | + |
| 16 | +CREATE UNIQUE INDEX /*i*/sl_from ON /*_*/scriptlinks (sl_from,sl_to); |
| 17 | +CREATE UNIQUE INDEX /*i*/sl_title ON /*_*/scriptlinks (sl_to,sl_from); |
Index: trunk/extensions/WikiScripts/interpreterTests.txt |
— | — | @@ -0,0 +1,630 @@ |
| 2 | +# Test cases for MediaWiki inline scripts engine |
| 3 | + |
| 4 | +!! article |
| 5 | +Module:Basic mathematics |
| 6 | +!! text |
| 7 | +function run() { |
| 8 | + return -2 + 2 * 2 ** 2 - 3 * 7 % 5; |
| 9 | +} |
| 10 | +!! endarticle |
| 11 | + |
| 12 | +!! test |
| 13 | +Basic mathematics |
| 14 | +!! input |
| 15 | +{{i:Basic mathematics|run}} |
| 16 | +!! result |
| 17 | +<p>5 |
| 18 | +</p> |
| 19 | +!! end |
| 20 | + |
| 21 | +!! article |
| 22 | +Module:Pow associativity |
| 23 | +!! text |
| 24 | +function run() { |
| 25 | + // Not 4096 |
| 26 | + return 4 ** 3 ** 2; |
| 27 | +} |
| 28 | +!! endarticle |
| 29 | + |
| 30 | +!! test |
| 31 | +** associativity |
| 32 | +!! input |
| 33 | +{{i:Pow associativity|run}} |
| 34 | +!! result |
| 35 | +<p>262144 |
| 36 | +</p> |
| 37 | +!! end |
| 38 | + |
| 39 | +!! article |
| 40 | +Module:String contecation |
| 41 | +!! text |
| 42 | +function add( a, b ) { |
| 43 | + // if you pass 3 and 7, it would be 37, because all arguments from wikitext |
| 44 | + // are strings |
| 45 | + return a + b; |
| 46 | +} |
| 47 | +!! endarticle |
| 48 | + |
| 49 | +!! test |
| 50 | +String contecation |
| 51 | +!! input |
| 52 | +{{i:string contecation|add|3|7}} |
| 53 | +!! result |
| 54 | +<p>37 |
| 55 | +</p> |
| 56 | +!! end |
| 57 | + |
| 58 | +!! article |
| 59 | +Module:Multiple variable assignment |
| 60 | +!! text |
| 61 | +function run() { |
| 62 | + // if you pass 3 and 7, it would be 37, because all arguments from wikitext |
| 63 | + // are strings |
| 64 | + a = b = 3; |
| 65 | + return a + b; |
| 66 | +} |
| 67 | +!! endarticle |
| 68 | + |
| 69 | +!! test |
| 70 | +Multiple variable assignment |
| 71 | +!! input |
| 72 | +{{i:Multiple variable assignment|run}} |
| 73 | +!! result |
| 74 | +<p>6 |
| 75 | +</p> |
| 76 | +!! end |
| 77 | + |
| 78 | +!! article |
| 79 | +Module:Assigment with arithmetics |
| 80 | +!! text |
| 81 | +function run() { |
| 82 | + a = 2; |
| 83 | + a += 3; |
| 84 | + a -= 7; |
| 85 | + return a; |
| 86 | +} |
| 87 | +!! endarticle |
| 88 | + |
| 89 | +!! test |
| 90 | +Assigment with arithmetics (+=, -=, etc) |
| 91 | +!! input |
| 92 | +{{i:Assigment with arithmetics|run}} |
| 93 | +!! result |
| 94 | +<p>-2 |
| 95 | +</p> |
| 96 | +!! end |
| 97 | + |
| 98 | +!! article |
| 99 | +Module:Boolean shortcut |
| 100 | +!! text |
| 101 | +function run() { |
| 102 | + /* Only first statement should be performed */ |
| 103 | + !(b = 2) | (b = 3) | (b = 4); |
| 104 | + return b; |
| 105 | +} |
| 106 | +!! endarticle |
| 107 | + |
| 108 | +!! test |
| 109 | +Boolean shortcut |
| 110 | +!! input |
| 111 | +{{i:boolean shortcut|run}} |
| 112 | +!! result |
| 113 | +<p>3 |
| 114 | +</p> |
| 115 | +!! end |
| 116 | + |
| 117 | +!! article |
| 118 | +Module:Equality |
| 119 | +!! text |
| 120 | +function run() { |
| 121 | + return "2" == 2 & "2" !== 2 & 4 === (2 + 2) & |
| 122 | + null == "" & false == null & 0 == ""; |
| 123 | +} |
| 124 | +!! endarticle |
| 125 | + |
| 126 | +!! test |
| 127 | +Equality |
| 128 | +!! input |
| 129 | +{{i:equality|run}} |
| 130 | +!! result |
| 131 | +<p>1 |
| 132 | +</p> |
| 133 | +!! end |
| 134 | + |
| 135 | +!! article |
| 136 | +Module:Comparisons |
| 137 | +!! text |
| 138 | +function run() { |
| 139 | + return 2 > 1 & 2 >= 2 & 2 <= 2 & 1 < 2; |
| 140 | +} |
| 141 | +!! endarticle |
| 142 | + |
| 143 | +!! test |
| 144 | +Comparsions |
| 145 | +!! input |
| 146 | +{{i:comparisons|run}} |
| 147 | +!! result |
| 148 | +<p>1 |
| 149 | +</p> |
| 150 | +!! end |
| 151 | + |
| 152 | +!! article |
| 153 | +Module:Trivial |
| 154 | +!! text |
| 155 | +function getText() { |
| 156 | + return "AA"; |
| 157 | +} |
| 158 | +!! endarticle |
| 159 | + |
| 160 | +!! test |
| 161 | +Integration with other functions |
| 162 | +!! input |
| 163 | +{{lc:{{i:trivial|getText}}}} |
| 164 | +!! result |
| 165 | +<p>aa |
| 166 | +</p> |
| 167 | +!! end |
| 168 | + |
| 169 | +!! article |
| 170 | +Module:Conditions |
| 171 | +!! text |
| 172 | +function run() { |
| 173 | + return 2 + 2 == 4 ? "a" : "b"; |
| 174 | +} |
| 175 | +!! endarticle |
| 176 | + |
| 177 | +!! test |
| 178 | +Conditions (?) |
| 179 | +!! input |
| 180 | +{{i:conditions|run}} |
| 181 | +!! result |
| 182 | +<p>a |
| 183 | +</p> |
| 184 | +!! end |
| 185 | + |
| 186 | +!! article |
| 187 | +Module:Conditions (if-then-else) |
| 188 | +!! text |
| 189 | +function run() { |
| 190 | + if( 2 * 7 > 3 * 4 ) { |
| 191 | + a = 7; |
| 192 | + } else { |
| 193 | + a = 10; |
| 194 | + } |
| 195 | + |
| 196 | + if( a ** 2 < 50 ) |
| 197 | + return "ok"; |
| 198 | +} |
| 199 | +!! endarticle |
| 200 | + |
| 201 | +!! test |
| 202 | +Conditions (if-then, if-then-else) |
| 203 | +!! input |
| 204 | +{{i:Conditions (if-then-else)|run}} |
| 205 | +!! result |
| 206 | +<p>ok |
| 207 | +</p> |
| 208 | +!! end |
| 209 | + |
| 210 | +!! article |
| 211 | +Module:Bullets |
| 212 | +!! text |
| 213 | +function run() { |
| 214 | + out = ""; |
| 215 | + for( a in args() ) |
| 216 | + out += "* " + a + "\n"; |
| 217 | + return out; |
| 218 | +} |
| 219 | +!! endarticle |
| 220 | + |
| 221 | +!! article |
| 222 | +Template:Bullets |
| 223 | +!! text |
| 224 | +{{i:bullets|run}} |
| 225 | +!! endarticle |
| 226 | + |
| 227 | +!! test |
| 228 | +args() function |
| 229 | +!! input |
| 230 | +{{bullets|a|b|c}} |
| 231 | +!! result |
| 232 | +<ul><li> a |
| 233 | +</li><li> b |
| 234 | +</li><li> c |
| 235 | +</li></ul> |
| 236 | + |
| 237 | +!! end |
| 238 | + |
| 239 | +!! article |
| 240 | +Module:TranscludedSwitch |
| 241 | +!! text |
| 242 | +function run() { |
| 243 | + return isTranscluded() ? arg(1) : "?!"; |
| 244 | +} |
| 245 | +!! endarticle |
| 246 | + |
| 247 | +!! article |
| 248 | +Template:TranscludedSwitch |
| 249 | +!! text |
| 250 | +{{i:TranscludedSwitch|run}} |
| 251 | +!! endarticle |
| 252 | + |
| 253 | +!! test |
| 254 | +isTranscluded()/arg() check |
| 255 | +!! input |
| 256 | +{{TranscludedSwitch|11}} |
| 257 | +!! result |
| 258 | +<p>11 |
| 259 | +</p> |
| 260 | +!! end |
| 261 | + |
| 262 | +!! article |
| 263 | +Module:Empty argument handling check |
| 264 | +!! text |
| 265 | +function run() { |
| 266 | + return arg("test") === null; |
| 267 | +} |
| 268 | +!! endarticle |
| 269 | + |
| 270 | +!! test |
| 271 | +Empty argument handling check |
| 272 | +!! input |
| 273 | +{{i:Empty argument handling check|run}} |
| 274 | +!! result |
| 275 | +<p>1 |
| 276 | +</p> |
| 277 | +!! end |
| 278 | + |
| 279 | +!! article |
| 280 | +Module:Casts |
| 281 | +!! text |
| 282 | +function run() { |
| 283 | + return string(float(2)) === "2.0" & int(7.99) === 7; |
| 284 | +} |
| 285 | +!! endarticle |
| 286 | + |
| 287 | +!! test |
| 288 | +Casts |
| 289 | +!! input |
| 290 | +{{i:Casts|run}} |
| 291 | +!! result |
| 292 | +<p>1 |
| 293 | +</p> |
| 294 | +!! end |
| 295 | + |
| 296 | +!! article |
| 297 | +Module:Exception handling |
| 298 | +!! text |
| 299 | +function run() { |
| 300 | + try |
| 301 | + 2 / 0; |
| 302 | + catch( e ) |
| 303 | + return e; |
| 304 | +} |
| 305 | +!! endarticle |
| 306 | + |
| 307 | +!! test |
| 308 | +Exception handling |
| 309 | +!! input |
| 310 | +{{i:Exception handling|run}} |
| 311 | +!! result |
| 312 | +<p>dividebyzero |
| 313 | +</p> |
| 314 | +!! end |
| 315 | + |
| 316 | +!! article |
| 317 | +Template:Numberofsomething |
| 318 | +!! text |
| 319 | +721 |
| 320 | +!! endarticle |
| 321 | + |
| 322 | +!! article |
| 323 | +Module:Numberofsomething |
| 324 | +!! text |
| 325 | +function run() { |
| 326 | + numofsmth = int( parse( '{{numberofsomething}}' ) ) + 279; |
| 327 | + return '{{numberofsomething}}: ' + numofsmth; |
| 328 | +} |
| 329 | +!! endarticle |
| 330 | + |
| 331 | +!! test |
| 332 | +Template access via parse() |
| 333 | +!! input |
| 334 | +{{i:Numberofsomething|run}} |
| 335 | +!! result |
| 336 | +<p>{{numberofsomething}}: 1000 |
| 337 | +</p> |
| 338 | +!! end |
| 339 | + |
| 340 | +!! article |
| 341 | +Module:123 |
| 342 | +!! text |
| 343 | +function run1() { |
| 344 | + return 123; |
| 345 | +} |
| 346 | + |
| 347 | +function run2() { |
| 348 | + return parse( '{{123}}' ); |
| 349 | +} |
| 350 | +!! endarticle |
| 351 | + |
| 352 | +!! article |
| 353 | +Template:123 |
| 354 | +!! text |
| 355 | +{{i:123|run1}} |
| 356 | +!! endarticle |
| 357 | + |
| 358 | +!! test |
| 359 | +Nested wikiscripts via parse() |
| 360 | +!! input |
| 361 | +{{i:123|run2}} |
| 362 | +!! result |
| 363 | +<p>123 |
| 364 | +</p> |
| 365 | +!! end |
| 366 | + |
| 367 | +!! article |
| 368 | +Module:String functions 1 |
| 369 | +!! text |
| 370 | +function run() { |
| 371 | + return lc( 'FOO' ) == 'foo' & uc( 'foo' ) == 'FOO' & |
| 372 | + ucfirst( 'bar' ) == 'Bar' & urlencode( 'a="b"' ) == "a%3D%22b%22"; |
| 373 | +} |
| 374 | +!! endarticle |
| 375 | + |
| 376 | +!! test |
| 377 | +String functions 1 |
| 378 | +!! input |
| 379 | +{{i:String functions 1|run}} |
| 380 | +!! result |
| 381 | +<p>1 |
| 382 | +</p> |
| 383 | +!! end |
| 384 | + |
| 385 | +!! article |
| 386 | +Module:String functions 2 |
| 387 | +!! text |
| 388 | +function run() { |
| 389 | + return strlen( "тест" ) == 4 & substr( "слово", 1, 2 ) == "ло" & |
| 390 | + strreplace( "abcd", 'bc', 'ad' ) == 'aadd'; |
| 391 | +} |
| 392 | +!! endarticle |
| 393 | + |
| 394 | +!! test |
| 395 | +String functions 2 |
| 396 | +!! input |
| 397 | +{{i:String functions 2|run}} |
| 398 | +!! result |
| 399 | +<p>1 |
| 400 | +</p> |
| 401 | +!! end |
| 402 | + |
| 403 | +!! article |
| 404 | +Module:split/join |
| 405 | +!! text |
| 406 | +function run() { |
| 407 | + return join( '!', split( ':', 'a:b:c:d' ) ) + join( ' ', '', 'e', 'f' ); |
| 408 | +} |
| 409 | +!! endarticle |
| 410 | + |
| 411 | +!! test |
| 412 | +split()/join() |
| 413 | +!! input |
| 414 | +{{i:split/join|run}} |
| 415 | +!! result |
| 416 | +<p>a!b!c!d e f |
| 417 | +</p> |
| 418 | +!! end |
| 419 | + |
| 420 | +!! article |
| 421 | +Module:isset/delete |
| 422 | +!! text |
| 423 | +function run() { |
| 424 | + a = null; |
| 425 | + b = 1; |
| 426 | + delete( b ); |
| 427 | + return 'a: ' + isset( a ) + '; b: ' + int( isset( b ) ); |
| 428 | +} |
| 429 | +!! endarticle |
| 430 | + |
| 431 | +!! test |
| 432 | +isset/delete |
| 433 | +!! input |
| 434 | +{{i:isset/delete|run}} |
| 435 | +!! result |
| 436 | +<p>a: 1; b: 0 |
| 437 | +</p> |
| 438 | +!! end |
| 439 | + |
| 440 | +!! article |
| 441 | +Module:in/contains |
| 442 | +!! text |
| 443 | +function run() { |
| 444 | + return int( "a" in "b" + "c" in "cd" + "foobar" contains "oo" + "foobar" contains "baz" ); |
| 445 | +} |
| 446 | +!! endarticle |
| 447 | + |
| 448 | +!! test |
| 449 | +in/contains |
| 450 | +!! input |
| 451 | +{{i:in/contains|run}} |
| 452 | +!! result |
| 453 | +<p>2 |
| 454 | +</p> |
| 455 | +!! end |
| 456 | + |
| 457 | +# |
| 458 | +## Lists |
| 459 | +# |
| 460 | + |
| 461 | +!! article |
| 462 | +Module:Lists: basics |
| 463 | +!! text |
| 464 | +function run() { |
| 465 | + a = [ b = "a", b = "b", b = "c" ]; |
| 466 | + return a[1] + b; |
| 467 | +} |
| 468 | +!! endarticle |
| 469 | + |
| 470 | +!! test |
| 471 | +Lists: basics |
| 472 | +!! input |
| 473 | +{{i:Lists: basics|run}} |
| 474 | +!! result |
| 475 | +<p>bc |
| 476 | +</p> |
| 477 | +!! end |
| 478 | + |
| 479 | +!! article |
| 480 | +Module:Lists: foreach |
| 481 | +!! text |
| 482 | +function run() { |
| 483 | + a = [ 1, 2, 3, 4, 5 ]; |
| 484 | + for( n in a ) |
| 485 | + append n * n + "\n\n"; |
| 486 | +} |
| 487 | +!! endarticle |
| 488 | + |
| 489 | +!! test |
| 490 | +Lists: foreach |
| 491 | +!! input |
| 492 | +{{i:Lists: foreach|run}} |
| 493 | +!! result |
| 494 | +<p>1 |
| 495 | +</p><p>4 |
| 496 | +</p><p>9 |
| 497 | +</p><p>16 |
| 498 | +</p><p>25 |
| 499 | +</p> |
| 500 | +!! end |
| 501 | + |
| 502 | +!! article |
| 503 | +Module:List merging |
| 504 | +!! text |
| 505 | +function run() { |
| 506 | + for( element in [ 7, 4 ] + [ 2, 8 ] + 1 ) |
| 507 | + append string( element ); |
| 508 | +} |
| 509 | +!! endarticle |
| 510 | + |
| 511 | +!! test |
| 512 | +List merging |
| 513 | +!! input |
| 514 | +{{i:List merging|run}} |
| 515 | +!! result |
| 516 | +<p>74281 |
| 517 | +</p> |
| 518 | +!! end |
| 519 | + |
| 520 | +!! article |
| 521 | +Module:Lists: loop control (break/continue) |
| 522 | +!! text |
| 523 | +function run() { |
| 524 | + a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; |
| 525 | + for( e in a ) { |
| 526 | + if( e >= 6 & e < 9 ) |
| 527 | + continue; |
| 528 | + append string( e ); |
| 529 | + } |
| 530 | + for( e in a ) { |
| 531 | + if( e == 3 ) |
| 532 | + break; |
| 533 | + append e; |
| 534 | + } |
| 535 | +} |
| 536 | +!! endarticle |
| 537 | + |
| 538 | +!! test |
| 539 | +Lists: loop control (break/continue) |
| 540 | +!! input |
| 541 | +{{i:Lists: loop control (break/continue)|run}} |
| 542 | +!! result |
| 543 | +<p>12345912 |
| 544 | +</p> |
| 545 | +!! end |
| 546 | + |
| 547 | +!! article |
| 548 | +Module:Lists: changing value of an element |
| 549 | +!! text |
| 550 | +function run() { |
| 551 | + a = [ [ 2, 3 ], [ 5, 6 ], 7 ]; |
| 552 | + a[1][0] = 3; |
| 553 | + a[0][] = 1; |
| 554 | + return a; |
| 555 | +} |
| 556 | +!! endarticle |
| 557 | + |
| 558 | +!! test |
| 559 | +Lists: changing value of an element |
| 560 | +!! input |
| 561 | +{{i:Lists: changing value of an element|run}} |
| 562 | +!! result |
| 563 | +<p>2 |
| 564 | +3 |
| 565 | +1 |
| 566 | +3 |
| 567 | +6 |
| 568 | +7 |
| 569 | +</p> |
| 570 | +!! end |
| 571 | + |
| 572 | +!! article |
| 573 | +Module:Lists: isset |
| 574 | +!! text |
| 575 | +function run() { |
| 576 | + lst = [ 'a', 'b', 'c' ]; |
| 577 | + return isset( lst[1] ) + isset( lst[2] ) + isset( list[3] ); |
| 578 | +} |
| 579 | +!! endarticle |
| 580 | + |
| 581 | +!! test |
| 582 | +Lists: isset |
| 583 | +!! input |
| 584 | +{{i:Lists: isset|run}} |
| 585 | +!! result |
| 586 | +<p>2 |
| 587 | +</p> |
| 588 | +!! end |
| 589 | + |
| 590 | +!! article |
| 591 | +Module:Associated arrays: basics |
| 592 | +!! text |
| 593 | +function run() { |
| 594 | + a = { "a" : 2, "b" : 13 }; |
| 595 | + a["c"] = 21; |
| 596 | + |
| 597 | + for( k : v in a ) { |
| 598 | + append k + " = " + v + "\n\n"; |
| 599 | + } |
| 600 | +} |
| 601 | +!! endarticle |
| 602 | + |
| 603 | +!! test |
| 604 | +Associated arrays: basics |
| 605 | +!! input |
| 606 | +{{i:Associated arrays: basics|run}} |
| 607 | +!! result |
| 608 | +<p>a = 2 |
| 609 | +</p><p>b = 13 |
| 610 | +</p><p>c = 21 |
| 611 | +</p> |
| 612 | +!! end |
| 613 | + |
| 614 | +!! article |
| 615 | +Module:Mixed arrays |
| 616 | +!! text |
| 617 | +function run() { |
| 618 | + a["b"][][]["c"] = 11; |
| 619 | + return a["b"][0][0]["c"]; |
| 620 | +} |
| 621 | +!! endarticle |
| 622 | + |
| 623 | +!! test |
| 624 | +Mixed arrays |
| 625 | +!! input |
| 626 | +{{i:Mixed arrays|run}} |
| 627 | +!! result |
| 628 | +<p>11 |
| 629 | +</p> |
| 630 | +!! end |
| 631 | + |
Property changes on: trunk/extensions/WikiScripts/interpreterTests.txt |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 632 | + native |
Index: trunk/extensions/WikiScripts/Hooks.php |
— | — | @@ -0,0 +1,204 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki: hooks. |
| 5 | + * Copyright (C) 2009-2011 Victor Vasiliev <vasilvv@gmail.com> |
| 6 | + * http://www.mediawiki.org/ |
| 7 | + * |
| 8 | + * This program is free software; you can redistribute it and/or modify |
| 9 | + * it under the terms of the GNU General Public License as published by |
| 10 | + * the Free Software Foundation; either version 2 of the License, or |
| 11 | + * (at your option) any later version. |
| 12 | + * |
| 13 | + * This program is distributed in the hope that it will be useful, |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | + * GNU General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU General Public License along |
| 19 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 20 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 21 | + * http://www.gnu.org/copyleft/gpl.html |
| 22 | + */ |
| 23 | + |
| 24 | +/** |
| 25 | + * Hooks for InlineScripts extension. |
| 26 | + */ |
| 27 | +class ISHooks { |
| 28 | + /** |
| 29 | + * Returns the interpreter for a given parser. |
| 30 | + * |
| 31 | + * @static |
| 32 | + * @return InlineScriptInterpreter |
| 33 | + */ |
| 34 | + public static function getInterpreter( $parser ) { |
| 35 | + if( !isset( $parser->is_interpreter ) || !$parser->is_interpreter ) { |
| 36 | + $parser->is_interpreter = new ISInterpreter( $parser ); |
| 37 | + } |
| 38 | + return $parser->is_interpreter; |
| 39 | + } |
| 40 | + |
| 41 | + /** |
| 42 | + * Register parser hooks. |
| 43 | + * @param $parser Parser |
| 44 | + */ |
| 45 | + public static function setupParserHook( &$parser ) { |
| 46 | + $parser->setFunctionHook( 'i', 'ISHooks::callHook', SFH_NO_HASH | SFH_OBJECT_ARGS ); |
| 47 | + return true; |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * Called when interpreter is to be reset. |
| 52 | + * |
| 53 | + * @static |
| 54 | + * @param $parser Parser |
| 55 | + * @return bool |
| 56 | + */ |
| 57 | + public static function clearState( &$parser ) { |
| 58 | + $parser->is_interpreter = null; |
| 59 | + return true; |
| 60 | + } |
| 61 | + |
| 62 | + /** |
| 63 | + * Adds scriptlinks table to parser tests. |
| 64 | + */ |
| 65 | + public static function addTestTables( &$tables ) { |
| 66 | + $tables[] = 'scriptlinks'; |
| 67 | + return true; |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * Handles the {{i:module|func}} construction. |
| 72 | + * |
| 73 | + * @static |
| 74 | + * @param $parser Parser |
| 75 | + * @param $frame |
| 76 | + * @param $args |
| 77 | + * @return string |
| 78 | + */ |
| 79 | + public static function callHook( &$parser, $frame, $args ) { |
| 80 | + wfProfileIn( __METHOD__ ); |
| 81 | + $i = self::getInterpreter( $parser ); |
| 82 | + |
| 83 | + try { |
| 84 | + if( count( $args ) < 2 ) { |
| 85 | + throw new ISTransclusionException( 'nofunction' ); |
| 86 | + } |
| 87 | + |
| 88 | + $moduleName = $parser->mStripState->unstripBoth( array_shift( $args ) ); |
| 89 | + $funcName = $frame->expand( array_shift( $args ) ); |
| 90 | + foreach( $args as &$arg ) { |
| 91 | + $arg = $frame->expand( $arg ); |
| 92 | + } |
| 93 | + |
| 94 | + $result = $i->invokeUserFunctionFromWikitext( $moduleName, $funcName, $args, $frame ); |
| 95 | + } catch( ISException $e ) { |
| 96 | + $msg = $e->getMessage(); |
| 97 | + wfProfileOut( __METHOD__ ); |
| 98 | + return "<strong class=\"error\">{$msg}</strong>"; |
| 99 | + } |
| 100 | + |
| 101 | + wfProfileOut( __METHOD__ ); |
| 102 | + return trim( $result ); |
| 103 | + } |
| 104 | + |
| 105 | + /** |
| 106 | + * Overrides the standard view for modules. Enables syntax highlighting when |
| 107 | + * possible. |
| 108 | + * |
| 109 | + * @static |
| 110 | + * @param $text |
| 111 | + * @param $title Title |
| 112 | + * @param $output OutputPage |
| 113 | + * @return bool |
| 114 | + */ |
| 115 | + public static function handleScriptView( $text, $title, $output ) { |
| 116 | + global $wgInlineScriptsUseGeSHi; |
| 117 | + |
| 118 | + if( $title->getNamespace() == NS_MODULE ) { |
| 119 | + if( $wgInlineScriptsUseGeSHi ) { |
| 120 | + $geshi = SyntaxHighlight_GeSHi::prepare( $text, 'wikiscript' ); |
| 121 | + $geshi->set_language_path( dirname( __FILE__ ) . '/geshi' ); |
| 122 | + $geshi->set_language( 'wikiscript' ); |
| 123 | + if( $geshi instanceof GeSHi && !$geshi->error() ) { |
| 124 | + $code = $geshi->parse_code(); |
| 125 | + if( $code ) { |
| 126 | + $output->addHeadItem( "source-wikiscript", SyntaxHighlight_GeSHi::buildHeadItem( $geshi ) ); |
| 127 | + $output->addHTML( "<div dir=\"ltr\">{$code}</div>" ); |
| 128 | + return false; |
| 129 | + } |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + // No GeSHi, or GeSHi can't parse it, use plain <pre> |
| 134 | + $output->addHTML( "<pre class=\"mw-code mw-script\" dir=\"ltr\">\n" ); |
| 135 | + $output->addHTML( htmlspecialchars( $text ) ); |
| 136 | + $output->addHTML( "\n</pre>\n" ); |
| 137 | + return false; |
| 138 | + } else { |
| 139 | + return true; |
| 140 | + } |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Indicates that modules are not wikitext. |
| 145 | + */ |
| 146 | + public static function isWikitextPage( $title, &$result ) { |
| 147 | + if( $title->getNamespace() == NS_MODULE ) { |
| 148 | + $result = false; |
| 149 | + return false; |
| 150 | + } |
| 151 | + return true; |
| 152 | + } |
| 153 | + |
| 154 | + /** |
| 155 | + * Adds report of number of evaluations by the single wikitext page. |
| 156 | + * |
| 157 | + * @static |
| 158 | + * @param $parser Parser |
| 159 | + * @param $report |
| 160 | + * @return bool |
| 161 | + */ |
| 162 | + public static function reportLimits( $parser, &$report ) { |
| 163 | + global $wgInlineScriptsLimits; |
| 164 | + $i = self::getInterpreter( $parser ); |
| 165 | + $report .= |
| 166 | + "Inline scripts parser evaluations: {$i->mEvaluations}/{$wgInlineScriptsLimits['evaluations']}\n" . |
| 167 | + "Inline scripts AST maximal depth: {$i->mMaxRecursion}/{$wgInlineScriptsLimits['depth']}\n"; |
| 168 | + return true; |
| 169 | + } |
| 170 | + |
| 171 | + /** |
| 172 | + * Adds the module namespaces. |
| 173 | + */ |
| 174 | + public static function addCanonicalNamespaces( &$list ) { |
| 175 | + $list[NS_MODULE] = 'Module'; |
| 176 | + $list[NS_MODULE_TALK] = 'Module_talk'; |
| 177 | + return true; |
| 178 | + } |
| 179 | + |
| 180 | + public static function validateScript( $editor, $text, $section, &$error ) { |
| 181 | + global $wgUser; |
| 182 | + $title = $editor->mTitle; |
| 183 | + |
| 184 | + if( $title->getNamespace() == NS_MODULE ) { |
| 185 | + $errors = ISInterpreter::getSyntaxErrors( $title->getText(), $text ); |
| 186 | + if( !$errors ) { |
| 187 | + return true; |
| 188 | + } |
| 189 | + |
| 190 | + $errmsg = wfMsgExt( 'inlinescripts-error', array( 'parsemag' ), array( count( $errors ) ) ); |
| 191 | + $errlines = '* ' . implode( "\n* ", array_map( 'wfEscapeWikiText', $errors ) ); |
| 192 | + $error = <<<HTML |
| 193 | +<div class="errorbox"> |
| 194 | +{$errmsg} |
| 195 | +{$errlines} |
| 196 | +</div> |
| 197 | +<br clear="all" /> |
| 198 | +HTML; |
| 199 | + |
| 200 | + return true; |
| 201 | + } |
| 202 | + |
| 203 | + return true; |
| 204 | + } |
| 205 | +} |
Index: trunk/extensions/WikiScripts/LinksUpdate.php |
— | — | @@ -0,0 +1,199 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki: link updating code |
| 5 | + * Copyright (C) 2011 Victor Vasiliev <vasilvv@gmail.com> et al |
| 6 | + * Based on MediaWiki file LinksUpdate.php |
| 7 | + * http://www.mediawiki.org/ |
| 8 | + * |
| 9 | + * This program is free software; you can redistribute it and/or modify |
| 10 | + * it under the terms of the GNU General Public License as published by |
| 11 | + * the Free Software Foundation; either version 2 of the License, or |
| 12 | + * (at your option) any later version. |
| 13 | + * |
| 14 | + * This program is distributed in the hope that it will be useful, |
| 15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | + * GNU General Public License for more details. |
| 18 | + * |
| 19 | + * You should have received a copy of the GNU General Public License along |
| 20 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 21 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 22 | + * http://www.gnu.org/copyleft/gpl.html |
| 23 | + */ |
| 24 | + |
| 25 | +if( !defined( 'MEDIAWIKI' ) ) |
| 26 | + die(); |
| 27 | + |
| 28 | + |
| 29 | +/** |
| 30 | + * Class that contains hooks related to tracking links to scripts and invalidating |
| 31 | + * pages on script change. |
| 32 | + */ |
| 33 | +class ISLinksUpdateHooks { |
| 34 | + /** |
| 35 | + * Appends script links to the output. |
| 36 | + */ |
| 37 | + public static function appendToOutput( &$parser, &$text ) { |
| 38 | + if( isset( $parser->is_interpreter ) ) { |
| 39 | + $parser->mOutput->is_links = $parser->is_interpreter->mUsedModules; |
| 40 | + } |
| 41 | + return true; |
| 42 | + } |
| 43 | + |
| 44 | + /** |
| 45 | + * Runs the link updater. |
| 46 | + */ |
| 47 | + public static function updateLinks( &$update ) { |
| 48 | + $output = $update->mParserOutput; |
| 49 | + if( isset( $output->is_links ) ) { |
| 50 | + $new = $output->is_links; |
| 51 | + } else { |
| 52 | + $new = array(); |
| 53 | + } |
| 54 | + |
| 55 | + $isupdate = new ISLinksUpdate( $update, $new ); |
| 56 | + $isupdate->run(); |
| 57 | + return true; |
| 58 | + } |
| 59 | + |
| 60 | + /** |
| 61 | + * Purges cache for all the pages where the script is used. |
| 62 | + */ |
| 63 | + public static function purgeCache( &$article, &$editInfo, $changed ) { |
| 64 | + global $wgDeferredUpdateList; |
| 65 | + |
| 66 | + if( $article->mTitle->getNamespace() == NS_MODULE ) { |
| 67 | + // Invalidate the script cache |
| 68 | + ISInterpreter::invalidateModule( $article->mTitle ); |
| 69 | + |
| 70 | + // Invalidate caches of articles which include the script |
| 71 | + $wgDeferredUpdateList[] = new HTMLCacheUpdate( $article->mTitle, 'scriptlinks' ); |
| 72 | + } |
| 73 | + |
| 74 | + return true; |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * Adds scriptlinks to the list of tables supported by BacklinkCache. |
| 79 | + */ |
| 80 | + public static function getBacklinkCachePrefix( $table, &$prefix ) { |
| 81 | + if( $table == 'scriptlinks' ) { |
| 82 | + $prefix = 'sl'; |
| 83 | + return false; |
| 84 | + } else { |
| 85 | + return true; |
| 86 | + } |
| 87 | + } |
| 88 | + |
| 89 | + /** |
| 90 | + * Adds scriptlinks to the list of tables supported by BacklinkCache. |
| 91 | + */ |
| 92 | + public static function getBacklinkCacheConditions( $table, $title, &$conds ) { |
| 93 | + if( $table == 'scriptlinks' ) { |
| 94 | + $conds = array( |
| 95 | + 'sl_to' => $title->getDBkey(), |
| 96 | + 'page_id=sl_from' |
| 97 | + ); |
| 98 | + return false; |
| 99 | + } else { |
| 100 | + return true; |
| 101 | + } |
| 102 | + } |
| 103 | +} |
| 104 | + |
| 105 | +/** |
| 106 | + * A class that updates links on scripts like phase3/includes/LinksUpdate.php does that |
| 107 | + * with templates. |
| 108 | + */ |
| 109 | +class ISLinksUpdate { |
| 110 | + var $mUpdate, $mId, $mNew; |
| 111 | + |
| 112 | + public function __construct( $update, $new ) { |
| 113 | + $this->mUpdate = $update; |
| 114 | + $this->mId = $update->mId; |
| 115 | + $this->mNew = $new; |
| 116 | + } |
| 117 | + |
| 118 | + public function run() { |
| 119 | + global $wgUseDumbLinkUpdate; |
| 120 | + |
| 121 | + wfProfileIn( __METHOD__ ); |
| 122 | + |
| 123 | + if( $wgUseDumbLinkUpdate ) { |
| 124 | + $this->mUpdate->dumbTableUpdate( 'scriptlinks', $this->getScriptInsertions(), 'sl_from' ); |
| 125 | + } else { |
| 126 | + $existing = $this->getExistingScripts(); |
| 127 | + $this->mUpdate->incrTableUpdate( 'scriptlinks', 'sl', $this->getScriptDeletions( $existing ), |
| 128 | + $this->getScriptInsertions( $existing ) ); |
| 129 | + } |
| 130 | + |
| 131 | + if( $this->mUpdate->mRecursive && $this->mUpdate->mTitle->getNamespace() == NS_MODULE ) { |
| 132 | + $this->queueRecursiveJobs(); |
| 133 | + } |
| 134 | + |
| 135 | + wfProfileOut( __METHOD__ ); |
| 136 | + } |
| 137 | + |
| 138 | + protected function getExistingScripts() { |
| 139 | + $result = array(); |
| 140 | + |
| 141 | + $res = $this->mUpdate->mDb->select( 'scriptlinks', array( 'sl_to' ), |
| 142 | + array( 'sl_from' => $this->mId ), __METHOD__, $this->mUpdate->mOptions ); |
| 143 | + foreach ( $res as $row ) { |
| 144 | + $result[] = $row->sl_to; |
| 145 | + } |
| 146 | + |
| 147 | + return $result; |
| 148 | + } |
| 149 | + |
| 150 | + protected function getScriptInsertions( $existing = array() ) { |
| 151 | + $result = array(); |
| 152 | + |
| 153 | + foreach( array_diff( $this->mNew, $existing ) as $module ) { |
| 154 | + $result[] = array( |
| 155 | + 'sl_from' => $this->mId, |
| 156 | + 'sl_to' => $module, |
| 157 | + ); |
| 158 | + } |
| 159 | + |
| 160 | + return $result; |
| 161 | + } |
| 162 | + |
| 163 | + protected function getScriptDeletions( $existing = array() ) { |
| 164 | + $result = array(); |
| 165 | + |
| 166 | + foreach( array_diff( $existing, $this->mNew ) as $module ) { |
| 167 | + $result[] = array( |
| 168 | + 'sl_from' => $this->mId, |
| 169 | + 'sl_to' => $module, |
| 170 | + ); |
| 171 | + } |
| 172 | + |
| 173 | + return $result; |
| 174 | + } |
| 175 | + |
| 176 | + protected function queueRecursiveJobs() { |
| 177 | + global $wgUpdateRowsPerJob; |
| 178 | + wfProfileIn( __METHOD__ ); |
| 179 | + |
| 180 | + $cache = $this->mUpdate->mTitle->getBacklinkCache(); |
| 181 | + $batches = $cache->partition( 'scriptlinks', $wgUpdateRowsPerJob ); |
| 182 | + if ( !$batches ) { |
| 183 | + wfProfileOut( __METHOD__ ); |
| 184 | + return; |
| 185 | + } |
| 186 | + $jobs = array(); |
| 187 | + foreach ( $batches as $batch ) { |
| 188 | + list( $start, $end ) = $batch; |
| 189 | + $params = array( |
| 190 | + 'table' => 'scriptlinks', |
| 191 | + 'start' => $start, |
| 192 | + 'end' => $end, |
| 193 | + ); |
| 194 | + $jobs[] = new RefreshLinksJob2( $this->mUpdate->mTitle, $params ); |
| 195 | + } |
| 196 | + Job::batchInsert( $jobs ); |
| 197 | + |
| 198 | + wfProfileOut( __METHOD__ ); |
| 199 | + } |
| 200 | +} |
Index: trunk/extensions/WikiScripts/InlineScripts.php |
— | — | @@ -0,0 +1,130 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Built-in scripting language for MediaWiki. |
| 5 | + * Copyright (C) 2009-2011 Victor Vasiliev <vasilvv@gmail.com> |
| 6 | + * http://www.mediawiki.org/ |
| 7 | + * |
| 8 | + * This program is free software; you can redistribute it and/or modify |
| 9 | + * it under the terms of the GNU General Public License as published by |
| 10 | + * the Free Software Foundation; either version 2 of the License, or |
| 11 | + * (at your option) any later version. |
| 12 | + * |
| 13 | + * This program is distributed in the hope that it will be useful, |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | + * GNU General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU General Public License along |
| 19 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 20 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 21 | + * http://www.gnu.org/copyleft/gpl.html |
| 22 | + */ |
| 23 | + |
| 24 | +if( !defined( 'MEDIAWIKI' ) ) |
| 25 | + die(); |
| 26 | + |
| 27 | +$wgExtensionCredits['parserhook']['InlineScripts'] = array( |
| 28 | + 'path' => __FILE__, |
| 29 | + 'name' => 'InlineScripts', |
| 30 | + 'author' => 'Victor Vasiliev', |
| 31 | + 'descriptionmsg' => 'inlinescripts-desc', |
| 32 | + 'url' => 'http://www.mediawiki.org/wiki/Extension:InlineScripts', |
| 33 | +); |
| 34 | + |
| 35 | +$dir = dirname(__FILE__) . '/'; |
| 36 | +$wgExtensionMessagesFiles['InlineScripts'] = $dir . 'i18n/Messages.php'; |
| 37 | +$wgExtensionMessagesFiles['InlineScriptsMagic'] = $dir . 'i18n/Magic.php'; |
| 38 | +$wgExtensionMessagesFiles['InlineScriptsNamespaces'] = $dir . 'i18n/Namespaces.php'; |
| 39 | + |
| 40 | +$wgAutoloadClasses['ISHooks'] = $dir . '/Hooks.php'; |
| 41 | +$wgAutoloadClasses['ISLinksUpdateHooks'] = $dir . '/LinksUpdate.php'; |
| 42 | + |
| 43 | +$wgAutoloadClasses['ISInterpreter'] = $dir . 'interpreter/Interpreter.php'; |
| 44 | +$wgAutoloadClasses['ISScanner'] = $dir . 'interpreter/Scanner.php'; |
| 45 | +$wgAutoloadClasses['ISLRParser'] = $dir . 'interpreter/LRParser.php'; |
| 46 | + |
| 47 | +$wgParserTestFiles[] = $dir . 'interpreterTests.txt'; |
| 48 | +$wgHooks['ParserFirstCallInit'][] = 'ISHooks::setupParserHook'; |
| 49 | +$wgHooks['ParserLimitReport'][] = 'ISHooks::reportLimits'; |
| 50 | +$wgHooks['ParserClearState'][] = 'ISHooks::clearState'; |
| 51 | +$wgHooks['ParserTestTables'][] = 'ISHooks::addTestTables'; |
| 52 | + |
| 53 | +$wgHooks['CanonicalNamespaces'][] = 'ISHooks::addCanonicalNamespaces'; |
| 54 | +$wgHooks['ArticleViewCustom'][] = 'ISHooks::handleScriptView'; |
| 55 | +$wgHooks['TitleIsWikitextPage'][] = 'ISHooks::isWikitextPage'; |
| 56 | +$wgHooks['EditFilter'][] = 'ISHooks::validateScript'; |
| 57 | + |
| 58 | +$wgHooks['LinksUpdate'][] = 'ISLinksUpdateHooks::updateLinks'; |
| 59 | +$wgHooks['ArticleEditUpdates'][] = 'ISLinksUpdateHooks::purgeCache'; |
| 60 | +$wgHooks['ParserAfterTidy'][] = 'ISLinksUpdateHooks::appendToOutput'; |
| 61 | +$wgHooks['BacklinkCacheGetPrefix'][] = 'ISLinksUpdateHooks::getBacklinkCachePrefix'; |
| 62 | +$wgHooks['BacklinkCacheGetConditions'][] = 'ISLinksUpdateHooks::getBacklinkCacheConditions'; |
| 63 | + |
| 64 | +/** Configuration */ |
| 65 | + |
| 66 | +/** |
| 67 | + * Script namespace numbers. Should be redefined before |
| 68 | + * the inlcusion of the extension. |
| 69 | + */ |
| 70 | +if( !isset( $wgScriptsNamespaceNumbers ) ) { |
| 71 | + $wgScriptsNamespaceNumbers = array( |
| 72 | + 'Module' => 20, |
| 73 | + 'Module_talk' => 21, |
| 74 | + ); |
| 75 | +} |
| 76 | + |
| 77 | +/** |
| 78 | + * Different limits of the scripts. |
| 79 | + */ |
| 80 | +$wgInlineScriptsLimits = array( |
| 81 | + /** |
| 82 | + * Maximal amount of tokens (strings, keywords, numbers, operators, |
| 83 | + * but not whitespace) in a single module to be parsed. |
| 84 | + */ |
| 85 | + 'tokens' => 1000000, |
| 86 | + |
| 87 | + /** |
| 88 | + * Maximal amount of operations (multiplications, comarsions, function |
| 89 | + * calls) to be done. |
| 90 | + */ |
| 91 | + 'evaluations' => 300000, |
| 92 | + |
| 93 | + /** |
| 94 | + * Maximal depth of recursion when evaluating the parser tree in a single function. For |
| 95 | + * example 2 + 2 * 2 ** 2 is parsed to (2 + (2 * (2 ** 2))) and needs |
| 96 | + * depth 3 to be parsed. |
| 97 | + */ |
| 98 | + 'depth' => 100, |
| 99 | +); |
| 100 | + |
| 101 | +/** |
| 102 | + * Turn on to true if you have linked or copied wikiscripts.php and |
| 103 | + * SyntaxHighlight_GeSHi extension is enabled. |
| 104 | + */ |
| 105 | +$wgInlineScriptsUseGeSHi = false; |
| 106 | + |
| 107 | +/** |
| 108 | + * Class of the actual parser. Must implement ISParser interface, as well as |
| 109 | + * static getVersion() method. |
| 110 | + */ |
| 111 | +$wgInlineScriptsParserClass = 'ISLRParser'; |
| 112 | + |
| 113 | +/** |
| 114 | + * Should be enabled unless you are debugging or just have sado-masochistic |
| 115 | + * attitude towards your server. |
| 116 | + */ |
| 117 | +$wgInlineScriptsUseCache = true; |
| 118 | + |
| 119 | +/** |
| 120 | + * Indicates whether the function recursion is enabled. If it is, then users may |
| 121 | + * build a Turing-complete machinge and do nice things like parsers, etc in wikitext! |
| 122 | + */ |
| 123 | +$wgInlineScriptsAllowRecursion = false; |
| 124 | + |
| 125 | +/** |
| 126 | + * Maximun call stack depth. Includes functions and invokations of parse() function. |
| 127 | + */ |
| 128 | +$wgInlineScriptsMaxCallStackDepth = 25; |
| 129 | + |
| 130 | +define( 'NS_MODULE', $wgScriptsNamespaceNumbers['Module'] ); |
| 131 | +define( 'NS_MODULE_TALK', $wgScriptsNamespaceNumbers['Module_talk'] ); |
Property changes on: trunk/extensions/WikiScripts/InlineScripts.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 132 | + native |