1<?php 2 3/** 4 * Wikitext scripting infrastructure for MediaWiki: base classes. 5 * Copyright (C) 2012 Victor Vasiliev <vasilvv@gmail.com> et al 6 * https://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 * Base class for all script engines. Includes all code 26 * not related to particular modules, like tracking links between 27 * modules or loading module texts. 28 */ 29abstract class ScribuntoEngineBase { 30 31 // Flags for ScribuntoEngineBase::getResourceUsage() 32 public const CPU_SECONDS = 1; 33 public const MEM_PEAK_BYTES = 2; 34 35 /** 36 * @var Title|null 37 */ 38 protected $title; 39 40 /** 41 * @var array 42 */ 43 protected $options; 44 45 /** 46 * @var (ScribuntoModuleBase|null)[] 47 */ 48 protected $modules = []; 49 50 /** 51 * @var Parser|null 52 */ 53 protected $parser; 54 55 /** 56 * Creates a new module object within this engine 57 * 58 * @param string $text 59 * @param string|bool $chunkName 60 * @return ScribuntoModuleBase 61 */ 62 abstract protected function newModule( $text, $chunkName ); 63 64 /** 65 * Run an interactive console request 66 * 67 * @param array $params Associative array. Options are: 68 * - title: The title object for the module being debugged 69 * - content: The text content of the module 70 * - prevQuestions: An array of previous "questions" used to establish the state 71 * - question: The current "question", a string script 72 * 73 * @return array containing: 74 * - print: The resulting print buffer 75 * - return: The resulting return value 76 */ 77 abstract public function runConsole( array $params ); 78 79 /** 80 * Get software information for Special:Version 81 * @param array &$software 82 */ 83 abstract public function getSoftwareInfo( array &$software ); 84 85 /** 86 * @param array $options Associative array of options: 87 * - parser: A Parser object 88 */ 89 public function __construct( array $options ) { 90 $this->options = $options; 91 if ( isset( $options['parser'] ) ) { 92 $this->parser = $options['parser']; 93 } 94 if ( isset( $options['title'] ) ) { 95 $this->title = $options['title']; 96 } 97 } 98 99 public function __destruct() { 100 $this->destroy(); 101 } 102 103 public function destroy() { 104 // Break reference cycles 105 $this->parser = null; 106 $this->title = null; 107 $this->modules = []; 108 } 109 110 /** 111 * @param Title $title 112 */ 113 public function setTitle( $title ) { 114 $this->title = $title; 115 } 116 117 /** 118 * @return Title 119 */ 120 public function getTitle() { 121 return $this->title; 122 } 123 124 /** 125 * Get an element from the configuration array 126 * 127 * @param string $optionName 128 * @return mixed 129 */ 130 public function getOption( $optionName ) { 131 return $this->options[$optionName] ?? null; 132 } 133 134 /** 135 * @param string $message 136 * @param array $params 137 * @return ScribuntoException 138 */ 139 public function newException( $message, array $params = [] ) { 140 return new ScribuntoException( $message, $this->getDefaultExceptionParams() + $params ); 141 } 142 143 /** 144 * @return array 145 */ 146 public function getDefaultExceptionParams() { 147 $params = []; 148 if ( $this->title ) { 149 $params['title'] = $this->title; 150 } 151 return $params; 152 } 153 154 /** 155 * Load a module from some parser-defined template loading mechanism and 156 * register a parser output dependency. 157 * 158 * Does not initialize the module, i.e. do not expect it to complain if the module 159 * text is garbage or has syntax error. Returns a module or null if it doesn't exist. 160 * 161 * @param Title $title The title of the module 162 * @return ScribuntoModuleBase|null 163 */ 164 public function fetchModuleFromParser( Title $title ) { 165 $key = $title->getPrefixedDBkey(); 166 if ( !array_key_exists( $key, $this->modules ) ) { 167 list( $text, $finalTitle ) = $this->parser->fetchTemplateAndTitle( $title ); 168 if ( $text === false ) { 169 $this->modules[$key] = null; 170 return null; 171 } 172 173 $finalKey = $finalTitle->getPrefixedDBkey(); 174 if ( !isset( $this->modules[$finalKey] ) ) { 175 $this->modules[$finalKey] = $this->newModule( $text, $finalKey ); 176 } 177 // Almost certainly $key === $finalKey, but just in case... 178 $this->modules[$key] = $this->modules[$finalKey]; 179 } 180 return $this->modules[$key]; 181 } 182 183 /** 184 * Validates the script and returns a Status object containing the syntax 185 * errors for the given code. 186 * 187 * @param string $text 188 * @param string|bool $chunkName 189 * @return Status 190 */ 191 public function validate( $text, $chunkName = false ) { 192 $module = $this->newModule( $text, $chunkName ); 193 return $module->validate(); 194 } 195 196 /** 197 * Get CPU and memory usage information, if the script engine 198 * provides it. 199 * 200 * If the script engine is capable of reporting CPU and memory usage 201 * data, it should override this implementation. 202 * 203 * @param int $resource One of ScribuntoEngineBase::CPU_SECONDS 204 * or ScribuntoEngineBase::MEM_PEAK_BYTES. 205 * @return float|int|false Resource usage for the specified resource 206 * or false if not available. 207 */ 208 public function getResourceUsage( $resource ) { 209 return false; 210 } 211 212 /** 213 * Get the language for GeSHi syntax highlighter. 214 * @return string|false 215 */ 216 public function getGeSHiLanguage() { 217 return false; 218 } 219 220 /** 221 * Get the language for Ace code editor. 222 * @return string|false 223 */ 224 public function getCodeEditorLanguage() { 225 return false; 226 } 227 228 /** 229 * @return Parser 230 */ 231 public function getParser() { 232 return $this->parser; 233 } 234 235 /** 236 * Load a list of all libraries supported by this engine 237 * 238 * The return value is an array with keys being the library name seen by 239 * the module and values being either a PHP class name or an array with the 240 * following elements: 241 * - class: (string) Class to load (required) 242 * - deferLoad: (bool) Library should not be loaded at startup; modules 243 * needing the library must request it (e.g. via 'require' in Lua) 244 * 245 * @param string $engine script engine we're using (eg: lua) 246 * @param array $coreLibraries Array of core libraries we support 247 * @return array 248 */ 249 protected function getLibraries( $engine, array $coreLibraries = [] ) { 250 $extraLibraries = []; 251 Hooks::run( 'ScribuntoExternalLibraries', [ $engine, &$extraLibraries ] ); 252 return $coreLibraries + $extraLibraries; 253 } 254 255 /** 256 * Load a list of all paths libraries can be in for this engine 257 * 258 * @param string $engine script engine we're using (eg: lua) 259 * @param array $coreLibraryPaths Array of library paths to use by default 260 * @return array 261 */ 262 protected function getLibraryPaths( $engine, array $coreLibraryPaths = [] ) { 263 $extraLibraryPaths = []; 264 Hooks::run( 'ScribuntoExternalLibraryPaths', [ $engine, &$extraLibraryPaths ] ); 265 return array_merge( $coreLibraryPaths, $extraLibraryPaths ); 266 } 267 268 /** 269 * Add limit report data to a ParserOutput object 270 * 271 * @param ParserOutput $output ParserOutput object in which to add limit data 272 */ 273 public function reportLimitData( ParserOutput $output ) { 274 } 275 276 /** 277 * Format limit report data 278 * 279 * @param string $key 280 * @param mixed &$value 281 * @param string &$report 282 * @param bool $isHTML 283 * @param bool $localize 284 * @return bool 285 */ 286 public function formatLimitData( $key, &$value, &$report, $isHTML, $localize ) { 287 return true; 288 } 289} 290