Index: trunk/extensions/Scribunto/Scripting.i18n.php |
— | — | @@ -0,0 +1,25 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Internationalisation file for extension Scripting. |
| 5 | + * |
| 6 | + * @file |
| 7 | + * @ingroup Extensions |
| 8 | + */ |
| 9 | + |
| 10 | +$messages = array(); |
| 11 | + |
| 12 | +/** English |
| 13 | + * @author Victor Vasiliev |
| 14 | + */ |
| 15 | +$messages['en'] = array( |
| 16 | + 'scripting-desc' => 'Framework for embedding scripting languages into MediaWiki pages', |
| 17 | + 'scripting-codelocation' => 'in $1 at line $2', |
| 18 | + 'scripting-luasandbox-error' => 'Lua error: $2', |
| 19 | + 'scripting-common-toofewargs' => 'Lua error: Too few arguments to function $2', |
| 20 | + 'scripting-common-nosuchmodule' => 'Script error: No such module', |
| 21 | + 'scripting-luasandbox-noreturn' => 'Script error: The module did not return a value, it should return an export table.', |
| 22 | + 'scripting-luasandbox-toomanyreturns' => 'Script error: The module returned multiple values, it should return an export table.', |
| 23 | + 'scripting-luasandbox-notarrayreturn' => 'Script error: The module returned something other than a table, it should return an export table.', |
| 24 | + 'scripting-common-nofunction' => 'Script error: You must specify a function to call.', |
| 25 | + 'scripting-common-nosuchfunction' => 'Script error: The function you specified did not exist.', |
| 26 | +); |
Property changes on: trunk/extensions/Scribunto/Scripting.i18n.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 27 | + native |
Index: trunk/extensions/Scribunto/Scripting.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 | +); |
Property changes on: trunk/extensions/Scribunto/Scripting.namespaces.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 10 | + native |
Index: trunk/extensions/Scribunto/Scripting.magic.php |
— | — | @@ -0,0 +1,9 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +$magicWords = array(); |
| 5 | + |
| 6 | +$magicWords['en'] = array( |
| 7 | + 'invoke' => array( 0, 'invoke' ), |
| 8 | + 'script' => array( 0, 'script' ), |
| 9 | +); |
| 10 | + |
Property changes on: trunk/extensions/Scribunto/Scripting.magic.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 11 | + native |
Index: trunk/extensions/Scribunto/Scripting.php |
— | — | @@ -0,0 +1,102 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Wikitext scripting infrastructure for MediaWiki. |
| 5 | + * Copyright (C) 2009-2012 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']['Scripting'] = array( |
| 28 | + 'path' => __FILE__, |
| 29 | + 'name' => 'Scripting', |
| 30 | + 'author' => 'Victor Vasiliev', |
| 31 | + 'descriptionmsg' => 'scripting-desc', |
| 32 | + 'url' => 'https://www.mediawiki.org/wiki/Extension:Scripting', |
| 33 | +); |
| 34 | + |
| 35 | +$dir = dirname(__FILE__) . '/'; |
| 36 | +$wgExtensionMessagesFiles['Scripting'] = $dir . 'Scripting.i18n.php'; |
| 37 | +$wgExtensionMessagesFiles['ScriptingMagic'] = $dir . 'Scripting.magic.php'; |
| 38 | +$wgExtensionMessagesFiles['ScriptingNamespaces'] = $dir . 'Scripting.namespaces.php'; |
| 39 | + |
| 40 | +$wgAutoloadClasses['ScriptingEngineBase'] = $dir.'common/Base.php'; |
| 41 | +$wgAutoloadClasses['ScriptingModuleBase'] = $dir.'common/Base.php'; |
| 42 | +$wgAutoloadClasses['ScriptingFunctionBase'] = $dir.'common/Base.php'; |
| 43 | +$wgAutoloadClasses['ScriptingHooks'] = $dir.'common/Hooks.php'; |
| 44 | +$wgAutoloadClasses['ScriptingException'] = $dir.'common/Common.php'; |
| 45 | +$wgAutoloadClasses['Scripting'] = $dir.'common/Common.php'; |
| 46 | + |
| 47 | +$wgHooks['ParserFirstCallInit'][] = 'ScriptingHooks::setupParserHook'; |
| 48 | +$wgHooks['ParserLimitReport'][] = 'ScriptingHooks::reportLimits'; |
| 49 | +$wgHooks['ParserClearState'][] = 'ScriptingHooks::clearState'; |
| 50 | + |
| 51 | +$wgHooks['CanonicalNamespaces'][] = 'ScriptingHooks::addCanonicalNamespaces'; |
| 52 | +$wgHooks['ArticleViewCustom'][] = 'ScriptingHooks::handleScriptView'; |
| 53 | +$wgHooks['TitleIsWikitextPage'][] = 'ScriptingHooks::isWikitextPage'; |
| 54 | +$wgHooks['CodeEditorGetPageLanguage'][] = 'ScriptingHooks::getCodeLanguage'; |
| 55 | +$wgHooks['EditFilter'][] = 'ScriptingHooks::validateScript'; |
| 56 | + |
| 57 | +/***** Individual engines and their configurations *****/ |
| 58 | + |
| 59 | +$wgAutoloadClasses['LuaSandboxEngine'] = $dir.'engines/LuaSandbox/Engine.php'; |
| 60 | + |
| 61 | +/***** Configuration *****/ |
| 62 | + |
| 63 | +/** |
| 64 | + * The name of the default scripting engine. |
| 65 | + */ |
| 66 | +$wgScriptingDefaultEngine = 'luasandbox'; |
| 67 | + |
| 68 | +/** |
| 69 | + * Configuration for each scripting engine |
| 70 | + */ |
| 71 | +$wgScriptingEngineConf = array( |
| 72 | + 'luasandbox' => array( |
| 73 | + 'class' => 'LuaSandboxEngine', |
| 74 | + 'memoryLimit' => 50 * 1024 * 1024, |
| 75 | + 'cpuLimit' => 7, |
| 76 | + ), |
| 77 | +); |
| 78 | + |
| 79 | +/** |
| 80 | + * Script namespace numbers. |
| 81 | + */ |
| 82 | +$wgScriptingNamespaceNumbers = array( |
| 83 | + 'Module' => 20, |
| 84 | + 'Module_talk' => 21, |
| 85 | +); |
| 86 | + |
| 87 | +/** |
| 88 | + * Turn on to true if SyntaxHighlight_GeSHi extension is enabled. |
| 89 | + */ |
| 90 | +$wgScriptingUseGeSHi = false; |
| 91 | + |
| 92 | +/** |
| 93 | + * Turn on to true if CodeEditor extension is enabled. |
| 94 | + */ |
| 95 | +$wgScriptingUseCodeEditor = false; |
| 96 | + |
| 97 | +function efDefineScriptingNamespace() { |
| 98 | + global $wgScriptingNamespaceNumbers; |
| 99 | + define( 'NS_MODULE', $wgScriptingNamespaceNumbers['Module'] ); |
| 100 | + define( 'NS_MODULE_TALK', $wgScriptingNamespaceNumbers['Module_talk'] ); |
| 101 | +} |
| 102 | + |
| 103 | +$wgExtensionFunctions[] = 'efDefineScriptingNamespace'; |
Property changes on: trunk/extensions/Scribunto/Scripting.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 104 | + native |
Index: trunk/extensions/Scribunto/common/Base.php |
— | — | @@ -0,0 +1,183 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Wikitext scripting infrastructure for MediaWiki: base classes. |
| 6 | + * Copyright (C) 2012 Victor Vasiliev <vasilvv@gmail.com> et al |
| 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 | +/** |
| 26 | + * Base class for all scripting engines. Includes all code |
| 27 | + * not related to particular modules, like tracking links between |
| 28 | + * modules or loading module texts. |
| 29 | + */ |
| 30 | +abstract class ScriptingEngineBase { |
| 31 | + protected |
| 32 | + $parser, |
| 33 | + $options, |
| 34 | + $modules = array(); |
| 35 | + |
| 36 | + /** |
| 37 | + * Creates a new module object within this engine |
| 38 | + */ |
| 39 | + abstract protected function newModule( $text, $chunkName ); |
| 40 | + |
| 41 | + /** |
| 42 | + * Constructor. |
| 43 | + * |
| 44 | + * @param $options Associative array of options: |
| 45 | + * - parser: A Parser object |
| 46 | + */ |
| 47 | + public function __construct( $options ) { |
| 48 | + $this->options = $options; |
| 49 | + if ( isset( $options['parser'] ) ) { |
| 50 | + $this->parser = $options['parser']; |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + /** |
| 55 | + * Load a module from some parser-defined template loading mechanism and |
| 56 | + * register a parser output dependency. |
| 57 | + * |
| 58 | + * Does not initialize the module, i.e. do not expect it to complain if the module |
| 59 | + * text is garbage or has syntax error. Returns a module or throws an exception. |
| 60 | + * |
| 61 | + * @param $title The title of the module |
| 62 | + * @return ScriptingEngineModule |
| 63 | + */ |
| 64 | + function fetchModuleFromParser( Title $title ) { |
| 65 | + list( $text, $finalTitle ) = $this->parser->fetchTemplateAndTitle( $title ); |
| 66 | + if ( $text === false ) { |
| 67 | + throw new ScriptingException( 'scripting-common-nosuchmodule' ); |
| 68 | + } |
| 69 | + |
| 70 | + $key = $finalTitle->getPrefixedDBkey(); |
| 71 | + if ( !isset( $this->modules[$key] ) ) { |
| 72 | + $this->modules[$key] = $this->newModule( $text, $key ); |
| 73 | + } |
| 74 | + return $this->modules[$key]; |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * Validates the script and returns an array of the syntax errors for the |
| 79 | + * given code. |
| 80 | + * |
| 81 | + * @param $code Code to validate |
| 82 | + * @param $title Title of the code page |
| 83 | + * @return array |
| 84 | + */ |
| 85 | + function validate( $text, $chunkName = false ) { |
| 86 | + $module = $this->newModule( $text, $chunkName ); |
| 87 | + |
| 88 | + try { |
| 89 | + $module->initialize(); |
| 90 | + } catch( ScriptingException $e ) { |
| 91 | + return array( $e->getMessage() ); |
| 92 | + } |
| 93 | + |
| 94 | + return array(); |
| 95 | + } |
| 96 | + |
| 97 | + /** |
| 98 | + * Allows the engine to append their information to the limits |
| 99 | + * report. |
| 100 | + */ |
| 101 | + public function getLimitsReport() { |
| 102 | + /* No-op by default */ |
| 103 | + return ''; |
| 104 | + } |
| 105 | + |
| 106 | + /** |
| 107 | + * Get the language for GeSHi syntax highlighter. |
| 108 | + */ |
| 109 | + function getGeSHiLanguage() { |
| 110 | + return false; |
| 111 | + } |
| 112 | + |
| 113 | + /** |
| 114 | + * Get the language for Ace code editor. |
| 115 | + */ |
| 116 | + function getCodeEditorLanguage() { |
| 117 | + return false; |
| 118 | + } |
| 119 | +} |
| 120 | + |
| 121 | +/** |
| 122 | + * Class that represents a module. Responsible for initial module parsing |
| 123 | + * and maintaining the contents of the module. |
| 124 | + */ |
| 125 | +abstract class ScriptingModuleBase { |
| 126 | + var $engine, $code, $chunkName; |
| 127 | + |
| 128 | + public function __construct( $engine, $code, $chunkName ) { |
| 129 | + $this->engine = $engine; |
| 130 | + $this->code = $code; |
| 131 | + $this->chunkName = $chunkName; |
| 132 | + } |
| 133 | + |
| 134 | + /** Accessors **/ |
| 135 | + public function getEngine() { return $this->engine; } |
| 136 | + public function getCode() { return $this->code; } |
| 137 | + public function getChunkName() { return $this->chunkName; } |
| 138 | + |
| 139 | + /** |
| 140 | + * Initialize the module. That means parse it and load the |
| 141 | + * functions/constants/whatever into the object. |
| 142 | + * |
| 143 | + * Protection of double-initialization is the responsibility of this method. |
| 144 | + */ |
| 145 | + abstract function initialize(); |
| 146 | + |
| 147 | + /** |
| 148 | + * Returns the object for a given function. Should return null if it does not exist. |
| 149 | + * |
| 150 | + * @return ScriptingFunctionBase or null |
| 151 | + */ |
| 152 | + abstract function getFunction( $name ); |
| 153 | + |
| 154 | + /** |
| 155 | + * Returns the list of the functions in the module. |
| 156 | + * |
| 157 | + * @return array(string) |
| 158 | + */ |
| 159 | + abstract function getFunctions(); |
| 160 | +} |
| 161 | + |
| 162 | +abstract class ScriptingFunctionBase { |
| 163 | + protected $mName, $mContents, $mModule, $mEngine; |
| 164 | + |
| 165 | + public function __construct( $module, $name, $contents ) { |
| 166 | + $this->name = $name; |
| 167 | + $this->contents = $contents; |
| 168 | + $this->module = $module; |
| 169 | + $this->engine = $module->getEngine(); |
| 170 | + } |
| 171 | + |
| 172 | + /** |
| 173 | + * Calls the function. Returns its first result or null if no result. |
| 174 | + * |
| 175 | + * @param $args array Arguments to the function |
| 176 | + * @param $frame PPFrame |
| 177 | + */ |
| 178 | + abstract public function call( $args, $frame ); |
| 179 | + |
| 180 | + /** Accessors **/ |
| 181 | + public function getName() { return $this->name; } |
| 182 | + public function getModule() { return $this->module; } |
| 183 | + public function getEngine() { return $this->engine; } |
| 184 | +} |
Property changes on: trunk/extensions/Scribunto/common/Base.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 185 | + native |
Index: trunk/extensions/Scribunto/common/Hooks.php |
— | — | @@ -0,0 +1,240 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Wikitext scripting infrastructure for MediaWiki: hooks. |
| 5 | + * Copyright (C) 2009-2012 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 the Scripting extension. |
| 26 | + */ |
| 27 | +class ScriptingHooks { |
| 28 | + /** |
| 29 | + * Register parser hooks. |
| 30 | + * @param $parser Parser |
| 31 | + */ |
| 32 | + public static function setupParserHook( &$parser ) { |
| 33 | + $parser->setFunctionHook( 'invoke', 'ScriptingHooks::callHook', SFH_OBJECT_ARGS ); |
| 34 | + $parser->setFunctionHook( 'script', 'ScriptingHooks::transcludeHook', SFH_NO_HASH | SFH_OBJECT_ARGS ); |
| 35 | + return true; |
| 36 | + } |
| 37 | + |
| 38 | + /** |
| 39 | + * Called when the interpreter is to be reset. |
| 40 | + * |
| 41 | + * @static |
| 42 | + * @param $parser Parser |
| 43 | + * @return bool |
| 44 | + */ |
| 45 | + public static function clearState( &$parser ) { |
| 46 | + Scripting::resetParserEngine( $parser ); |
| 47 | + return true; |
| 48 | + } |
| 49 | + |
| 50 | + /** |
| 51 | + * Hook function for {{#invoke:module|func}} |
| 52 | + * |
| 53 | + * @param $parser Parser |
| 54 | + * @param $frame PPFrame |
| 55 | + * @param $args array |
| 56 | + * @return string |
| 57 | + */ |
| 58 | + public static function callHook( &$parser, $frame, $args ) { |
| 59 | + if( count( $args ) < 2 ) { |
| 60 | + throw new ScriptingException( 'scripting-common-nofunction' ); |
| 61 | + } |
| 62 | + |
| 63 | + $module = $parser->mStripState->unstripBoth( array_shift( $args ) ); |
| 64 | + $function = $frame->expand( array_shift( $args ) ); |
| 65 | + return self::doRunHook( $parser, $frame, $module, $function, $args ); |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * Hook function for {{script:module}} |
| 70 | + * |
| 71 | + * @param $parser Parser |
| 72 | + * @param $frame PPFrame |
| 73 | + * @param $args |
| 74 | + * @return string |
| 75 | + */ |
| 76 | + public static function transcludeHook( &$parser, $frame, $args ) { |
| 77 | + $module = $parser->mStripState->unstripBoth( array_shift( $args ) ); |
| 78 | + return self::doRunHook( $parser, $frame, $module, 'main', $args ); |
| 79 | + } |
| 80 | + |
| 81 | + /** |
| 82 | + * @param $parser Parser |
| 83 | + * @param $frame PPFrame |
| 84 | + * @param $moduleName |
| 85 | + * @param $functionName |
| 86 | + * @param $args |
| 87 | + * @return string |
| 88 | + * @throws ScriptingException |
| 89 | + */ |
| 90 | + private static function doRunHook( $parser, $frame, $moduleName, $functionName, $args ) { |
| 91 | + wfProfileIn( __METHOD__ ); |
| 92 | + |
| 93 | + try { |
| 94 | + $engine = Scripting::getParserEngine( $parser ); |
| 95 | + $title = Title::makeTitleSafe( NS_MODULE, $moduleName ); |
| 96 | + if ( !$title ) { |
| 97 | + throw new ScriptingException( 'scripting-common-nosuchmodule' ); |
| 98 | + } |
| 99 | + $module = $engine->fetchModuleFromParser( $title ); |
| 100 | + |
| 101 | + $functionObj = $module->getFunction( $functionName ); |
| 102 | + if( !$functionObj ) { |
| 103 | + throw new ScriptingException( 'scripting-common-nosuchfunction' ); |
| 104 | + } |
| 105 | + |
| 106 | + foreach( $args as &$arg ) { |
| 107 | + $arg = $frame->expand( $arg ); |
| 108 | + } |
| 109 | + |
| 110 | + $result = $functionObj->call( $args, $frame ); |
| 111 | + |
| 112 | + wfProfileOut( __METHOD__ ); |
| 113 | + return trim( strval( $result ) ); |
| 114 | + } catch( ScriptingException $e ) { |
| 115 | + $msg = $e->getMessage(); |
| 116 | + wfProfileOut( __METHOD__ ); |
| 117 | + return "<strong class=\"error\">{$msg}</strong>"; |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + /** |
| 122 | + * Overrides the standard view for modules. Enables syntax highlighting when |
| 123 | + * possible. |
| 124 | + * |
| 125 | + * @param $text string |
| 126 | + * @param $title Title |
| 127 | + * @param $output OutputPage |
| 128 | + * @return bool |
| 129 | + */ |
| 130 | + public static function handleScriptView( $text, $title, $output ) { |
| 131 | + global $wgScriptingUseGeSHi; |
| 132 | + |
| 133 | + if( $title->getNamespace() == NS_MODULE ) { |
| 134 | + $engine = Scripting::newDefaultEngine(); |
| 135 | + $language = $engine->getGeSHiLanguage(); |
| 136 | + |
| 137 | + if( $wgScriptingUseGeSHi && $language ) { |
| 138 | + $geshi = SyntaxHighlight_GeSHi::prepare( $text, $language ); |
| 139 | + $geshi->set_language( $language ); |
| 140 | + if( $geshi instanceof GeSHi && !$geshi->error() ) { |
| 141 | + $code = $geshi->parse_code(); |
| 142 | + if( $code ) { |
| 143 | + $output->addHeadItem( "source-{$language}", SyntaxHighlight_GeSHi::buildHeadItem( $geshi ) ); |
| 144 | + $output->addHTML( "<div dir=\"ltr\">{$code}</div>" ); |
| 145 | + return false; |
| 146 | + } |
| 147 | + } |
| 148 | + } |
| 149 | + |
| 150 | + // No GeSHi, or GeSHi can't parse it, use plain <pre> |
| 151 | + $output->addHTML( "<pre class=\"mw-code mw-script\" dir=\"ltr\">\n" ); |
| 152 | + $output->addHTML( htmlspecialchars( $text ) ); |
| 153 | + $output->addHTML( "\n</pre>\n" ); |
| 154 | + return false; |
| 155 | + } else { |
| 156 | + return true; |
| 157 | + } |
| 158 | + } |
| 159 | + |
| 160 | + public static function getCodeLanguage( $title, &$lang ) { |
| 161 | + global $wgScriptingUseCodeEditor; |
| 162 | + if( $wgScriptingUseCodeEditor && $title->getNamespace() == NS_MODULE ) { |
| 163 | + $engine = Scripting::newDefaultEngine(); |
| 164 | + if( $engine->getCodeEditorLanguage() ) { |
| 165 | + $lang = $engine->getCodeEditorLanguage(); |
| 166 | + return false; |
| 167 | + } |
| 168 | + } |
| 169 | + |
| 170 | + return true; |
| 171 | + } |
| 172 | + |
| 173 | + /** |
| 174 | + * Indicates that modules are not wikitext. |
| 175 | + * @param $title Title |
| 176 | + * @param $result |
| 177 | + * @return bool |
| 178 | + */ |
| 179 | + public static function isWikitextPage( $title, &$result ) { |
| 180 | + if( $title->getNamespace() == NS_MODULE ) { |
| 181 | + $result = false; |
| 182 | + return false; |
| 183 | + } |
| 184 | + return true; |
| 185 | + } |
| 186 | + |
| 187 | + /** |
| 188 | + * Adds report of number of evaluations by the single wikitext page. |
| 189 | + * |
| 190 | + * @param $parser Parser |
| 191 | + * @param $report |
| 192 | + * @return bool |
| 193 | + */ |
| 194 | + public static function reportLimits( $parser, &$report ) { |
| 195 | + # FIXME |
| 196 | + global $wgScriptsLimits; |
| 197 | + $engine = Scripting::getParserEngine( $parser ); |
| 198 | + $report .= $engine->getLimitReport(); |
| 199 | + return true; |
| 200 | + } |
| 201 | + |
| 202 | + /** |
| 203 | + * Adds the module namespaces. |
| 204 | + */ |
| 205 | + public static function addCanonicalNamespaces( &$list ) { |
| 206 | + $list[NS_MODULE] = 'Module'; |
| 207 | + $list[NS_MODULE_TALK] = 'Module_talk'; |
| 208 | + return true; |
| 209 | + } |
| 210 | + |
| 211 | + public static function validateScript( $editor, $text, $section, &$error ) { |
| 212 | + global $wgUser; |
| 213 | + $title = $editor->mTitle; |
| 214 | + |
| 215 | + if( $title->getNamespace() == NS_MODULE ) { |
| 216 | + $engine = Scripting::newDefaultEngine(); |
| 217 | + $errors = $engine->validate( $text, $title->getPrefixedDBkey() ); |
| 218 | + if( !$errors ) { |
| 219 | + return true; |
| 220 | + } |
| 221 | + |
| 222 | + $errmsg = wfMsgExt( 'scripting-error', array( 'parsemag' ), array( count( $errors ) ) ); |
| 223 | + if( count( $errors ) == 1 ) { |
| 224 | + $errlines = ': ' . wfEscapeWikiText( $errors[0] ); |
| 225 | + } else { |
| 226 | + $errlines = '* ' . implode( "\n* ", array_map( 'wfEscapeWikiText', $errors ) ); |
| 227 | + } |
| 228 | + $error = <<<HTML |
| 229 | +<div class="errorbox"> |
| 230 | +{$errmsg} |
| 231 | +{$errlines} |
| 232 | +</div> |
| 233 | +<br clear="all" /> |
| 234 | +HTML; |
| 235 | + |
| 236 | + return true; |
| 237 | + } |
| 238 | + |
| 239 | + return true; |
| 240 | + } |
| 241 | +} |
Property changes on: trunk/extensions/Scribunto/common/Hooks.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 242 | + native |
Index: trunk/extensions/Scribunto/common/Common.php |
— | — | @@ -0,0 +1,85 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Generic scripting functions. |
| 6 | + */ |
| 7 | +class Scripting { |
| 8 | + const LOCAL = 'local'; |
| 9 | + |
| 10 | + /** |
| 11 | + * Create a new engine object with specified parameters. |
| 12 | + */ |
| 13 | + public static function newEngine( $options ) { |
| 14 | + $class = $options['class']; |
| 15 | + return new $class( $options ); |
| 16 | + } |
| 17 | + |
| 18 | + /** |
| 19 | + * Create a new engine object with default parameters |
| 20 | + * @param $extraOptions Extra options to pass to the constructor, in addition to the configured options |
| 21 | + */ |
| 22 | + public static function newDefaultEngine( $extraOptions = array() ) { |
| 23 | + global $wgScriptingDefaultEngine, $wgScriptingEngineConf; |
| 24 | + if( !$wgScriptingDefaultEngine ) { |
| 25 | + throw new MWException( 'Scripting extension is enabled but $wgScriptingDefaultEngine is not set' ); |
| 26 | + } |
| 27 | + |
| 28 | + if( !isset( $wgScriptingEngineConf[$wgScriptingDefaultEngine] ) ) { |
| 29 | + throw new MWException( 'Invalid scripting engine is specified in $wgScriptingDefaultEngine' ); |
| 30 | + } |
| 31 | + $options = $extraOptions + $wgScriptingEngineConf[$wgScriptingDefaultEngine]; |
| 32 | + return self::newEngine( $options ); |
| 33 | + } |
| 34 | + |
| 35 | + /** |
| 36 | + * Get an engine instance for the given parser, and cache it in the parser |
| 37 | + * so that subsequent calls to this function for the same parser will return |
| 38 | + * the same engine. |
| 39 | + * |
| 40 | + * @param Parser $parser |
| 41 | + */ |
| 42 | + public static function getParserEngine( $parser ) { |
| 43 | + if( !isset( $parser->scripting_engine ) || !$parser->scripting_engine ) { |
| 44 | + $parser->scripting_engine = self::newDefaultEngine( array( 'parser' => $parser ) ); |
| 45 | + } |
| 46 | + return $parser->scripting_engine; |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * Remove the current engine instance from the parser |
| 51 | + */ |
| 52 | + public static function resetParserEngine( $parser ) { |
| 53 | + $parser->scripting_engine = null; |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +/** |
| 58 | + * An exception class which represents an error in the script. This does not |
| 59 | + * normally abort the request, instead it is caught and shown to the user. |
| 60 | + */ |
| 61 | +class ScriptingException extends MWException { |
| 62 | + var $messageName, $params; |
| 63 | + |
| 64 | + function __construct( $messageName, $params = array() ) { |
| 65 | + if ( isset( $params['args'] ) ) { |
| 66 | + $args = $params['args']; |
| 67 | + } else { |
| 68 | + $args = array(); |
| 69 | + } |
| 70 | + if ( isset( $params['module'] ) && isset( $params['line'] ) ) { |
| 71 | + $codelocation = wfMsg( 'scripting-codelocation', $params['module'], $params['line'] ); |
| 72 | + } else { |
| 73 | + $codelocation = '[UNKNOWN]'; // should never happen |
| 74 | + } |
| 75 | + array_unshift( $args, $codelocation ); |
| 76 | + $msg = wfMsgExt( $messageName, array(), $args ); |
| 77 | + parent::__construct( $msg ); |
| 78 | + |
| 79 | + $this->messageName = $messageName; |
| 80 | + $this->params = $params; |
| 81 | + } |
| 82 | + |
| 83 | + public function getMessageName() { |
| 84 | + return $this->messageName; |
| 85 | + } |
| 86 | +} |
Property changes on: trunk/extensions/Scribunto/common/Common.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 87 | + native |
Index: trunk/extensions/Scribunto/engines/LuaSandbox/Engine.php |
— | — | @@ -0,0 +1,149 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +class LuaSandboxEngine extends ScriptingEngineBase { |
| 5 | + public $sandbox, $options, $loaded = false; |
| 6 | + |
| 7 | + public function newModule( $text, $chunkName ) { |
| 8 | + return new LuaSandboxEngineModule( $this, $text, $chunkName ); |
| 9 | + } |
| 10 | + |
| 11 | + public function load() { |
| 12 | + if( $this->loaded ) { |
| 13 | + return; |
| 14 | + } |
| 15 | + |
| 16 | + if( !MWInit::classExists( 'luasandbox' ) ) { |
| 17 | + throw new MWException( 'luasandbox PHP extension is not installed' ); |
| 18 | + } |
| 19 | + |
| 20 | + $this->sandbox = new LuaSandbox; |
| 21 | + $this->sandbox->setMemoryLimit( $this->options['memoryLimit'] ); |
| 22 | + $this->sandbox->setCPULimit( $this->options['cpuLimit'] ); |
| 23 | + $this->sandbox->registerLibrary( 'mw', array( 'import' => array( $this, 'importModule' ) ) ); |
| 24 | + |
| 25 | + $this->loaded = true; |
| 26 | + } |
| 27 | + |
| 28 | + protected function getModuleClassName() { |
| 29 | + return 'LuaSandboxEngineModule'; |
| 30 | + } |
| 31 | + |
| 32 | + public function getGeSHiLanguage() { |
| 33 | + return 'lua'; |
| 34 | + } |
| 35 | + |
| 36 | + public function getCodeEditorLanguage() { |
| 37 | + return 'lua'; |
| 38 | + } |
| 39 | + |
| 40 | + public function getLimitReport() { |
| 41 | + $this->load(); |
| 42 | + |
| 43 | + $usage = $this->sandbox->getMemoryUsage(); |
| 44 | + if( $usage < 8 * 1024 ) { |
| 45 | + $usageStr = $usage . " bytes"; |
| 46 | + } elseif( $usage < 8 * 1024 * 1024 ) { |
| 47 | + $usageStr = round( $usage / 1024, 2 ) . " kilobytes"; |
| 48 | + } else { |
| 49 | + $usageStr = round( $usage / 1024 / 1024, 2 ) . " megabytes"; |
| 50 | + } |
| 51 | + |
| 52 | + return "Lua scripts memory usage: {$usageStr}\n"; |
| 53 | + } |
| 54 | + |
| 55 | + function importModule() { |
| 56 | + $args = func_get_args(); |
| 57 | + if( count( $args ) < 1 ) { |
| 58 | + // FIXME: LuaSandbox PHP extension should provide proper context |
| 59 | + throw new ScriptingException( 'scripting-common-toofewargs', |
| 60 | + array( 'args' => array( 'mw.import' ) ) ); |
| 61 | + } |
| 62 | + |
| 63 | + $title = Title::makeTitleSafe( NS_MODULE, $args[0] ); |
| 64 | + if ( !$title ) { |
| 65 | + throw new ScriptingException( 'scripting-common-nosuchmodule' ); |
| 66 | + } |
| 67 | + $module = $this->fetchModuleFromParser( $title ); |
| 68 | + return $module->getContents(); |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +class LuaSandboxEngineModule extends ScriptingModuleBase { |
| 73 | + protected $initialized; |
| 74 | + |
| 75 | + function initialize() { |
| 76 | + if( $this->initialized ) { |
| 77 | + return; |
| 78 | + } |
| 79 | + $this->engine->load(); |
| 80 | + |
| 81 | + // FIXME: caching? |
| 82 | + |
| 83 | + try { |
| 84 | + $this->body = $this->engine->sandbox->loadString( |
| 85 | + $this->code, |
| 86 | + // Prepending an "@" to the chunk name makes Lua think it is a file name |
| 87 | + '@' . $this->chunkName ); |
| 88 | + $output = $this->body->call(); |
| 89 | + } catch( LuaSandboxError $e ) { |
| 90 | + throw new ScriptingException( 'scripting-luasandbox-error', |
| 91 | + array( 'args' => array( $e->getMessage() ) ) ); |
| 92 | + } |
| 93 | + |
| 94 | + if( !$output ) { |
| 95 | + throw new ScriptingException( 'scripting-luasandbox-noreturn' ); |
| 96 | + } |
| 97 | + if( count( $output ) > 2 ) { |
| 98 | + throw new ScriptingException( 'scripting-luasandbox-toomanyreturns' ); |
| 99 | + } |
| 100 | + if( !is_array( $output[0] ) ) { |
| 101 | + throw new ScriptingException( 'scripting-luasandbox-notarrayreturn' ); |
| 102 | + } |
| 103 | + |
| 104 | + $this->contents = $output[0]; |
| 105 | + $this->functions = array(); |
| 106 | + foreach( $this->contents as $key => $content ) { |
| 107 | + if( $content instanceof LuaSandboxFunction ) |
| 108 | + $this->functions[] = $key; |
| 109 | + } |
| 110 | + |
| 111 | + $this->initialized = true; |
| 112 | + } |
| 113 | + |
| 114 | + function getFunction( $name ) { |
| 115 | + $this->initialize(); |
| 116 | + |
| 117 | + if( isset( $this->contents[$name] ) ) { |
| 118 | + return new LuaSandboxEngineFunction( $this, $name, $this->contents[$name] ); |
| 119 | + } else { |
| 120 | + return null; |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + function getFunctions() { |
| 125 | + $this->initialize(); |
| 126 | + return $this->functions; |
| 127 | + } |
| 128 | + |
| 129 | + function getContents() { |
| 130 | + $this->initialize(); |
| 131 | + return $this->contents; |
| 132 | + } |
| 133 | +} |
| 134 | + |
| 135 | +class LuaSandboxEngineFunction extends ScriptingFunctionBase { |
| 136 | + public function call( $args, $frame ) { |
| 137 | + try { |
| 138 | + $result = call_user_func_array( array( $this->contents, 'call' ), $args ); |
| 139 | + } catch( LuaSandboxError $e ) { |
| 140 | + throw new ScriptingException( 'scripting-luasandbox-error', |
| 141 | + array( 'args' => array( $e->getMessage() ) ) ); |
| 142 | + } |
| 143 | + |
| 144 | + if ( isset( $result[0] ) ) { |
| 145 | + return $result[0]; |
| 146 | + } else { |
| 147 | + return null; |
| 148 | + } |
| 149 | + } |
| 150 | +} |
Property changes on: trunk/extensions/Scribunto/engines/LuaSandbox/Engine.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 151 | + native |